+++ /dev/null
-project(juk)
-set( CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake )
-find_package( KDE4 REQUIRED )
-include( KDE4Defaults )
-include( MacroLibrary )
-include( CheckIncludeFileCXX )
-
-find_package( Taglib 1.6 )
-
-include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} )
-
-add_subdirectory( tests )
-add_subdirectory( pics )
-
-macro_optional_find_package(TunePimp)
-macro_log_feature(TUNEPIMP_FOUND "TunePimp" "A library for developing MusicBrainz enabled tagging applications" "http://www.musicbrainz.org/products/tunepimp" FALSE "" "Provides MusicBrainz tagging in Juk.")
-if(TUNEPIMP_FOUND)
- set(HAVE_TUNEPIMP 1)
- if(TUNEPIMP_FOUND_VERSION_4)
- set(HAVE_TUNEPIMP 4)
- endif(TUNEPIMP_FOUND_VERSION_4)
- if(TUNEPIMP_FOUND_VERSION_5)
- set(HAVE_TUNEPIMP 5)
- endif(TUNEPIMP_FOUND_VERSION_5)
-else(TUNEPIMP_FOUND)
- set(HAVE_TUNEPIMP 0)
-endif(TUNEPIMP_FOUND)
-
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
-
-########### next target ###############
-
-include_directories( ${TAGLIB_INCLUDES} )
-add_definitions(-DQT3_SUPPORT -DQT3_SUPPORT_WARNINGS -DQT_STL)
-
-# Look for Ogg Opus support in taglib (not released yet)
-macro_push_required_vars()
-set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${TAGLIB_INCLUDES})
-check_include_file_cxx(opusfile.h TAGLIB_HAS_OPUSFILE)
-macro_pop_required_vars()
-
-configure_file (config-juk.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-juk.h )
-
-set(tunepimp_SRCS)
-if(TUNEPIMP_FOUND)
- set(tunepimp_SRCS trackpickerdialog.cpp)
- include_directories( ${TUNEPIMP_INCLUDE_DIR} )
-endif(TUNEPIMP_FOUND)
-
-set(juk_SRCS ${tunepimp_SRCS}
- advancedsearchdialog.cpp
- slider.cpp
- svghandler.cpp
- volumepopupbutton.cpp
- actioncollection.cpp
- cache.cpp
- categoryreaderinterface.cpp
- collectionlist.cpp
- coverdialog.cpp
- covericonview.cpp
- coverinfo.cpp
- covermanager.cpp
- coverproxy.cpp
- dbuscollectionproxy.cpp
- deletedialog.cpp
- directorylist.cpp
- dynamicplaylist.cpp
- exampleoptions.cpp
- folderplaylist.cpp
- filehandle.cpp
- filerenamer.cpp
- filerenameroptions.cpp
- filerenamerconfigdlg.cpp
- webimagefetcher.cpp
- historyplaylist.cpp
- juk.cpp
- k3bexporter.cpp
- keydialog.cpp
- lyricswidget.cpp
- main.cpp
- mediafiles.cpp
- mpris2/mediaplayer2.cpp
- mpris2/mediaplayer2player.cpp
- mpris2/mpris2.cpp
- musicbrainzquery.cpp
- nowplaying.cpp
- playermanager.cpp
- playlist.cpp
- playlistbox.cpp
- playlistcollection.cpp
- playlistexporter.cpp
- playlistinterface.cpp
- playlistitem.cpp
- playlistsearch.cpp
- playlistsplitter.cpp
- scrobbler.cpp
- scrobbleconfigdlg.cpp
- searchplaylist.cpp
- searchwidget.cpp
- slideraction.cpp
- sortedstringlist.cpp
- splashscreen.cpp
- statuslabel.cpp
- stringshare.cpp
- systemtray.cpp
- tag.cpp
- tageditor.cpp
- tagguesser.cpp
- tagguesserconfigdlg.cpp
- tagrenameroptions.cpp
- tagtransactionmanager.cpp
- tracksequenceiterator.cpp
- tracksequencemanager.cpp
- treeviewitemplaylist.cpp
- upcomingplaylist.cpp
- ktrm.cpp
- viewmode.cpp )
-
-qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.collection.xml
- dbuscollectionproxy.h DBusCollectionProxy )
-qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.player.xml playermanager.h PlayerManager)
-qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.search.xml searchwidget.h SearchWidget)
-
-
-kde4_add_ui_files(juk_SRCS
- filerenamerbase.ui
- filerenameroptionsbase.ui
- directorylistbase.ui
- trackpickerdialogbase.ui
- tagguesserconfigdlgwidget.ui
- exampleoptionsbase.ui
- coverdialogbase.ui
- deletedialogbase.ui
- tageditor.ui
-)
-
-kde4_add_app_icon(juk_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/hi*-app-juk.png")
-kde4_add_executable(juk ${juk_SRCS})
-
-if(NOT MSVC AND NOT ( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) )
- set( LIBMATH m )
-endif(NOT MSVC AND NOT ( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) )
-
-target_link_libraries(juk ${LIBMATH} ${KDE4_KHTML_LIBS} ${TAGLIB_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBS} ${KDE4_PHONON_LIBS})
-if(TUNEPIMP_FOUND)
- target_link_libraries(juk ${TUNEPIMP_LIBRARIES})
-endif(TUNEPIMP_FOUND)
-
-
-install(TARGETS juk ${INSTALL_TARGETS_DEFAULT_ARGS} )
-
-
-########### install files ###############
-
-install( PROGRAMS juk.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
-install( FILES juk.notifyrc jukui.rc jukui-rtl.rc DESTINATION ${DATA_INSTALL_DIR}/juk )
-install( FILES juk.appdata.xml DESTINATION ${SHARE_INSTALL_PREFIX}/appdata )
-install( FILES jukservicemenu.desktop DESTINATION
-${SERVICES_INSTALL_DIR}/ServiceMenus )
-install( FILES org.kde.juk.collection.xml org.kde.juk.player.xml org.kde.juk.search.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
-
-kde4_install_icons( ${ICON_INSTALL_DIR} )
+++ /dev/null
- 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
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+++ /dev/null
-Since I tend to be one of the more pedantic people on coding style I'll provide
-a bit of a reference here. Please take a few minutes to read this as it will
-save us both time when processing patches.
-
-================================================================================
-Indentation
-================================================================================
-
-Older versions of JuK had two different indenting schemes. Now all JuK source
-code files simply use 4 spaces at all levels. In most cases the style of the
-file currently being worked in should be followed. So:
-
-static void foo()
-{
- if(bar()) // <-- 4 spaces
- baz() // <-- 8 spaces
-}
-
-================================================================================
-Braces
-================================================================================
-
-Braces opening classes, structs, namespaces and functions should be on their own
-line. Braces opening conditionals should be on the same line with one notable
-exception: if the conditional is split up onto several lines then the opening
-brace should be on its own line. i.e.
-
-class Foo
-{
- // stuff
-};
-
-if(foo == bar) {
- // stuff
-}
-
-while(foo == bar &&
- baz == quux &&
- flop == pop)
-{
- // stuff
-}
-
-static void foo()
-{
- // stuff
-}
-
-Other exceptions include inline functions that are just returning or setting a
-value. However multiple statements should not ever be combined onto one line:
-
-class Foo
-{
-public:
- String value() const { return m_value; }
-};
-
-Also conditionals / loops that only contiain one line in their body (but where
-the conditional statement fits onto one line) should omit braces:
-
-if(foo == bar)
- baz();
-
-But:
-
-if(baz == quux &&
- ralf == spot)
-{
- bar();
-}
-
-================================================================================
-Spaces
-================================================================================
-
-Spaces should not be used between the conditional / loop type and the
-conditional statement. They should also not be used after parenthesis. However
-the should be to mark of mathematical or comparative operators.
-
-if ( foo == bar )
- ^ ^ ^
-
-The marked spaces should be ommitted to produce:
-
-if(foo == bar)
-
-================================================================================
-Header Organization
-================================================================================
-
-Member variables should always be private and prefixed with "m_". Accessors may
-be inline in the headers. The organization of the members in a class should be
-roughly as follows:
-
-public:
-public slots:
-protected:
-protected slots:
-signals:
-private: // member funtions
-private slots:
-private: // member variables
-
-If there are no private slots there is no need for two private sections, however
-private functions and private variables should be clearly separated.
-
-The implementations files -- .cpp files -- should follow (when possible) the
-same order of function declarations as the header files.
-
-Virtual functions should always be marked as such even in derrived classes where
-it is not strictly necessary.
-
-Header guards should be of the form FILENAME_H, as below (for an example file
-foo.h:
-
-/* copyright/license stuff
- * blah
- */
-
-#ifndef FOO_H
-#define FOO_H
-
-#include <qt stuff>
-
-// classes
-
-#endif
-
-// vim modeline (see below)
-
-================================================================================
-Whitespace
-================================================================================
-
-Whitespace should be used liberally. When blocks of code are logically distinct
-I tend to put a blank line between them. This is difficult to explain
-systematically but after looking a bit at the current code organization this
-ideally will be somewhat clear.
-
-Also I tend to separate comments by blank lines on both sides.
-
-================================================================================
-Pointer and Reference Operators
-================================================================================
-
-This one is pretty simple. I prefer "Foo *f" to "Foo* f" in function signatures
-and declarations. The same goes for "Foo &f" over "Foo& f".
-
-================================================================================
-Editor Support
-================================================================================
-
-Most JuK files that Michael Pyne has touched will eventually have a vim modeline
-at the bottom of the file (after any moc #includes). The current vim modeline
-is the following:
-
-// vim: set et sw=4 tw=0 sta:
-
-The vim: ... : part encloses the commands to automatically use when opening the
-file in vim. The following commands are set:
- et : Uses spaces instead of the <TAB> when the Tab key is pressed. No
- JuK source should have tab characters anymore, this helps enforce
- that. Full name is expandtab.
- sw = 4 : Makes indenting levels 4 spaces wide, for use with the vim indenting
- features. Full name is shiftwidth.
- tw = 0 : Prevents vim from wrapping lines as you are typing. Full name is
- textwidth.
- sta : Use shiftwidth to determine tab size at the beginning of the line,
- instead of tabstop (which is normally 8 spaces wide). Full name is
- smarttab.
-
-Also, vim users will want to have the command "let c_space_errors=1" in their
-.vimrc in order to flag extra whitespace at the end of lines, which is also a
-no-no in source code.
-
-There are vim and emacs scripts for KDE developers in kdesdk/scripts, you may
-also want to see what is available there.
-
-================================================================================
-
-There are likely things missing here and I'll try to add them over time as I
-notice things that are often missed. Please let me know if specific points are
-ambiguous.
-
-Scott Wheeler <wheeler@kde.org>
+++ /dev/null
-#! /bin/sh
-$EXTRACTRC *.rc *.ui >> rc.cpp || exit 11
-$XGETTEXT *.rc *.cpp *.h -o $podir/juk.pot
+++ /dev/null
-Just a quick 3.4 checklist. I'll add things as they pop into my mind...
-
-( ) Make the upcoming playlist not suck, specifically I'd like to see it as a
- real and usable replacement for the "Play Next" feature, which it
- presently is not.
-
-( ) At least play with making the "Now Playing" bar resizable. Currently have
- something sort of working putting it in a slider type of thing. Not sure
- if I like it.
-
-( ) Fix the cover manager in lots of ways. I really don't like having the icon
- in the listview and have played around with a few things to fix this. What
- I'm currently thinking is making a "cover manager" as a view mode and when
- the user clicks to set the cover switching to that mode. Or something like
- that. Something's got to give.
-
-( ) Show a preview of the cover to be added before saving it.
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "actioncollection.h"
-#include "juk.h"
-
-#include <kactioncollection.h>
-#include <kdebug.h>
-
-namespace ActionCollection
-{
- KActionCollection *actions()
- {
- // Use KXMLGUIClient::actionCollection() (class JuK derives from
- // KXMLGUIClient) to construct the KActionCollection.
- // This makes sure that KActionCollection::parentGUIClient() is not
- // NULL and prevents the application from crashing when adding an
- // item to a toolbar using RMB (see bug #258641).
- // XXX This should not just be:
- // return JuK::JuKInstance()->actionCollection();
- // as actions() may be called while within JuK's dtor, in which case
- // JuKInstance()->... would result to a crash.
- static KActionCollection *a = JuK::JuKInstance()->actionCollection();
- // The widget of the action collection is set in Juk::setupActions().
- return a;
- }
-
- QAction *action(const QString &key)
- {
-#ifndef NO_DEBUG
- QAction *a = actions()->action(key);
- if(!a)
- kWarning() << "KAction \"" << key << "\" is not defined yet.";
- return a;
-#else
- return actions()->action(key);
-#endif
- }
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ACTIONCOLLECTION_H
-#define ACTIONCOLLECTION_H
-
-class KActionCollection;
-class QAction;
-class QString;
-
-namespace ActionCollection
-{
- /**
- * The global action collection for JuK.
- */
- KActionCollection *actions();
-
- /**
- * Returns the action for the associated key from the global action
- * collection.
- */
- QAction *action(const QString &key);
-
- /**
- * Returns the action for the associated key but includes a cast to the
- * type \a T. i.e. KSelectAction *a = action<KSelectAction>("chooser");
- */
- template <class T> T *action(const QString &key)
- {
- return dynamic_cast<T *>(action(key));
- }
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "advancedsearchdialog.h"
-
-#include <kcombobox.h>
-#include <klineedit.h>
-#include <kpushbutton.h>
-#include <klocale.h>
-#include <kvbox.h>
-
-#include <QRadioButton>
-#include <QLabel>
-#include <QHBoxLayout>
-#include <QVBoxLayout>
-#include <QGroupBox>
-
-#include "collectionlist.h"
-#include "searchwidget.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-AdvancedSearchDialog::AdvancedSearchDialog(const QString &defaultName,
- const PlaylistSearch &defaultSearch,
- QWidget *parent,
- const char *name) :
- KDialog(parent)
-{
- setCaption( i18n("Create Search Playlist") );
- setButtons( Ok|Cancel );
- setDefaultButton( Ok );
- setObjectName( QLatin1String( name ) );
- setModal(true);
-
- KVBox *mw = new KVBox(this);
- setMainWidget(mw);
-
- KHBox *box = new KHBox(mw);
- box->setSpacing(5);
-
- new QLabel(i18n("Playlist name:"), box);
- m_playlistNameLineEdit = new KLineEdit(defaultName, box);
-
- QGroupBox *criteriaGroupBox = new QGroupBox(i18n("Search Criteria"), mw);
- mw->setStretchFactor(criteriaGroupBox, 1);
-
- m_criteriaLayout = new QVBoxLayout;
-
- QGroupBox *group = new QGroupBox();
-
- m_matchAnyButton = new QRadioButton(i18n("Match any of the following"));
- m_matchAllButton = new QRadioButton(i18n("Match all of the following"));
-
- QHBoxLayout *hgroupbox = new QHBoxLayout;
- hgroupbox->addWidget(m_matchAnyButton);
- hgroupbox->addWidget(m_matchAllButton);
-
- group->setLayout(hgroupbox);
-
- m_criteriaLayout->addWidget(group);
-
- if(defaultSearch.isNull()) {
- SearchLine *newSearchLine = new SearchLine(this);
- m_searchLines.append(newSearchLine);
- m_criteriaLayout->addWidget(newSearchLine);
- newSearchLine = new SearchLine(this);
- m_searchLines.append(newSearchLine);
- m_criteriaLayout->addWidget(newSearchLine);
- m_matchAnyButton->setChecked(true);
- }
- else {
- PlaylistSearch::ComponentList components = defaultSearch.components();
- for(PlaylistSearch::ComponentList::ConstIterator it = components.constBegin();
- it != components.constEnd();
- ++it)
- {
- SearchLine *s = new SearchLine(this);
- s->setSearchComponent(*it);
- m_searchLines.append(s);
- m_criteriaLayout->addWidget(s);
- }
- if(defaultSearch.searchMode() == PlaylistSearch::MatchAny)
- m_matchAnyButton->setChecked(true);
- else
- m_matchAllButton->setChecked(true);
- }
-
- QWidget *buttons = new QWidget(mw);
- QHBoxLayout *l = new QHBoxLayout(buttons);
- l->setSpacing(5);
- l->setMargin(0);
-
- KPushButton *clearButton = new KPushButton(KStandardGuiItem::clear(), buttons);
- connect(clearButton, SIGNAL(clicked()), SLOT(clear()));
- l->addWidget(clearButton);
-
- l->addStretch(1);
-
- m_moreButton = new KPushButton(i18nc("additional search options", "More"), buttons);
- connect(m_moreButton, SIGNAL(clicked()), SLOT(more()));
- l->addWidget(m_moreButton);
-
- m_fewerButton = new KPushButton(i18n("Fewer"), buttons);
- connect(m_fewerButton, SIGNAL(clicked()), SLOT(fewer()));
- l->addWidget(m_fewerButton);
-
- m_criteriaLayout->addStretch(1);
-
- criteriaGroupBox->setLayout(m_criteriaLayout);
-
- m_playlistNameLineEdit->setFocus();
-}
-
-AdvancedSearchDialog::~AdvancedSearchDialog()
-{
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-AdvancedSearchDialog::Result AdvancedSearchDialog::exec()
-{
- Result r;
- r.result = DialogCode(KDialog::exec());
- r.search = m_search;
- r.playlistName = m_playlistName;
- return r;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected slots
-////////////////////////////////////////////////////////////////////////////////
-
-void AdvancedSearchDialog::accept()
-{
- m_search.clearPlaylists();
- m_search.clearComponents();
-
- m_search.addPlaylist(CollectionList::instance());
-
- QList<SearchLine *>::const_iterator it = m_searchLines.constBegin();
- for(; it != m_searchLines.constEnd(); ++it)
- m_search.addComponent((*it)->searchComponent());
-
- PlaylistSearch::SearchMode m = PlaylistSearch::SearchMode(!m_matchAnyButton->isChecked());
- m_search.setSearchMode(m);
-
- m_playlistName = m_playlistNameLineEdit->text();
-
- KDialog::accept();
-}
-
-void AdvancedSearchDialog::clear()
-{
- QList<SearchLine *>::const_iterator it = m_searchLines.constBegin();
- for(; it != m_searchLines.constEnd(); ++it)
- (*it)->clear();
-}
-
-void AdvancedSearchDialog::more()
-{
- SearchLine *searchLine = new SearchLine(this);
- m_criteriaLayout->addWidget(searchLine);
- m_searchLines.append(searchLine);
- searchLine->show();
- updateButtons();
-}
-
-void AdvancedSearchDialog::fewer()
-{
- SearchLine *searchLine = m_searchLines.last();
- m_searchLines.removeAll(searchLine);
- delete searchLine;
- updateButtons();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void AdvancedSearchDialog::updateButtons()
-{
- m_moreButton->setEnabled(m_searchLines.count() < 16);
- m_fewerButton->setEnabled(m_searchLines.count() > 1);
-}
-
-#include "advancedsearchdialog.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ADVANCEDSEARCHDIALOG_H
-#define ADVANCEDSEARCHDIALOG_H
-
-#include <kdialog.h>
-#include <QList>
-
-#include "playlistsearch.h"
-
-class KLineEdit;
-class KPushButton;
-class QRadioButton;
-class SearchLine;
-class QBoxLayout;
-
-class AdvancedSearchDialog : public KDialog
-{
- Q_OBJECT
-
-public:
- struct Result
- {
- DialogCode result;
- PlaylistSearch search;
- QString playlistName;
- };
-
- explicit AdvancedSearchDialog(const QString &defaultName,
- const PlaylistSearch &defaultSearch = PlaylistSearch(),
- QWidget *parent = 0,
- const char *name = 0);
-
- virtual ~AdvancedSearchDialog();
-
-public slots:
- Result exec();
-
-protected slots:
- virtual void accept();
- virtual void clear();
- virtual void more();
- virtual void fewer();
-
-private:
- void updateButtons();
-
- QBoxLayout *m_criteriaLayout;
- PlaylistSearch m_search;
- QString m_playlistName;
- QList<SearchLine *> m_searchLines;
- KLineEdit *m_playlistNameLineEdit;
- QRadioButton *m_matchAnyButton;
- QRadioButton *m_matchAllButton;
- KPushButton *m_moreButton;
- KPushButton *m_fewerButton;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2008, 2013 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "cache.h"
-#include "juk-exception.h"
-
-#include <kstandarddirs.h>
-#include <ksavefile.h>
-#include <kmessagebox.h>
-#include <kconfig.h>
-#include <klocale.h>
-#include <kdebug.h>
-#include <ktoggleaction.h>
-
-#include <QDir>
-#include <QBuffer>
-
-#include "tag.h"
-#include "searchplaylist.h"
-#include "historyplaylist.h"
-#include "upcomingplaylist.h"
-#include "folderplaylist.h"
-#include "playlistcollection.h"
-#include "actioncollection.h"
-
-using namespace ActionCollection;
-
-const int Cache::playlistListCacheVersion = 3;
-const int Cache::playlistItemsCacheVersion = 2;
-
-enum PlaylistType
-{
- Normal = 0,
- Search = 1,
- History = 2,
- Upcoming = 3,
- Folder = 4
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-Cache *Cache::instance()
-{
- static Cache cache;
- return &cache;
-}
-
-void Cache::loadPlaylists(PlaylistCollection *collection) // static
-{
- QString playlistsFile = KGlobal::dirs()->saveLocation("appdata") + "playlists";
-
- QFile f(playlistsFile);
-
- if(!f.open(QIODevice::ReadOnly))
- return;
-
- QDataStream fs(&f);
- int dataStreamVersion = QDataStream::Qt_3_3;
-
- qint32 version;
- fs >> version;
- kDebug() << "Playlists file is version" << version;
-
- switch(version) {
- case 3:
- dataStreamVersion = QDataStream::Qt_4_3;
- // Fall-through
-
- case 1:
- case 2:
- {
- // Our checksum is only for the values after the version and checksum so
- // we want to get a byte array with just the checksummed data.
-
- QByteArray data;
- quint16 checksum;
- fs >> checksum >> data;
-
- if(checksum != qChecksum(data.data(), data.size()))
- return;
-
- // If we chose the wrong QDataStream version we may have to back out
- // and try again, so get ready by noting the playlists we have made.
-
- QList<Playlist *> createdPlaylists;
- bool errorOccurred = true;
-
- while(errorOccurred) {
- // Create a new stream just based on the data.
-
- QDataStream s(&data, QIODevice::ReadOnly);
- s.setVersion(dataStreamVersion);
-
- try { // Failure due to wrong version can be indicated by an exception
-
- while(!s.atEnd()) {
-
- qint32 playlistType;
- s >> playlistType;
-
- Playlist *playlist = 0;
-
- switch(playlistType) {
- case Search:
- {
- SearchPlaylist *p = new SearchPlaylist(collection);
- createdPlaylists.append(p);
- s >> *p;
- playlist = p;
- break;
- }
- case History:
- {
- action<KToggleAction>("showHistory")->setChecked(true);
- collection->setHistoryPlaylistEnabled(true);
- s >> *collection->historyPlaylist();
- playlist = collection->historyPlaylist();
- break;
- }
- case Upcoming:
- {
- /*
- collection->setUpcomingPlaylistEnabled(true);
- Playlist *p = collection->upcomingPlaylist();
- action<KToggleAction>("saveUpcomingTracks")->setChecked(true);
- s >> *p;
- playlist = p;
- */
- break;
- }
- case Folder:
- {
- FolderPlaylist *p = new FolderPlaylist(collection);
- createdPlaylists.append(p);
- s >> *p;
- playlist = p;
- break;
- }
- default:
- Playlist *p = new Playlist(collection, true);
- createdPlaylists.append(p);
- s >> *p;
-
- // We may have already read this playlist from the folder
- // scanner, if an .m3u playlist
- if(collection->containsPlaylistFile(p->fileName())) {
- delete p;
- p = 0;
- }
-
- playlist = p;
- break;
- } // switch
-
- if(version >= 2) {
- qint32 sortColumn;
- s >> sortColumn;
- if(playlist)
- playlist->setSorting(sortColumn);
- }
-
- } // while !s.atEnd()
-
- // Must be ok if we got this far, break out of loop.
- errorOccurred = false;
-
- } // try
- catch(BICStreamException &) {
- kError() << "Exception loading playlists - binary incompatible stream.";
-
- // Delete created playlists which probably have junk now.
- foreach(Playlist *p, createdPlaylists)
- delete p;
- createdPlaylists.clear();
-
- if(dataStreamVersion == QDataStream::Qt_3_3) {
- kError() << "Attempting other binary protocol - Qt 4.3";
- dataStreamVersion = QDataStream::Qt_4_3;
-
- break; // escape from while(!s.atEnd()) to try again
- }
-#if QT_VERSION >= 0x040400
- // Unlikely, but maybe user had Qt 4.4 with KDE 4.0.0?
- else if(dataStreamVersion == QDataStream::Qt_4_3) {
- kError() << "Attempting other binary protocol - Qt 4.4";
- dataStreamVersion = QDataStream::Qt_4_4;
-
- break;
- }
-#endif
- // We tried 3.3 first, if 4.3/4.4 doesn't work who knows...
- kError() << "Unable to recover, no playlists will be loaded.";
- return;
- } // catch
- } // while dataStreamVersion != -1
- break;
- }
- default:
- {
- // Because the original version of the playlist cache did not contain a
- // version number, we want to revert to the beginning of the file before
- // reading the data.
-
- f.reset();
-
- while(!fs.atEnd()) {
- Playlist *p = new Playlist(collection);
- fs >> *p;
- }
- break;
- }
- }
-
- f.close();
-}
-
-void Cache::savePlaylists(const PlaylistList &playlists)
-{
- QString dirName = KGlobal::dirs()->saveLocation("appdata");
- QString playlistsFile = dirName + "playlists";
- KSaveFile f(playlistsFile);
-
- if(!f.open(QIODevice::WriteOnly)) {
- kError() << "Error saving collection:" << f.errorString();
- return;
- }
-
- QByteArray data;
- QDataStream s(&data, QIODevice::WriteOnly);
- s.setVersion(QDataStream::Qt_4_3);
-
- for(PlaylistList::ConstIterator it = playlists.begin(); it != playlists.end(); ++it) {
- if(*it) {
- if(dynamic_cast<HistoryPlaylist *>(*it)) {
- s << qint32(History)
- << *static_cast<HistoryPlaylist *>(*it);
- }
- else if(dynamic_cast<SearchPlaylist *>(*it)) {
- s << qint32(Search)
- << *static_cast<SearchPlaylist *>(*it);
- }
- else if(dynamic_cast<UpcomingPlaylist *>(*it)) {
- if(!action<KToggleAction>("saveUpcomingTracks")->isChecked())
- continue;
- s << qint32(Upcoming)
- << *static_cast<UpcomingPlaylist *>(*it);
- }
- else if(dynamic_cast<FolderPlaylist *>(*it)) {
- s << qint32(Folder)
- << *static_cast<FolderPlaylist *>(*it);
- }
- else {
- s << qint32(Normal)
- << *(*it);
- }
- s << qint32((*it)->sortColumn());
- }
- }
-
- QDataStream fs(&f);
- fs << qint32(playlistListCacheVersion);
- fs << qChecksum(data.data(), data.size());
-
- fs << data;
- f.close();
-
- if(!f.finalize())
- kError() << "Error saving collection:" << f.errorString();
-}
-
-bool Cache::cacheFileExists() // static
-{
- return QFile::exists(KGlobal::dirs()->saveLocation("appdata") + "cache");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-Cache::Cache()
-{
-
-}
-
-bool Cache::prepareToLoadCachedItems()
-{
- QString cacheFileName = KGlobal::dirs()->saveLocation("appdata") + "cache";
-
- m_loadFile.setFileName(cacheFileName);
- if(!m_loadFile.open(QIODevice::ReadOnly))
- return false;
-
- m_loadDataStream.setDevice(&m_loadFile);
-
- int dataStreamVersion = CacheDataStream::Qt_3_3;
-
- qint32 version;
- m_loadDataStream >> version;
-
- switch(version) {
- case 2:
- dataStreamVersion = CacheDataStream::Qt_4_3;
-
- // Other than that we're compatible with cache v1, so fallthrough
- // to setCacheVersion
-
- case 1: {
- m_loadDataStream.setCacheVersion(1);
- m_loadDataStream.setVersion(dataStreamVersion);
-
- qint32 checksum;
- m_loadDataStream >> checksum
- >> m_loadFileBuffer.buffer();
-
- m_loadFileBuffer.open(QIODevice::ReadOnly);
- m_loadDataStream.setDevice(&m_loadFileBuffer);
-
- qint32 checksumExpected = qChecksum(
- m_loadFileBuffer.data(), m_loadFileBuffer.size());
- if(m_loadDataStream.status() != CacheDataStream::Ok ||
- checksum != checksumExpected)
- {
- kError() << "Music cache checksum expected to get" << checksumExpected <<
- "actually was" << checksum;
- KMessageBox::sorry(0, i18n("The music data cache has been corrupted. JuK "
- "needs to rescan it now. This may take some time."));
- return false;
- }
-
- break;
- }
- default: {
- m_loadDataStream.device()->reset();
- m_loadDataStream.setCacheVersion(0);
-
- // This cache is so old that this is just a wild guess here that 3.3
- // is compatible.
- m_loadDataStream.setVersion(CacheDataStream::Qt_3_3);
- break;
- }
- }
-
- return true;
-}
-
-FileHandle Cache::loadNextCachedItem()
-{
- if(!m_loadFile.isOpen() || !m_loadDataStream.device()) {
- kWarning() << "Already completed reading cache file.";
- return FileHandle::null();
- }
-
- if(m_loadDataStream.status() == QDataStream::ReadCorruptData) {
- kError() << "Attempted to read file handle from corrupt cache file.";
- return FileHandle::null();
- }
-
- if(!m_loadDataStream.atEnd()) {
- QString fileName;
- m_loadDataStream >> fileName;
- fileName.squeeze();
-
- return FileHandle(fileName, m_loadDataStream);
- }
- else {
- m_loadDataStream.setDevice(0);
- m_loadFile.close();
-
- return FileHandle::null();
- }
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2008, 2013 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_CACHE_H
-#define JUK_CACHE_H
-
-#include <QtCore/QDataStream>
-#include <QtCore/QFile>
-#include <QtCore/QBuffer>
-
-class Playlist;
-class PlaylistCollection;
-class FileHandle;
-
-template<class T>
-class QList;
-
-typedef QList<Playlist *> PlaylistList;
-
-/**
- * A simple QDataStream subclass that has an extra field to indicate the cache
- * version.
- */
-
-class CacheDataStream : public QDataStream
-{
-public:
- CacheDataStream(QIODevice *d) : QDataStream(d), m_cacheVersion(0) {}
- CacheDataStream() : m_cacheVersion(0) { }
-
- int cacheVersion() const { return m_cacheVersion; }
- void setCacheVersion(int v) { m_cacheVersion = v; }
-
-private:
- int m_cacheVersion;
-};
-
-
-class Cache
-{
-public:
- static Cache *instance();
-
- static void loadPlaylists(PlaylistCollection *collection);
- static void savePlaylists(const PlaylistList &playlists);
-
- static bool cacheFileExists();
-
- bool prepareToLoadCachedItems();
- FileHandle loadNextCachedItem();
-
- /**
- * QDataStream version for serialized list of playlists
- * 1, 2: Who knows?
- * 3: Current.
- */
- static const int playlistListCacheVersion;
-
- /**
- * QDataStream version for serialized list of playlist items in a playlist
- * 1: Original cache version
- * 2: KDE 4.0.1+, explicitly sets QDataStream encoding.
- */
- static const int playlistItemsCacheVersion;
-
-private:
- // private to force access through instance()
- Cache();
-
-private:
- QFile m_loadFile;
- QBuffer m_loadFileBuffer;
- CacheDataStream m_loadDataStream;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "categoryreaderinterface.h"
-#include "filerenameroptions.h"
-
-#include <QString>
-
-QString CategoryReaderInterface::value(const CategoryID &category) const
-{
- QString value = categoryValue(category.category).trimmed();
-
- if(category.category == Track)
- value = fixupTrack(value, category.categoryNumber).trimmed();
-
- if(value.isEmpty()) {
- switch(emptyAction(category)) {
- case TagRenamerOptions::UseReplacementValue:
- value = emptyText(category);
- break;
-
- case TagRenamerOptions::IgnoreEmptyTag:
- return QString();
-
- default:
- // No extra action needed.
- break;
- }
- }
-
- return prefix(category) + value + suffix(category);
-}
-
-bool CategoryReaderInterface::isRequired(const CategoryID &category) const
-{
- return emptyAction(category) != TagRenamerOptions::IgnoreEmptyTag;
-}
-
-bool CategoryReaderInterface::isEmpty(TagType category) const
-{
- return categoryValue(category).isEmpty();
-}
-
-QString CategoryReaderInterface::fixupTrack(const QString &track, int categoryNum) const
-{
- QString str(track);
- CategoryID trackId(Track, categoryNum);
-
- if(track == "0") {
- if(emptyAction(trackId) == TagRenamerOptions::UseReplacementValue)
- str = emptyText(trackId);
- else
- return QString();
- }
-
- int minimumWidth = trackWidth(categoryNum);
-
- if(str.length() < minimumWidth) {
- QString prefix;
- prefix.fill('0', minimumWidth - str.length());
- return prefix + str;
- }
-
- return str;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CATEGORYREADERINTERFACE_H
-#define CATEGORYREADERINTERFACE_H
-
-#include "tagrenameroptions.h"
-
-enum TagType;
-
-class QString;
-
-template<class T> class QList;
-
-/**
- * This class is used to map categories into values. You should implement the
- * functionality in a subclass.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class CategoryReaderInterface
-{
-public:
- virtual ~CategoryReaderInterface() { }
-
- /**
- * Returns the textual representation of \p type, without any processing done
- * on it. For example, track values shouldn't be expanded out to the minimum
- * width from this function. No CategoryID is needed since the value is constant
- * for a category.
- *
- * @param type, The category to retrieve the value of.
- * @return textual representation of that category's value.
- */
- virtual QString categoryValue(TagType type) const = 0;
-
- /**
- * Returns the user-specified prefix string for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified prefix string for \p category.
- */
- virtual QString prefix(const CategoryID &category) const = 0;
-
- /**
- * Returns the user-specified suffix string for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified suffix string for \p category.
- */
- virtual QString suffix(const CategoryID &category) const = 0;
-
- /**
- * Returns the user-specified empty action for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified empty action for \p category.
- */
- virtual TagRenamerOptions::EmptyActions emptyAction(const CategoryID &category) const = 0;
-
- /**
- * Returns the user-specified empty text for \p category. This text might
- * be used to replace an empty value.
- *
- * @param category the category to retrieve the value for.
- * @return the user-specified empty text for \p category.
- */
- virtual QString emptyText(const CategoryID &category) const = 0;
-
- /**
- * @return the categories in the order the user has chosen. Categories may
- * be repeated (which is why CategoryID has the categoryNumber value to
- * disambiguate duplicates).
- */
- virtual QList<CategoryID> categoryOrder() const = 0;
-
- /**
- * @return track width for the Track item identified by categoryNum.
- */
- virtual int trackWidth(int categoryNum) const = 0;
-
- // You probably shouldn't reimplement this
- virtual QString value(const CategoryID &category) const;
-
- virtual QString separator() const = 0;
-
- virtual QString musicFolder() const = 0;
-
- /**
- * @param index the zero-based index of the item just before the
- * separator in question.
- * @return true if a folder separator should be placed between the tags
- * at index and index + 1.
- */
- virtual bool hasFolderSeparator(int index) const = 0;
-
- virtual bool isDisabled(const CategoryID &category) const = 0;
-
- // You probably shouldn't reimplement this
- virtual bool isRequired(const CategoryID &category) const;
-
- // You probably shouldn't reimplement this
- virtual bool isEmpty(TagType category) const;
-
- // You probably shouldn't reimplement this
- virtual QString fixupTrack(const QString &track, int categoryNum) const;
-};
-
-#endif /* CATEGORYREADERINTERFACE_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-# Option for build or not TunePimp
-
-# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-
-if(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
- # Already in cache, be silent
- set(TunePimp_FIND_QUIETLY TRUE)
-endif(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
-
-FIND_PATH(TUNEPIMP_INCLUDE_DIR tunepimp/tp_c.h)
-
-# Search tunepimp-0.5
-if(NOT TUNEPIMP_INCLUDE_DIR)
- FIND_PATH(TUNEPIMP_INCLUDE_DIR tunepimp-0.5/tp_c.h)
-endif(NOT TUNEPIMP_INCLUDE_DIR)
-
-FIND_LIBRARY(TUNEPIMP_LIBRARIES NAMES tunepimp)
-
-if(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
- MESSAGE( STATUS "tunepimp found: includes in ${TUNEPIMP_INCLUDE_DIR}, library in ${TUNEPIMP_LIBRARIES}")
- set(TUNEPIMP_FOUND TRUE)
- INCLUDE(CheckLibraryExists)
- SET(old_flags ${CMAKE_REQUIRED_LIBRARIES})
- SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
- CHECK_LIBRARY_EXISTS(${TUNEPIMP_LIBRARIES} tp_SetFileNameEncoding "" TUNEPIMP_FOUND_VERSION_4)
- CHECK_LIBRARY_EXISTS(${TUNEPIMP_LIBRARIES} tr_GetPUID "" TUNEPIMP_FOUND_VERSION_5)
- SET(CMAKE_REQUIRED_LIBRARIES ${old_flags})
- MESSAGE(STATUS "TUNEPIMP_FOUND_VERSION_4 :<${TUNEPIMP_FOUND_VERSION_4}>")
- MESSAGE(STATUS "TUNEPIMP_FOUND_VERSION_5 :<${TUNEPIMP_FOUND_VERSION_5}>")
-else(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
- MESSAGE( STATUS "tunepimp not found")
-endif(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
-
-MARK_AS_ADVANCED(TUNEPIMP_INCLUDE_DIR TUNEPIMP_LIBRARIES)
-
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "collectionlist.h"
-
-#include <klocale.h>
-#include <kmessagebox.h>
-#include <kdebug.h>
-#include <kmenu.h>
-#include <kconfig.h>
-#include <kconfiggroup.h>
-#include <kglobal.h>
-#include <kactioncollection.h>
-#include <ksavefile.h>
-#include <kstandarddirs.h>
-#include <ktoolbarpopupaction.h>
-#include <kdirwatch.h>
-
-#include <QStringBuilder>
-#include <QList>
-#include <QDragMoveEvent>
-#include <QDropEvent>
-#include <QApplication>
-#include <QTimer>
-#include <QTime>
-#include <QClipboard>
-#include <QFileInfo>
-
-#include "playlistcollection.h"
-#include "splashscreen.h"
-#include "stringshare.h"
-#include "cache.h"
-#include "actioncollection.h"
-#include "tag.h"
-#include "viewmode.h"
-
-using ActionCollection::action;
-
-////////////////////////////////////////////////////////////////////////////////
-// static methods
-////////////////////////////////////////////////////////////////////////////////
-
-CollectionList *CollectionList::m_list = 0;
-
-CollectionList *CollectionList::instance()
-{
- return m_list;
-}
-
-static QTime stopwatch;
-
-void CollectionList::startLoadingCachedItems()
-{
- if(!m_list)
- return;
-
- kDebug() << "Starting to load cached items";
- stopwatch.start();
-
- if(!Cache::instance()->prepareToLoadCachedItems()) {
- kError() << "Unable to setup to load cache... perhaps it doesn't exist?";
-
- completedLoadingCachedItems();
- return;
- }
-
- kDebug() << "Kicked off first batch";
- QTimer::singleShot(0, this, SLOT(loadNextBatchCachedItems()));
-}
-
-void CollectionList::loadNextBatchCachedItems()
-{
- Cache *cache = Cache::instance();
- bool done = false;
-
- for(int i = 0; i < 20; ++i) {
- FileHandle cachedItem(cache->loadNextCachedItem());
-
- if(cachedItem.isNull()) {
- done = true;
- break;
- }
-
- // This may have already been created via a loaded playlist.
- if(!m_itemsDict.contains(cachedItem.absFilePath())) {
- CollectionListItem *newItem = new CollectionListItem(this, cachedItem);
- setupItem(newItem);
- }
- }
-
- SplashScreen::update();
-
- if(!done) {
- QTimer::singleShot(0, this, SLOT(loadNextBatchCachedItems()));
- }
- else {
- completedLoadingCachedItems();
- }
-}
-
-void CollectionList::completedLoadingCachedItems()
-{
- // The CollectionList is created with sorting disabled for speed. Re-enable
- // it here, and perform the sort.
- KConfigGroup config(KGlobal::config(), "Playlists");
-
- Qt::SortOrder order = Qt::DescendingOrder;
- if(config.readEntry("CollectionListSortAscending", true))
- order = Qt::AscendingOrder;
-
- m_list->setSortOrder(order);
- m_list->setSortColumn(config.readEntry("CollectionListSortColumn", 1));
-
- m_list->sort();
-
- SplashScreen::finishedLoading();
-
- kDebug() << "Finished loading cached items, took" << stopwatch.elapsed() << "ms";
- kDebug() << m_itemsDict.size() << "items are in the CollectionList";
-
- emit cachedItemsLoaded();
-}
-
-void CollectionList::initialize(PlaylistCollection *collection)
-{
- if(m_list)
- return;
-
- // We have to delay initialization here because dynamic_cast or comparing to
- // the collection instance won't work in the PlaylistBox::Item initialization
- // won't work until the CollectionList is fully constructed.
-
- m_list = new CollectionList(collection);
- m_list->setName(i18n("Collection List"));
-
- collection->setupPlaylist(m_list, "folder-sound");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-CollectionListItem *CollectionList::createItem(const FileHandle &file, Q3ListViewItem *, bool)
-{
- // It's probably possible to optimize the line below away, but, well, right
- // now it's more important to not load duplicate items.
-
- if(m_itemsDict.contains(file.absFilePath()))
- return 0;
-
- CollectionListItem *item = new CollectionListItem(this, file);
-
- if(!item->isValid()) {
- kError() << "CollectionList::createItem() -- A valid tag was not created for \""
- << file.absFilePath() << "\"" << endl;
- delete item;
- return 0;
- }
-
- setupItem(item);
-
- return item;
-}
-
-void CollectionList::clearItems(const PlaylistItemList &items)
-{
- foreach(PlaylistItem *item, items) {
- delete item;
- }
-
- dataChanged();
-}
-
-void CollectionList::setupTreeViewEntries(ViewMode *viewMode) const
-{
- TreeViewMode *treeViewMode = dynamic_cast<TreeViewMode *>(viewMode);
- if(!treeViewMode) {
- kWarning() << "Can't setup entries on a non-tree-view mode!\n";
- return;
- }
-
- QList<int> columnList;
- columnList << PlaylistItem::ArtistColumn;
- columnList << PlaylistItem::GenreColumn;
- columnList << PlaylistItem::AlbumColumn;
-
- foreach(int column, columnList)
- treeViewMode->addItems(m_columnTags[column]->keys(), column);
-}
-
-void CollectionList::slotNewItems(const KFileItemList &items)
-{
- QStringList files;
-
- for(KFileItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it)
- files.append((*it).url().path());
-
- addFiles(files);
- update();
-}
-
-void CollectionList::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items)
-{
- for(int i = 0; i < items.count(); ++i) {
- const KFileItem fileItem = items[i].second;
- CollectionListItem *item = lookup(fileItem.url().path());
-
- if(item) {
- item->refreshFromDisk();
-
- // If the item is no longer on disk, remove it from the collection.
-
- if(item->file().fileInfo().exists())
- item->repaint();
- else
- delete item;
- }
- }
-
- update();
-}
-
-void CollectionList::slotDeleteItem(const KFileItem &item)
-{
- delete lookup(item.url().path());
-}
-
-void CollectionList::saveItemsToCache() const
-{
- kDebug() << "Saving collection list to cache";
-
- QString cacheFileName =
- KGlobal::dirs()->saveLocation("appdata") % QLatin1String("cache");
-
- KSaveFile f(cacheFileName);
-
- if(!f.open(QIODevice::WriteOnly)) {
- kError() << "Error saving cache:" << f.errorString();
- return;
- }
-
- QByteArray data;
- QDataStream s(&data, QIODevice::WriteOnly);
- s.setVersion(QDataStream::Qt_4_3);
-
- QHash<QString, CollectionListItem *>::const_iterator it;
- for(it = m_itemsDict.begin(); it != m_itemsDict.end(); ++it) {
- s << it.key();
- s << (*it)->file();
- }
-
- QDataStream fs(&f);
-
- qint32 checksum = qChecksum(data.data(), data.size());
-
- fs << qint32(Cache::playlistItemsCacheVersion)
- << checksum
- << data;
-
- f.close();
-
- if(!f.finalize())
- kError() << "Error saving cache:" << f.errorString();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void CollectionList::paste()
-{
- decode(QApplication::clipboard()->mimeData());
-}
-
-void CollectionList::clear()
-{
- int result = KMessageBox::warningContinueCancel(this,
- i18n("Removing an item from the collection will also remove it from "
- "all of your playlists. Are you sure you want to continue?\n\n"
- "Note, however, that if the directory that these files are in is in "
- "your \"scan on startup\" list, they will be readded on startup."));
-
- if(result == KMessageBox::Continue) {
- Playlist::clear();
- emit signalCollectionChanged();
- }
-}
-
-void CollectionList::slotCheckCache()
-{
- PlaylistItemList invalidItems;
- kDebug() << "Starting to check cached items for consistency";
- stopwatch.start();
-
- int i = 0;
- foreach(CollectionListItem *item, m_itemsDict) {
- if(!item->checkCurrent())
- invalidItems.append(item);
- if(++i == (m_itemsDict.size() / 2))
- kDebug() << "Checkpoint";
- }
-
- clearItems(invalidItems);
-
- kDebug() << "Finished consistency check, took" << stopwatch.elapsed() << "ms";
-}
-
-void CollectionList::slotRemoveItem(const QString &file)
-{
- delete m_itemsDict[file];
-}
-
-void CollectionList::slotRefreshItem(const QString &file)
-{
- if(m_itemsDict[file])
- m_itemsDict[file]->refresh();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-CollectionList::CollectionList(PlaylistCollection *collection) :
- Playlist(collection, true),
- m_columnTags(15, 0)
-{
- QAction *spaction = ActionCollection::actions()->addAction("showPlaying");
- spaction->setText(i18n("Show Playing"));
- connect(spaction, SIGNAL(triggered(bool)), SLOT(slotShowPlaying()));
-
- connect(action<KToolBarPopupAction>("back")->menu(), SIGNAL(aboutToShow()),
- this, SLOT(slotPopulateBackMenu()));
- connect(action<KToolBarPopupAction>("back")->menu(), SIGNAL(triggered(QAction*)),
- this, SLOT(slotPlayFromBackMenu(QAction*)));
- setSorting(-1); // Temporarily disable sorting to add items faster.
-
- m_columnTags[PlaylistItem::ArtistColumn] = new TagCountDict;
- m_columnTags[PlaylistItem::AlbumColumn] = new TagCountDict;
- m_columnTags[PlaylistItem::GenreColumn] = new TagCountDict;
-}
-
-CollectionList::~CollectionList()
-{
- KConfigGroup config(KGlobal::config(), "Playlists");
- config.writeEntry("CollectionListSortColumn", sortColumn());
- config.writeEntry("CollectionListSortAscending", sortOrder() == Qt::AscendingOrder);
-
- // In some situations the dataChanged signal from clearItems will cause observers to
- // subsequently try to access a deleted item. Since we're going away just remove all
- // observers.
-
- clearObservers();
-
- // The CollectionListItems will try to remove themselves from the
- // m_columnTags member, so we must make sure they're gone before we
- // are.
-
- clearItems(items());
-
- qDeleteAll(m_columnTags);
- m_columnTags.clear();
-}
-
-void CollectionList::contentsDropEvent(QDropEvent *e)
-{
- if(e->source() == this)
- return; // Don't rearrange in the CollectionList.
- else
- Playlist::contentsDropEvent(e);
-}
-
-void CollectionList::contentsDragMoveEvent(QDragMoveEvent *e)
-{
- if(e->source() != this)
- Playlist::contentsDragMoveEvent(e);
- else
- e->setAccepted(false);
-}
-
-QString CollectionList::addStringToDict(const QString &value, int column)
-{
- if(column > m_columnTags.count() || value.trimmed().isEmpty())
- return QString();
-
- if(m_columnTags[column]->contains(value))
- ++((*m_columnTags[column])[value]);
- else {
- m_columnTags[column]->insert(value, 1);
- emit signalNewTag(value, column);
- }
-
- return value;
-}
-
-QStringList CollectionList::uniqueSet(UniqueSetType t) const
-{
- int column;
-
- switch(t)
- {
- case Artists:
- column = PlaylistItem::ArtistColumn;
- break;
-
- case Albums:
- column = PlaylistItem::AlbumColumn;
- break;
-
- case Genres:
- column = PlaylistItem::GenreColumn;
- break;
-
- default:
- return QStringList();
- }
-
- return m_columnTags[column]->keys();
-}
-
-CollectionListItem *CollectionList::lookup(const QString &file) const
-{
- return m_itemsDict.value(file, 0);
-}
-
-void CollectionList::removeStringFromDict(const QString &value, int column)
-{
- if(column > m_columnTags.count() || value.trimmed().isEmpty())
- return;
-
- if(m_columnTags[column]->contains(value) &&
- --((*m_columnTags[column])[value])) // If the decrement goes to 0...
- {
- emit signalRemovedTag(value, column);
- m_columnTags[column]->remove(value);
- }
-}
-
-void CollectionList::addWatched(const QString &file)
-{
- m_dirWatch->addFile(file);
-}
-
-void CollectionList::removeWatched(const QString &file)
-{
- m_dirWatch->removeFile(file);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CollectionListItem public methods
-////////////////////////////////////////////////////////////////////////////////
-
-void CollectionListItem::refresh()
-{
- int offset = CollectionList::instance()->columnOffset();
- int columns = lastColumn() + offset + 1;
-
- data()->metadata.resize(columns);
- data()->cachedWidths.resize(columns);
-
- for(int i = offset; i < columns; i++) {
- int id = i - offset;
- if(id != TrackNumberColumn && id != LengthColumn) {
- // All columns other than track num and length need local-encoded data for sorting
-
- QString toLower = text(i).toLower();
-
- // For some columns, we may be able to share some strings
-
- if((id == ArtistColumn) || (id == AlbumColumn) ||
- (id == GenreColumn) || (id == YearColumn) ||
- (id == CommentColumn))
- {
- toLower = StringShare::tryShare(toLower);
-
- if(id != YearColumn && id != CommentColumn && data()->metadata[id] != toLower) {
- CollectionList::instance()->removeStringFromDict(data()->metadata[id], id);
- CollectionList::instance()->addStringToDict(text(i), id);
- }
- }
-
- data()->metadata[id] = toLower;
- }
-
- int newWidth = width(listView()->fontMetrics(), listView(), i);
- if(newWidth != data()->cachedWidths[i])
- playlist()->slotWeightDirty(i);
-
- data()->cachedWidths[i] = newWidth;
- }
-
- if(listView()->isVisible())
- repaint();
-
- for(PlaylistItemList::Iterator it = m_children.begin(); it != m_children.end(); ++it) {
- (*it)->playlist()->update();
- (*it)->playlist()->dataChanged();
- if((*it)->listView()->isVisible())
- (*it)->repaint();
- }
-
- CollectionList::instance()->dataChanged();
- emit CollectionList::instance()->signalCollectionChanged();
-}
-
-PlaylistItem *CollectionListItem::itemForPlaylist(const Playlist *playlist)
-{
- if(playlist == CollectionList::instance())
- return this;
-
- PlaylistItemList::ConstIterator it;
- for(it = m_children.constBegin(); it != m_children.constEnd(); ++it)
- if((*it)->playlist() == playlist)
- return *it;
- return 0;
-}
-
-void CollectionListItem::updateCollectionDict(const QString &oldPath, const QString &newPath)
-{
- CollectionList *collection = CollectionList::instance();
-
- if(!collection)
- return;
-
- collection->removeFromDict(oldPath);
- collection->addToDict(newPath, this);
-}
-
-void CollectionListItem::repaint() const
-{
- Q3ListViewItem::repaint();
- for(PlaylistItemList::ConstIterator it = m_children.constBegin(); it != m_children.constEnd(); ++it)
- (*it)->repaint();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CollectionListItem protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-CollectionListItem::CollectionListItem(CollectionList *parent, const FileHandle &file) :
- PlaylistItem(parent),
- m_shuttingDown(false)
-{
- parent->addToDict(file.absFilePath(), this);
-
- data()->fileHandle = file;
-
- if(file.tag()) {
- refresh();
- parent->dataChanged();
- }
- else {
- kError() << "CollectionListItem::CollectionListItem() -- Tag() could not be created." << endl;
- }
-
- SplashScreen::increment();
-}
-
-CollectionListItem::~CollectionListItem()
-{
- m_shuttingDown = true;
-
- foreach(PlaylistItem *item, m_children)
- delete item;
-
- CollectionList *l = CollectionList::instance();
- if(l) {
- l->removeFromDict(file().absFilePath());
- l->removeStringFromDict(file().tag()->album(), AlbumColumn);
- l->removeStringFromDict(file().tag()->artist(), ArtistColumn);
- l->removeStringFromDict(file().tag()->genre(), GenreColumn);
- }
-}
-
-void CollectionListItem::addChildItem(PlaylistItem *child)
-{
- m_children.append(child);
-}
-
-void CollectionListItem::removeChildItem(PlaylistItem *child)
-{
- if(!m_shuttingDown)
- m_children.removeAll(child);
-}
-
-bool CollectionListItem::checkCurrent()
-{
- if(!file().fileInfo().exists() || !file().fileInfo().isFile())
- return false;
-
- if(!file().current()) {
- file().refresh();
- refresh();
- }
-
- return true;
-}
-
-#include "collectionlist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COLLECTIONLIST_H
-#define COLLECTIONLIST_H
-
-#include <QHash>
-#include <QVector>
-
-#include "playlist.h"
-#include "playlistitem.h"
-
-class ViewMode;
-class KFileItem;
-class KFileItemList;
-class KDirWatch;
-
-/**
- * This type is for mapping QString track attributes like the album, artist
- * and track to an integer count representing the number of outstanding items
- * that hold the string.
- */
-
-typedef QHash<QString, int> TagCountDict;
-typedef QHashIterator<QString, int> TagCountDictIterator;
-
-/**
- * We then have an array of dicts, one for each column in the list view.
- * The array is sparse (not every vector will have a TagCountDict so we use
- * pointers.
- */
-
-typedef QVector<TagCountDict *> TagCountDicts;
-
-/**
- * This is the "collection", or all of the music files that have been opened
- * in any playlist and not explicitly removed from the collection.
- *
- * It is being implemented as a "semi-singleton" because I need universal access
- * to just one instance. However, because the collection needs initialization
- * parameters (that will not always be available when an instance is needed).
- * Hence there will be the familiar singleton "instance()" method allong with an
- * "initialize()" method.
- */
-
-class CollectionListItem : public PlaylistItem
-{
- friend class Playlist;
- friend class CollectionList;
- friend class PlaylistItem;
-
-public:
- virtual void refresh();
- PlaylistItem *itemForPlaylist(const Playlist *playlist);
- void updateCollectionDict(const QString &oldPath, const QString &newPath);
- void repaint() const;
- PlaylistItemList children() const { return m_children; }
-
-protected:
- CollectionListItem(CollectionList *parent, const FileHandle &file);
- virtual ~CollectionListItem();
-
- void addChildItem(PlaylistItem *child);
- void removeChildItem(PlaylistItem *child);
-
- /**
- * Returns true if the item is now up to date (even if this required a refresh) or
- * false if the item is invalid.
- */
- bool checkCurrent();
-
- virtual CollectionListItem *collectionItem() { return this; }
-
-private:
- bool m_shuttingDown;
- PlaylistItemList m_children;
-};
-
-class CollectionList : public Playlist
-{
- friend class CollectionListItem;
-
- Q_OBJECT
-
-public:
- /**
- * A variety of unique value lists will be kept in the collection. This
- * enum can be used as an index into those structures.
- */
- enum UniqueSetType { Artists = 0, Albums = 1, Genres = 2 };
-
- static CollectionList *instance();
- static void initialize(PlaylistCollection *collection);
-
- /**
- * Returns a unique set of values associated with the type specified.
- */
- QStringList uniqueSet(UniqueSetType t) const;
-
- CollectionListItem *lookup(const QString &file) const;
-
- virtual CollectionListItem *createItem(const FileHandle &file,
- Q3ListViewItem * = 0,
- bool = false);
-
- void emitVisibleColumnsChanged() { emit signalVisibleColumnsChanged(); }
-
- virtual void clearItems(const PlaylistItemList &items);
-
- void setupTreeViewEntries(ViewMode *viewMode) const;
-
- virtual bool canReload() const { return true; }
-
- void saveItemsToCache() const;
-
-public slots:
- virtual void paste();
- virtual void clear();
- void slotCheckCache();
-
- void slotRemoveItem(const QString &file);
- void slotRefreshItem(const QString &file);
-
- void slotNewItems(const KFileItemList &items);
- void slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items);
- void slotDeleteItem(const KFileItem &item);
-
-protected:
- CollectionList(PlaylistCollection *collection);
- virtual ~CollectionList();
-
- virtual void contentsDropEvent(QDropEvent *e);
- virtual void contentsDragMoveEvent(QDragMoveEvent *e);
-
- // These methods are used by CollectionListItem, which is a friend class.
-
- void addToDict(const QString &file, CollectionListItem *item) { m_itemsDict.insert(file, item); }
- void removeFromDict(const QString &file) { m_itemsDict.remove(file); }
-
- // These methods are also used by CollectionListItem, to manage the
- // strings used in generating the unique sets and tree view mode playlists.
-
- QString addStringToDict(const QString &value, int column);
- void removeStringFromDict(const QString &value, int column);
-
- void addWatched(const QString &file);
- void removeWatched(const QString &file);
-
- virtual bool hasItem(const QString &file) const { return m_itemsDict.contains(file); }
-
-signals:
- void signalCollectionChanged();
-
- /**
- * This is emitted when the set of columns that is visible is changed.
- *
- * \see Playlist::hideColumn()
- * \see Playlist::showColumn()
- * \see Playlsit::isColumnVisible()
- */
- void signalVisibleColumnsChanged();
- void signalNewTag(const QString &, unsigned);
- void signalRemovedTag(const QString &, unsigned);
-
- // Emitted once cached items are loaded, which allows for folder scanning
- // and invalid track detection to proceed.
- void cachedItemsLoaded();
-
-public slots:
- /**
- * Loads the CollectionListItems from the Cache. Should be called after program
- * initialization.
- */
- void startLoadingCachedItems();
-
- /**
- * Loads a few items at a time. Intended to be single-shotted into the event
- * loop so that loading the music doesn't freeze the GUI.
- */
- void loadNextBatchCachedItems();
-
- /**
- * Teardown from cache loading (e.g. splash screen, sorting, etc.). Should
- * always be called if startLoadingCachedItems is called.
- */
- void completedLoadingCachedItems();
-
-private:
- /**
- * Just the size of the above enum to keep from hard coding it in several
- * locations.
- */
- static const int m_uniqueSetCount = 3;
-
- static CollectionList *m_list;
- QHash<QString, CollectionListItem *> m_itemsDict;
- KDirWatch *m_dirWatch;
- TagCountDicts m_columnTags;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/* Define if you tunepimp installed */
-#define HAVE_TUNEPIMP @HAVE_TUNEPIMP@
-
-/* Defined if taglib supports Ogg::Opus::File */
-#cmakedefine01 TAGLIB_HAS_OPUSFILE
+++ /dev/null
-/**
- * Copyright (C) 2005 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "coverdialog.h"
-
-#include <kiconloader.h>
-#include <kapplication.h>
-#include <kmenu.h>
-#include <klocale.h>
-
-#include <QTimer>
-
-#include "covericonview.h"
-#include "covermanager.h"
-#include "collectionlist.h"
-
-using CoverUtility::CoverIconViewItem;
-
-class AllArtistsListViewItem : public QListWidgetItem
-{
-public:
- AllArtistsListViewItem(KListWidget *parent) :
- QListWidgetItem(i18n("<All Artists>"), parent)
- {
- }
-
- bool operator< (const QListWidgetItem& other) const
- {
- Q_UNUSED(other);
- return true; // Always be at the top.
- }
-};
-
-class CaseInsensitiveItem : public QListWidgetItem
-{
-public:
- CaseInsensitiveItem(KListWidget *parent, const QString &text) :
- QListWidgetItem(text, parent)
- {
- }
-
- bool operator< (const QListWidgetItem& other) const
- {
- return text().toLower().localeAwareCompare(other.text().toLower());
- }
-};
-
-CoverDialog::CoverDialog(QWidget *parent) :
- QWidget(parent, Qt::WType_Dialog)
-{
- setupUi(this);
-
- setObjectName( QLatin1String("juk_cover_dialog" ));
-
- m_searchLine->setClearButtonShown(true);
-
- connect(m_artists, SIGNAL(itemClicked(QListWidgetItem*)),
- this, SLOT(slotArtistClicked(QListWidgetItem*)));
-
- connect(m_covers, SIGNAL(customContextMenuRequested(QPoint)),
- this, SLOT(slotContextRequested(QPoint)));
-
- connect(m_searchLine, SIGNAL(textChanged(QString)),
- this, SLOT(slotSearchPatternChanged(QString)));
-}
-
-CoverDialog::~CoverDialog()
-{
-}
-
-void CoverDialog::show()
-{
- m_artists->clear();
- m_covers->clear();
-
- QStringList artists = CollectionList::instance()->uniqueSet(CollectionList::Artists);
-
- new AllArtistsListViewItem(m_artists);
- for(QStringList::ConstIterator it = artists.constBegin(); it != artists.constEnd(); ++it)
- new CaseInsensitiveItem(m_artists, *it);
-
- QTimer::singleShot(0, this, SLOT(loadCovers()));
- QWidget::show();
-}
-
-// Here we try to keep the GUI from freezing for too long while we load the
-// covers.
-void CoverDialog::loadCovers()
-{
- CoverDataMapIterator it, end;
- int i = 0;
-
- it = CoverManager::begin();
- end = CoverManager::end();
-
- for(; it != end; ++it) {
- (void) new CoverIconViewItem(it.key(), m_covers);
-
- // TODO: Threading!
- if(++i == 10) {
- i = 0;
- kapp->processEvents();
- }
- }
-}
-
-// TODO: Add a way to show cover art for tracks with no artist.
-void CoverDialog::slotArtistClicked(QListWidgetItem *item)
-{
- m_covers->clear();
- if (!item) {
- return;
- }
- if(dynamic_cast<AllArtistsListViewItem *>(item)) {
- // All artists.
- loadCovers();
- }
- else {
- QString artist = item->text().toLower();
-
- CoverDataMapIterator it, end;
-
- it = CoverManager::begin();
- end = CoverManager::end();
-
- for(; it != end; ++it) {
- if(it.value()->artist == artist)
- (void) new CoverIconViewItem(it.key(), m_covers);
- }
- }
-}
-
-void CoverDialog::slotContextRequested(const QPoint &pt)
-{
- static KMenu *menu = 0;
-
- QListWidgetItem* item = m_covers->currentItem();
-
- if(!item)
- return;
-
- if(!menu) {
- menu = new KMenu(this);
- menu->addAction(i18n("Remove Cover"), this, SLOT(removeSelectedCover()));
- }
-
- QPoint globalPt = m_covers->mapToGlobal(pt);
- menu->popup(globalPt);
-}
-
-void CoverDialog::slotSearchPatternChanged(const QString& pattern)
-{
- m_covers->clear();
-
- QListWidgetItem* item = m_artists->currentItem();
-
- // If the expression is cleared, then use slotArtistClicked.
- if (pattern.isEmpty()) {
- slotArtistClicked(item);
- }
-
- else {
- QRegExp filter(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
- QString artist = item->text().toLower();
-
- CoverDataMapIterator it, end;
-
- it = CoverManager::begin();
- end = CoverManager::end();
-
- // Here, only show cover that match the search pattern.
- if (dynamic_cast<AllArtistsListViewItem *>(item)) {
-
- for(; it != end; ++it) {
- if (filter.indexIn(it.value()->artist) != -1) {
-
- (void) new CoverIconViewItem(it.key(), m_covers);
- }
- }
- }
-
- // Here, only show the covers that match the search pattern and
- // that have the same artist as the currently selected one.
- else {
-
- for(; it != end; ++it) {
- if (it.value()->artist == artist
- && ((filter.indexIn(it.value()->artist) != -1)
- || (filter.indexIn(it.value()->album) != -1))) {
-
- (void) new CoverIconViewItem(it.key(), m_covers);
- }
- }
- }
- }
-}
-
-void CoverDialog::removeSelectedCover()
-{
- CoverIconViewItem *coverItem = m_covers->currentItem();
-
- if(!coverItem || !coverItem->isSelected()) {
- kWarning() << "No item selected for removeSelectedCover.\n";
- return;
- }
-
- if(!CoverManager::removeCover(coverItem->id()))
- kError() << "Unable to remove selected cover: " << coverItem->id() << endl;
- else
- delete coverItem;
-}
-
-#include "coverdialog.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2005 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COVERDIALOG_H
-#define COVERDIALOG_H
-
-#include "ui_coverdialogbase.h"
-
-#include <QWidget>
-
-class QListWidgetItem;
-
-class CoverDialog : public QWidget, public Ui::CoverDialogBase
-{
- Q_OBJECT
-public:
- CoverDialog(QWidget *parent);
- ~CoverDialog();
-
- virtual void show();
-
-public slots:
- void slotArtistClicked(QListWidgetItem *item);
- void slotContextRequested(const QPoint &pt);
- void slotSearchPatternChanged(const QString& pattern);
-
-private slots:
- void loadCovers();
- void removeSelectedCover();
-};
-
-#endif /* COVERDIALOG_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<ui version="4.0" >
- <class>CoverDialogBase</class>
- <widget class="QWidget" name="CoverDialogBase" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>685</width>
- <height>554</height>
- </rect>
- </property>
- <property name="windowTitle" >
- <string>Cover Manager</string>
- </property>
- <layout class="QHBoxLayout" >
- <property name="margin" >
- <number>11</number>
- </property>
- <property name="spacing" >
- <number>6</number>
- </property>
- <item>
- <widget class="KListWidget" name="m_artists" >
- <property name="sizePolicy" >
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize" >
- <size>
- <width>164</width>
- <height>0</height>
- </size>
- </property>
- <column>
- <property name="text" >
- <string>Artist</string>
- </property>
- </column>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <property name="spacing" >
- <number>6</number>
- </property>
- <item>
- <layout class="QHBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <property name="spacing" >
- <number>6</number>
- </property>
- <item>
- <widget class="KLineEdit" native="1" name="m_searchLine" >
- <property name="sizePolicy" >
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="CoverIconView" native="1" name="m_covers" >
- <property name="sizePolicy" >
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KListWidget</class>
- <extends>QListWidget</extends>
- <header>klistwidget.h</header>
- </customwidget>
- <customwidget>
- <class>KLineEdit</class>
- <extends>QWidget</extends>
- <header>klineedit.h</header>
- </customwidget>
- <customwidget>
- <class>CoverIconView</class>
- <extends>QWidget</extends>
- <header>covericonview.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <includes>
- <include location="local" >k3listview.h</include>
- <include location="local" >klineedit.h</include>
- <include location="local" >covericonview.h</include>
- </includes>
- <resources/>
- <connections>
- </connections>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2005 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "covericonview.h"
-#include "covermanager.h"
-
-using CoverUtility::CoverIconViewItem;
-
-CoverIconViewItem::CoverIconViewItem(coverKey id, KListWidget *parent) :
- QListWidgetItem(parent), m_id(id)
-{
- CoverDataPtr data = CoverManager::coverInfo(id);
- setText(QString("%1 - %2").arg(data->artist, data->album));
- setIcon(data->thumbnail());
- setSizeHint(QSize(140, 150));
-}
-
-CoverIconView::CoverIconView(QWidget *parent, const char *name) : KListWidget(parent)
-{
- setObjectName(QLatin1String(name));
- setResizeMode(KListWidget::Adjust);
- setViewMode(KListWidget::IconMode);
- setIconSize(QSize(130, 140));
- setMovement(KListWidget::Static);
- setContextMenuPolicy(Qt::CustomContextMenu);
-}
-
-CoverIconViewItem *CoverIconView::currentItem() const
-{
- return static_cast<CoverIconViewItem *>(KListWidget::currentItem());
-}
-
-// TODO: port to Qt4
-#if 0
-Q3DragObject *CoverIconView::dragObject()
-{
- // Temporarily disabled pending conversion of the cover manager icon view
- // to Qt 4 ish stuff.
- CoverIconViewItem *item = currentItem();
- if(item)
- return new CoverDrag(item->id(), this);
- return 0;
-}
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2005 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COVERICONVIEW_H
-#define COVERICONVIEW_H
-
-#include <klistwidget.h>
-
-#include "covermanager.h"
-
-// The WebImageFetcher dialog also has a class named CoverIconViewItem and I
-// don't like the idea of naming it "CoverIVI" or something, so just namespace
-// it out. I would merge them except for webimagefetcher's dependence on KIO
-// and such.
-
-namespace CoverUtility
-{
- class CoverIconViewItem : public QListWidgetItem
- {
- public:
- CoverIconViewItem(coverKey id, KListWidget *parent);
-
- coverKey id() const { return m_id; }
-
- private:
- coverKey m_id;
- };
-}
-
-using CoverUtility::CoverIconViewItem;
-
-/**
- * This class subclasses QListWidget in order to provide cover drag-and-drop
- * support.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class CoverIconView : public KListWidget
-{
-public:
- explicit CoverIconView(QWidget *parent, const char *name = 0);
-
- CoverIconViewItem *currentItem() const;
-
-protected:
- // virtual Q3DragObject *dragObject();
-};
-
-#endif /* COVERICONVIEW_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
- * Copyright (C) 2005, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "coverinfo.h"
-
-#include <kglobal.h>
-#include <kapplication.h>
-#include <kdebug.h>
-
-#include <QRegExp>
-#include <QLabel>
-#include <QCursor>
-#include <QPixmap>
-#include <QMouseEvent>
-#include <QFrame>
-#include <QHBoxLayout>
-#include <QEvent>
-#include <QFile>
-#include <QFileInfo>
-#include <QDesktopWidget>
-#include <QImage>
-#include <QScopedPointer>
-
-#include <taglib/mpegfile.h>
-#include <taglib/tstring.h>
-#include <taglib/id3v2tag.h>
-#include <taglib/attachedpictureframe.h>
-
-#ifdef TAGLIB_WITH_MP4
-#include <taglib/mp4coverart.h>
-#include <taglib/mp4file.h>
-#include <taglib/mp4tag.h>
-#include <taglib/mp4item.h>
-#endif
-
-#include "mediafiles.h"
-#include "collectionlist.h"
-#include "playlistsearch.h"
-#include "playlistitem.h"
-#include "tag.h"
-
-struct CoverPopup : public QWidget
-{
- CoverPopup(const QPixmap &image, const QPoint &p) :
- QWidget(0, Qt::WDestructiveClose | Qt::WX11BypassWM)
- {
- QHBoxLayout *layout = new QHBoxLayout(this);
- QLabel *label = new QLabel(this);
-
- layout->addWidget(label);
- label->setFrameStyle(QFrame::Box | QFrame::Raised);
- label->setLineWidth(1);
- label->setPixmap(image);
-
- setGeometry(p.x(), p.y(), label->width(), label->height());
- show();
- }
- virtual void leaveEvent(QEvent *) { close(); }
- virtual void mouseReleaseEvent(QMouseEvent *) { close(); }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-
-CoverInfo::CoverInfo(const FileHandle &file) :
- m_file(file),
- m_hasCover(false),
- m_hasAttachedCover(false),
- m_haveCheckedForCover(false),
- m_coverKey(CoverManager::NoMatch)
-{
-
-}
-
-bool CoverInfo::hasCover() const
-{
- if(m_haveCheckedForCover)
- return m_hasCover || m_hasAttachedCover;
-
- m_haveCheckedForCover = true;
-
- // Check for new-style covers. First let's determine what our coverKey is
- // if it's not already set, as that's also tracked by the CoverManager.
- if(m_coverKey == CoverManager::NoMatch)
- m_coverKey = CoverManager::idForTrack(m_file.absFilePath());
-
- // We were assigned a key, let's see if we already have a cover. Notice
- // that due to the way the CoverManager is structured, we should have a
- // cover if we have a cover key. If we don't then either there's a logic
- // error, or the user has been mucking around where they shouldn't.
- if(m_coverKey != CoverManager::NoMatch)
- m_hasCover = CoverManager::hasCover(m_coverKey);
-
- // Check if it's embedded in the file itself.
-
- m_hasAttachedCover = hasEmbeddedAlbumArt();
-
- if(m_hasAttachedCover)
- return true;
-
- // Look for cover.jpg or cover.png in the directory.
- if(QFile::exists(m_file.fileInfo().absolutePath() + "/cover.jpg") ||
- QFile::exists(m_file.fileInfo().absolutePath() + "/cover.png"))
- {
- m_hasCover = true;
- }
-
- return m_hasCover;
-}
-
-void CoverInfo::clearCover()
-{
- m_hasCover = false;
- m_hasAttachedCover = false;
-
- // Re-search for cover since we may still have a different type of cover.
- m_haveCheckedForCover = false;
-
- // We don't need to call removeCover because the CoverManager will
- // automatically unlink the cover if we were the last track to use it.
- CoverManager::setIdForTrack(m_file.absFilePath(), CoverManager::NoMatch);
- m_coverKey = CoverManager::NoMatch;
-}
-
-void CoverInfo::setCover(const QImage &image)
-{
- if(image.isNull())
- return;
-
- m_haveCheckedForCover = true;
- m_hasCover = true;
-
- QPixmap cover = QPixmap::fromImage(image);
-
- // If we use replaceCover we'll change the cover for every other track
- // with the same coverKey, which we don't want since that case will be
- // handled by Playlist. Instead just replace this track's cover.
- m_coverKey = CoverManager::addCover(cover, m_file.tag()->artist(), m_file.tag()->album());
- if(m_coverKey != CoverManager::NoMatch)
- CoverManager::setIdForTrack(m_file.absFilePath(), m_coverKey);
-}
-
-void CoverInfo::setCoverId(coverKey id)
-{
- m_coverKey = id;
- m_haveCheckedForCover = true;
- m_hasCover = id != CoverManager::NoMatch;
-
- // Inform CoverManager of the change.
- CoverManager::setIdForTrack(m_file.absFilePath(), m_coverKey);
-}
-
-void CoverInfo::applyCoverToWholeAlbum(bool overwriteExistingCovers) const
-{
- QString artist = m_file.tag()->artist();
- QString album = m_file.tag()->album();
- PlaylistSearch::ComponentList components;
- ColumnList columns;
-
- columns.append(PlaylistItem::ArtistColumn);
- components.append(PlaylistSearch::Component(artist, false, columns, PlaylistSearch::Component::Exact));
-
- columns.clear();
- columns.append(PlaylistItem::AlbumColumn);
- components.append(PlaylistSearch::Component(album, false, columns, PlaylistSearch::Component::Exact));
-
- PlaylistList playlists;
- playlists.append(CollectionList::instance());
-
- PlaylistSearch search(playlists, components, PlaylistSearch::MatchAll);
-
- // Search done, iterate through results.
-
- PlaylistItemList results = search.matchedItems();
- PlaylistItemList::ConstIterator it = results.constBegin();
- for(; it != results.constEnd(); ++it) {
-
- // Don't worry about files that somehow already have a tag,
- // unless the conversion is forced.
- if(!overwriteExistingCovers && (*it)->file().coverInfo()->coverId() != CoverManager::NoMatch)
- continue;
-
- (*it)->file().coverInfo()->setCoverId(m_coverKey);
- }
-}
-
-coverKey CoverInfo::coverId() const
-{
- if(m_coverKey == CoverManager::NoMatch)
- m_coverKey = CoverManager::idForTrack(m_file.absFilePath());
-
- return m_coverKey;
-}
-
-QPixmap CoverInfo::pixmap(CoverSize size) const
-{
- if(hasCover() && m_coverKey != CoverManager::NoMatch) {
- return CoverManager::coverFromId(m_coverKey,
- size == Thumbnail
- ? CoverManager::Thumbnail
- : CoverManager::FullSize);
- }
-
- QImage cover;
-
- // If m_hasCover is still true we must have a directory cover image.
- if(m_hasCover) {
- QString fileName = m_file.fileInfo().absolutePath() + "/cover.jpg";
-
- if(!cover.load(fileName)) {
- fileName = m_file.fileInfo().absolutePath() + "/cover.png";
-
- if(!cover.load(fileName))
- return QPixmap();
- }
- }
-
- // If we get here, see if there is an embedded cover.
- cover = embeddedAlbumArt();
- if(!cover.isNull() && size == Thumbnail)
- cover = scaleCoverToThumbnail(cover);
-
- if(cover.isNull()) {
- return QPixmap();
- }
-
- return QPixmap::fromImage(cover);
-}
-
-QString CoverInfo::localPathToCover(const QString &fallbackFileName) const
-{
- if(m_coverKey != CoverManager::NoMatch) {
- QString path = CoverManager::coverInfo(m_coverKey)->path;
- if(!path.isEmpty())
- return path;
- }
-
- if(hasEmbeddedAlbumArt()) {
- QFile albumArtFile(fallbackFileName);
- if(!albumArtFile.open(QIODevice::ReadWrite)) {
- return QString();
- }
-
- QImage albumArt = embeddedAlbumArt();
- albumArt.save(&albumArtFile, "PNG");
- return fallbackFileName;
- }
-
- QString basePath = m_file.fileInfo().absolutePath();
- if(QFile::exists(basePath + "/cover.jpg"))
- return basePath + "/cover.jpg";
- else if(QFile::exists(basePath + "/cover.png"))
- return basePath + "/cover.png";
-
- return QString();
-}
-
-bool CoverInfo::hasEmbeddedAlbumArt() const
-{
- QScopedPointer<TagLib::File> fileTag(
- MediaFiles::fileFactoryByType(m_file.absFilePath()));
-
- if (TagLib::MPEG::File *mpegFile =
- dynamic_cast<TagLib::MPEG::File *>(fileTag.data()))
- {
- TagLib::ID3v2::Tag *id3tag = mpegFile->ID3v2Tag(false);
-
- if (!id3tag) {
- kError() << m_file.absFilePath() << "seems to have invalid ID3 tag";
- return false;
- }
-
- // Look for attached picture frames.
- TagLib::ID3v2::FrameList frames = id3tag->frameListMap()["APIC"];
- return !frames.isEmpty();
- }
-#ifdef TAGLIB_WITH_MP4
- else if(TagLib::MP4::File *mp4File =
- dynamic_cast<TagLib::MP4::File *>(fileTag.data()))
- {
- TagLib::MP4::Tag *tag = mp4File->tag();
- if (tag) {
- TagLib::MP4::ItemListMap &items = tag->itemListMap();
- return items.contains("covr");
- }
- }
-#endif
-
- return false;
-}
-
-static QImage embeddedMPEGAlbumArt(TagLib::ID3v2::Tag *id3tag)
-{
- if(!id3tag)
- return QImage();
-
- // Look for attached picture frames.
- TagLib::ID3v2::FrameList frames = id3tag->frameListMap()["APIC"];
-
- if(frames.isEmpty())
- return QImage();
-
- // According to the spec attached picture frames have different types.
- // So we should look for the corresponding picture depending on what
- // type of image (i.e. front cover, file info) we want. If only 1
- // frame, just return that (scaled if necessary).
-
- TagLib::ID3v2::AttachedPictureFrame *selectedFrame = 0;
-
- if(frames.size() != 1) {
- TagLib::ID3v2::FrameList::Iterator it = frames.begin();
- for(; it != frames.end(); ++it) {
-
- // This must be dynamic_cast<>, TagLib will return UnknownFrame in APIC for
- // encrypted frames.
- TagLib::ID3v2::AttachedPictureFrame *frame =
- dynamic_cast<TagLib::ID3v2::AttachedPictureFrame *>(*it);
-
- // Both thumbnail and full size should use FrontCover, as
- // FileIcon may be too small even for thumbnail.
- if(frame && frame->type() != TagLib::ID3v2::AttachedPictureFrame::FrontCover)
- continue;
-
- selectedFrame = frame;
- break;
- }
- }
-
- // If we get here we failed to pick a picture, or there was only one,
- // so just use the first picture.
-
- if(!selectedFrame)
- selectedFrame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame *>(frames.front());
-
- if(!selectedFrame) // Could occur for encrypted picture frames.
- return QImage();
-
- TagLib::ByteVector picture = selectedFrame->picture();
- return QImage::fromData(
- reinterpret_cast<const uchar *>(picture.data()),
- picture.size());
-}
-
-#ifdef TAGLIB_WITH_MP4
-static QImage embeddedMP4AlbumArt(TagLib::MP4::Tag *tag)
-{
- TagLib::MP4::ItemListMap &items = tag->itemListMap();
-
- if(!items.contains("covr"))
- return QImage();
-
- TagLib::MP4::CoverArtList covers = items["covr"].toCoverArtList();
- TagLib::MP4::CoverArtList::ConstIterator end = covers.end();
-
- for(TagLib::MP4::CoverArtList::ConstIterator it = covers.begin(); it != end; ++it) {
- TagLib::MP4::CoverArt cover = *it;
- TagLib::ByteVector coverData = cover.data();
-
- QImage result = QImage::fromData(
- reinterpret_cast<const uchar *>(coverData.data()),
- coverData.size());
-
- if(!result.isNull())
- return result;
- }
-
- // No appropriate image found
- return QImage();
-}
-#endif
-
-void CoverInfo::popup() const
-{
- QPixmap image = pixmap(FullSize);
- QPoint mouse = QCursor::pos();
- QRect desktop = QApplication::desktop()->screenGeometry(mouse);
-
- int x = mouse.x();
- int y = mouse.y();
- int height = image.size().height() + 4;
- int width = image.size().width() + 4;
-
- // Detect the right direction to pop up (always towards the center of the
- // screen), try to pop up with the mouse pointer 10 pixels into the image in
- // both directions. If we're too close to the screen border for this margin,
- // show it at the screen edge, accounting for the four pixels (two on each
- // side) for the window border.
-
- if(x - desktop.x() < desktop.width() / 2)
- x = (x - desktop.x() < 10) ? desktop.x() : (x - 10);
- else
- x = (x - desktop.x() > desktop.width() - 10) ? desktop.width() - width +desktop.x() : (x - width + 10);
-
- if(y - desktop.y() < desktop.height() / 2)
- y = (y - desktop.y() < 10) ? desktop.y() : (y - 10);
- else
- y = (y - desktop.y() > desktop.height() - 10) ? desktop.height() - height + desktop.y() : (y - height + 10);
-
- new CoverPopup(image, QPoint(x, y));
-}
-
-QImage CoverInfo::embeddedAlbumArt() const
-{
- QScopedPointer<TagLib::File> fileTag(
- MediaFiles::fileFactoryByType(m_file.absFilePath()));
-
- if (TagLib::MPEG::File *mpegFile =
- dynamic_cast<TagLib::MPEG::File *>(fileTag.data()))
- {
- TagLib::ID3v2::Tag *id3tag = mpegFile->ID3v2Tag(false);
- return embeddedMPEGAlbumArt(id3tag);
- }
-#ifdef TAGLIB_WITH_MP4
- else if(TagLib::MP4::File *mp4File =
- dynamic_cast<TagLib::MP4::File *>(fileTag.data()))
- {
- TagLib::MP4::Tag *tag = mp4File->tag();
- if (tag) {
- return embeddedMP4AlbumArt(tag);
- }
- }
-#endif
-
- return QImage();
-}
-
-QImage CoverInfo::scaleCoverToThumbnail(const QImage &image) const
-{
- return image.scaled(80, 80, Qt::KeepAspectRatio, Qt::SmoothTransformation);
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
- * Copyright (C) 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COVERINFO_H
-#define COVERINFO_H
-
-#include "filehandle.h"
-#include "covermanager.h"
-
-#include <QImage>
-
-class QPixmap;
-
-class CoverInfo
-{
- friend class FileHandle;
-
-public:
- enum CoverSize { FullSize, Thumbnail };
-
- CoverInfo(const FileHandle &file);
-
- bool hasCover() const;
-
- void clearCover();
- void setCover(const QImage &image = QImage());
-
- // Use this to assign to a specific cover id.
- void setCoverId(coverKey id);
-
- /**
- * This function sets the cover identifier for all tracks that have the
- * same Artist and Album as this track, to the cover identifier of this
- * track.
- *
- * @param overwriteExistingCovers If set to true, this function will always
- * apply the new cover to a track even if the track already had
- * a different cover set.
- */
- void applyCoverToWholeAlbum(bool overwriteExistingCovers = false) const;
-
- coverKey coverId() const;
-
- QPixmap pixmap(CoverSize size) const;
-
- /**
- * Returns the path to the cover data. For embedded covers the art will be
- * extracted to a temporary file, and the returned path will be that of the
- * temporary file. The temporary file will be owned by the caller.
- *
- * Note that it is possible to have a valid filename even for covers that
- * do not have "coverKey" since JuK supports using cover.{jpg,png} in a
- * directory.
- *
- * @param fallbackFileName The filename (including full absolute path)
- * of the file to write to if embedded album art is present and to be
- * extracted.
- *
- * If no cover is present, an empty string is returned.
- */
- QString localPathToCover(const QString &fallbackFileName) const;
-
- void popup() const;
-
-private:
- QImage scaleCoverToThumbnail(const QImage &image) const;
-
- // Not supported for all file types as we must build on top of TagLib
- // support.
- QImage embeddedAlbumArt() const;
-
- bool hasEmbeddedAlbumArt() const;
-
- FileHandle m_file;
-
- // Mutable to allow this info to be cached.
- mutable bool m_hasCover;
- mutable bool m_hasAttachedCover;
- mutable bool m_haveCheckedForCover;
- mutable coverKey m_coverKey;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2005, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "covermanager.h"
-
-#include <QTimer>
-#include <QPixmap>
-#include <QString>
-#include <QFile>
-#include <QImage>
-#include <QDir>
-#include <QDataStream>
-#include <QHash>
-#include <QPixmapCache>
-#include <QByteArray>
-#include <QMap>
-
-#include <kdebug.h>
-#include <ktemporaryfile.h>
-#include <kdemacros.h>
-#include <kurl.h>
-#include <kstandarddirs.h>
-#include <kglobal.h>
-#include <kio/job.h>
-
-#include "juk.h"
-#include "coverproxy.h"
-
-// This is a dictionary to map the track path to their ID. Otherwise we'd have
-// to store this info with each CollectionListItem, which would break the cache
-// of users who upgrade, and would just generally be a big mess.
-typedef QHash<QString, coverKey> TrackLookupMap;
-
-static const char dragMimetype[] = "application/x-juk-coverid";
-
-const coverKey CoverManager::NoMatch = 0;
-
-// Used to save and load CoverData from a QDataStream
-QDataStream &operator<<(QDataStream &out, const CoverData &data);
-QDataStream &operator>>(QDataStream &in, CoverData &data);
-
-//
-// Implementation of CoverSaveHelper class
-//
-
-CoverSaveHelper::CoverSaveHelper(QObject *parent) :
- QObject(parent),
- m_timer(new QTimer(this))
-{
- connect(m_timer, SIGNAL(timeout()), SLOT(commitChanges()));
-
- // Wait 5 seconds before committing to avoid lots of disk activity for
- // rapid changes.
-
- m_timer->setSingleShot(true);
- m_timer->setInterval(5000);
-}
-
-void CoverSaveHelper::saveCovers()
-{
- m_timer->start(); // Restarts if already triggered.
-}
-
-void CoverSaveHelper::commitChanges()
-{
- CoverManager::saveCovers();
-}
-
-//
-// Implementation of CoverData struct
-//
-
-QPixmap CoverData::pixmap() const
-{
- return CoverManager::coverFromData(*this, CoverManager::FullSize);
-}
-
-QPixmap CoverData::thumbnail() const
-{
- return CoverManager::coverFromData(*this, CoverManager::Thumbnail);
-}
-
-/**
- * This class is responsible for actually keeping track of the storage for the
- * different covers and such. It holds the covers, and the map of path names
- * to cover ids, and has a few utility methods to load and save the data.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see CoverManager
- */
-class CoverManagerPrivate
-{
-public:
-
- /// Maps coverKey id's to CoverDataPtrs
- CoverDataMap covers;
-
- /// Maps file names to coverKey id's.
- TrackLookupMap tracks;
-
- /// A map of outstanding download KJobs to their coverKey
- QMap<KJob*, coverKey> downloadJobs;
-
- /// A static pixmap cache is maintained for covers, with key format of:
- /// 'f' followed by the pathname for FullSize covers, and
- /// 't' followed by the pathname for Thumbnail covers.
- /// However only thumbnails are currently cached.
-
- CoverManagerPrivate() : m_timer(new CoverSaveHelper(0)), m_coverProxy(0)
- {
- loadCovers();
- }
-
- ~CoverManagerPrivate()
- {
- delete m_timer;
- delete m_coverProxy;
- saveCovers();
- }
-
- void requestSave()
- {
- m_timer->saveCovers();
- }
-
- /**
- * Creates the data directory for the covers if it doesn't already exist.
- * Must be in this class for loadCovers() and saveCovers().
- */
- void createDataDir() const;
-
- /**
- * Returns the next available unused coverKey that can be used for
- * inserting new items.
- *
- * @return unused id that can be used for new CoverData
- */
- coverKey nextId() const;
-
- void saveCovers() const;
-
- CoverProxy *coverProxy() {
- if(!m_coverProxy)
- m_coverProxy = new CoverProxy;
- return m_coverProxy;
- }
-
- private:
- void loadCovers();
-
- /**
- * @return the full path and filename of the file storing the cover
- * lookup map and the translations between pathnames and ids.
- */
- QString coverLocation() const;
-
- CoverSaveHelper *m_timer;
-
- CoverProxy *m_coverProxy;
-};
-
-// This is responsible for making sure that the CoverManagerPrivate class
-// gets properly destructed on shutdown.
-K_GLOBAL_STATIC(CoverManagerPrivate, sd)
-
-//
-// Implementation of CoverManagerPrivate methods.
-//
-void CoverManagerPrivate::createDataDir() const
-{
- QDir dir;
- QString dirPath(QDir::cleanPath(coverLocation() + "/.."));
- if(!dir.exists(dirPath))
- KStandardDirs::makeDir(dirPath);
-}
-
-void CoverManagerPrivate::saveCovers() const
-{
- // Make sure the directory exists first.
- createDataDir();
-
- QFile file(coverLocation());
-
- kDebug() << "Opening covers db: " << coverLocation();
-
- if(!file.open(QIODevice::WriteOnly)) {
- kError() << "Unable to save covers to disk!\n";
- return;
- }
-
- QDataStream out(&file);
-
- // Write out the version and count
- out << quint32(0) << quint32(covers.count());
-
- kDebug() << "Writing out" << covers.count() << "covers.";
-
- // Write out the data
- for(CoverDataMap::const_iterator it = covers.begin(); it != covers.end(); ++it) {
- out << quint32(it.key());
- out << *it.value();
- }
-
- // Now write out the track mapping.
- out << quint32(tracks.count());
-
- kDebug() << "Writing out" << tracks.count() << "tracks.";
-
- TrackLookupMap::ConstIterator trackMapIt = tracks.constBegin();
- while(trackMapIt != tracks.constEnd()) {
- out << trackMapIt.key() << quint32(trackMapIt.value());
- ++trackMapIt;
- }
-}
-
-void CoverManagerPrivate::loadCovers()
-{
- QFile file(coverLocation());
-
- if(!file.open(QIODevice::ReadOnly)) {
- // Guess we don't have any covers yet.
- return;
- }
-
- QDataStream in(&file);
- quint32 count, version;
-
- // First thing we'll read in will be the version.
- // Only version 0 is defined for now.
- in >> version;
- if(version > 0) {
- kError() << "Cover database was created by a higher version of JuK,\n";
- kError() << "I don't know what to do with it.\n";
-
- return;
- }
-
- // Read in the count next, then the data.
- in >> count;
-
- kDebug() << "Loading" << count << "covers.";
- for(quint32 i = 0; i < count; ++i) {
- // Read the id, and 3 QStrings for every 1 of the count.
- quint32 id;
- CoverDataPtr data(new CoverData);
-
- in >> id;
- in >> *data;
- data->refCount = 0;
-
- covers[(coverKey) id] = data;
- }
-
- in >> count;
- kDebug() << "Loading" << count << "tracks";
- for(quint32 i = 0; i < count; ++i) {
- QString path;
- quint32 id;
-
- in >> path >> id;
-
- // If we somehow already managed to load a cover id with this path,
- // don't do so again. Possible due to a coding error during 3.5
- // development.
-
- if(KDE_ISLIKELY(!tracks.contains(path))) {
- ++covers[(coverKey) id]->refCount; // Another track using this.
- tracks.insert(path, id);
- }
- }
-
- kDebug() << "Tracks hash table has" << tracks.size() << "entries.";
-}
-
-QString CoverManagerPrivate::coverLocation() const
-{
- return KGlobal::dirs()->saveLocation("appdata") + "coverdb/covers";
-}
-
-// XXX: This could probably use some improvement, I don't like the linear
-// search for ID idea. Linear search is used instead of covers.size() since we want to
-// re-use old IDs if possible.
-coverKey CoverManagerPrivate::nextId() const
-{
- // Start from 1...
- coverKey key = 1;
-
- while(covers.contains(key))
- ++key;
-
- return key;
-}
-
-//
-// Implementation of CoverDrag
-//
-CoverDrag::CoverDrag(coverKey id) :
- QMimeData()
-{
- QPixmap cover = CoverManager::coverFromId(id);
- setImageData(cover.toImage());
- setData(dragMimetype, QByteArray::number(qulonglong(id), 10));
-}
-
-bool CoverDrag::isCover(const QMimeData *data)
-{
- return data->hasImage() || data->hasFormat(dragMimetype);
-}
-
-coverKey CoverDrag::idFromData(const QMimeData *data)
-{
- bool ok = false;
-
- if(!data->hasFormat(dragMimetype))
- return CoverManager::NoMatch;
-
- coverKey id = data->data(dragMimetype).toULong(&ok);
- if(!ok)
- return CoverManager::NoMatch;
-
- return id;
-}
-
-const char *CoverDrag::mimetype()
-{
- return dragMimetype;
-}
-
-//
-// Implementation of CoverManager methods.
-//
-coverKey CoverManager::idFromMetadata(const QString &artist, const QString &album)
-{
- // Search for the string, yay! It might make sense to use a cache here,
- // if so it's not hard to add a QCache.
- CoverDataMap::const_iterator it = begin();
- CoverDataMap::const_iterator endIt = end();
-
- for(; it != endIt; ++it) {
- if(it.value()->album == album.toLower() && it.value()->artist == artist.toLower())
- return it.key();
- }
-
- return NoMatch;
-}
-
-QPixmap CoverManager::coverFromId(coverKey id, Size size)
-{
- CoverDataPtr info = coverInfo(id);
-
- if(!info)
- return QPixmap();
-
- if(size == Thumbnail)
- return info->thumbnail();
-
- return info->pixmap();
-}
-
-QPixmap CoverManager::coverFromData(const CoverData &coverData, Size size)
-{
- QString path = coverData.path;
-
- // Prepend a tag to the path to separate in the cache between full size
- // and thumbnail pixmaps. If we add a different kind of pixmap in the
- // future we also need to add a tag letter for it.
- if(size == FullSize)
- path.prepend('f');
- else
- path.prepend('t');
-
- // Check in cache for the pixmap.
-
- QPixmap pix;
- if(QPixmapCache::find(path, pix))
- return pix;
-
- // Not in cache, load it and add it.
-
- if(!pix.load(coverData.path))
- return QPixmap();
-
- // Only thumbnails are cached to avoid depleting global cache. Caching
- // full size pics is not really useful as they are infrequently shown.
-
- if(size == Thumbnail) {
- // Double scale is faster and 99% as accurate
- QSize newSize(pix.size());
- newSize.scale(80, 80, Qt::KeepAspectRatio);
- pix = pix.scaled(2 * newSize)
- .scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
- QPixmapCache::insert(path, pix);
- }
-
- return pix;
-}
-
-coverKey CoverManager::addCover(const QPixmap &large, const QString &artist, const QString &album)
-{
- kDebug() << "Adding new pixmap to cover database.\n";
-
- if(large.isNull()) {
- kDebug() << "The pixmap you're trying to add is NULL!\n";
- return NoMatch;
- }
-
- KTemporaryFile tempFile;
- if(!tempFile.open()) {
- kError() << "Unable to open file for pixmap cover, unable to add cover to DB\n";
- return NoMatch;
- }
-
- // Now that file is open, file name will be available, which is where we want
- // to save the pixmap as a .png.
-
- if(!large.save(tempFile.fileName(), "PNG")) {
- kError() << "Unable to save pixmap to " << tempFile.fileName() << endl;
- return NoMatch;
- }
-
- return addCover(KUrl::fromPath(tempFile.fileName()), artist, album);
-}
-
-coverKey CoverManager::addCover(const KUrl &path, const QString &artist, const QString &album)
-{
- coverKey id = data()->nextId();
- CoverDataPtr coverData(new CoverData);
-
- QString fileNameExt = path.fileName();
- int extPos = fileNameExt.lastIndexOf('.');
-
- fileNameExt = fileNameExt.mid(extPos);
- if(extPos == -1)
- fileNameExt = "";
-
- // Copy it to a local file first.
-
- QString ext = QString("/coverdb/coverID-%1%2").arg(id).arg(fileNameExt);
- coverData->path = KGlobal::dirs()->saveLocation("appdata") + ext;
-
- kDebug() << "Saving pixmap to " << coverData->path;
- data()->createDataDir();
-
- coverData->artist = artist.toLower();
- coverData->album = album.toLower();
- coverData->refCount = 0;
-
- data()->covers[id] = coverData;
-
- // Can't use NetAccess::download() since if path is already a local file
- // (which is possible) then that function will return without copying, since
- // it assumes we merely want the file on the hard disk somewhere.
-
- KIO::FileCopyJob *job = KIO::file_copy(
- path, KUrl::fromPath(coverData->path),
- -1 /* perms */,KIO::HideProgressInfo | KIO::Overwrite
- );
- QObject::connect(job, SIGNAL(result(KJob*)),
- data()->coverProxy(), SLOT(handleResult(KJob*)));
- data()->downloadJobs.insert(job, id);
-
- job->start();
-
- data()->requestSave(); // Save changes when possible.
-
- return id;
-}
-
-/**
- * This is called when our cover downloader has completed. Typically there
- * should be no issues so we just need to ensure that the newly downloaded
- * cover is picked up by invalidating any cache entry for it. If it didn't
- * download successfully we're in kind of a pickle as we've already assigned
- * a coverKey, which we need to go and erase.
- */
-void CoverManager::jobComplete(KJob *job, bool completedSatisfactory)
-{
- coverKey id = NoMatch;
- if(data()->downloadJobs.contains(job))
- id = data()->downloadJobs[job];
-
- if(id == NoMatch) {
- kError() << "No information on what download job" << job << "is.";
- data()->downloadJobs.remove(job);
- return;
- }
-
- if(!completedSatisfactory) {
- kError() << "Job" << job << "failed, but not handled yet.";
- removeCover(id);
- data()->downloadJobs.remove(job);
- JuK::JuKInstance()->coverDownloaded(QPixmap());
- return;
- }
-
- CoverDataPtr coverData = data()->covers[id];
-
- // Make sure the new cover isn't inadvertently cached.
- QPixmapCache::remove(QString("f%1").arg(coverData->path));
- QPixmapCache::remove(QString("t%1").arg(coverData->path));
-
- JuK::JuKInstance()->coverDownloaded(coverFromData(*coverData, CoverManager::Thumbnail));
-}
-
-bool CoverManager::hasCover(coverKey id)
-{
- return data()->covers.contains(id);
-}
-
-bool CoverManager::removeCover(coverKey id)
-{
- if(!hasCover(id))
- return false;
-
- // Remove cover from cache.
- CoverDataPtr coverData = coverInfo(id);
- QPixmapCache::remove(QString("f%1").arg(coverData->path));
- QPixmapCache::remove(QString("t%1").arg(coverData->path));
-
- // Remove references to files that had that track ID.
- QList<QString> affectedFiles = data()->tracks.keys(id);
- foreach (const QString &file, affectedFiles) {
- data()->tracks.remove(file);
- }
-
- // Remove covers from disk.
- QFile::remove(coverData->path);
-
- // Finally, forget that we ever knew about this cover.
- data()->covers.remove(id);
- data()->requestSave();
-
- return true;
-}
-
-bool CoverManager::replaceCover(coverKey id, const QPixmap &large)
-{
- if(!hasCover(id))
- return false;
-
- CoverDataPtr coverData = coverInfo(id);
-
- // Empty old pixmaps from cache.
- QPixmapCache::remove(QString("t%1").arg(coverData->path));
- QPixmapCache::remove(QString("f%1").arg(coverData->path));
-
- large.save(coverData->path, "PNG");
-
- // No save is needed, as all that has changed is the on-disk cover data,
- // not the list of tracks or covers.
-
- return true;
-}
-
-CoverManagerPrivate *CoverManager::data()
-{
- return sd;
-}
-
-void CoverManager::saveCovers()
-{
- data()->saveCovers();
-}
-
-void CoverManager::shutdown()
-{
- sd.destroy();
-}
-
-CoverDataMapIterator CoverManager::begin()
-{
- return data()->covers.constBegin();
-}
-
-CoverDataMapIterator CoverManager::end()
-{
- return data()->covers.constEnd();
-}
-
-CoverList CoverManager::keys()
-{
- return data()->covers.keys();
-}
-
-void CoverManager::setIdForTrack(const QString &path, coverKey id)
-{
- coverKey oldId = data()->tracks.value(path, NoMatch);
- if(data()->tracks.contains(path) && (id == oldId))
- return; // We're already done.
-
- if(oldId != NoMatch) {
- data()->covers[oldId]->refCount--;
- data()->tracks.remove(path);
-
- if(data()->covers[oldId]->refCount == 0) {
- kDebug() << "Cover " << oldId << " is unused, removing.\n";
- removeCover(oldId);
- }
- }
-
- if(id != NoMatch) {
- data()->covers[id]->refCount++;
- data()->tracks.insert(path, id);
- }
-
- data()->requestSave();
-}
-
-coverKey CoverManager::idForTrack(const QString &path)
-{
- return data()->tracks.value(path, NoMatch);
-}
-
-CoverDataPtr CoverManager::coverInfo(coverKey id)
-{
- if(data()->covers.contains(id))
- return data()->covers[id];
-
- return CoverDataPtr(0);
-}
-
-/**
- * Write @p data out to @p out.
- *
- * @param out the data stream to write @p data out to.
- * @param data the CoverData to write out.
- * @return the data stream that the data was written to.
- */
-QDataStream &operator<<(QDataStream &out, const CoverData &data)
-{
- out << data.artist;
- out << data.album;
- out << data.path;
-
- return out;
-}
-
-/**
- * Read @p data from @p in.
- *
- * @param in the data stream to read from.
- * @param data the CoverData to read into.
- * @return the data stream read from.
- */
-QDataStream &operator>>(QDataStream &in, CoverData &data)
-{
- in >> data.artist;
- in >> data.album;
- in >> data.path;
-
- return in;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2005, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_COVERMANAGER_H
-#define JUK_COVERMANAGER_H
-
-#include <ksharedptr.h>
-
-#include <QObject>
-#include <QMimeData>
-#include <QString>
-
-class CoverManagerPrivate;
-class CoverProxy;
-class QPixmap;
-class QTimer;
-class KJob;
-
-template<class Key, class Value>
-class QMap;
-
-template<class T>
-class QList;
-
-class KUrl;
-
-/**
- * This class saves the covers when its saveCovers() slot is called to avoid
- * making CoverManager a QObject and avoid moving the actual implementation
- * class (CoverManagerPrivate) to this .h file. Used with a QTimer to save
- * the covers after changes are made.
- */
-class CoverSaveHelper : public QObject
-{
- Q_OBJECT
-
-public:
- CoverSaveHelper(QObject *parent);
- void saveCovers();
-
-private slots:
- void commitChanges();
-
-private:
- QTimer *m_timer;
-};
-
-/**
- * This class holds the data on a cover. This includes the path to the cover
- * representation on-disk, and the artist and album associated with the cover.
- * Don't assume that the artist or album information is filled out, it is
- * there to allow the CoverManager to try to automatically assign covers to
- * new tracks.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see CoverManager
- */
-class CoverData : public KShared
-{
-public:
- QPixmap pixmap() const;
- QPixmap thumbnail() const;
-
- QString artist;
- QString album;
- QString path;
-
- unsigned refCount; // Refers to number of tracks using this.
-};
-
-typedef KSharedPtr<CoverData> CoverDataPtr;
-typedef unsigned long coverKey; ///< Type of the id for a cover.
-
-typedef QMap<coverKey, CoverDataPtr> CoverDataMap;
-
-// I can't believe this actually works...
-typedef CoverDataMap::const_iterator CoverDataMapIterator;
-
-typedef QList<coverKey> CoverList;
-
-/**
- * This class is used to drag covers in JuK. It adds a special mimetype that
- * contains the cover ID used for this cover, and also supports an image/png
- * mimetype for dragging to other applications.
- *
- * As of this writing the mimetype is application/x-juk-coverid
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class CoverDrag : public QMimeData
-{
- Q_OBJECT
-
-public:
- CoverDrag(coverKey id);
-
- static const char* mimetype();
-
- static bool isCover(const QMimeData *data);
-
- // CoverDrag stores QByteArray data for the cover id, this can convert it
- // back.
- static coverKey idFromData(const QMimeData *data);
-};
-
-/**
- * This class holds all of the cover art, and manages looking it up by artist
- * and/or album. This class is similar to a singleton class, but instead all
- * of the methods are static. This way you can invoke methods like this:
- * \code
- * CoverManager::method()
- * \endcode
- * instead of using:
- * \code
- * CoverManager::instance()->method()
- * \endcode
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class CoverManager
-{
-public:
- /// The set of different sizes you can request a pixmap as.
- typedef enum { Thumbnail, FullSize } Size;
-
- /**
- * Tries to match @p artist and @p album to a cover in the database.
- *
- * @param artist The artist to look for matching covers on.
- * @param album The album to look for matching covers on.
- * @return NoMatch if no match could be found, otherwise the id of the
- * cover art that matches the given metadata.
- */
- static coverKey idFromMetadata(const QString &artist, const QString &album);
-
- /**
- * Returns the cover art for @p id.
- *
- * @param id The id of the cover.
- * @param size The size to return it as. Note that FullSize doesn't
- * necessarily mean the pixmap is large, so you may need to
- * scale it up.
- * @return QPixmap::null if there is no cover art for @p id, otherwise the
- * cover art.
- */
- static QPixmap coverFromId(coverKey id, Size size = Thumbnail);
-
- /**
- * Returns the cover art for @p ptr. This function is intended for use
- * by CoverData.
- *
- * @param ptr The CoverData to get the cover of. Note that it is a
- * CoverData, not CoverDataPtr.
- * @param size The size to return it as.
- * @see CoverData
- */
- static QPixmap coverFromData(const CoverData &coverData, Size size = Thumbnail);
-
- /**
- * Returns the full suite of information known about the cover given by
- * @p id.
- *
- * @param id the id of the cover to retrieve info on.
- * @return 0 if there is no info on @p id, otherwise its information.
- */
- static CoverDataPtr coverInfo(coverKey id);
-
- /**
- * Adds @p large to the cover database, associating with it @p artist and
- * @p album.
- *
- * @param large The full size cover (the thumbnail is automatically
- * generated).
- * @param artist The artist of the new cover.
- * @param album The album of the new cover.
- */
- static coverKey addCover(const QPixmap &large, const QString &artist = "", const QString &album = "");
-
- /**
- * Adds the file pointed to by the local path @p path to the database,
- * associating it with @p artist and @p album.
- *
- * @param path The absolute path to the fullsize cover art.
- * @param artist The artist of the new cover.
- * @param album The album of the new cover.
- */
- static coverKey addCover(const KUrl &path, const QString &artist = "", const QString &album = "");
-
- /**
- * Function to determine if @p id matches any covers in the database.
- *
- * @param id The id of the cover to search for.
- * @return true if the database has a cover identified by @p id, false
- * otherwise.
- */
- static bool hasCover(coverKey id);
-
- /**
- * Removes the cover identified by @p id.
- *
- * @param id the id of the cover to remove.
- * @return true if the removal was successful, false if unsuccessful or if
- * the cover didn't exist.
- */
- static bool removeCover(coverKey id);
-
- /**
- * Replaces the cover art for the cover identified by @p id with @p large.
- * Any other metadata such as artist and album is unchanged.
- *
- * @param id The id of the cover to replace.
- * @param large The full size cover art for the new cover.
- */
- static bool replaceCover(coverKey id, const QPixmap &large);
-
- /**
- * Saves the current CoverManager information to disk. Changes are not
- * automatically written to disk due to speed issues, so you can
- * periodically call this function while running to reduce the chance of
- * lost data in the event of a crash.
- */
- static void saveCovers();
-
- /**
- * This is a hack, as we should be shut down automatically by
- * KStaticDeleter, but JuK is crashing for me on shutdown before
- * KStaticDeleter gets a chance to run, which is cramping my testing.
- */
- static void shutdown();
-
- /**
- * @return Iterator pointing to the first element in the cover database.
- */
- static CoverDataMapIterator begin();
-
- /**
- * @return Iterator pointing after the last element in the cover database.
- */
- static CoverDataMapIterator end();
-
- /**
- * @return A list of all of the id's listed in the database.
- */
- static CoverList keys();
-
- /**
- * Associates @p path with the cover identified by @id. No comparison of
- * metadata is performed to enforce this matching.
- *
- * @param path The absolute file path to the track.
- * @param id The identifier of the cover to use with @p path.
- */
- static void setIdForTrack(const QString &path, coverKey id);
-
- /**
- * Returns the identifier of the cover for the track at @p path.
- *
- * @param path The absolute file path to the track.
- * @return NoMatch if @p path doesn't have a cover, otherwise the id of
- * its cover.
- */
- static coverKey idForTrack(const QString &path);
-
- /**
- * This identifier is used to indicate that no cover was found in the
- * database.
- */
- static const coverKey NoMatch;
-
- private:
- friend class CoverProxy; // Our QObject-wielding friend.
-
- /// Called by CoverProxy to notify of a completed job.
- static void jobComplete(KJob *job, bool completedSatisfactory);
- static CoverManagerPrivate *data();
- static QPixmap createThumbnail(const QPixmap &base);
-};
-
-#endif /* JUK_COVERMANAGER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "coverproxy.h"
-#include "covermanager.h"
-
-#include <kdebug.h>
-#include <kio/job.h>
-
-CoverProxy::CoverProxy(QObject *parent) :
- QObject(parent)
-{
-}
-
-void CoverProxy::handleResult(KJob *job)
-{
- if(job->error()) {
- kError() << "Cover download job failed with the following error:" << job->errorString();
- CoverManager::jobComplete(job, false);
- }
- else {
- CoverManager::jobComplete(job, true);
- }
-}
-
-#include "coverproxy.moc"
+++ /dev/null
-/**
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_COVERPROXY_H
-#define JUK_COVERPROXY_H
-
-#include <QtCore/QObject>
-
-class KJob;
-
-/**
- * This class is responsible for tracking status of KIO::Jobs that are
- * downloading covers for the CoverManager.
- */
-class CoverProxy : public QObject
-{
- Q_OBJECT
-
-public:
- CoverProxy(QObject *parent = 0);
-
-private slots:
- void handleResult(KJob *);
-};
-
-#endif
+++ /dev/null
-/**
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "dbuscollectionproxy.h"
-
-#include <QtCore/QStringList>
-#include <QtCore/QFile>
-#include <QtGui/QPixmap>
-#include <QtDBus/QDBusConnection>
-
-#include <KTemporaryFile>
-#include <kdebug.h>
-
-#include "collectionadaptor.h"
-#include "playlistcollection.h"
-#include "covermanager.h"
-#include "collectionlist.h"
-#include "coverinfo.h"
-#include "filehandle.h"
-
-DBusCollectionProxy::DBusCollectionProxy (QObject *parent, PlaylistCollection *collection) :
- QObject(parent), m_collection(collection)
-{
- setObjectName( QLatin1String("DBusCollectionProxy" ));
-
- new CollectionAdaptor(this);
- QDBusConnection::sessionBus().registerObject("/Collection",this);
-}
-
-DBusCollectionProxy::~DBusCollectionProxy()
-{
- // Clean's the way to be
- if(!m_lastCover.isEmpty())
- QFile::remove(m_lastCover);
-}
-
-void DBusCollectionProxy::openFile(const QString &file)
-{
- m_collection->open(QStringList(file));
-}
-
-void DBusCollectionProxy::openFile(const QStringList &files)
-{
- m_collection->open(files);
-}
-
-void DBusCollectionProxy::openFile(const QString &playlist, const QString &file)
-{
- m_collection->open(playlist, QStringList(file));
-}
-
-void DBusCollectionProxy::openFile(const QString &playlist, const QStringList &files)
-{
- m_collection->open(playlist, files);
-}
-
-QString DBusCollectionProxy::visiblePlaylist()
-{
- return m_collection->playlist();
-}
-
-QString DBusCollectionProxy::playingPlaylist()
-{
- return m_collection->playingPlaylist();
-}
-
-QStringList DBusCollectionProxy::playlists()
-{
- return m_collection->playlists();
-}
-
-QStringList DBusCollectionProxy::playlistTracks(const QString &playlist)
-{
- return m_collection->playlistTracks(playlist);
-}
-
-QString DBusCollectionProxy::trackProperty(const QString &file, const QString &property)
-{
- return m_collection->trackProperty(file, property);
-}
-
-void DBusCollectionProxy::createPlaylist(const QString &name)
-{
- m_collection->createPlaylist(name);
-}
-
-void DBusCollectionProxy::setPlaylist(const QString &name)
-{
- m_collection->setPlaylist(name);
-}
-
-void DBusCollectionProxy::remove()
-{
- m_collection->remove();
-}
-
-void DBusCollectionProxy::removeTrack(const QString &playlist, const QStringList &files)
-{
- m_collection->removeTrack(playlist, files);
-}
-
-QString DBusCollectionProxy::trackCover(const QString &track)
-{
- coverKey id = CoverManager::idForTrack(track);
- if(id != CoverManager::NoMatch) {
- CoverDataPtr coverData = CoverManager::coverInfo(id);
- return coverData->path;
- }
-
- // No cover, let's see if one is embedded.
- CollectionListItem *collectionItem = CollectionList::instance()->lookup(track);
-
- if(!collectionItem)
- return QString();
-
- CoverInfo *coverInfo = collectionItem->file().coverInfo();
- if(!coverInfo)
- return QString();
-
- QPixmap cover = coverInfo->pixmap(CoverInfo::FullSize);
- if(cover.isNull())
- return QString();
-
- // We have a cover, extract it and save it to a temporary file.
- KTemporaryFile tempFile;
-
- tempFile.setSuffix(".png");
- tempFile.setAutoRemove(false);
-
- if(!tempFile.open()) {
- kError() << "Unable to open temporary file for embedded cover art.";
- return QString();
- }
-
- // Save last file name cover, remove it if it's there so that we don't fill
- // the temp directory with pixmaps.
- if(!m_lastCover.isEmpty())
- QFile::remove(m_lastCover);
- m_lastCover = tempFile.fileName();
-
- cover.save(&tempFile, "PNG");
- return tempFile.fileName();
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DBUS_COLLECTION_PROXY_H
-#define DBUS_COLLECTION_PROXY_H
-
-#include <QtCore/QObject>
-#include <QtCore/QStringList> // Required for Q_CLASSINFO ?
-
-class PlaylistCollection;
-
-class DBusCollectionProxy : public QObject
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.kde.juk.collection")
-
-public:
- DBusCollectionProxy (QObject *parent, PlaylistCollection *collection);
- ~DBusCollectionProxy();
-
-public slots: // Expose to D-Bus
- void openFile(const QString &file);
- void openFile(const QStringList &files);
- void openFile(const QString &playlist, const QString &file);
- void openFile(const QString &playlist, const QStringList &files);
-
- QString visiblePlaylist();
- QString playingPlaylist();
- QStringList playlists();
- QStringList playlistTracks(const QString &playlist);
- QString trackProperty(const QString &file, const QString &property);
-
- void createPlaylist(const QString &name);
- void setPlaylist(const QString &name);
- void remove();
- void removeTrack(const QString &playlist, const QStringList &files);
-
- /**
- * Returns the path to the cover art for the given file. Returns the empty
- * string if the track has no cover art. Some tracks have embedded cover
- * art -- in this case JuK returns the path to a temporary file with the
- * extracted cover art.
- */
- QString trackCover(const QString &track);
-
-private:
- PlaylistCollection *m_collection;
- QString m_lastCover;
-};
-
-#endif /* DBUS_COLLECTION_PROXY_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "deletedialog.h"
-#include "ui_deletedialogbase.h"
-
-#include <KApplication>
-#include <KStandardGuiItem>
-#include <klocale.h>
-#include <kiconloader.h>
-#include <kconfig.h>
-#include <kconfiggroup.h>
-
-#include <QStringList>
-#include <QCheckBox>
-
-//////////////////////////////////////////////////////////////////////////////
-// DeleteWidget implementation
-//////////////////////////////////////////////////////////////////////////////
-
-DeleteWidget::DeleteWidget(QWidget *parent)
- : QWidget(parent), m_ui(new Ui::DeleteDialogBase)
-{
- m_ui->setupUi(this);
-
- setObjectName( QLatin1String("delete_dialog_widget" ));
-
- KConfigGroup messageGroup(KGlobal::config()->group("FileRemover"));
-
- bool deleteInstead = messageGroup.readEntry("deleteInsteadOfTrash", false);
- slotShouldDelete(deleteInstead);
- m_ui->ddShouldDelete->setChecked(deleteInstead);
-
- // Forward on this signal.
- connect(m_ui->ddShouldDelete, SIGNAL(toggled(bool)), SIGNAL(signalShouldDelete(bool)));
-}
-
-void DeleteWidget::setFiles(const QStringList &files)
-{
- m_ui->ddFileList->clear();
- m_ui->ddFileList->insertItems(0, files);
- m_ui->ddNumFiles->setText(i18np("<b>1</b> file selected.", "<b>%1</b> files selected.", files.count()));
-}
-
-bool DeleteWidget::shouldDelete() const
-{
- return m_ui->ddShouldDelete->isChecked();
-}
-
-void DeleteWidget::slotShouldDelete(bool shouldDelete)
-{
- if(shouldDelete) {
- m_ui->ddDeleteText->setText(i18n("<qt>These items will be <b>permanently "
- "deleted</b> from your hard disk.</qt>"));
- m_ui->ddWarningIcon->setPixmap(KIconLoader::global()->loadIcon("dialog-warning",
- KIconLoader::Desktop, KIconLoader::SizeLarge));
- }
- else {
- m_ui->ddDeleteText->setText(i18n("<qt>These items will be moved to the Trash Bin.</qt>"));
- m_ui->ddWarningIcon->setPixmap(KIconLoader::global()->loadIcon("user-trash-full",
- KIconLoader::Desktop, KIconLoader::SizeLarge));
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// DeleteDialog implementation
-//////////////////////////////////////////////////////////////////////////////
-
-DeleteDialog::DeleteDialog(QWidget *parent) :
- KDialog(parent, Qt::WStyle_DialogBorder),
- m_trashGuiItem(i18n("&Send to Trash"), "user-trash-full")
-{
- setObjectName( QLatin1String("delete_dialog" ));
- setModal(true);
- setCaption(i18n("About to delete selected files"));
- setButtons(Ok | Cancel);
- setDefaultButton(Cancel);
- showButtonSeparator(true);
-
- m_widget = new DeleteWidget(this);
- setMainWidget(m_widget);
-
- m_widget->setMinimumSize(400, 300);
-
- // Trying to adjust for Qt bug with rich text where the layout is ignored
- // (something about not being able to get height-for-width on X11?)
- setMinimumSize(410, 326);
- adjustSize();
-
- slotShouldDelete(shouldDelete());
-
- connect(m_widget, SIGNAL(signalShouldDelete(bool)), SLOT(slotShouldDelete(bool)));
-}
-
-bool DeleteDialog::confirmDeleteList(const QStringList &condemnedFiles)
-{
- m_widget->setFiles(condemnedFiles);
-
- return exec() == QDialog::Accepted;
-}
-
-void DeleteDialog::setFiles(const QStringList &files)
-{
- m_widget->setFiles(files);
-}
-
-void DeleteDialog::accept()
-{
- KConfigGroup messageGroup(KGlobal::config()->group("FileRemover"));
-
- // Save user's preference
-
- messageGroup.writeEntry("deleteInsteadOfTrash", shouldDelete());
- messageGroup.sync();
-
- KDialog::accept();
-}
-
-void DeleteDialog::slotShouldDelete(bool shouldDelete)
-{
- setButtonGuiItem(Ok, shouldDelete ? KStandardGuiItem::del() : m_trashGuiItem);
-}
-
-#include "deletedialog.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DELETEDIALOG_H
-#define DELETEDIALOG_H
-
-class QStringList;
-
-#include <QWidget>
-
-#include <KDialog>
-
-namespace Ui
-{
- class DeleteDialogBase;
-}
-
-class DeleteWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- DeleteWidget(QWidget *parent);
-
- void setFiles(const QStringList &files);
- bool shouldDelete() const;
-
-signals:
- void signalShouldDelete(bool);
-
-protected slots:
- virtual void slotShouldDelete(bool shouldDelete);
-
-private:
- Ui::DeleteDialogBase *m_ui;
-};
-
-class DeleteDialog : public KDialog
-{
- Q_OBJECT
-
-public:
- DeleteDialog(QWidget *parent);
-
- bool confirmDeleteList(const QStringList &condemnedFiles);
- void setFiles(const QStringList &files);
- bool shouldDelete() const { return m_widget->shouldDelete(); }
-
-protected slots:
- virtual void accept();
- void slotShouldDelete(bool shouldDelete);
-
-private:
- DeleteWidget *m_widget;
- KGuiItem m_trashGuiItem;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DeleteDialogBase</class>
- <widget class="QWidget" name="DeleteDialogBase">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>542</width>
- <height>374</height>
- </rect>
- </property>
- <property name="minimumSize">
- <size>
- <width>420</width>
- <height>320</height>
- </size>
- </property>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>11</number>
- </property>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="ddWarningIcon">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string comment="KDE::DoNotExtract">Icon Placeholder, not in GUI</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="textLabel1">
- <property name="text">
- <string>Are you sure that you want to remove these items?</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="ddDeleteText">
- <property name="text">
- <string comment="KDE::DoNotExtract">Deletion method placeholder, never shown to user.</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QListWidget" name="ddFileList">
- <property name="selectionMode">
- <enum>QAbstractItemView::NoSelection</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="ddNumFiles">
- <property name="text">
- <string comment="KDE::DoNotExtract">Placeholder for number of files, not in GUI</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="ddShouldDelete">
- <property name="toolTip">
- <string>If checked, files will be permanently removed instead of being placed in the Trash Bin</string>
- </property>
- <property name="whatsThis">
- <string><qt><p>If this box is checked, files will be <b>permanently removed</b> instead of being placed in the Trash Bin.</p>
-
-<p><em>Use this option with caution</em>: Most filesystems are unable to reliably undelete deleted files.</p></qt></string>
- </property>
- <property name="text">
- <string>&Delete files instead of moving them to the trash</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>ddShouldDelete</sender>
- <signal>toggled(bool)</signal>
- <receiver>DeleteDialogBase</receiver>
- <slot>slotShouldDelete(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel">
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Georg Grabler <ggrabler@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "directorylist.h"
-
-#include <QtGui/QCheckBox>
-#include <QtGui/QStringListModel>
-#include <QtCore/QVariant>
-
-#include <kfiledialog.h>
-#include <klocale.h>
-#include <kpushbutton.h>
-#include <kdebug.h>
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-DirectoryList::DirectoryList(QStringList directories,
- QStringList excludedDirectories,
- bool importPlaylists,
- QWidget *parent) :
- KDialog(parent),
- m_dirListModel(0)
-{
- if(directories.isEmpty()) {
- directories = defaultFolders();
- m_result.addedDirs = directories;
- }
-
- m_dirListModel = new QStringListModel(directories, this);
- m_excludedDirListModel = new QStringListModel(excludedDirectories, this);
-
- setCaption(i18n("Folder List"));
- setModal(true);
- showButtonSeparator(true);
- setButtons(KDialog::Ok | KDialog::Cancel);
-
- m_base = new DirectoryListBase(this);
-
- setMainWidget(m_base);
-
- connect(m_base->addDirectoryButton, SIGNAL(clicked()),
- SLOT(slotAddDirectory()));
- connect(m_base->removeDirectoryButton, SIGNAL(clicked()),
- SLOT(slotRemoveDirectory()));
- connect(m_base->addExcludeDirectoryButton, SIGNAL(clicked()),
- SLOT(slotAddExcludeDirectory()));
- connect(m_base->removeExcludeDirectoryButton, SIGNAL(clicked()),
- SLOT(slotRemoveExcludeDirectory()));
-
- m_base->directoryListView->setModel(m_dirListModel);
- m_base->excludeDirectoryListView->setModel(m_excludedDirListModel);
- m_base->importPlaylistsCheckBox->setChecked(importPlaylists);
-
- resize(QSize(440, 280).expandedTo(minimumSizeHint()));
-}
-
-DirectoryList::~DirectoryList()
-{
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-DirectoryList::Result DirectoryList::exec()
-{
- m_result.status = static_cast<DialogCode>(KDialog::exec());
- m_result.addPlaylists = m_base->importPlaylistsCheckBox->isChecked();
- return m_result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void DirectoryList::slotAddDirectory()
-{
- QString dir = KFileDialog::getExistingDirectory();
-
- if(dir.isEmpty())
- return;
-
- QStringList dirs = m_dirListModel->stringList();
- if(!dirs.contains(dir)) {
- dirs.append(dir);
- m_dirListModel->setStringList(dirs);
-
- m_result.addedDirs.append(dir);
- m_result.removedDirs.removeAll(dir);
- }
-}
-
-void DirectoryList::slotRemoveDirectory()
-{
- QItemSelectionModel *itemSelection = m_base->directoryListView->selectionModel();
-
- // These will be used in the loop below
- QModelIndexList indexes;
- QModelIndex firstIndex;
- QString dir;
-
- // The multiple indexes that are possibly present cannot be deleted one
- // after the other, as changing the layout of the model can change the
- // indexes (similar to iterators and container remove methods). So, just
- // loop deleting the first index until there is no selection.
-
- while(itemSelection->hasSelection()) {
- indexes = itemSelection->selectedIndexes();
- firstIndex = indexes.first();
- dir = m_dirListModel->data(firstIndex, Qt::DisplayRole).toString();
-
- m_dirListModel->removeRow(firstIndex.row());
-
- // Don't mess up if user removes directory they've just added before
- // closing out of the dialog.
- if(m_result.addedDirs.contains(dir))
- m_result.addedDirs.removeAll(dir);
- else
- m_result.removedDirs.append(dir);
- }
-}
-
-void DirectoryList::slotAddExcludeDirectory()
-{
- QString dir = KFileDialog::getExistingDirectory();
-
- if(dir.isEmpty())
- return;
-
- QStringList dirs = m_excludedDirListModel->stringList();
- if(!dirs.contains(dir)) {
- dirs.append(dir);
- m_excludedDirListModel->setStringList(dirs);
- }
- m_result.excludedDirs = m_excludedDirListModel->stringList();
-}
-
-void DirectoryList::slotRemoveExcludeDirectory()
-{
- QItemSelectionModel *itemSelection = m_base->excludeDirectoryListView->selectionModel();
-
- // These will be used in the loop below
- QModelIndexList indexes;
- QModelIndex firstIndex;
- QString dir;
-
- // The multiple indexes that are possibly present cannot be deleted one
- // after the other, as changing the layout of the model can change the
- // indexes (similar to iterators and container remove methods). So, just
- // loop deleting the first index until there is no selection.
-
- while(itemSelection->hasSelection()) {
- indexes = itemSelection->selectedIndexes();
- firstIndex = indexes.first();
-
- m_excludedDirListModel->removeRow(firstIndex.row());
- }
- m_result.excludedDirs = m_excludedDirListModel->stringList();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-QStringList DirectoryList::defaultFolders()
-{
- QDir home = QDir::home();
- if(home.cd("Music"))
- return QStringList(home.path());
- if(home.cd("music"))
- return QStringList(home.path());
- if(home.cd(i18n("Music")))
- return QStringList(home.path());
- return QStringList();
-}
-
-#include "directorylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DIRECTORYLIST_H
-#define DIRECTORYLIST_H
-
-#include <kdialog.h>
-#include "ui_directorylistbase.h"
-
-class QStringListModel;
-
-class DirectoryListBase : public QWidget, public Ui::DirectoryListBase
-{
-public:
- DirectoryListBase(QWidget *parent) : QWidget(parent)
- {
- setupUi(this);
- }
-};
-
-class DirectoryList : public KDialog
-{
- Q_OBJECT
-
-public:
- struct Result
- {
- QStringList addedDirs;
- QStringList removedDirs;
- QStringList excludedDirs;
- DialogCode status;
- bool addPlaylists;
- };
-
- DirectoryList(QStringList directories, QStringList excludeDirectories, bool importPlaylists,
- QWidget *parent = 0);
- virtual ~DirectoryList();
-
-public slots:
- Result exec();
-
-signals:
- void signalDirectoryAdded(const QString &directory);
- void signalDirectoryRemoved(const QString &directory);
- void signalExcludeDirectoryAdded(const QString &directory);
- void signalExcludeDirectoryRemoved(const QString &directory);
-
-private slots:
- void slotAddDirectory();
- void slotRemoveDirectory();
- void slotAddExcludeDirectory();
- void slotRemoveExcludeDirectory();
-
-private:
- static QStringList defaultFolders();
-
- QStringListModel *m_dirListModel;
- QStringListModel *m_excludedDirListModel;
- DirectoryListBase *m_base;
- Result m_result;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DirectoryListBase</class>
- <widget class="QWidget" name="DirectoryListBase">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>440</width>
- <height>332</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QLabel" name="informationLabel">
- <property name="text">
- <string>Please choose the folders where you keep your music:</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QListView" name="directoryListView">
- <property name="toolTip">
- <string>These folders will be scanned on startup for new files.</string>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::MultiSelection</enum>
- </property>
- <property name="textElideMode">
- <enum>Qt::ElideMiddle</enum>
- </property>
- <property name="layoutMode">
- <enum>QListView::Batched</enum>
- </property>
- <property name="uniformItemSizes">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="KPushButton" name="addDirectoryButton">
- <property name="text">
- <string>Add Folder...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KPushButton" name="removeDirectoryButton">
- <property name="text">
- <string>Remove Folder</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="rightColumnSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>158</width>
- <height>48</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <item>
- <widget class="QLabel" name="ExcludeInformationLabel">
- <property name="text">
- <string>Please choose the folders that should be excluded from music search:</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QListView" name="excludeDirectoryListView">
- <property name="toolTip">
- <string>These folders will be scanned on startup for new files.</string>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::MultiSelection</enum>
- </property>
- <property name="textElideMode">
- <enum>Qt::ElideMiddle</enum>
- </property>
- <property name="layoutMode">
- <enum>QListView::Batched</enum>
- </property>
- <property name="uniformItemSizes">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="KPushButton" name="addExcludeDirectoryButton">
- <property name="text">
- <string>Add Folder...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KPushButton" name="removeExcludeDirectoryButton">
- <property name="text">
- <string>Remove Folder</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="rightExcludeColumnSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>158</width>
- <height>48</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QCheckBox" name="importPlaylistsCheckBox">
- <property name="text">
- <string>Import playlists</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KPushButton</class>
- <extends>QPushButton</extends>
- <header>kpushbutton.h</header>
- </customwidget>
- </customwidgets>
- <includes>
- <include location="local">kpushbutton.h</include>
- </includes>
- <resources/>
- <connections/>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "dynamicplaylist.h"
-#include "collectionlist.h"
-#include "playlistcollection.h"
-#include "tracksequencemanager.h"
-
-#include <QTimer>
-
-class PlaylistDirtyObserver : public PlaylistObserver
-{
-public:
- PlaylistDirtyObserver(DynamicPlaylist *parent, Playlist *playlist) :
- PlaylistObserver(playlist),
- m_parent(parent)
- {
-
- }
- virtual void updateData() { m_parent->slotSetDirty(); }
- virtual void updateCurrent() {}
-
-private:
- DynamicPlaylist *m_parent;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-DynamicPlaylist::DynamicPlaylist(const PlaylistList &playlists,
- PlaylistCollection *collection,
- const QString &name,
- const QString &iconName,
- bool setupPlaylist,
- bool synchronizePlaying) :
- Playlist(collection, true),
- m_playlists(playlists),
- m_dirty(true),
- m_synchronizePlaying(synchronizePlaying)
-{
- if(setupPlaylist)
- collection->setupPlaylist(this, iconName);
- setName(name);
-
- setSorting(columns() + 1);
-
- for(PlaylistList::ConstIterator it = playlists.constBegin(); it != playlists.constEnd(); ++it)
- m_observers.append(new PlaylistDirtyObserver(this, *it));
-
- connect(CollectionList::instance(), SIGNAL(signalCollectionChanged()), this, SLOT(slotSetDirty()));
-}
-
-DynamicPlaylist::~DynamicPlaylist()
-{
- lower();
-
- foreach(PlaylistObserver *observer, m_observers)
- delete observer;
-}
-
-void DynamicPlaylist::setPlaylists(const PlaylistList &playlists)
-{
- m_playlists = playlists;
- updateItems();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void DynamicPlaylist::slotReload()
-{
- for(PlaylistList::Iterator it = m_playlists.begin(); it != m_playlists.end(); ++it)
- (*it)->slotReload();
-
- checkUpdateItems();
-}
-
-void DynamicPlaylist::lower(QWidget *top)
-{
- if(top == this)
- return;
-
- if(playing()) {
- PlaylistList l;
- l.append(this);
- for(PlaylistList::Iterator it = m_playlists.begin();
- it != m_playlists.end(); ++it)
- {
- (*it)->synchronizePlayingItems(l, true);
- }
- }
-
- PlaylistItemList list = PlaylistItem::playingItems();
- for(PlaylistItemList::Iterator it = list.begin(); it != list.end(); ++it) {
- if((*it)->playlist() == this) {
- list.erase(it);
- break;
- }
- }
-
- if(!list.isEmpty())
- TrackSequenceManager::instance()->setCurrentPlaylist(list.front()->playlist());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistItemList DynamicPlaylist::items()
-{
- checkUpdateItems();
- return Playlist::items();
-}
-
-void DynamicPlaylist::showEvent(QShowEvent *e)
-{
- checkUpdateItems();
- Playlist::showEvent(e);
-}
-
-void DynamicPlaylist::paintEvent(QPaintEvent *e)
-{
- checkUpdateItems();
- Playlist::paintEvent(e);
-}
-
-void DynamicPlaylist::updateItems()
-{
- PlaylistItemList siblings;
-
- for(PlaylistList::ConstIterator it = m_playlists.constBegin(); it != m_playlists.constEnd(); ++it)
- siblings += (*it)->items();
-
-
- PlaylistItemList newSiblings = siblings;
- if(m_siblings != newSiblings) {
- m_siblings = newSiblings;
- QTimer::singleShot(0, this, SLOT(slotUpdateItems()));
- }
-}
-
-bool DynamicPlaylist::synchronizePlaying() const
-{
- return m_synchronizePlaying;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void DynamicPlaylist::checkUpdateItems()
-{
- if(!m_dirty)
- return;
-
- updateItems();
-
- m_dirty = false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void DynamicPlaylist::slotUpdateItems()
-{
- // This should be optimized to check to see which items are already in the
- // list and just adding those and removing the ones that aren't.
-
- clear();
- createItems(m_siblings);
- if(m_synchronizePlaying)
- synchronizePlayingItems(m_playlists, true);
-}
-
-#include "dynamicplaylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DYNAMICPLAYLIST_H
-#define DYNAMICPLAYLIST_H
-
-#include "playlist.h"
-
-#include <QList>
-
-/**
- * A Playlist that is a union of other playlists that is created dynamically.
- */
-
-class DynamicPlaylist : public Playlist
-{
- Q_OBJECT
-public:
- /**
- * Creates a dynamic playlist based on lists.
- */
- DynamicPlaylist(const PlaylistList &lists,
- PlaylistCollection *collection,
- const QString &name = QString(),
- const QString &iconName = "audio-midi",
- bool setupPlaylist = true,
- bool synchronizePlaying = false);
-
- virtual ~DynamicPlaylist();
-
- virtual bool canReload() const { return false; }
-
- void setPlaylists(const PlaylistList &playlists);
-
-public slots:
- /**
- * Reimplemented so that it will reload all of the playlists that are
- * associated with the dynamic list.
- */
- virtual void slotReload();
- void slotSetDirty() { m_dirty = true; }
-
- /**
- * This is called when lowering the widget from the widget stack so that
- * it can synchronize the playing item with the one that playlist it was
- * create from.
- */
- void lower(QWidget *top = 0);
-
-protected:
- /**
- * Returns true if this list's items need to be updated the next time it's
- * shown.
- */
- bool dirty() const { return m_dirty; }
-
- /**
- * Return a list of the items in this playlist. For example in a search
- * list this should return only the matched items. By default it returns
- * all of the items in the playlists associated with this dynamic list.
- */
- virtual PlaylistItemList items();
-
- /**
- * Reimplemented from QWidget. Here it updates the list of items (when
- * appropriate) as the widget is shown.
- */
- virtual void showEvent(QShowEvent *e);
-
- virtual void paintEvent(QPaintEvent *e);
-
- /**
- * Updates the items (unconditionally). This should be reimplemented in
- * subclasses to refresh the items in the dynamic list (i.e. running a
- * search).
- */
- virtual void updateItems();
-
- bool synchronizePlaying() const;
-
-private:
- /**
- * Checks to see if the current list of items is "dirty" and if so updates
- * this dynamic playlist's items to be in sync with the lists that it is a
- * wrapper around.
- */
- void checkUpdateItems();
-
-private slots:
- void slotUpdateItems();
-
-private:
- QList<PlaylistObserver *> m_observers;
- PlaylistItemList m_siblings;
- PlaylistList m_playlists;
- bool m_dirty;
- bool m_synchronizePlaying;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "exampleoptions.h"
-
-#include <QHideEvent>
-#include <QShowEvent>
-#include <QVBoxLayout>
-
-#include <kurlrequester.h>
-#include <klocale.h>
-
-ExampleOptions::ExampleOptions(QWidget *parent) :
- QWidget(parent)
-{
- setupUi(this);
-
- setObjectName( QLatin1String("example options widget" ));
-}
-
-void ExampleOptions::exampleSelectionChanged()
-{
- if(m_fileTagsButton->isChecked())
- emit fileChanged();
- else
- emit dataChanged();
-}
-
-void ExampleOptions::exampleDataChanged()
-{
- emit dataChanged();
-}
-
-void ExampleOptions::exampleFileChanged()
-{
- emit fileChanged();
-}
-
-ExampleOptionsDialog::ExampleOptionsDialog(QWidget *parent) :
- QDialog(parent)
-{
- setObjectName( QLatin1String("example options dialog" ));
- setWindowTitle(i18n("JuK"));
- QVBoxLayout *l = new QVBoxLayout(this);
-
- m_options = new ExampleOptions(this);
- m_options->m_exampleFile->setMode(KFile::ExistingOnly|KFile::LocalOnly);
- l->addWidget(m_options);
-
- // Forward signals
-
- connect(m_options, SIGNAL(fileChanged()), SLOT(fileModeSelected()));
- connect(m_options, SIGNAL(dataChanged()), SIGNAL(dataChanged()));
- connect(m_options->m_exampleFile, SIGNAL(urlSelected(KUrl)),
- this, SLOT(fileChanged(KUrl)));
- connect(m_options->m_exampleFile, SIGNAL(returnPressed(QString)),
- this, SIGNAL(fileChanged(QString)));
-}
-
-void ExampleOptionsDialog::fileChanged(const KUrl &url)
-{
- emit fileChanged(url.path());
-}
-
-void ExampleOptionsDialog::hideEvent(QHideEvent *)
-{
- emit signalHidden();
-}
-
-void ExampleOptionsDialog::showEvent(QShowEvent *)
-{
- emit signalShown();
-}
-
-void ExampleOptionsDialog::fileModeSelected()
-{
- emit fileChanged(m_options->m_exampleFile->url());
-}
-
-#include "exampleoptions.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EXAMPLEOPTIONS_H
-#define EXAMPLEOPTIONS_H
-
-#include <qdialog.h>
-
-#include <QHideEvent>
-#include <QShowEvent>
-#include <QWidget>
-#include "ui_exampleoptionsbase.h"
-
-class ExampleOptions : public QWidget, public Ui::ExampleOptionsBase
-{
- Q_OBJECT
-public:
- ExampleOptions(QWidget *parent);
-
-protected slots:
- virtual void exampleSelectionChanged();
- virtual void exampleDataChanged();
- virtual void exampleFileChanged();
-
-signals:
- void dataChanged();
- void fileChanged();
-};
-
-// We're not using KDialog(Base) because this dialog won't have any push
-// buttons to close it. It's just a little floating dialog.
-class ExampleOptionsDialog : public QDialog
-{
- Q_OBJECT
-public:
- ExampleOptionsDialog(QWidget *parent);
-
- const ExampleOptions *widget() const { return m_options; }
-
- protected:
- virtual void hideEvent(QHideEvent *);
- virtual void showEvent(QShowEvent *);
-
-protected slots:
- void fileModeSelected();
- void fileChanged(const KUrl &);
-signals:
- void fileChanged(const QString &);
- void dataChanged();
- void signalHidden();
- void signalShown();
-
-private:
- ExampleOptions *m_options;
-};
-
-#endif /* EXAMPLEOPTIONS_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<ui version="4.0" >
- <class>ExampleOptionsBase</class>
- <widget class="QWidget" name="ExampleOptionsBase" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>404</width>
- <height>473</height>
- </rect>
- </property>
- <property name="windowTitle" >
- <string>Example</string>
- </property>
- <layout class="QGridLayout" >
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <property name="horizontalSpacing" >
- <number>6</number>
- </property>
- <property name="verticalSpacing" >
- <number>6</number>
- </property>
- <item row="0" column="0" >
- <widget class="QGroupBox" name="groupBox" >
- <property name="title" >
- <string>Example Tag Selection</string>
- </property>
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <item>
- <widget class="QRadioButton" name="m_fileTagsButton" >
- <property name="text" >
- <string>Get example tags from this file:</string>
- </property>
- <property name="checked" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KUrlRequester" name="m_exampleFile" >
- <property name="enabled" >
- <bool>false</bool>
- </property>
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="m_manualTagsButton" >
- <property name="text" >
- <string>Enter example tags manually:</string>
- </property>
- <property name="checked" >
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="m_manualGroup" >
- <property name="title" >
- <string>Example Tags</string>
- </property>
- <property name="flat" >
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" >
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <property name="horizontalSpacing" >
- <number>6</number>
- </property>
- <property name="verticalSpacing" >
- <number>6</number>
- </property>
- <item row="0" column="0" >
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>0</number>
- </property>
- <property name="topMargin" >
- <number>0</number>
- </property>
- <property name="rightMargin" >
- <number>0</number>
- </property>
- <property name="bottomMargin" >
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="textLabel1" >
- <property name="text" >
- <string comment="song title" >Title:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="textLabel2" >
- <property name="text" >
- <string>Artist:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="textLabel3" >
- <property name="text" >
- <string>Album:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="textLabel4" >
- <property name="text" >
- <string>Genre:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="textLabel5" >
- <property name="text" >
- <string>Track number:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="textLabel6" >
- <property name="text" >
- <string>Year:</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1" >
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>0</number>
- </property>
- <property name="topMargin" >
- <number>0</number>
- </property>
- <property name="rightMargin" >
- <number>0</number>
- </property>
- <property name="bottomMargin" >
- <number>0</number>
- </property>
- <item>
- <widget class="KLineEdit" name="m_exampleTitle" >
- <property name="text" >
- <string comment="example song title" >Title</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KLineEdit" name="m_exampleArtist" >
- <property name="text" >
- <string>Artist</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KLineEdit" name="m_exampleAlbum" >
- <property name="text" >
- <string>Album</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KLineEdit" name="m_exampleGenre" >
- <property name="text" >
- <string>Genre</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KIntSpinBox" name="m_exampleTrack">
- <property name="value" >
- <number>1</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KIntSpinBox" name="m_exampleYear">
- <property name="minimum" >
- <number>1000</number>
- </property>
- <property name="maximum" >
- <number>2999</number>
- </property>
- <property name="value" >
- <number>2007</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation" >
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KIntSpinBox</class>
- <extends>QSpinBox</extends>
- <header>knuminput.h</header>
- </customwidget>
- <customwidget>
- <class>KUrlRequester</class>
- <extends>QFrame</extends>
- <header>kurlrequester.h</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>m_exampleFile</tabstop>
- <tabstop>m_manualTagsButton</tabstop>
- <tabstop>m_exampleTitle</tabstop>
- <tabstop>m_exampleArtist</tabstop>
- <tabstop>m_exampleAlbum</tabstop>
- <tabstop>m_exampleGenre</tabstop>
- <tabstop>m_exampleTrack</tabstop>
- <tabstop>m_exampleYear</tabstop>
- </tabstops>
- <includes>
- <include location="local" >kurlrequester.h</include>
- <include location="local" >klineedit.h</include>
- <include location="local" >kpushbutton.h</include>
- </includes>
- <resources/>
- <connections>
- <connection>
- <sender>m_fileTagsButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>m_exampleFile</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_fileTagsButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleSelectionChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_manualTagsButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleSelectionChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleTitle</sender>
- <signal>textChanged(QString)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleArtist</sender>
- <signal>textChanged(QString)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleAlbum</sender>
- <signal>textChanged(QString)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleGenre</sender>
- <signal>textChanged(QString)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleTrack</sender>
- <signal>valueChanged(int)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_exampleYear</sender>
- <signal>valueChanged(int)</signal>
- <receiver>ExampleOptionsBase</receiver>
- <slot>exampleDataChanged()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel" >
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "filehandle.h"
-
-#include <kdebug.h>
-
-#include <QFileInfo>
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include "filehandleproperties.h"
-#include "tag.h"
-#include "cache.h"
-#include "coverinfo.h"
-
-AddProperty(Title, tag()->title())
-AddProperty(Artist, tag()->artist())
-AddProperty(Album, tag()->album())
-AddProperty(Genre, tag()->genre())
-AddNumberProperty(Track, tag()->track())
-AddNumberProperty(Year, tag()->year())
-AddProperty(Comment, tag()->comment())
-AddNumberProperty(Seconds, tag()->seconds())
-AddNumberProperty(Bitrate, tag()->bitrate())
-AddProperty(Path, absFilePath())
-AddNumberProperty(Size, fileInfo().size())
-AddProperty(Extension, fileInfo().suffix())
-
-static QString resolveSymLinks(const QFileInfo &file) // static
-{
- char real[PATH_MAX];
-
- if(file.exists() && realpath(QFile::encodeName(file.absoluteFilePath()).data(), real))
- return QFile::decodeName(real);
- else
- return file.filePath();
-}
-
-/**
- * A simple reference counter -- pasted from TagLib.
- */
-
-class RefCounter
-{
-public:
- RefCounter() : refCount(1) {}
- void ref() { refCount++; }
- bool deref() { return ! --refCount ; }
- int count() const { return refCount; }
-private:
- uint refCount;
-};
-
-class FileHandle::FileHandlePrivate : public RefCounter
-{
-public:
- FileHandlePrivate() :
- tag(0),
- coverInfo(0) {}
-
- ~FileHandlePrivate()
- {
- delete tag;
- delete coverInfo;
- }
-
- mutable Tag *tag;
- mutable CoverInfo *coverInfo;
- mutable QString absFilePath;
- QFileInfo fileInfo;
- QDateTime modificationTime;
- QDateTime lastModified;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-FileHandle::FileHandle()
-{
- static FileHandlePrivate nullPrivate;
- d = &nullPrivate;
- d->ref();
-}
-
-FileHandle::FileHandle(const FileHandle &f) :
- d(f.d)
-{
- if(!d) {
- kDebug() << "The source FileHandle was not initialized.";
- d = null().d;
- }
- d->ref();
-}
-
-FileHandle::FileHandle(const QFileInfo &info, const QString &path) :
- d(0)
-{
- setup(info, path);
-}
-
-FileHandle::FileHandle(const QString &path) :
- d(0)
-{
- setup(QFileInfo(path), path);
-}
-
-FileHandle::FileHandle(const QString &path, CacheDataStream &s)
-{
- d = new FileHandlePrivate;
- if(!QFile::exists(path)) {
- kWarning() << "File" << path << "no longer exists!";
- return;
- }
- d->fileInfo = QFileInfo(path);
- d->absFilePath = path;
- read(s);
-}
-
-FileHandle::~FileHandle()
-{
- if(d->deref())
- delete d;
-}
-
-void FileHandle::refresh()
-{
- d->fileInfo.refresh();
- delete d->tag;
- d->tag = new Tag(d->absFilePath);
-}
-
-void FileHandle::setFile(const QString &path)
-{
- if(path.isEmpty()) {
- kError() << "trying to set an empty path" << endl;
- return;
- }
-
- if(!QFile::exists(path)) {
- kError() << "trying to set non-existent file: " << path << endl;
- return;
- }
-
- if(!d || isNull())
- setup(QFileInfo(path), path);
- else {
- d->absFilePath = resolveSymLinks(path);
- d->fileInfo.setFile(path);
- d->tag->setFileName(d->absFilePath);
- }
-}
-
-Tag *FileHandle::tag() const
-{
- if(!d->tag)
- d->tag = new Tag(d->absFilePath);
-
- return d->tag;
-}
-
-CoverInfo *FileHandle::coverInfo() const
-{
- if(!d->coverInfo)
- d->coverInfo = new CoverInfo(*this);
-
- return d->coverInfo;
-}
-
-QString FileHandle::absFilePath() const
-{
- if(d->absFilePath.isEmpty())
- d->absFilePath = resolveSymLinks(d->fileInfo.absoluteFilePath());
- return d->absFilePath;
-}
-
-const QFileInfo &FileHandle::fileInfo() const
-{
- return d->fileInfo;
-}
-
-bool FileHandle::isNull() const
-{
- return *this == null();
-}
-
-bool FileHandle::current() const
-{
- return (d->modificationTime.isValid() &&
- lastModified().isValid() &&
- d->modificationTime >= lastModified());
-}
-
-const QDateTime &FileHandle::lastModified() const
-{
- if(d->lastModified.isNull())
- d->lastModified = d->fileInfo.lastModified();
-
- return d->lastModified;
-}
-
-void FileHandle::read(CacheDataStream &s)
-{
- switch(s.cacheVersion()) {
- case 1:
- default:
- if(!d->tag)
- d->tag = new Tag(d->absFilePath, true);
-
- s >> *(d->tag);
- s >> d->modificationTime;
- break;
- }
-}
-
-FileHandle &FileHandle::operator=(const FileHandle &f)
-{
- if(&f == this)
- return *this;
-
- if(d->deref())
- delete d;
-
- d = f.d;
- d->ref();
-
- return *this;
-}
-
-bool FileHandle::operator==(const FileHandle &f) const
-{
- return d == f.d;
-}
-
-bool FileHandle::operator!=(const FileHandle &f) const
-{
- return d != f.d;
-}
-
-QStringList FileHandle::properties() // static
-{
- return FileHandleProperties::properties();
-}
-
-QString FileHandle::property(const QString &name) const
-{
- return FileHandleProperties::property(*this, name.toAscii());
-}
-
-const FileHandle &FileHandle::null() // static
-{
- static FileHandle f;
- return f;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void FileHandle::setup(const QFileInfo &info, const QString &path)
-{
- if(d && !isNull())
- return;
-
- QString fileName = path.isEmpty() ? info.absoluteFilePath() : path;
-
- d = new FileHandlePrivate;
- d->fileInfo = info;
- d->absFilePath = resolveSymLinks(fileName);
- d->modificationTime = info.lastModified();
- if(!info.exists())
- kWarning() << "File" << path << "no longer exists!";
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// related functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const FileHandle &f)
-{
- s << *(f.tag())
- << f.lastModified();
-
- return s;
-}
-
-CacheDataStream &operator>>(CacheDataStream &s, FileHandle &f)
-{
- f.read(s);
- return s;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FILEHANDLE_H
-#define FILEHANDLE_H
-
-#include <QString>
-
-class QFileInfo;
-class QDateTime;
-class QDataStream;
-class QStringList;
-
-class CoverInfo;
-class Tag;
-class CacheDataStream;
-
-template<class T>
-class QList;
-
-/**
- * An value based, explicitly shared wrapper around file related information
- * used in JuK's playlists.
- */
-
-class FileHandle
-{
-public:
- FileHandle();
- FileHandle(const FileHandle &f);
- explicit FileHandle(const QFileInfo &info, const QString &path = QString());
- explicit FileHandle(const QString &path);
- FileHandle(const QString &path, CacheDataStream &s);
- ~FileHandle();
-
- /**
- * Forces the FileHandle to reread its information from the disk.
- */
- void refresh();
- void setFile(const QString &path);
-
- Tag *tag() const;
- CoverInfo *coverInfo() const;
- QString absFilePath() const;
- const QFileInfo &fileInfo() const;
-
- bool isNull() const;
- bool current() const;
- const QDateTime &lastModified() const;
-
- void read(CacheDataStream &s);
-
- FileHandle &operator=(const FileHandle &f);
- bool operator==(const FileHandle &f) const;
- bool operator!=(const FileHandle &f) const;
-
- static QStringList properties();
- QString property(const QString &name) const;
-
- static const FileHandle &null();
-
-private:
- class FileHandlePrivate;
- FileHandlePrivate *d;
-
- void setup(const QFileInfo &info, const QString &path);
-};
-
-typedef QList<FileHandle> FileHandleList;
-
-QDataStream &operator<<(QDataStream &s, const FileHandle &f);
-CacheDataStream &operator>>(CacheDataStream &s, FileHandle &f);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FILEHANDLEPROPERTIES_H
-#define FILEHANDLEPROPERTIES_H
-
-#include <QMap>
-#include <QStringList>
-
-/*
- * These ugly macros make possible a property registration system that makes it
- * easy to add properties to the FileHandle that can be accessed via the DCOP
- * interface.
- *
- * Properties should actually be added to the filehandle.cpp file. This file
- * is just here to separate out some of the macro-related ugliness.
- */
-
-#define AddProperty(name, method) \
- namespace FileHandleProperties \
- { \
- struct name##Property : public Property \
- { \
- virtual QString value(const FileHandle &f) const \
- { \
- return f.method; \
- } \
- static const int dummy; \
- }; \
- static name##Property name##Instance; \
- const int name##Property::dummy = addToPropertyMap(#name, &name##Instance); \
- }
-
-#define AddNumberProperty(name, method) \
- namespace FileHandleProperties \
- { \
- struct name##Property : public Property \
- { \
- virtual QString value(const FileHandle &f) const \
- { \
- return QString::number(f.method); \
- } \
- static const int dummy; \
- }; \
- static name##Property name##Instance; \
- const int name##Property::dummy = addToPropertyMap(#name, &name##Instance); \
- }
-
-namespace FileHandleProperties
-{
- struct Property
- {
- virtual ~Property() {}
- virtual QString value(const FileHandle &) const
- {
- return QString();
- }
- };
-
- static QMap<QByteArray, const Property *> propertyMap;
-
- static int addToPropertyMap(const QByteArray &name, Property *property)
- {
- propertyMap[name] = property;
- return 0;
- }
-
- static QString property(const FileHandle &file, const QByteArray &key)
- {
- return propertyMap.contains(key) ? propertyMap[key]->value(file) : QString();
- }
-
- static QStringList properties()
- {
- static QStringList l;
-
- if(l.isEmpty()) {
- QMap<QByteArray, const Property *>::ConstIterator it = propertyMap.constBegin();
- for(; it != propertyMap.constEnd(); ++it)
- l.append(QString(it.key()));
- }
- return l;
- }
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004, 2007, 2009 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "filerenamer.h"
-
-#include <algorithm>
-
-#include <kdebug.h>
-#include <kurl.h>
-#include <kurlrequester.h>
-#include <kiconloader.h>
-#include <knuminput.h>
-#include <kstandarddirs.h>
-#include <kio/job.h>
-#include <kio/netaccess.h>
-#include <kdesktopfile.h>
-#include <kconfiggroup.h>
-#include <kglobal.h>
-#include <klineedit.h>
-#include <klocale.h>
-#include <kpushbutton.h>
-#include <kapplication.h>
-#include <kmessagebox.h>
-#include <kvbox.h>
-
-#include <QFile>
-#include <QTimer>
-#include <QCheckBox>
-#include <QDir>
-#include <QLabel>
-#include <QSignalMapper>
-#include <QPixmap>
-#include <QFrame>
-#include <QTreeWidget>
-
-#include "tag.h"
-#include "filerenameroptions.h"
-#include "filehandle.h"
-#include "exampleoptions.h"
-#include "playlistitem.h"
-#include "playlist.h" // processEvents()
-#include "coverinfo.h"
-
-class ConfirmationDialog : public KDialog
-{
-public:
- ConfirmationDialog(const QMap<QString, QString> &files,
- QWidget *parent = 0, const char *name = 0)
- : KDialog(parent)
- {
- setObjectName( QLatin1String( name ) );
- setModal(true);
- setCaption(i18nc("warning about mass file rename", "Warning"));
- setButtons(Ok | Cancel);
-
- KVBox *vbox = new KVBox(this);
- setMainWidget(vbox);
- KVBox *hbox = new KVBox(vbox);
-
- QLabel *l = new QLabel(hbox);
- l->setPixmap(SmallIcon("dialog-warning", 32));
-
- l = new QLabel(i18n("You are about to rename the following files. "
- "Are you sure you want to continue?"), hbox);
- hbox->setStretchFactor(l, 1);
-
- QTreeWidget *lv = new QTreeWidget(vbox);
-
- QStringList headers;
- headers << i18n("Original Name");
- headers << i18n("New Name");
-
- lv->setHeaderLabels(headers);
- lv->setRootIsDecorated(false);
-
- int lvHeight = 0;
-
- QMap<QString, QString>::ConstIterator it = files.constBegin();
- for(; it != files.constEnd(); ++it) {
- QTreeWidgetItem *item = new QTreeWidgetItem(lv);
- item->setText(0, it.key());
-
- if (it.key() != it.value()) {
- item->setText(1, it.value());
- }
-
- else {
- item->setText(1, i18n("No Change"));
- }
-
- lvHeight += lv->visualItemRect(item).height();
- }
-
- lvHeight += lv->horizontalScrollBar()->height() + lv->header()->height();
- lv->setMinimumHeight(qMin(lvHeight, 400));
- resize(qMin(width(), 500), qMin(minimumHeight(), 400));
-
- show();
- }
-};
-
-//
-// Implementation of ConfigCategoryReader
-//
-
-ConfigCategoryReader::ConfigCategoryReader() : CategoryReaderInterface(),
- m_currentItem(0)
-{
- KConfigGroup config(KGlobal::config(), "FileRenamer");
-
- QList<int> categoryOrder = config.readEntry("CategoryOrder", QList<int>());
- int categoryCount[NumTypes] = { 0 }; // Keep track of each category encountered.
-
- // Set a default:
-
- if(categoryOrder.isEmpty())
- categoryOrder << Artist << Album << Title << Track;
-
- QList<int>::ConstIterator catIt = categoryOrder.constBegin();
- for(; catIt != categoryOrder.constEnd(); ++catIt)
- {
- int catCount = categoryCount[*catIt]++;
- TagType category = static_cast<TagType>(*catIt);
- CategoryID catId(category, catCount);
-
- m_options[catId] = TagRenamerOptions(catId);
- m_categoryOrder << catId;
- }
-
- m_folderSeparators.fill(false, m_categoryOrder.count() - 1);
-
- QList<int> checkedSeparators = config.readEntry("CheckedDirSeparators", QList<int>());
-
- QList<int>::ConstIterator it = checkedSeparators.constBegin();
- for(; it != checkedSeparators.constEnd(); ++it) {
- if(*it < m_folderSeparators.count())
- m_folderSeparators[*it] = true;
- }
-
- m_musicFolder = config.readPathEntry("MusicFolder", "${HOME}/music");
- m_separator = config.readEntry("Separator", " - ");
-}
-
-QString ConfigCategoryReader::categoryValue(TagType type) const
-{
- if(!m_currentItem)
- return QString();
-
- Tag *tag = m_currentItem->file().tag();
-
- switch(type) {
- case Track:
- return QString::number(tag->track());
-
- case Year:
- return QString::number(tag->year());
-
- case Title:
- return tag->title();
-
- case Artist:
- return tag->artist();
-
- case Album:
- return tag->album();
-
- case Genre:
- return tag->genre();
-
- default:
- return QString();
- }
-}
-
-QString ConfigCategoryReader::prefix(const CategoryID &category) const
-{
- return m_options[category].prefix();
-}
-
-QString ConfigCategoryReader::suffix(const CategoryID &category) const
-{
- return m_options[category].suffix();
-}
-
-TagRenamerOptions::EmptyActions ConfigCategoryReader::emptyAction(const CategoryID &category) const
-{
- return m_options[category].emptyAction();
-}
-
-QString ConfigCategoryReader::emptyText(const CategoryID &category) const
-{
- return m_options[category].emptyText();
-}
-
-QList<CategoryID> ConfigCategoryReader::categoryOrder() const
-{
- return m_categoryOrder;
-}
-
-QString ConfigCategoryReader::separator() const
-{
- return m_separator;
-}
-
-QString ConfigCategoryReader::musicFolder() const
-{
- return m_musicFolder;
-}
-
-int ConfigCategoryReader::trackWidth(int categoryNum) const
-{
- return m_options[CategoryID(Track, categoryNum)].trackWidth();
-}
-
-bool ConfigCategoryReader::hasFolderSeparator(int index) const
-{
- if(index >= m_folderSeparators.count())
- return false;
- return m_folderSeparators[index];
-}
-
-bool ConfigCategoryReader::isDisabled(const CategoryID &category) const
-{
- return m_options[category].disabled();
-}
-
-//
-// Implementation of FileRenamerWidget
-//
-
-FileRenamerWidget::FileRenamerWidget(QWidget *parent) :
- QWidget(parent),
- CategoryReaderInterface(),
- m_ui(new Ui::FileRenamerBase),
- m_exampleFromFile(false)
-{
- m_ui->setupUi(this);
-
- // This must be created before createTagRows() is called.
-
- m_exampleDialog = new ExampleOptionsDialog(this);
-
- createTagRows();
- loadConfig();
-
- // Add correct text to combo box.
- m_ui->m_category->clear();
- for(int i = StartTag; i < NumTypes; ++i) {
- QString category = TagRenamerOptions::tagTypeText(static_cast<TagType>(i));
- m_ui->m_category->addItem(category);
- }
-
- connect(m_exampleDialog, SIGNAL(signalShown()), SLOT(exampleDialogShown()));
- connect(m_exampleDialog, SIGNAL(signalHidden()), SLOT(exampleDialogHidden()));
- connect(m_exampleDialog, SIGNAL(dataChanged()), SLOT(dataSelected()));
- connect(m_exampleDialog, SIGNAL(fileChanged(QString)),
- this, SLOT(fileSelected(QString)));
-
- exampleTextChanged();
-}
-
-void FileRenamerWidget::loadConfig()
-{
- QList<int> checkedSeparators;
- KConfigGroup config(KGlobal::config(), "FileRenamer");
-
- for(int i = 0; i < m_rows.count(); ++i)
- m_rows[i].options = TagRenamerOptions(m_rows[i].category);
-
- checkedSeparators = config.readEntry("CheckedDirSeparators", QList<int>());
-
- foreach(int separator, checkedSeparators) {
- if(separator < m_folderSwitches.count())
- m_folderSwitches[separator]->setChecked(true);
- }
-
- QString path = config.readEntry("MusicFolder", "${HOME}/music");
- m_ui->m_musicFolder->setUrl(KUrl(path));
- m_ui->m_musicFolder->setMode(KFile::Directory |
- KFile::ExistingOnly |
- KFile::LocalOnly);
-
- m_ui->m_separator->setEditText(config.readEntry("Separator", " - "));
-}
-
-void FileRenamerWidget::saveConfig()
-{
- KConfigGroup config(KGlobal::config(), "FileRenamer");
- QList<int> checkedSeparators;
- QList<int> categoryOrder;
-
- for(int i = 0; i < m_rows.count(); ++i) {
- int rowId = idOfPosition(i); // Write out in GUI order, not m_rows order
- m_rows[rowId].options.saveConfig(m_rows[rowId].category.categoryNumber);
- categoryOrder += m_rows[rowId].category.category;
- }
-
- for(int i = 0; i < m_folderSwitches.count(); ++i)
- if(m_folderSwitches[i]->isChecked() == true)
- checkedSeparators += i;
-
- config.writeEntry("CheckedDirSeparators", checkedSeparators);
- config.writeEntry("CategoryOrder", categoryOrder);
- config.writePathEntry("MusicFolder", m_ui->m_musicFolder->url().path());
- config.writeEntry("Separator", m_ui->m_separator->currentText());
-
- config.sync();
-}
-
-FileRenamerWidget::~FileRenamerWidget()
-{
-}
-
-int FileRenamerWidget::addRowCategory(TagType category)
-{
- static QIcon up = SmallIcon("go-up");
- static QIcon down = SmallIcon("go-down");
-
- // Find number of categories already of this type.
- int categoryCount = 0;
- for(int i = 0; i < m_rows.count(); ++i)
- if(m_rows[i].category.category == category)
- ++categoryCount;
-
- Row row;
-
- row.category = CategoryID(category, categoryCount);
- row.position = m_rows.count();
- int id = row.position;
-
- QFrame *frame = new QFrame(m_mainFrame);
- QHBoxLayout *frameLayout = new QHBoxLayout(frame);
- frameLayout->setMargin(3);
-
- row.widget = frame;
- frame->setFrameShape(QFrame::Box);
- frame->setLineWidth(1);
-
- QBoxLayout *mainFrameLayout = static_cast<QBoxLayout *>(m_mainFrame->layout());
- mainFrameLayout->addWidget(frame, 1);
-
- QFrame *buttons = new QFrame(frame);
- QVBoxLayout *buttonLayout = new QVBoxLayout(buttons);
- frameLayout->addWidget(buttons);
- buttons->setFrameStyle(QFrame::Plain | QFrame::Box);
- buttons->setLineWidth(1);
-
- row.upButton = new KPushButton(buttons);
- row.downButton = new KPushButton(buttons);
-
- row.upButton->setIcon(up);
- row.downButton->setIcon(down);
- row.upButton->setFlat(true);
- row.downButton->setFlat(true);
-
- upMapper->connect(row.upButton, SIGNAL(clicked()), SLOT(map()));
- upMapper->setMapping(row.upButton, id);
- downMapper->connect(row.downButton, SIGNAL(clicked()), SLOT(map()));
- downMapper->setMapping(row.downButton, id);
-
- buttonLayout->addWidget(row.upButton);
- buttonLayout->addWidget(row.downButton);
-
- QString labelText = QString("<b>%1</b>").arg(TagRenamerOptions::tagTypeText(category));
- QLabel *label = new QLabel(labelText, frame);
- frameLayout->addWidget(label, 1);
- label->setAlignment(Qt::AlignCenter);
-
- QVBoxLayout *optionLayout = new QVBoxLayout;
- frameLayout->addLayout(optionLayout);
-
- row.enableButton = new KPushButton(i18nc("remove music genre from file renamer", "Remove"), frame);
- optionLayout->addWidget(row.enableButton);
- toggleMapper->connect(row.enableButton, SIGNAL(clicked()), SLOT(map()));
- toggleMapper->setMapping(row.enableButton, id);
-
- row.optionsButton = new KPushButton(i18nc("file renamer genre options", "Options"), frame);
- optionLayout->addWidget(row.optionsButton);
- mapper->connect(row.optionsButton, SIGNAL(clicked()), SLOT(map()));
- mapper->setMapping(row.optionsButton, id);
-
- row.widget->show();
- m_rows.append(row);
-
- // Disable add button if there's too many rows.
- if(m_rows.count() == MAX_CATEGORIES)
- m_ui->m_insertCategory->setEnabled(false);
-
- return id;
-}
-
-void FileRenamerWidget::moveSignalMappings(int oldId, int newId)
-{
- mapper->setMapping(m_rows[oldId].optionsButton, newId);
- downMapper->setMapping(m_rows[oldId].downButton, newId);
- upMapper->setMapping(m_rows[oldId].upButton, newId);
- toggleMapper->setMapping(m_rows[oldId].enableButton, newId);
-}
-
-bool FileRenamerWidget::removeRow(int id)
-{
- if(id >= m_rows.count()) {
- kWarning() << "Trying to remove row, but " << id << " is out-of-range.\n";
- return false;
- }
-
- if(m_rows.count() == 1) {
- kError() << "Can't remove last row of File Renamer.\n";
- return false;
- }
-
- // Remove widget. Don't delete it since it appears QSignalMapper may still need it.
- m_rows[id].widget->deleteLater();
- m_rows[id].widget = 0;
- m_rows[id].enableButton = 0;
- m_rows[id].upButton = 0;
- m_rows[id].optionsButton = 0;
- m_rows[id].downButton = 0;
-
- int checkboxPosition = 0; // Remove first checkbox.
-
- // If not the first row, remove the checkbox before it.
- if(m_rows[id].position > 0)
- checkboxPosition = m_rows[id].position - 1;
-
- // The checkbox is contained within a layout widget, so the layout
- // widget is the one the needs to die.
- delete m_folderSwitches[checkboxPosition]->parent();
- m_folderSwitches.erase(&m_folderSwitches[checkboxPosition]);
-
- // Go through all the rows and if they have the same category and a
- // higher categoryNumber, decrement the number. Also update the
- // position identifier.
- for(int i = 0; i < m_rows.count(); ++i) {
- if(i == id)
- continue; // Don't mess with ourself.
-
- if((m_rows[id].category.category == m_rows[i].category.category) &&
- (m_rows[id].category.categoryNumber < m_rows[i].category.categoryNumber))
- {
- --m_rows[i].category.categoryNumber;
- }
-
- // Items are moving up.
- if(m_rows[id].position < m_rows[i].position)
- --m_rows[i].position;
- }
-
- // Every row after the one we delete will have a different identifier, since
- // the identifier is simply its index into m_rows. So we need to re-do the
- // signal mappings for the affected rows.
- for(int i = id + 1; i < m_rows.count(); ++i)
- moveSignalMappings(i, i - 1);
-
- m_rows.erase(&m_rows[id]);
-
- // Make sure we update the buttons of affected rows.
- m_rows[idOfPosition(0)].upButton->setEnabled(false);
- m_rows[idOfPosition(m_rows.count() - 1)].downButton->setEnabled(false);
-
- // We can insert another row now, make sure GUI is updated to match.
- m_ui->m_insertCategory->setEnabled(true);
-
- QTimer::singleShot(0, this, SLOT(exampleTextChanged()));
- return true;
-}
-
-void FileRenamerWidget::addFolderSeparatorCheckbox()
-{
- QWidget *temp = new QWidget(m_mainFrame);
- m_mainFrame->layout()->addWidget(temp);
-
- QHBoxLayout *l = new QHBoxLayout(temp);
-
- QCheckBox *cb = new QCheckBox(i18n("Insert folder separator"), temp);
- m_folderSwitches.append(cb);
- l->addWidget(cb, 0, Qt::AlignCenter);
- cb->setChecked(false);
-
- connect(cb, SIGNAL(toggled(bool)),
- SLOT(exampleTextChanged()));
-
- temp->show();
-}
-
-void FileRenamerWidget::createTagRows()
-{
- KConfigGroup config(KGlobal::config(), "FileRenamer");
- QList<int> categoryOrder = config.readEntry("CategoryOrder", QList<int>());
-
- if(categoryOrder.isEmpty())
- categoryOrder << Artist << Album << Title << Track;
-
- // Setup arrays.
- m_rows.reserve(categoryOrder.count());
- m_folderSwitches.reserve(categoryOrder.count() - 1);
-
- mapper = new QSignalMapper(this);
- mapper->setObjectName( QLatin1String("signal mapper" ));
- toggleMapper = new QSignalMapper(this);
- toggleMapper->setObjectName( QLatin1String("toggle mapper" ));
- upMapper = new QSignalMapper(this);
- upMapper->setObjectName( QLatin1String("up button mapper" ));
- downMapper = new QSignalMapper(this);
- downMapper->setObjectName( QLatin1String("down button mapper" ));
-
- connect(mapper, SIGNAL(mapped(int)), SLOT(showCategoryOption(int)));
- connect(toggleMapper, SIGNAL(mapped(int)), SLOT(slotRemoveRow(int)));
- connect(upMapper, SIGNAL(mapped(int)), SLOT(moveItemUp(int)));
- connect(downMapper, SIGNAL(mapped(int)), SLOT(moveItemDown(int)));
-
- m_mainFrame = new QFrame(m_ui->m_mainView);
- m_ui->m_mainView->setWidget(m_mainFrame);
- m_ui->m_mainView->setWidgetResizable(true);
-
- QVBoxLayout *frameLayout = new QVBoxLayout(m_mainFrame);
- frameLayout->setMargin(10);
- frameLayout->setSpacing(5);
-
- // OK, the deal with the categoryOrder variable is that we need to create
- // the rows in the order that they were saved in (the order given by categoryOrder).
- // The signal mappers operate according to the row identifier. To find the position of
- // a row given the identifier, use m_rows[id].position. To find the id of a given
- // position, use idOfPosition(position).
-
- QList<int>::ConstIterator it = categoryOrder.constBegin();
-
- for(; it != categoryOrder.constEnd(); ++it) {
- if(*it < StartTag || *it >= NumTypes) {
- kError() << "Invalid category encountered in file renamer configuration.\n";
- continue;
- }
-
- if(m_rows.count() == MAX_CATEGORIES) {
- kError() << "Maximum number of File Renamer tags reached, bailing.\n";
- break;
- }
-
- TagType i = static_cast<TagType>(*it);
-
- addRowCategory(i);
-
- // Insert the directory separator checkbox if this isn't the last
- // item.
-
- QList<int>::ConstIterator dup(it);
-
- // Check for last item
- if(++dup != categoryOrder.constEnd())
- addFolderSeparatorCheckbox();
- }
-
- m_rows.first().upButton->setEnabled(false);
- m_rows.last().downButton->setEnabled(false);
-
- // If we have maximum number of categories already, don't let the user
- // add more.
- if(m_rows.count() >= MAX_CATEGORIES)
- m_ui->m_insertCategory->setEnabled(false);
-}
-
-void FileRenamerWidget::exampleTextChanged()
-{
- // Just use .mp3 as an example
- if(m_exampleFromFile && (m_exampleFile.isEmpty() ||
- !FileHandle(m_exampleFile).tag()->isValid()))
- {
- m_ui->m_exampleText->setText(i18n("No file selected, or selected file has no tags."));
- return;
- }
-
- m_ui->m_exampleText->setText(FileRenamer::fileName(*this) + ".mp3");
-}
-
-QString FileRenamerWidget::fileCategoryValue(TagType category) const
-{
- FileHandle file(m_exampleFile);
- Tag *tag = file.tag();
-
- switch(category) {
- case Track:
- return QString::number(tag->track());
-
- case Year:
- return QString::number(tag->year());
-
- case Title:
- return tag->title();
-
- case Artist:
- return tag->artist();
-
- case Album:
- return tag->album();
-
- case Genre:
- return tag->genre();
-
- default:
- return QString();
- }
-}
-
-QString FileRenamerWidget::categoryValue(TagType category) const
-{
- if(m_exampleFromFile)
- return fileCategoryValue(category);
-
- const ExampleOptions *example = m_exampleDialog->widget();
-
- switch (category) {
- case Track:
- return example->m_exampleTrack->text();
-
- case Year:
- return example->m_exampleYear->text();
-
- case Title:
- return example->m_exampleTitle->text();
-
- case Artist:
- return example->m_exampleArtist->text();
-
- case Album:
- return example->m_exampleAlbum->text();
-
- case Genre:
- return example->m_exampleGenre->text();
-
- default:
- return QString();
- }
-}
-
-QList<CategoryID> FileRenamerWidget::categoryOrder() const
-{
- QList<CategoryID> list;
-
- // Iterate in GUI row order.
- for(int i = 0; i < m_rows.count(); ++i) {
- int rowId = idOfPosition(i);
- list += m_rows[rowId].category;
- }
-
- return list;
-}
-
-bool FileRenamerWidget::hasFolderSeparator(int index) const
-{
- if(index >= m_folderSwitches.count())
- return false;
- return m_folderSwitches[index]->isChecked();
-}
-
-void FileRenamerWidget::moveItem(int id, MovementDirection direction)
-{
- QWidget *l = m_rows[id].widget;
- int bottom = m_rows.count() - 1;
- int pos = m_rows[id].position;
- int newPos = (direction == MoveUp) ? pos - 1 : pos + 1;
-
- // Item we're moving can't go further down after this.
-
- if((pos == (bottom - 1) && direction == MoveDown) ||
- (pos == bottom && direction == MoveUp))
- {
- int idBottomRow = idOfPosition(bottom);
- int idAboveBottomRow = idOfPosition(bottom - 1);
-
- m_rows[idBottomRow].downButton->setEnabled(true);
- m_rows[idAboveBottomRow].downButton->setEnabled(false);
- }
-
- // We're moving the top item, do some button switching.
-
- if((pos == 0 && direction == MoveDown) || (pos == 1 && direction == MoveUp)) {
- int idTopItem = idOfPosition(0);
- int idBelowTopItem = idOfPosition(1);
-
- m_rows[idTopItem].upButton->setEnabled(true);
- m_rows[idBelowTopItem].upButton->setEnabled(false);
- }
-
- // This is the item we're swapping with.
-
- int idSwitchWith = idOfPosition(newPos);
- QWidget *w = m_rows[idSwitchWith].widget;
-
- // Update the table of widget rows.
-
- std::swap(m_rows[id].position, m_rows[idSwitchWith].position);
-
- // Move the item two spaces above/below its previous position. It has to
- // be 2 spaces because of the checkbox.
-
- QBoxLayout *layout = dynamic_cast<QBoxLayout *>(m_mainFrame->layout());
- if ( !layout )
- return;
-
- layout->removeWidget(l);
- layout->insertWidget(2 * newPos, l);
-
- // Move the top item two spaces in the opposite direction, for a similar
- // reason.
-
- layout->removeWidget(w);
- layout->insertWidget(2 * pos, w);
- layout->invalidate();
-
- QTimer::singleShot(0, this, SLOT(exampleTextChanged()));
-}
-
-int FileRenamerWidget::idOfPosition(int position) const
-{
- if(position >= m_rows.count()) {
- kError() << "Search for position " << position << " out-of-range.\n";
- return -1;
- }
-
- for(int i = 0; i < m_rows.count(); ++i)
- if(m_rows[i].position == position)
- return i;
-
- kError() << "Unable to find identifier for position " << position << endl;
- return -1;
-}
-
-int FileRenamerWidget::findIdentifier(const CategoryID &category) const
-{
- for(int index = 0; index < m_rows.count(); ++index)
- if(m_rows[index].category == category)
- return index;
-
- kError() << "Unable to find match for category " <<
- TagRenamerOptions::tagTypeText(category.category) <<
- ", number " << category.categoryNumber << endl;
-
- return MAX_CATEGORIES;
-}
-
-void FileRenamerWidget::enableAllUpButtons()
-{
- for(int i = 0; i < m_rows.count(); ++i)
- m_rows[i].upButton->setEnabled(true);
-}
-
-void FileRenamerWidget::enableAllDownButtons()
-{
- for(int i = 0; i < m_rows.count(); ++i)
- m_rows[i].downButton->setEnabled(true);
-}
-
-void FileRenamerWidget::showCategoryOption(int id)
-{
- TagOptionsDialog *dialog = new TagOptionsDialog(this, m_rows[id].options, m_rows[id].category.categoryNumber);
-
- if(dialog->exec() == QDialog::Accepted) {
- m_rows[id].options = dialog->options();
- exampleTextChanged();
- }
-
- delete dialog;
-}
-
-void FileRenamerWidget::moveItemUp(int id)
-{
- moveItem(id, MoveUp);
-}
-
-void FileRenamerWidget::moveItemDown(int id)
-{
- moveItem(id, MoveDown);
-}
-
-void FileRenamerWidget::toggleExampleDialog()
-{
- m_exampleDialog->setHidden(!m_exampleDialog->isHidden());
-}
-
-void FileRenamerWidget::insertCategory()
-{
- TagType category = static_cast<TagType>(m_ui->m_category->currentIndex());
- if(m_ui->m_category->currentIndex() < 0 || category >= NumTypes) {
- kError() << "Trying to add unknown category somehow.\n";
- return;
- }
-
- // We need to enable the down button of the current bottom row since it
- // can now move down.
- int idBottom = idOfPosition(m_rows.count() - 1);
- m_rows[idBottom].downButton->setEnabled(true);
-
- addFolderSeparatorCheckbox();
-
- // Identifier of new row.
- int id = addRowCategory(category);
-
- // Set its down button to be disabled.
- m_rows[id].downButton->setEnabled(false);
-
- m_mainFrame->layout()->invalidate();
- m_ui->m_mainView->update();
-
- // Now update according to the code in loadConfig().
- m_rows[id].options = TagRenamerOptions(m_rows[id].category);
- exampleTextChanged();
-}
-
-void FileRenamerWidget::exampleDialogShown()
-{
- m_ui->m_showExample->setText(i18n("Hide Renamer Test Dialog"));
-}
-
-void FileRenamerWidget::exampleDialogHidden()
-{
- m_ui->m_showExample->setText(i18n("Show Renamer Test Dialog"));
-}
-
-void FileRenamerWidget::fileSelected(const QString &file)
-{
- m_exampleFromFile = true;
- m_exampleFile = file;
- exampleTextChanged();
-}
-
-void FileRenamerWidget::dataSelected()
-{
- m_exampleFromFile = false;
- exampleTextChanged();
-}
-
-QString FileRenamerWidget::separator() const
-{
- return m_ui->m_separator->currentText();
-}
-
-QString FileRenamerWidget::musicFolder() const
-{
- return m_ui->m_musicFolder->url().path();
-}
-
-void FileRenamerWidget::slotRemoveRow(int id)
-{
- // Remove the given identified row.
- if(!removeRow(id))
- kError() << "Unable to remove row " << id << endl;
-}
-
-//
-// Implementation of FileRenamer
-//
-
-FileRenamer::FileRenamer()
-{
-}
-
-void FileRenamer::rename(PlaylistItem *item)
-{
- PlaylistItemList list;
- list.append(item);
-
- rename(list);
-}
-
-void FileRenamer::rename(const PlaylistItemList &items)
-{
- ConfigCategoryReader reader;
- QStringList errorFiles;
- QMap<QString, QString> map;
- QMap<QString, PlaylistItem *> itemMap;
-
- for(PlaylistItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
- reader.setPlaylistItem(*it);
- QString oldFile = (*it)->file().absFilePath();
- QString extension = (*it)->file().fileInfo().suffix();
- QString newFile = fileName(reader) + '.' + extension;
-
- if(oldFile != newFile) {
- map[oldFile] = newFile;
- itemMap[oldFile] = *it;
- }
- }
-
- if(itemMap.isEmpty() || ConfirmationDialog(map).exec() != QDialog::Accepted)
- return;
-
- KApplication::setOverrideCursor(Qt::waitCursor);
- for(QMap<QString, QString>::ConstIterator it = map.constBegin();
- it != map.constEnd(); ++it)
- {
- if(moveFile(it.key(), it.value())) {
- itemMap[it.key()]->setFile(it.value());
- itemMap[it.key()]->refresh();
-
- setFolderIcon(it.value(), itemMap[it.key()]);
- }
- else
- errorFiles << i18n("%1 to %2", it.key(), it.value());
-
- processEvents();
- }
- KApplication::restoreOverrideCursor();
-
- if(!errorFiles.isEmpty())
- KMessageBox::errorList(0, i18n("The following rename operations failed:\n"), errorFiles);
-}
-
-bool FileRenamer::moveFile(const QString &src, const QString &dest)
-{
- kDebug() << "Moving file " << src << " to " << dest;
-
- if(src == dest)
- return false;
-
- // Escape URL.
- KUrl srcURL = KUrl(src);
- KUrl dstURL = KUrl(dest);
-
- // Clean it.
- srcURL.cleanPath();
- dstURL.cleanPath();
-
- // Make sure it is valid.
- if(!srcURL.isValid() || !dstURL.isValid())
- return false;
-
- // Get just the directory.
- KUrl dir = dstURL;
- dir.setFileName(QString());
-
- // Create the directory.
- if(!KStandardDirs::exists(dir.path()))
- if(!KStandardDirs::makeDir(dir.path())) {
- kError() << "Unable to create directory " << dir.path() << endl;
- return false;
- }
-
- // Move the file.
- KIO::Job *job = KIO::file_move(srcURL, dstURL);
- return KIO::NetAccess::synchronousRun(job, 0);
-}
-
-void FileRenamer::setFolderIcon(const KUrl &dst, const PlaylistItem *item)
-{
- if(item->file().tag()->album().isEmpty() ||
- !item->file().coverInfo()->hasCover())
- {
- return;
- }
-
- KUrl dstURL = dst;
- dstURL.cleanPath();
-
- // Split path, and go through each path element. If a path element has
- // the album information, set its folder icon.
- QStringList elements = dstURL.directory().split('/', QString::SkipEmptyParts);
- QString path;
-
- for(QStringList::ConstIterator it = elements.constBegin(); it != elements.constEnd(); ++it) {
- path.append('/' + (*it));
-
- kDebug() << "Checking path: " << path;
- if((*it).contains(item->file().tag()->album() ) &&
- !QFile::exists(path + "/.directory"))
- {
- // Seems to be a match, let's set the folder icon for the current
- // path. First we should write out the file.
-
- QPixmap thumb = item->file().coverInfo()->pixmap(CoverInfo::Thumbnail);
- thumb.save(path + "/.juk-thumbnail.png", "PNG");
-
- KDesktopFile dirFile(path + "/.directory");
- KConfigGroup desktopGroup(dirFile.desktopGroup());
-
- if(!desktopGroup.hasKey("Icon")) {
- desktopGroup.writePathEntry("Icon", QString("%1/.juk-thumbnail.png").arg(path));
- dirFile.sync();
- }
-
- return;
- }
- }
-}
-
-/**
- * Returns iterator pointing to the last item enabled in the given list with
- * a non-empty value (or is required to be included).
- */
-QList<CategoryID>::ConstIterator lastEnabledItem(const QList<CategoryID> &list,
- const CategoryReaderInterface &interface)
-{
- QList<CategoryID>::ConstIterator it = list.constBegin();
- QList<CategoryID>::ConstIterator last = list.constEnd();
-
- for(; it != list.constEnd(); ++it) {
- if(interface.isRequired(*it) || (!interface.isDisabled(*it) &&
- !interface.categoryValue((*it).category).isEmpty()))
- {
- last = it;
- }
- }
-
- return last;
-}
-
-QString FileRenamer::fileName(const CategoryReaderInterface &interface)
-{
- const QList<CategoryID> categoryOrder = interface.categoryOrder();
- const QString separator = interface.separator();
- const QString folder = interface.musicFolder();
- QList<CategoryID>::ConstIterator lastEnabled;
- int i = 0;
- QStringList list;
- QChar dirSeparator (QDir::separator());
-
- // Use lastEnabled to properly handle folder separators.
- lastEnabled = lastEnabledItem(categoryOrder, interface);
- bool pastLast = false; // Toggles to true once we've passed lastEnabled.
-
- for(QList<CategoryID>::ConstIterator it = categoryOrder.constBegin();
- it != categoryOrder.constEnd();
- ++it, ++i)
- {
- if(it == lastEnabled)
- pastLast = true;
-
- if(interface.isDisabled(*it))
- continue;
-
- QString value = interface.value(*it);
-
- // The user can use the folder separator checkbox to add folders, so don't allow
- // slashes that slip in to accidentally create new folders. Should we filter this
- // back out when showing it in the GUI?
- value.replace('/', "%2f");
-
- if(!pastLast && interface.hasFolderSeparator(i))
- value.append(dirSeparator);
-
- if(interface.isRequired(*it) || !value.isEmpty())
- list.append(value);
- }
-
- // Construct a single string representation, handling strings ending in
- // '/' specially
-
- QString result;
-
- for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); /* Empty */) {
- result += *it;
-
- ++it; // Manually advance iterator to check for end-of-list.
-
- // Add separator unless at a directory boundary
- if(it != list.constEnd() &&
- !(*it).startsWith(dirSeparator) && // Check beginning of next item.
- !result.endsWith(dirSeparator))
- {
- result += separator;
- }
- }
-
- return QString(folder + dirSeparator + result);
-}
-
-#include "filerenamer.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004, 2007 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FILERENAMER_H
-#define FILERENAMER_H
-
-#include <QString>
-#include <QVector>
-#include <QMap>
-
-#include "ui_filerenamerbase.h"
-#include "categoryreaderinterface.h"
-#include "tagrenameroptions.h"
-
-class QCheckBox;
-class QPushButton;
-class QSignalMapper;
-
-class ExampleOptionsDialog;
-class PlaylistItem;
-
-template<class T>
-class QList;
-
-typedef QList<PlaylistItem *> PlaylistItemList;
-
-// Used to decide what direction the FileRenamerWidget will move rows in.
-enum MovementDirection { MoveUp, MoveDown };
-
-/**
- * This is used by FileRenamerWidget to store information about a particular
- * tag type, including its position, the QFrame holding the information,
- * the up, down, and enable buttons, and the user-selected renaming options.
- */
-struct Row
-{
- Row() : widget(0), upButton(0), downButton(0), enableButton(0) {}
-
- QWidget *widget;
-
- QPushButton *upButton, *downButton, *optionsButton, *enableButton;
-
- TagRenamerOptions options;
- CategoryID category; // Includes category and a disambiguation id.
- int position; ///< Position in the GUI (0 == top)
- QString name;
-};
-
-/**
- * A list of rows, each of which may have its own category options and other
- * associated data. There is no relation between the order of rows in the vector and their
- * GUI layout. Instead, each Row has a position member which indicates what GUI position it
- * takes up. The index into the vector is known as the row identifier (which is unique but
- * not necessarily constant).
- */
-typedef QVector<Row> Rows;
-
-/**
- * Holds a list directory separator checkboxes which separate a row. There
- * should always be 1 less than the number of rows in the GUI.
- *
- * Used for ConfigCategoryReader.
- */
-typedef QVector<QCheckBox *> DirSeparatorCheckBoxes;
-
-/**
- * Associates a CategoryID combination with a set of options.
- *
- * Used for ConfigCategoryReader
- */
-typedef QMap<CategoryID, TagRenamerOptions> CategoryOptionsMap;
-
-/**
- * An implementation of CategoryReaderInterface that reads the user's settings
- * from the global KConfig configuration object, and reads track information
- * from whatever the given PlaylistItem is. You can assign different
- * PlaylistItems in order to change the returned tag category information.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class ConfigCategoryReader : public CategoryReaderInterface
-{
-public:
- // ConfigCategoryReader specific members
-
- ConfigCategoryReader();
-
- const PlaylistItem *playlistItem() const { return m_currentItem; }
- void setPlaylistItem(const PlaylistItem *item) { m_currentItem = item; }
-
- // CategoryReaderInterface reimplementations
-
- virtual QString categoryValue(TagType type) const;
- virtual QString prefix(const CategoryID &category) const;
- virtual QString suffix(const CategoryID &category) const;
- virtual TagRenamerOptions::EmptyActions emptyAction(const CategoryID &category) const;
- virtual QString emptyText(const CategoryID &category) const;
- virtual QList<CategoryID> categoryOrder() const;
- virtual QString separator() const;
- virtual QString musicFolder() const;
- virtual int trackWidth(int categoryNum) const;
- virtual bool hasFolderSeparator(int index) const;
- virtual bool isDisabled(const CategoryID &category) const;
-
-private:
- const PlaylistItem *m_currentItem;
- CategoryOptionsMap m_options;
- QList<CategoryID> m_categoryOrder;
- QString m_separator;
- QString m_musicFolder;
- QVector<bool> m_folderSeparators;
-};
-
-/**
- * This class implements a dialog that allows the user to alter the behavior
- * of the file renamer. It supports 6 different genre types at this point,
- * and it shouldn't be too difficult to extend that in the future if needed.
- * It allows the user to open an external dialog, which will let the user see
- * an example of what their current options will look like, by either allowing
- * the user to type in some sample information, or by loading a file and
- * reading tags from there.
- *
- * It also implements the CategoryReaderInterface in order to implement the
- * example filename functionality.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class FileRenamerWidget : public QWidget, public CategoryReaderInterface
-{
- Q_OBJECT
-
-public:
- FileRenamerWidget(QWidget *parent);
- ~FileRenamerWidget();
-
- /// Maximum number of total categories the widget will allow.
- static int const MAX_CATEGORIES = 16;
-
- /**
- * This function saves all of the category options to the global KConfig
- * object. You must call this manually, FileRenamerWidget doesn't call it
- * automatically so that situations where the user hits "Cancel" work
- * correctly.
- */
- void saveConfig();
-
-protected slots:
- /**
- * This function should be called whenever the example text may need to be
- * changed. For example, when the user selects a different separator or
- * changes the example text, this slot should be called.
- */
- virtual void exampleTextChanged();
-
- /**
- * This function shows the example dialog if it is hidden, and hides the
- * example dialog if it is shown.
- */
- virtual void toggleExampleDialog();
-
- /**
- * This function inserts the currently selected category, so that the
- * user can use duplicate tags in the file renamer.
- */
- virtual void insertCategory();
-
-private:
- /**
- * This function initializes the category options by loading the data from
- * the global KConfig object. This is called automatically in the constructor.
- */
- void loadConfig();
-
- /**
- * This function adds a "Insert Folder separator" checkbox to the end of
- * the current layout. The setting defaults to being unchecked.
- */
- void addFolderSeparatorCheckbox();
-
- /**
- * This function creates a row in the main view for category, appending it
- * to the end. It handles connecting signals to the mapper and such as
- * well.
- *
- * @param category Type of row to append.
- * @return identifier of newly added row.
- */
- int addRowCategory(TagType category);
-
- /**
- * Removes the given row, updating the other rows to have the correct
- * number of categoryNumber.
- *
- * @param id The identifier of the row to remove.
- * @return true if the delete succeeded, false otherwise.
- */
- bool removeRow(int id);
-
- /**
- * Updates the mappings currently set for the row identified by oldId so
- * that they emit newId instead. Does not actually delete the row given
- * by oldId.
- *
- * @param oldId The identifier of the row to change mappings for.
- * @param newId The identifier to use instead.
- */
- void moveSignalMappings(int oldId, int newId);
-
- /**
- * This function sets up the internal view by creating the checkboxes and
- * the rows for each category.
- */
- void createTagRows();
-
- /**
- * Returns the value for \p category by retrieving the tag from m_exampleFile.
- * If \p category is Track, then an appropriate fixup will be applied if needed
- * to match the user's desired minimum width.
- *
- * @param category the category to retrieve the value for.
- * @return the string representation of the value for \p category.
- */
- QString fileCategoryValue(TagType category) const;
-
- /**
- * Returns the value for \p category by reading the user entry for that
- * category. If \p category is Track, then an appropriate fixup will be applied
- * if needed to match the user's desired minimum width.
- *
- * @param category the category to retrieve the value for.
- * @return the string representation of the value for \p category.
- */
- virtual QString categoryValue(TagType category) const;
-
- /**
- * Returns the user-specified prefix string for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified prefix string for \p category.
- */
- virtual QString prefix(const CategoryID &category) const
- {
- return m_rows[findIdentifier(category)].options.prefix();
- }
-
- /**
- * Returns the user-specified suffix string for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified suffix string for \p category.
- */
- virtual QString suffix(const CategoryID &category) const
- {
- return m_rows[findIdentifier(category)].options.suffix();
- }
-
- /**
- * Returns the user-specified empty action for \p category.
- *
- * @param category the category to retrieve the value for.
- * @return user-specified empty action for \p category.
- */
- virtual TagRenamerOptions::EmptyActions emptyAction(const CategoryID &category) const
- {
- return m_rows[findIdentifier(category)].options.emptyAction();
- }
-
- /**
- * Returns the user-specified empty text for \p category. This text might
- * be used to replace an empty value.
- *
- * @param category the category to retrieve the value for.
- * @return the user-specified empty text for \p category.
- */
- virtual QString emptyText(const CategoryID &category) const
- {
- return m_rows[findIdentifier(category)].options.emptyText();
- }
-
- /**
- * @return list of CategoryIDs corresponding to the user-specified category order.
- */
- virtual QList<CategoryID> categoryOrder() const;
-
- /**
- * @return string that separates the tag values in the file name.
- */
- virtual QString separator() const;
-
- /**
- * @return local path to the music folder used to store renamed files.
- */
- virtual QString musicFolder() const;
-
- /**
- * @param categoryNum Zero-based number of category to get results for (if more than one).
- * @return the minimum width of the track category.
- */
- virtual int trackWidth(int categoryNum) const
- {
- CategoryID id(Track, categoryNum);
- return m_rows[findIdentifier(id)].options.trackWidth();
- }
-
- /**
- * @param index, the 0-based index for the folder boundary.
- * @return true if there should be a folder separator between category
- * index and index + 1, and false otherwise. Note that for purposes
- * of this function, only categories that are required or non-empty
- * should count.
- */
- virtual bool hasFolderSeparator(int index) const;
-
- /**
- * @param category The category to get the status of.
- * @return true if \p category is disabled by the user, and false otherwise.
- */
- virtual bool isDisabled(const CategoryID &category) const
- {
- return m_rows[findIdentifier(category)].options.disabled();
- }
-
- /**
- * This moves the widget \p l in the direction given by \p direction, taking
- * care to make sure that the checkboxes are not moved, and that they are
- * enabled or disabled as appropriate for the new layout, and that the up and
- * down buttons are also adjusted as necessary.
- *
- * @param id the identifier of the row to move
- * @param direction the direction to move
- */
- void moveItem(int id, MovementDirection direction);
-
- /**
- * This function actually performs the work of showing the options dialog for
- * \p category.
- *
- * @param category the category to show the options dialog for.
- */
- void showCategoryOptions(TagType category);
-
- /**
- * This function enables or disables the widget in the row identified by \p id,
- * controlled by \p enable. This function also makes sure that checkboxes are
- * enabled or disabled as appropriate if they no longer make sense due to the
- * adjacent category being enabled or disabled.
- *
- * @param id the identifier of the row to change. This is *not* the category to
- * change.
- * @param enable enables the category if true, disables if false.
- */
- void setCategoryEnabled(int id, bool enable);
-
- /**
- * This function enables all of the up buttons.
- */
- void enableAllUpButtons();
-
- /**
- * This function enables all of the down buttons.
- */
- void enableAllDownButtons();
-
- /**
- * This function returns the identifier of the row at \p position.
- *
- * @param position The position to find the identifier of.
- * @return The unique id of the row at \p position.
- */
- int idOfPosition(int position) const;
-
- /**
- * This function returns the identifier of the row in the m_rows index that
- * contains \p category and matches \p categoryNum.
- *
- * @param category the category to find.
- * @return the identifier of the category, or MAX_CATEGORIES if it couldn't
- * be found.
- */
- int findIdentifier(const CategoryID &category) const;
-
-private slots:
- /**
- * This function reads the tags from \p file and ensures that the dialog will
- * use those tags until a different file is selected or dataSelected() is
- * called.
- *
- * @param file the path to the local file to read.
- */
- virtual void fileSelected(const QString &file);
-
- /**
- * This function reads the tags from the user-supplied examples and ensures
- * that the dialog will use those tags until a file is selected using
- * fileSelected().
- */
- virtual void dataSelected();
-
- /**
- * This function brings up a dialog that allows the user to edit the options
- * for \p id.
- *
- * @param id the unique id to bring up the options for.
- */
- virtual void showCategoryOption(int id);
-
- /**
- * This function removes the row identified by id and updates the internal data to be
- * consistent again, by forwarding the call to removeRow().
- * This roundabout way is done due to QSignalMapper.
- *
- * @param id The unique id to update
- */
- virtual void slotRemoveRow(int id);
-
- /**
- * This function moves \p category up in the layout.
- *
- * @param id the unique id of the widget to move up.
- */
- virtual void moveItemUp(int id);
-
- /**
- * This function moves \p category down in the layout.
- *
- * @param id the unique id of the widget to move down.
- */
- virtual void moveItemDown(int id);
-
- /**
- * This slot should be called whenever the example input dialog is shown.
- */
- virtual void exampleDialogShown();
-
- /**
- * This slot should be called whever the example input dialog is hidden.
- */
- virtual void exampleDialogHidden();
-
-private:
- /// This is the frame that holds all of the category widgets and checkboxes.
- QFrame *m_mainFrame;
-
- Ui::FileRenamerBase *m_ui;
-
- /**
- * This is the meat of the widget, it holds the rows for the user configuration. It is
- * initially created such that m_rows[0] is the top and row + 1 is the row just below.
- * However, this is NOT NECESSARILY true, so don't rely on this. As soon as the user
- * clicks an arrow to move a row then the order will be messed up. Use row.position to
- * determine where the row is in the GUI.
- *
- * @see idOfPosition
- * @see findIdentifier
- */
- Rows m_rows;
-
- /**
- * This holds an array of checkboxes that allow the user to insert folder
- * separators in between categories.
- */
- DirSeparatorCheckBoxes m_folderSwitches;
-
- ExampleOptionsDialog *m_exampleDialog;
-
- /// This is true if we're reading example tags from m_exampleFile.
- bool m_exampleFromFile;
- QString m_exampleFile;
-
- // Used to map signals from rows to the correct widget.
- QSignalMapper *mapper;
- QSignalMapper *toggleMapper;
- QSignalMapper *upMapper;
- QSignalMapper *downMapper;
-};
-
-/**
- * This class contains the backend code to actually implement the file renaming. It performs
- * the function of moving the files from one location to another, constructing the file name
- * based off of the user's options (see ConfigCategoryReader) and of setting folder icons
- * if appropriate.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class FileRenamer
-{
-public:
- FileRenamer();
-
- /**
- * Renames the filename on disk of the file represented by item according
- * to the user configuration stored in KConfig.
- *
- * @param item The item to rename.
- */
- void rename(PlaylistItem *item);
-
- /**
- * Renames the filenames on disk of the files given in items according to
- * the user configuration stored in KConfig.
- *
- * @param items The items to rename.
- */
- void rename(const PlaylistItemList &items);
-
- /**
- * Returns the file name that would be generated based on the options read from
- * interface, which must implement CategoryReaderInterface. (A whole interface is used
- * so that we can re-use the code to generate filenames from a in-memory GUI and from
- * KConfig).
- *
- * @param interface object to read options/data from.
- */
- static QString fileName(const CategoryReaderInterface &interface);
-
-private:
- /**
- * Sets the folder icon for elements of the destination path for item (if
- * there is not already a folder icon set, and if the folder's name has
- * the album name.
- */
- void setFolderIcon(const KUrl &dst, const PlaylistItem *item);
-
- /**
- * Attempts to rename the file from \a src to \a dest. Returns true if the
- * operation succeeded.
- */
- bool moveFile(const QString &src, const QString &dest);
-};
-
-#endif /* FILERENAMER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>FileRenamerBase</class>
- <widget class="QWidget" name="FileRenamerBase">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>489</width>
- <height>579</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="windowTitle">
- <string>File Renamer Configuration</string>
- </property>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <layout class="QGridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>6</number>
- </property>
- <item row="1" column="1">
- <widget class="KComboBox" name="m_separator">
- <property name="editable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="textLabel1_6">
- <property name="text">
- <string>Music folder:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="KComboBox" name="m_category">
- <item>
- <property name="text">
- <string>Album Tag</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Artist Tag</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Genre Tag</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Title Tag</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Track Tag</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Year Tag</string>
- </property>
- </item>
- </widget>
- </item>
- <item>
- <widget class="KPushButton" name="m_insertCategory">
- <property name="text">
- <string>Insert Category</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <widget class="KUrlRequester" name="m_musicFolder"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="textLabel1">
- <property name="text">
- <string>Add category:</string>
- </property>
- <property name="buddy">
- <cstring>m_category</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="textLabel1_7">
- <property name="text">
- <string>Separator:</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="Line" name="line1_2">
- <property name="frameShape">
- <enum>QFrame::HLine</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Sunken</enum>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QScrollArea" name="m_mainView">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>1</verstretch>
- </sizepolicy>
- </property>
- <property name="widgetResizable">
- <bool>true</bool>
- </property>
- <widget class="QWidget" name="scrollAreaWidgetContents">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>483</width>
- <height>340</height>
- </rect>
- </property>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="Line" name="line1">
- <property name="frameShape">
- <enum>QFrame::HLine</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Sunken</enum>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Example</string>
- </property>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>9</number>
- </property>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="KPushButton" name="m_showExample">
- <property name="text">
- <string>Show Renamer Test Dialog</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <widget class="KLineEdit" name="m_exampleText">
- <property name="focusPolicy">
- <enum>Qt::NoFocus</enum>
- </property>
- <property name="acceptDrops">
- <bool>false</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KUrlRequester</class>
- <extends>QFrame</extends>
- <header>kurlrequester.h</header>
- </customwidget>
- <customwidget>
- <class>KPushButton</class>
- <extends>QPushButton</extends>
- <header>kpushbutton.h</header>
- </customwidget>
- <customwidget>
- <class>KComboBox</class>
- <extends>QComboBox</extends>
- <header>kcombobox.h</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>m_musicFolder</tabstop>
- <tabstop>m_separator</tabstop>
- <tabstop>m_category</tabstop>
- <tabstop>m_insertCategory</tabstop>
- </tabstops>
- <resources/>
- <connections>
- <connection>
- <sender>m_musicFolder</sender>
- <signal>textChanged(QString)</signal>
- <receiver>FileRenamerBase</receiver>
- <slot>exampleTextChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>118</x>
- <y>16</y>
- </hint>
- <hint type="destinationlabel">
- <x>105</x>
- <y>103</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_separator</sender>
- <signal>textChanged(QString)</signal>
- <receiver>FileRenamerBase</receiver>
- <slot>exampleTextChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>131</x>
- <y>47</y>
- </hint>
- <hint type="destinationlabel">
- <x>144</x>
- <y>102</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_showExample</sender>
- <signal>clicked()</signal>
- <receiver>FileRenamerBase</receiver>
- <slot>toggleExampleDialog()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>173</x>
- <y>514</y>
- </hint>
- <hint type="destinationlabel">
- <x>144</x>
- <y>462</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_insertCategory</sender>
- <signal>clicked()</signal>
- <receiver>FileRenamerBase</receiver>
- <slot>insertCategory()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>340</x>
- <y>81</y>
- </hint>
- <hint type="destinationlabel">
- <x>340</x>
- <y>105</y>
- </hint>
- </hints>
- </connection>
- </connections>
- <slots>
- <slot>exampleTextChanged()</slot>
- <slot>toggleExampleDialog()</slot>
- <slot>insertCategory()</slot>
- </slots>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "filerenamerconfigdlg.h"
-#include "filerenamer.h"
-
-#include <klocale.h>
-
-FileRenamerConfigDlg::FileRenamerConfigDlg(QWidget *parent) :
- KDialog(parent),
- m_renamerWidget(new FileRenamerWidget(this))
-{
- setObjectName( QLatin1String("file renamer dialog" ));
- setModal(true);
- setCaption(i18n("File Renamer Options"));
- setButtons(Ok | Cancel);
-
- m_renamerWidget->setMinimumSize(400, 300);
-
- setMainWidget(m_renamerWidget);
-}
-
-void FileRenamerConfigDlg::accept()
-{
- // Make sure the config gets saved.
-
- m_renamerWidget->saveConfig();
-
- KDialog::accept();
-}
-
-#include "filerenamerconfigdlg.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FILERENAMERCONFIGDLG_H
-#define FILERENAMERCONFIGDLG_H
-
-#include <kdialog.h>
-
-class FileRenamerWidget;
-
-class FileRenamerConfigDlg : public KDialog
-{
- Q_OBJECT
- public:
- FileRenamerConfigDlg(QWidget *parent);
-
- protected slots:
- virtual void accept();
-
- private:
- FileRenamerWidget *m_renamerWidget;
-};
-
-#endif // FILERENAMERCONFIGDLG_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "filerenameroptions.h"
-
-#include <klocale.h>
-#include <kdebug.h>
-#include <knuminput.h>
-
-
-FileRenamerTagOptions::FileRenamerTagOptions(QWidget *parent,
- const TagRenamerOptions &options) :
- QWidget(parent),
- Ui::FileRenamerTagOptionsBase(),
- m_options(options)
-{
- setupUi(this);
-
- layout()->setMargin(0);
-
- if(m_options.category() != Track)
- m_trackGroup->hide();
-
- QString tagText = m_options.tagTypeText();
-
- setWindowTitle(i18nc("%1 will be a music tag category like Artist or Album", "%1 Options",tagText));
- m_tagFormatGroup->setTitle(i18n("%1 Format",tagText));
- m_emptyTagGroup->setTitle(i18n("When the Track's %1 is Empty",tagText));
- m_description->setText(i18n("When using the file renamer your files will be renamed to the values that you have in your track's %1 tag, plus any additional text that you specify below.",tagText));
- m_tagLabel->setText(tagText);
-
- m_prefixText->setText(options.prefix());
- m_suffixText->setText(options.suffix());
- if(options.emptyAction() == TagRenamerOptions::ForceEmptyInclude)
- m_includeEmptyButton->setChecked(true);
- else if(options.emptyAction() == TagRenamerOptions::UseReplacementValue)
- m_useValueButton->setChecked(true);
- m_emptyTagValue->setText(options.emptyText());
- m_trackWidth->setValue(options.trackWidth());
-
- slotBracketsChanged();
- slotEmptyActionChanged();
- slotTrackWidthChanged();
-}
-
-void FileRenamerTagOptions::slotBracketsChanged()
-{
- QString tag = m_options.tagTypeText();
-
- m_options.setPrefix(m_prefixText->text());
- m_options.setSuffix(m_suffixText->text());
-
- m_substitution->setText(m_options.prefix() + tag + m_options.suffix());
-}
-
-void FileRenamerTagOptions::slotTrackWidthChanged()
-{
- int width = m_trackWidth->value();
-
- m_options.setTrackWidth(width);
-
- QString singleDigitText = m_singleDigit->text();
- singleDigitText.remove(" ->");
- QString doubleDigitText = m_doubleDigit->text();
- doubleDigitText.remove(" ->");
-
- if(singleDigitText.length() < width) {
- QString p;
- p.fill('0', width - singleDigitText.length());
- singleDigitText.prepend(p);
- }
-
- if(doubleDigitText.length() < width) {
- QString p;
- p.fill('0', width - doubleDigitText.length());
- doubleDigitText.prepend(p);
- }
-
- m_singleDigitExample->setText(singleDigitText);
- m_doubleDigitExample->setText(doubleDigitText);
-}
-
-void FileRenamerTagOptions::slotEmptyActionChanged()
-{
- m_options.setEmptyText(m_emptyTagValue->text());
-
- m_options.setEmptyAction(TagRenamerOptions::IgnoreEmptyTag);
-
- if(m_useValueButton->isChecked())
- m_options.setEmptyAction(TagRenamerOptions::UseReplacementValue);
- else if(m_includeEmptyButton->isChecked())
- m_options.setEmptyAction(TagRenamerOptions::ForceEmptyInclude);
-}
-
-TagOptionsDialog::TagOptionsDialog(QWidget *parent,
- const TagRenamerOptions &options,
- unsigned categoryNumber) :
- KDialog(parent, 0),
- m_options(options),
- m_categoryNumber(categoryNumber)
-{
- setModal(true);
- setCaption(i18n("File Renamer"));
- setButtons(Ok|Cancel);
-
- loadConfig();
-
- m_widget = new FileRenamerTagOptions(this, m_options);
- m_widget->setMinimumSize(400, 200);
-
- setMainWidget(m_widget);
-}
-
-void TagOptionsDialog::accept()
-{
- m_options = m_widget->options();
-
- saveConfig();
- KDialog::accept();
-}
-
-void TagOptionsDialog::loadConfig()
-{
- // Our m_options may not have been loaded from KConfig, force that to
- // happen.
-
- CategoryID category(m_options.category(), m_categoryNumber);
- m_options = TagRenamerOptions(category);
-}
-
-void TagOptionsDialog::saveConfig()
-{
- m_options.saveConfig(m_categoryNumber);
-}
-
-#include "filerenameroptions.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FILERENAMEROPTIONS_H
-#define FILERENAMEROPTIONS_H
-
-#include <kdialog.h>
-#include "ui_filerenameroptionsbase.h"
-#include "tagrenameroptions.h"
-
-/**
- * Base widget implementing the options for a particular tag type.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class FileRenamerTagOptions : public QWidget, public Ui::FileRenamerTagOptionsBase
-{
- Q_OBJECT
-public:
- FileRenamerTagOptions(QWidget *parent, const TagRenamerOptions &options);
- virtual ~FileRenamerTagOptions() {}
-
- const TagRenamerOptions &options() const { return m_options; }
-
-protected slots:
- virtual void slotBracketsChanged();
- virtual void slotTrackWidthChanged();
- virtual void slotEmptyActionChanged();
-
-private:
- TagRenamerOptions m_options;
-};
-
-/**
- * This defines the dialog that actually gets the options from the user.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class TagOptionsDialog : public KDialog
-{
- Q_OBJECT
-
-public:
- TagOptionsDialog(QWidget *parent, const TagRenamerOptions &options, unsigned categoryNumber);
-
- const TagRenamerOptions &options() const { return m_options; }
-
- protected slots:
- virtual void accept();
-
-private:
-
- // Private methods
-
- void loadConfig(); // Loads m_options from KConfig
- void saveConfig(); // Saves m_options to KConfig
-
- // Private members
-
- FileRenamerTagOptions *m_widget;
- TagRenamerOptions m_options;
- unsigned m_categoryNumber;
-};
-
-#endif /* FILERENAMEROPTIONS_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>FileRenamerTagOptionsBase</class>
- <widget class="QWidget" name="FileRenamerTagOptionsBase">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>915</width>
- <height>377</height>
- </rect>
- </property>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>9</number>
- </property>
- <item>
- <widget class="QGroupBox" name="m_tagFormatGroup">
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>9</number>
- </property>
- <item>
- <widget class="QLabel" name="m_description">
- <property name="textFormat">
- <enum>Qt::RichText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="KLineEdit" name="m_prefixText">
- <property name="alignment">
- <set>Qt::AlignRight</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="m_tagLabel"/>
- </item>
- <item>
- <widget class="KLineEdit" name="m_suffixText">
- <property name="alignment">
- <set>Qt::AlignLeading</set>
- </property>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QLabel" name="m_substitution">
- <property name="font">
- <font>
- <family>Sans Serif</family>
- <pointsize>9</pointsize>
- <weight>50</weight>
- <italic>true</italic>
- <bold>false</bold>
- <underline>false</underline>
- <strikeout>false</strikeout>
- </font>
- </property>
- <property name="text">
- <string>Substitution Example</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="m_emptyTagGroup">
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>9</number>
- </property>
- <item>
- <widget class="QRadioButton" name="m_includeEmptyButton">
- <property name="text">
- <string>Include in the &filename anyways</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="m_ignoreTagButton">
- <property name="text">
- <string>&Ignore this tag when renaming the file</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QRadioButton" name="m_useValueButton">
- <property name="text">
- <string>Use &this value:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KLineEdit" name="m_emptyTagValue">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string comment="value to use in replacement when source tag empty">Empty</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="m_trackGroup">
- <property name="title">
- <string>Track numbering</string>
- </property>
- <layout class="QVBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>9</number>
- </property>
- <item>
- <widget class="QLabel" name="textLabel10">
- <property name="text">
- <string>JuK can force the track used in a file name to have a minimum number of digits. You may want to do this for better sorting in file managers.</string>
- </property>
- <property name="textFormat">
- <enum>Qt::RichText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="textLabel5">
- <property name="text">
- <string>Minimum number of digits:</string>
- </property>
- <property name="buddy">
- <cstring>m_trackWidth</cstring>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QSpinBox" name="m_trackWidth" >
- <property name="minimum" >
- <number>1</number>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QGridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>6</number>
- </property>
- <item row="1" column="1">
- <widget class="QLabel" name="m_doubleDigitExample">
- <property name="font">
- <font>
- <family>Sans Serif</family>
- <pointsize>9</pointsize>
- <weight>50</weight>
- <italic>true</italic>
- <bold>false</bold>
- <underline>false</underline>
- <strikeout>false</strikeout>
- </font>
- </property>
- <property name="text">
- <string>014</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="m_singleDigitExample">
- <property name="font">
- <font>
- <family>Sans Serif</family>
- <pointsize>9</pointsize>
- <weight>50</weight>
- <italic>true</italic>
- <bold>false</bold>
- <underline>false</underline>
- <strikeout>false</strikeout>
- </font>
- </property>
- <property name="text">
- <string>003</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="m_singleDigit">
- <property name="text">
- <string>3 -></string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="m_doubleDigit">
- <property name="text">
- <string>14 -></string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>546</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>m_trackWidth</sender>
- <signal>valueChanged(int)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotTrackWidthChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>395</x>
- <y>301</y>
- </hint>
- <hint type="destinationlabel">
- <x>394</x>
- <y>227</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_prefixText</sender>
- <signal>textChanged(QString)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotBracketsChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>356</x>
- <y>63</y>
- </hint>
- <hint type="destinationlabel">
- <x>356</x>
- <y>5</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_suffixText</sender>
- <signal>textChanged(QString)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotBracketsChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>497</x>
- <y>57</y>
- </hint>
- <hint type="destinationlabel">
- <x>490</x>
- <y>2</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_emptyTagValue</sender>
- <signal>textChanged(QString)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotEmptyActionChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>163</x>
- <y>197</y>
- </hint>
- <hint type="destinationlabel">
- <x>163</x>
- <y>225</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_useValueButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotEmptyActionChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>79</x>
- <y>195</y>
- </hint>
- <hint type="destinationlabel">
- <x>80</x>
- <y>224</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_ignoreTagButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotEmptyActionChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>56</x>
- <y>165</y>
- </hint>
- <hint type="destinationlabel">
- <x>6</x>
- <y>167</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_includeEmptyButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>FileRenamerTagOptionsBase</receiver>
- <slot>slotEmptyActionChanged()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>41</x>
- <y>140</y>
- </hint>
- <hint type="destinationlabel">
- <x>1</x>
- <y>141</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>m_useValueButton</sender>
- <signal>toggled(bool)</signal>
- <receiver>m_emptyTagValue</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>40</x>
- <y>192</y>
- </hint>
- <hint type="destinationlabel">
- <x>199</x>
- <y>193</y>
- </hint>
- </hints>
- </connection>
- </connections>
- <slots>
- <slot>slotBracketsChanged()</slot>
- <slot>slotTrackWidthChanged()</slot>
- <slot>slotEmptyActionChanged()</slot>
- </slots>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "folderplaylist.h"
-#include "playlistcollection.h"
-#include "juk-exception.h"
-
-#include <QTimer>
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-FolderPlaylist::FolderPlaylist(PlaylistCollection *collection, const QString &folder,
- const QString &name) :
- Playlist(collection, name, "folder"),
- m_folder(folder)
-{
- QTimer::singleShot(0, this, SLOT(slotReload()));
-}
-
-FolderPlaylist::~FolderPlaylist()
-{
-
-}
-
-QString FolderPlaylist::folder() const
-{
- return m_folder;
-}
-
-void FolderPlaylist::setFolder(const QString &s)
-{
- m_folder = s;
- QTimer::singleShot(0, this, SLOT(slotReload()));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void FolderPlaylist::slotReload()
-{
- if(!m_folder.isEmpty())
- addFiles(QStringList(m_folder));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// helper functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const FolderPlaylist &p)
-{
- s << p.name()
- << p.folder();
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, FolderPlaylist &p)
-{
- QString name;
- QString folder;
- s >> name
- >> folder;
-
- if(folder.isEmpty() || name.isEmpty())
- throw BICStreamException();
-
- p.setFolder(folder);
- p.setName(name);
- return s;
-}
-
-#include "folderplaylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef FOLDERPLAYLIST_H
-#define FOLDERPLAYLIST_H
-
-#include "playlist.h"
-
-class FolderPlaylist : public Playlist
-{
- Q_OBJECT
-
-public:
- explicit FolderPlaylist(PlaylistCollection *collection, const QString &folder = QString(),
- const QString &name = QString());
- virtual ~FolderPlaylist();
-
- QString folder() const;
- void setFolder(const QString &s);
-
- virtual bool canReload() const { return true; }
-
-public slots:
- virtual void slotReload();
-
-private:
- QString m_folder;
-};
-
-QDataStream &operator<<(QDataStream &s, const FolderPlaylist &p);
-QDataStream &operator>>(QDataStream &s, FolderPlaylist &p);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "historyplaylist.h"
-#include "collectionlist.h"
-#include "playermanager.h"
-#include "juk-exception.h"
-
-#include <QTimer>
-
-#include <klocale.h>
-#include <kglobal.h>
-#include <kdebug.h>
-
-////////////////////////////////////////////////////////////////////////////////
-// HistoryPlayList public members
-////////////////////////////////////////////////////////////////////////////////
-
-HistoryPlaylist::HistoryPlaylist(PlaylistCollection *collection) :
- Playlist(collection, true, 1),
- m_timer(new QTimer(this))
-{
- setAllowDuplicates(true);
-
- m_timer->setSingleShot(true);
- connect(m_timer, SIGNAL(timeout()), this, SLOT(slotCreateNewItem()));
-
- setSorting(-1);
- setColumnText(0, i18n("Time"));
-}
-
-HistoryPlaylist::~HistoryPlaylist()
-{
-
-}
-
-HistoryPlaylistItem *HistoryPlaylist::createItem(const FileHandle &file,
- Q3ListViewItem *after, bool emitChanged)
-{
- if(!after)
- after = lastItem();
- return Playlist::createItem<HistoryPlaylistItem>(file, after, emitChanged);
-}
-
-void HistoryPlaylist::createItems(const PlaylistItemList &siblings)
-{
- Playlist::createItems<HistoryPlaylistItem, PlaylistItem>(siblings);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void HistoryPlaylist::appendProposedItem(const FileHandle &file)
-{
- m_file = file;
-
- if(!m_file.isNull())
- m_timer->start(delay());
- else
- m_timer->stop();
-}
-
-void HistoryPlaylist::slotCreateNewItem()
-{
- createItem(m_file);
- m_file = FileHandle::null();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// HistoryPlaylistItem public members
-////////////////////////////////////////////////////////////////////////////////
-
-HistoryPlaylistItem::HistoryPlaylistItem(CollectionListItem *item, Playlist *parent, Q3ListViewItem *after) :
- PlaylistItem(item, parent, after),
- m_dateTime(QDateTime::currentDateTime())
-{
- setText(0, KGlobal::locale()->formatDateTime(m_dateTime));
-}
-
-HistoryPlaylistItem::HistoryPlaylistItem(CollectionListItem *item, Playlist *parent) :
- PlaylistItem(item, parent),
- m_dateTime(QDateTime::currentDateTime())
-{
- setText(0, KGlobal::locale()->formatDateTime(m_dateTime));
-}
-
-HistoryPlaylistItem::~HistoryPlaylistItem()
-{
-
-}
-
-void HistoryPlaylistItem::setDateTime(const QDateTime &dt)
-{
- m_dateTime = dt;
- setText(0, KGlobal::locale()->formatDateTime(m_dateTime));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// helper functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const HistoryPlaylist &p)
-{
- PlaylistItemList l = const_cast<HistoryPlaylist *>(&p)->items();
-
- s << qint32(l.count());
-
- for(PlaylistItemList::ConstIterator it = l.constBegin(); it != l.constEnd(); ++it) {
- const HistoryPlaylistItem *i = static_cast<HistoryPlaylistItem *>(*it);
- s << i->file().absFilePath();
- s << i->dateTime();
- }
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, HistoryPlaylist &p)
-{
- qint32 count;
- s >> count;
-
- HistoryPlaylistItem *after = 0;
-
- QString fileName;
- QDateTime dateTime;
-
- for(int i = 0; i < count; i++) {
- s >> fileName;
- s >> dateTime;
-
- if(fileName.isEmpty() || !dateTime.isValid())
- throw BICStreamException();
-
- HistoryPlaylistItem *a = p.createItem(FileHandle(fileName), after, false);
- if(a) {
- after = a;
- after->setDateTime(dateTime);
- }
- }
-
- p.dataChanged();
-
- return s;
-}
-
-#include "historyplaylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HISTORYPLAYLIST_H
-#define HISTORYPLAYLIST_H
-
-#include <QDateTime>
-
-#include "playlist.h"
-#include "playlistitem.h"
-
-class HistoryPlaylistItem : public PlaylistItem
-{
-public:
- HistoryPlaylistItem(CollectionListItem *item, Playlist *parent, Q3ListViewItem *after);
- HistoryPlaylistItem(CollectionListItem *item, Playlist *parent);
- virtual ~HistoryPlaylistItem();
-
- QDateTime dateTime() const { return m_dateTime; }
- void setDateTime(const QDateTime &dt);
-
-private:
- QDateTime m_dateTime;
-};
-
-class HistoryPlaylist : public Playlist
-{
- Q_OBJECT
-
-public:
- HistoryPlaylist(PlaylistCollection *collection);
- virtual ~HistoryPlaylist();
-
- virtual HistoryPlaylistItem *createItem(const FileHandle &file, Q3ListViewItem *after = 0,
- bool emitChanged = true);
- virtual void createItems(const PlaylistItemList &siblings);
- virtual int columnOffset() const { return 1; }
- virtual bool readOnly() const { return true; }
-
- static int delay() { return 5000; }
-
-public slots:
- void cut() {}
- void clear() {}
- void appendProposedItem(const FileHandle &file);
-
-private slots:
- void slotCreateNewItem();
-
-private:
- using Playlist::createItems;
-
- FileHandle m_file;
- QTimer *m_timer;
-};
-
-QDataStream &operator<<(QDataStream &s, const HistoryPlaylist &p);
-QDataStream &operator>>(QDataStream &s, HistoryPlaylist &p);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_EXCEPTION_H
-#define JUK_EXCEPTION_H
-
-#include <exception>
-
-/**
- * This exception is thrown when playlist reading code believes that it has
- * encountered a binary incompatible version of QDataStream. Added due to a
- * coding error which resulted in not setting a specific encoding for
- * QDataStreams.
- */
-class BICStreamException : public std::exception
-{
- virtual const char *what() const throw()
- {
- return "Read jibberish from a QDataStream, probably using an older protocol.";
- }
-};
-
-#endif /* JUK_EXCEPTION_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<component type="desktop">
- <id>juk.desktop</id>
- <metadata_license>CC0-1.0</metadata_license>
- <project_license>GPL-2.0+</project_license>
- <name>JuK</name>
- <name xml:lang="ca">JuK</name>
- <name xml:lang="cs">JuK</name>
- <name xml:lang="da">JuK</name>
- <name xml:lang="de">JuK</name>
- <name xml:lang="el">JuK</name>
- <name xml:lang="en-GB">JuK</name>
- <name xml:lang="es">JuK</name>
- <name xml:lang="et">JuK</name>
- <name xml:lang="fi">JuK</name>
- <name xml:lang="hu">JuK</name>
- <name xml:lang="ia">JuK</name>
- <name xml:lang="it">JuK</name>
- <name xml:lang="ko">JuK</name>
- <name xml:lang="nds">JuK</name>
- <name xml:lang="nl">JuK</name>
- <name xml:lang="pl">JuK</name>
- <name xml:lang="pt">JuK</name>
- <name xml:lang="pt-BR">JuK</name>
- <name xml:lang="sk">JuK</name>
- <name xml:lang="sl">JuK</name>
- <name xml:lang="sr">Џук</name>
- <name xml:lang="sr-Latn">Juk</name>
- <name xml:lang="sr-ijekavian">Џук</name>
- <name xml:lang="sr-ijekavianlatin">Juk</name>
- <name xml:lang="sv">Juk</name>
- <name xml:lang="uk">JuK</name>
- <name xml:lang="x-test">xxJuKxx</name>
- <name xml:lang="zh-TW">音樂播放_Juk</name>
- <summary>Music Player</summary>
- <summary xml:lang="ca">Reproductor musical</summary>
- <summary xml:lang="cs">Přehrávač hudby</summary>
- <summary xml:lang="da">Musikafspiller</summary>
- <summary xml:lang="de">Audio-Wiedergabe</summary>
- <summary xml:lang="el">Αναπαραγωγέας μουσικής</summary>
- <summary xml:lang="en-GB">Music Player</summary>
- <summary xml:lang="es">Music Player</summary>
- <summary xml:lang="et">Muusikamängija</summary>
- <summary xml:lang="fi">Musiikkisoitin</summary>
- <summary xml:lang="hu">Zenelejátszó</summary>
- <summary xml:lang="it">Lettore musicale</summary>
- <summary xml:lang="ko">음악 재생기</summary>
- <summary xml:lang="nds">Musikafspeler</summary>
- <summary xml:lang="nl">Muziekspeler</summary>
- <summary xml:lang="pl">Odtwarzacz muzyki</summary>
- <summary xml:lang="pt">Leitor de Música</summary>
- <summary xml:lang="pt-BR">Reprodutor de músicas</summary>
- <summary xml:lang="sk">Prehrávač hudby</summary>
- <summary xml:lang="sl">Glasbeni predvajalnik</summary>
- <summary xml:lang="sr">Музички плејер</summary>
- <summary xml:lang="sr-Latn">Muzički plejer</summary>
- <summary xml:lang="sr-ijekavian">Музички плејер</summary>
- <summary xml:lang="sr-ijekavianlatin">Muzički plejer</summary>
- <summary xml:lang="sv">Musikspelare</summary>
- <summary xml:lang="uk">Музичний програвач</summary>
- <summary xml:lang="x-test">xxMusic Playerxx</summary>
- <summary xml:lang="zh-TW">音樂播放器</summary>
- <description>
- <p>JuK is an audio jukebox application, supporting collections of MP3, Ogg Vorbis, and FLAC audio files. It allows you to edit the "tags" of your audio files, and manage your collection and playlists. It's main focus, in fact, is on music management.</p>
- <p xml:lang="ca">El JuK és una aplicació de màquina de discos musicals, que accepta col·leccions de fitxers d'àudio MP3, Ogg Vorbis, i FLAC. Permet editar les "etiquetes" dels fitxers d'àudio, i gestionar les col·leccions i les llistes de reproducció. De fet, els seu focus principal és en la gestió de la música.</p>
- <p xml:lang="da">JuK er et lydjukebox-program, som understøtter samlinger af MP3-, Ogg Vorbis- og FLAC-lydfiler. Den lader dig redigere "mærkerne" i dine lydfiler og håndtere din samling og spillelister. Dens hovedfokus er faktisk på musikhåndtering.</p>
- <p xml:lang="el">Το JuK είναι μια εφαρμογή μουσικού κουτιού, που υποστηρίζει συλλογές MP3, Ogg Vorbis, και FLAC αρχεία ήχου. Σας επιτρέπει να επεξεργαστείτε τις "ετικέτες" των αρχείων ήχου σας, και να διαχειριστείτε τις συλλογές και τις λίστες αναπαραγωγής. Εστιάζει κυρίως στη διαχείριση μουσικής.</p>
- <p xml:lang="en-GB">JuK is an audio jukebox application, supporting collections of MP3, Ogg Vorbis, and FLAC audio files. It allows you to edit the "tags" of your audio files, and manage your collection and playlists. It's main focus, in fact, is on music management.</p>
- <p xml:lang="es">JuK es una aplicación jukebox de audio, que soporta colecciones de archivos MP3, Ogg Vorbis y FLAC. Le permite editar los "tags" de sus archivos de audio, y administrar sus colecciones y listas de reproducción. Su principal cometido, de hecho, es administrar la música.</p>
- <p xml:lang="et">JuK on helifailide muusikamängija, mis toetab MP3, Ogg Vorbise ja FLAC-i vormingut. See võimaldab muuta helifailide "silte" ning hallata muusikakogusid ja esitusnimekirju. Õigupoolest ongi rakenduse rõhk eelkõige muusika haldamisel.</p>
- <p xml:lang="hu">A JuK egy zenedoboz alkalmazás, amely támogatja MP3, Ogg Vorbis és FLAC hangfájlok gyűjteményeit. Lehetővé teszi a hangfájlok „címkéinek” szerkesztését, és a gyűjtemények, illetve lejátszólisták kezelését. A fő célja valójában a zenekezelés.</p>
- <p xml:lang="it">JuK è un'applicazione jukebox, che supporta raccolte di file audio MP3, Ogg Vorbis e FLAC. Permette di modificare le etichette dei file audio, e gestire raccolte e scalette. Il suo scopo primario è la gestione della musica.</p>
- <p xml:lang="ko">JuK는 MP3, Ogg Vorbis, FLAC 오디오 파일 모음집을 지원하는 주크박스 프로그램입니다. 오디오 파일의 태그를 편집할 수 있으며, 모음집과 재생 목록을 관리할 수 있습니다.</p>
- <p xml:lang="nds">JuK is en Musikkist-Programm, dat Sammeln vun MP3-, Ogg-Vorbis- un FLAC-Klangdateien bruken kann. Du kannst dor de Slötelwöör („Tags“) vun Dien Dateien mit bewerken un Dien Sammeln un Afspeellisten mit plegen. Egens liggt em sien Fokus redig op de Musikpleeg.</p>
- <p xml:lang="nl">JuK is een jukebox toepassing voor geluid, die verzamelingen van MP3, Ogg Vorbis en FLAC geluidsbestanden ondersteunt. Het stelt u in staat om de "tags" van uw geluidsbestanden te bewerken en uw verzameling en afspeellijsten te beheren. De focus is in feite op beheer van muziek.</p>
- <p xml:lang="pl">JuK jest programem szafy grającej, obsługującym zbiory MP3, Ogg Vorbis oraz pliki dźwiękowe FLAC. Umożliwia edytowanie "znaczników" plików dźwiękowych i zarządzanie zbiorami oraz listami odtwarzania. Jednak jego głównym celem jest zarządzanie muzyką.</p>
- <p xml:lang="pt">O JuK é uma aplicação de reprodução de música, suportando colecções de ficheiros de áudio em MP3, Ogg Vorbis e FLAC. Permite-lhe editar as "marcas" dos seus ficheiros de áudio, gerir a sua colecção e as suas listas de reprodução. O seu foco principal é, de facto, a gestão de música.</p>
- <p xml:lang="pt-BR">JuK é um aplicativo para reprodução de músicas, com suporte a coleções de arquivos de áudio MP3, Ogg Vorbis e FLAC. Permite-lhe editar as etiquetas "tags" dos seus arquivos de áudio, gerenciar sua coleção e suas listas de músicas. Seu foco principal é, de fato, o gerenciamento de músicas.</p>
- <p xml:lang="sk">JuK je aplikácia hudobného jukeboxu, podporujúca kolekcie MP3, Ogg Vorbis a FLAC audio súborov. Umožní vám upraviť tagy vašich audio súborov a spravovať vašu kolekciu a zoznamy skladieb. Jeho hlavné zameranie je správa hudby.</p>
- <p xml:lang="sl">JuK je predvajalnik glasbe, ki podpira zbirke zvočnih datotek MP3, Ogg Vorbis in FLAC. Omogoča urejanje "oznak" vaših zvočnih datotek ter upravljanje zbirk in seznamov predvajanj. Glavni name programa je upravljanje glasbe.</p>
- <p xml:lang="sr">Џук је програм за виртуелни џубокс. Подржава збирке МП3, ОГГ, ворбис и ФЛАЦ аудио фајлова. Даје вам да уређујете „ознаке“ аудио фајлова, и управљате збиркама и листама нумера. Тежиште му је, у ствари, на управљању музиком.</p>
- <p xml:lang="sr-Latn">Juk je program za virtuelni džuboks. Podržava zbirke MP3, OGG, Vorbis i FLAC audio fajlova. Daje vam da uređujete „oznake“ audio fajlova, i upravljate zbirkama i listama numera. Težište mu je, u stvari, na upravljanju muzikom.</p>
- <p xml:lang="sr-ijekavian">Џук је програм за виртуелни џубокс. Подржава збирке МП3, ОГГ, ворбис и ФЛАЦ аудио фајлова. Даје вам да уређујете „ознаке“ аудио фајлова, и управљате збиркама и листама нумера. Тежиште му је, у ствари, на управљању музиком.</p>
- <p xml:lang="sr-ijekavianlatin">Juk je program za virtuelni džuboks. Podržava zbirke MP3, OGG, Vorbis i FLAC audio fajlova. Daje vam da uređujete „oznake“ audio fajlova, i upravljate zbirkama i listama numera. Težište mu je, u stvari, na upravljanju muzikom.</p>
- <p xml:lang="sv">Juk är ett Jukebox-program, som stöder samlingar av MP3, Ogg Vorbis och FLAC ljudfiler. Det låter dig redigera "taggarna" i ljudfilerna, och hantera samlingen och spellistor. Dess huvudfokus är just musikhantering.</p>
- <p xml:lang="uk">JuK — програма для відтворення музики, у якій передбачено підтримку роботи зі звуковими файлами у форматах MP3, Ogg Vorbis та FLAC. Програма допоможе вам у редагуванні міток ваших звукових файлів, керуванні вашою збіркою та списками відтворення. Основним її призначенням, фактично, є керування музичними даними.</p>
- <p xml:lang="x-test">xxJuK is an audio jukebox application, supporting collections of MP3, Ogg Vorbis, and FLAC audio files. It allows you to edit the "tags" of your audio files, and manage your collection and playlists. It's main focus, in fact, is on music management.xx</p>
- <p xml:lang="zh-TW">Juk 是一套類似自動唱機的應用程式,支援收藏 MP3,Ogg Vorbis 與 FLAC 音效檔。它能讓您編輯您的音效檔的「標籤」,並管理您的收藏與播放清單。它主要的焦點,在音樂管理。</p>
- <p>Features:</p>
- <p xml:lang="ca">Característiques:</p>
- <p xml:lang="cs">Vlastnosti:</p>
- <p xml:lang="da">Funktioner:</p>
- <p xml:lang="de">Funktionen:</p>
- <p xml:lang="el">Χαρακτηριστικά:</p>
- <p xml:lang="en-GB">Features:</p>
- <p xml:lang="es">Características:</p>
- <p xml:lang="et">Omadused:</p>
- <p xml:lang="fi">Ominaisuudet:</p>
- <p xml:lang="hu">Szolgáltatások:</p>
- <p xml:lang="it">Funzionalità:</p>
- <p xml:lang="ko">기능:</p>
- <p xml:lang="nds">Markmalen:</p>
- <p xml:lang="nl">Mogelijkheden:</p>
- <p xml:lang="pl">Cechy:</p>
- <p xml:lang="pt">Características:</p>
- <p xml:lang="pt-BR">Funcionalidades:</p>
- <p xml:lang="sk">Funkcie:</p>
- <p xml:lang="sl">Zmožnosti:</p>
- <p xml:lang="sr">Могућности:</p>
- <p xml:lang="sr-Latn">Mogućnosti:</p>
- <p xml:lang="sr-ijekavian">Могућности:</p>
- <p xml:lang="sr-ijekavianlatin">Mogućnosti:</p>
- <p xml:lang="sv">Funktioner:</p>
- <p xml:lang="uk">Можливості:</p>
- <p xml:lang="x-test">xxFeatures:xx</p>
- <p xml:lang="zh-TW">功能:</p>
- <ul>
- <li>Collection list and multiple user defined playlists</li>
- <li xml:lang="ca">Llista de col·leccions i múltiples llistes de reproducció definides per usuari</li>
- <li xml:lang="da">Samlingsliste og flere brugerdefinerede spillelister</li>
- <li xml:lang="de">Sammlungslisten und mehrere benutzerdefinierte Wiedergabelisten</li>
- <li xml:lang="el">Λίστα συλλογών και λίστες αναπαραγωγής πολλών χρηστών</li>
- <li xml:lang="en-GB">Collection list and multiple user defined playlists</li>
- <li xml:lang="es">Listas de colecciones y listas de reproducción definidas por múltiples usuarios</li>
- <li xml:lang="et">Muusikakogu nimekiri ja paljud kasutaja loodud esitusnimekirjad</li>
- <li xml:lang="hu">Gyűjteménylista és több felhasználó által megadott lejátszólista</li>
- <li xml:lang="it">Elenco di raccolte e scalette multiple definite dall'utente</li>
- <li xml:lang="ko">모음집 관리 및 사용자 정의 재생 목록</li>
- <li xml:lang="nds">Sammelnlist un en Reeg Bruker-Afspeellisten</li>
- <li xml:lang="nl">Verzamelingenlijst en afspeellijsten voor meerdere gebruikers</li>
- <li xml:lang="pl">Spisy zbiorów i wiele list odtwarzania określonych przez użytkownika</li>
- <li xml:lang="pt">Lista de colecções e várias listas de reprodução definidas pelo utilizador</li>
- <li xml:lang="pt-BR">Lista de coleções e várias listas de músicas definidas pelo usuário</li>
- <li xml:lang="sk">Zoznam kolekcií a viacnásobné používateľom definované zoznamy skladieb</li>
- <li xml:lang="sl">Seznam zbirk in več uporabniško določenih seznamov predvajanja</li>
- <li xml:lang="sr">Листа збирки и више кориснички дефинисаних листа нумера.</li>
- <li xml:lang="sr-Latn">Lista zbirki i više korisnički definisanih lista numera.</li>
- <li xml:lang="sr-ijekavian">Листа збирки и више кориснички дефинисаних листа нумера.</li>
- <li xml:lang="sr-ijekavianlatin">Lista zbirki i više korisnički definisanih lista numera.</li>
- <li xml:lang="sv">Samlingslista och flera användardefinierade spellistor.</li>
- <li xml:lang="uk">Список збірки та декілька визначених користувачем списків відтворення.</li>
- <li xml:lang="x-test">xxCollection list and multiple user defined playlistsxx</li>
- <li xml:lang="zh-TW">收藏清單與多個使用者定義的播放清單</li>
- <li>Ability to scan directories to automatically import playlists and music files on start up</li>
- <li xml:lang="ca">Capacitat d'explorar directoris per importar automàticament llistes de reproducció i fitxers de música en iniciar-se</li>
- <li xml:lang="da">Kan scanne mapper for automatisk at importere spillelister og musikfiler ved opstart</li>
- <li xml:lang="de">Ordner können durchsucht werden, um beim Start automatisch Wiedergabelisten und Musikdateien zu importieren</li>
- <li xml:lang="el">Ικανότητα σάρωσης καταλόγων για την αυτόματη εισαγωγή λιστών αναπαραγωγής και μουσικών αρχείων κατά την εκκίνηση</li>
- <li xml:lang="en-GB">Ability to scan directories to automatically import playlists and music files on start up</li>
- <li xml:lang="es">Capacidad de escanear directorios para importar listas de reproducción y archivos de música automáticamente al iniciar el programa</li>
- <li xml:lang="et">Oskus uurida kohe käivitamisel läbi katalooge ja importida sealt esitusnimekirju ja muusikafaile</li>
- <li xml:lang="hu">Könyvtárak átvizsgálásának képessége zenefájlok és lejátszólisták automatikus importálásához a program indulásakor</li>
- <li xml:lang="it">Capacità di scansionare cartelle per importare automaticamente scalette e file musicali all'avvio</li>
- <li xml:lang="ko">시작 시 디렉터리를 검사하여 자동으로 재생 목록과 음악 파일 가져오기</li>
- <li xml:lang="nds">Kann Ornern bi't Starten automaatsch op Afspeellisten un Musikdateien dörkieken</li>
- <li xml:lang="nl">Mogelijkheid om bij opstarten mappen te scannen om automatisch afspeellijsten en muziekbestanden te importeren</li>
- <li xml:lang="pl">Możliwość przeszukiwania katalogów w celu samoczynnego importowania list odtwarzania i plików muzycznych przy uruchomieniu</li>
- <li xml:lang="pt">Capacidade de sondar pastas para importar automaticamente as listas de reprodução e ficheiros de música no arranque</li>
- <li xml:lang="pt-BR">Capacidade de verificar as pastas para importar automaticamente arquivos de música e listas de músicas ao iniciar</li>
- <li xml:lang="sk">Schopnosť prehľadávať adresáre na automatický import zoznamov skladieb a hudobných súborov pri spustení</li>
- <li xml:lang="sl">Samodejen uvoz seznamov predvajanja in glasbenih datotek iz preiskanih map ob zagonu</li>
- <li xml:lang="sr">Скенирање фасцикли ради аутоматског увоза листа нумера и музичких фајлова при покретању.</li>
- <li xml:lang="sr-Latn">Skeniranje fascikli radi automatskog uvoza lista numera i muzičkih fajlova pri pokretanju.</li>
- <li xml:lang="sr-ijekavian">Скенирање фасцикли ради аутоматског увоза листа нумера и музичких фајлова при покретању.</li>
- <li xml:lang="sr-ijekavianlatin">Skeniranje fascikli radi automatskog uvoza lista numera i muzičkih fajlova pri pokretanju.</li>
- <li xml:lang="sv">Möjlighet att söka igenom kataloger vid start för att automatiskt importera spellistor och musikfiler.</li>
- <li xml:lang="uk">Можливість автоматичного пошуку та імпортування до збірки списків відтворення та файлів звукових даних.</li>
- <li xml:lang="x-test">xxAbility to scan directories to automatically import playlists and music files on start upxx</li>
- <li xml:lang="zh-TW">可以掃描目錄並於啟動時自動匯入播放清單與音樂檔</li>
- <li>Dynamic Search Playlists that are automatically updated as fields in the collection change</li>
- <li xml:lang="ca">Llistes de cerques dinàmiques que s'actualitzen automàticament a mesura que canvien els camps a la col·lecció.</li>
- <li xml:lang="da">Dynamisk søgning-spillelister som automatisk opdateres efterhånden som samlingen ændres</li>
- <li xml:lang="el">Λίστες αναπαραγωγής δυναμικής αναζήτησης που ενημερώνονται αυτόματα ως πεδία στην αλλαγή της συλλογής</li>
- <li xml:lang="en-GB">Dynamic Search Playlists that are automatically updated as fields in the collection change</li>
- <li xml:lang="es">Búsqueda dinámica de listas de reproducción que se actualiza automáticamente con los cambios de los campos de su colección</li>
- <li xml:lang="et">Dünaamilised esitusnimekirjad, mis uuenevad automaatselt kogu väljade muutumisel</li>
- <li xml:lang="hu">Lejátszólisták dinamikus keresése, amelyek automatikusan frissítésre kerülnek mezőkként a gyűjtemény módosításban</li>
- <li xml:lang="it">Scalette a ricerca dinamica, aggiornate automaticamente al cambiare dei campi nella raccolta</li>
- <li xml:lang="ko">모음집 필드 변경 사항에 따라 자동으로 업데이트되는 동적 재생 목록</li>
- <li xml:lang="nds">Dünaamsch Söök na Afspeellisten, de automaatsch topasst warrt, wenn sik Feller binnen de Sammeln ännern doot</li>
- <li xml:lang="nl">Dynamisch afspeellijsten te doorzoeken zodat velden automatisch bijgewerkt worden bij wijzigingen in de verzameling</li>
- <li xml:lang="pl">Dynamiczne przeszukiwanie list odtwarzania, które są samoczynnie uaktualnianie jako pola przy zmianie zbioru</li>
- <li xml:lang="pt">Listas de Pesquisas Dinâmicas que são actualizadas automaticamente à medida que os campos da colecção mudam</li>
- <li xml:lang="pt-BR">Listas de Pesquisas Dinâmicas que são atualizadas automaticamente à medida que os campos da coleção mudam</li>
- <li xml:lang="sk">Dynamicky hľadané zoznamy skladieb, ktoré sa automaticky aktualizujú pri zmene polí v kolekcii</li>
- <li xml:lang="sl">Dinamični iskalni seznami predvajanja, ki se s spremembo polj v zbirki samodejno posodabljajo</li>
- <li xml:lang="sr">Динамичке листе нумера за претраге, које се аутоматски ажурирају како се поља у збирци мењају.</li>
- <li xml:lang="sr-Latn">Dinamičke liste numera za pretrage, koje se automatski ažuriraju kako se polja u zbirci menjaju.</li>
- <li xml:lang="sr-ijekavian">Динамичке листе нумера за претраге, које се аутоматски ажурирају како се поља у збирци мењају.</li>
- <li xml:lang="sr-ijekavianlatin">Dinamičke liste numera za pretrage, koje se automatski ažuriraju kako se polja u zbirci menjaju.</li>
- <li xml:lang="sv">Spellistor med dynamisk sökning som automatiskt uppdateras när fält i samlingen ändras</li>
- <li xml:lang="uk">Динамічні списки пошуку, які оновлюються автоматично зі зміною у полях даних збірки.</li>
- <li xml:lang="x-test">xxDynamic Search Playlists that are automatically updated as fields in the collection changexx</li>
- <li xml:lang="zh-TW">動態搜尋播放清單,收藏有變更時自動更新</li>
- <li>A Tree View mode where playlists are automatically generated for sets of albums, artists and genres</li>
- <li xml:lang="ca">Un mode de vista en arbre quan es generen automàticament llistes de reproducció per a conjunts d'àlbums, artistes i gèneres.</li>
- <li xml:lang="da">En trævisningstilstand hvor spillelister automatisk genereres for sæt af albummer, kunstnere og genrer</li>
- <li xml:lang="el">Δενδρική άποψη όπου οι λίστες αναπαραγωγής παράγονται αυτόματα για σύνολα άλμπουμ, καλλιτεχνών και μουσικών ειδών</li>
- <li xml:lang="en-GB">A Tree View mode where playlists are automatically generated for sets of albums, artists and genres</li>
- <li xml:lang="es">Una vista de árbol donde las listas de reproducción se generan automáticamente por conjuntos de álbumes, artistas y géneros</li>
- <li xml:lang="et">Puuvaade, kus albumitele, esitajatele ja žanritele luuakse automaatselt esitusnimekirjad</li>
- <li xml:lang="hu">Egy fanézet mód, ahol a lejátszólisták automatikusan kerülnek előállításra albumok, előadók és műfajok halmazához</li>
- <li xml:lang="it">Modalità di vista ad albero in cui le scalette sono automaticamente generate per insiemi di album, artisti o generi</li>
- <li xml:lang="ko">음악가, 앨범, 장르별 자동 생성 트리 보기 모드</li>
- <li xml:lang="nds">En Boomansicht, över de sik Afspeellisten automaatsch för Setten vun Albums, Künstlers un Musikoorden opstellen laat</li>
- <li xml:lang="nl">Een boomstructuurweergave waar afspeellijsten automatisch gegenereerd worden voor sets van albums, artiesten en genres</li>
- <li xml:lang="pl">Tryb widoku drzewa, w którym listy odtwarzania są samoczynnie tworzone dla zestawów albumów, wykonawców i gatunków</li>
- <li xml:lang="pt">Um modo em Árvore, onde as listas são geradas automaticamente para determinados conjuntos de álbuns, artistas e géneros</li>
- <li xml:lang="pt-BR">Um modo de exibição em árvore, onde as listas de músicas são geradas automaticamente para determinados conjuntos de álbuns, artistas e gêneros</li>
- <li xml:lang="sk">Režim stromového zobrazenia, kde sa automaticky generujú zoznamy skladieb pre sady albumov, umelcov a žánrov</li>
- <li xml:lang="sl">Način drevesnega pogleda, v katerem so seznami predvajanja samodejno ustvarjeni za nabor albumov, izvajalcev in zvrsti</li>
- <li xml:lang="sr">Режим приказа стабла, где се листе нумера аутоматски генеришу по скуповима албума, извођача и жанрова.</li>
- <li xml:lang="sr-Latn">Režim prikaza stabla, gde se liste numera automatski generišu po skupovima albuma, izvođača i žanrova.</li>
- <li xml:lang="sr-ijekavian">Режим приказа стабла, где се листе нумера аутоматски генеришу по скуповима албума, извођача и жанрова.</li>
- <li xml:lang="sr-ijekavianlatin">Režim prikaza stabla, gde se liste numera automatski generišu po skupovima albuma, izvođača i žanrova.</li>
- <li xml:lang="sv">En trädvy där spellistor automatiskt skapas för uppsättningar av album, artister och genrer</li>
- <li xml:lang="uk">Режим ієрархічного перегляду, у якому списки відтворення створюються автоматично за наборами альбомів, виконавців та жанрів.</li>
- <li xml:lang="x-test">xxA Tree View mode where playlists are automatically generated for sets of albums, artists and genresxx</li>
- <li xml:lang="zh-TW">播放清單自動產生樹狀檢視模式,顯示專輯、演出者與風格</li>
- <li>Playlist history to indicate which files have been played and when</li>
- <li xml:lang="ca">Historial de les llistes de reproducció per indicar quins fitxers s'han reproduït i quan.</li>
- <li xml:lang="da">Spillelistehistorik som indikerer hvilke filer der er blevet afspillet og hvornår</li>
- <li xml:lang="el">Ιστορικό λιστών αναπαραγωγής με ένδειξη για το ποια αρχεία έχουν προηγηθεί και πότε</li>
- <li xml:lang="en-GB">Playlist history to indicate which files have been played and when</li>
- <li xml:lang="es">Un historial de reproducción que le indica qué archivos han sido reproducidos y cuándo</li>
- <li xml:lang="et">Esitusnimekirja ajalugu, mis näitab, milliseid faile ja millal on esitatud</li>
- <li xml:lang="hu">Lejátszólista előzmények annak jelölésére, hogy mely fájlok lettek már lejátszva és mikor</li>
- <li xml:lang="it">Cronologia delle scalette per indicare quali file sono stati letti e quando</li>
- <li xml:lang="ko">재생 목록 내 파일의 재생 이력 관리</li>
- <li xml:lang="nds">Afspeellist-Vörgeschicht, över de sik wiesen lett, welk Dateien Du wannehr afspeelt hest</li>
- <li xml:lang="nl">Geschiedenis van afspeellijsten om aan te geven welke bestanden zijn afgespeeld en wanneer</li>
- <li xml:lang="pl">Historia list odtwarzania do wskazania, które pliki i kiedy zostały odtworzone</li>
- <li xml:lang="pt">Um histórico da lista de reprodução que indica quais os ficheiros que foram reproduzidos e quando</li>
- <li xml:lang="pt-BR">Um histórico da lista de músicas que indica quais arquivos foram reproduzidos e quando</li>
- <li xml:lang="sk">História playlistu na indikáciu, ktoré súbory boli prehrané a kedy</li>
- <li xml:lang="sl">Zgodovina seznamov predvajanja, iz katere je razvidno katere datoteke ste predvajali in kdaj ste to storili</li>
- <li xml:lang="sr">Историјат листа нумера, који показује који су се фајлови пуштали и када.</li>
- <li xml:lang="sr-Latn">Istorijat lista numera, koji pokazuje koji su se fajlovi puštali i kada.</li>
- <li xml:lang="sr-ijekavian">Историјат листа нумера, који показује који су се фајлови пуштали и када.</li>
- <li xml:lang="sr-ijekavianlatin">Istorijat lista numera, koji pokazuje koji su se fajlovi puštali i kada.</li>
- <li xml:lang="sv">Spellistehistorik som anger vilka filer som har spelats och när</li>
- <li xml:lang="uk">Журнал списку відтворення, у якому зберігаються дані щодо того, які файли було відтворено і коли це сталося.</li>
- <li xml:lang="x-test">xxPlaylist history to indicate which files have been played and whenxx</li>
- <li xml:lang="zh-TW">播放清單歷史,可以指示哪些檔案於何時被播放過</li>
- <li>Inline search for filtering the list of visible items</li>
- <li xml:lang="ca">Cerca inclosa per filtrar la llista dels elements visibles.</li>
- <li xml:lang="da">Indlejret søgning til filtrering af synlige elementer i listen</li>
- <li xml:lang="el">Αναζήτηση για φιλτράρισμα της λίστας με τα ορατά αντικείμενα</li>
- <li xml:lang="en-GB">Inline search for filtering the list of visible items</li>
- <li xml:lang="es">Búsqueda bajo control para filtrar la lista de los elementos visibles</li>
- <li xml:lang="et">Reasisene otsing nähtavate elementide nimekirja filtreerimiseks</li>
- <li xml:lang="hu">Beágyazott keresés a látható elemek listájának szűréséhez</li>
- <li xml:lang="it">Ricerca in linea per filtrare l'elenco di elementi visibili</li>
- <li xml:lang="ko">재생 목록 내 빠른 검색</li>
- <li xml:lang="nds">Binnenreegs-Söök, mit de sik de List vun sichtbor Indrääg filtern lett</li>
- <li xml:lang="nl">Inline zoeken voor het filteren van de lijst met zichtbare items</li>
- <li xml:lang="pl">Wyszukiwanie w treści do odfiltrowywania spisu widocznych elementów</li>
- <li xml:lang="pt">Pesquisa incorporada para filtrar a lista de itens visíveis</li>
- <li xml:lang="pt-BR">Pesquisa incorporada para filtrar a lista de itens visíveis</li>
- <li xml:lang="sk">Inline hľadanie pre filtrovanie zoznamu viditeľných položiek</li>
- <li xml:lang="sl">Znotrajvrstično iskanje po seznamu vidnih predmetov</li>
- <li xml:lang="sr">Уткана претрага за филтрирање листе видљивих ставки.</li>
- <li xml:lang="sr-Latn">Utkana pretraga za filtriranje liste vidljivih stavki.</li>
- <li xml:lang="sr-ijekavian">Уткана претрага за филтрирање листе видљивих ставки.</li>
- <li xml:lang="sr-ijekavianlatin">Utkana pretraga za filtriranje liste vidljivih stavki.</li>
- <li xml:lang="sv">Sökning på plats för filtrering av listan med synliga objekt</li>
- <li xml:lang="uk">Вбудована можливість пошуку для фільтрування списку показаних записів.</li>
- <li xml:lang="x-test">xxInline search for filtering the list of visible itemsxx</li>
- <li xml:lang="zh-TW">清單內搜尋與過濾</li>
- <li>The ability to guess tag information based on the track's file name</li>
- <li xml:lang="ca">La capacitat d'estimar la informació de les etiquetes basada en el nom de fitxer de la peça.</li>
- <li xml:lang="da">Mulighed for at gætte mærkeinformation baseret på sporets filnavn</li>
- <li xml:lang="el">Η ικανότητα πρόγνωσης της ετικέτας πληροφοριών με βάση το όνομα του μουσικού αρχείου</li>
- <li xml:lang="en-GB">The ability to guess tag information based on the track's file name</li>
- <li xml:lang="es">La habilidad de adivinar metadatos basada en los nombres de los archivos</li>
- <li xml:lang="et">Oskus oletada silditeavet pala failinime põhjal</li>
- <li xml:lang="hu">Címkeinformációk kitalálásának képessége a szám fájlneve alapján</li>
- <li xml:lang="it">Capacità di indovinare informazioni per le etichette in base al nome del file audio</li>
- <li xml:lang="ko">파일 이름을 기반으로 한 태그 내용 추측</li>
- <li xml:lang="nds">Kann Slötelwöör ut dat Stück sien Dateinaam raden</li>
- <li xml:lang="nl">De mogelijkheid om tag-informatie te raden op basis van de bestandsnaam van de track</li>
- <li xml:lang="pl">Możliwość odgadywania informacji znacznika na podstawie nazwy pliku utworu</li>
- <li xml:lang="pt">A capacidade de adivinhar a informação das marcas com base no nome do ficheiro da faixa</li>
- <li xml:lang="pt-BR">A capacidade de adivinhar a informação das etiquetas com base no nome do arquivo da faixa</li>
- <li xml:lang="sk">Schopnosť uhádnutia informácie tagu založený na názve súboru skladby</li>
- <li xml:lang="sl">Ugibanje oznak glede na ime zvočne datoteke</li>
- <li xml:lang="sr">Могућност погађања ознака према имену фајла нумере.</li>
- <li xml:lang="sr-Latn">Mogućnost pogađanja oznaka prema imenu fajla numere.</li>
- <li xml:lang="sr-ijekavian">Могућност погађања ознака према имену фајла нумере.</li>
- <li xml:lang="sr-ijekavianlatin">Mogućnost pogađanja oznaka prema imenu fajla numere.</li>
- <li xml:lang="sv">Möjlighet att gissa tagginformation baserat på spårets filnamn</li>
- <li xml:lang="uk">Можливість вгадування міток на основі даних щодо назви файла композиції.</li>
- <li xml:lang="x-test">xxThe ability to guess tag information based on the track's file namexx</li>
- <li xml:lang="zh-TW">根據曲目名稱猜測標籤的功能</li>
- <li>File renamer that can rename files based on the tag content</li>
- <li xml:lang="ca">Reanomenador de fitxers que pot reanomenar els fitxers basant-se en el contingut de l'etiqueta.</li>
- <li xml:lang="da">Filomdøber som kan omdøbe filer baseret på mærkeindholdet</li>
- <li xml:lang="el">Πρόγραμμα μετονομασίας που λειτουργεί με βάση το περιεχόμενο της ετικέτας</li>
- <li xml:lang="en-GB">File renamer that can rename files based on the tag content</li>
- <li xml:lang="es">Un cambiador de nombres de archivo que puede renombrar archivos basándose en el contenido de sus metadatos</li>
- <li xml:lang="et">Failide nime muutmise tööriist, mis võib failinimesid muuta sildi sisu põhjal</li>
- <li xml:lang="hu">Fájlátnevező, amely képes a címketartalom alapján átnevezni fájlokat</li>
- <li xml:lang="it">Rinominatore di file per cambiare il nome ai file in base alle etichette</li>
- <li xml:lang="ko">태그 내용을 기반으로 한 파일 이름 변경</li>
- <li xml:lang="nds">Ümnömer, de Dateien na ehr Slötelwöör ümnömen kann</li>
- <li xml:lang="nl">Bestandshernoeming die kan bestanden kan hernoemen gebaseerd op de inhoud van de tag</li>
- <li xml:lang="pl">Narzędzie zmiany nazwy pliku, które może zmienić nazwę pliku na podstawie treści znacznika</li>
- <li xml:lang="pt">Um sistema de mudança de nomes dos ficheiros com base no conteúdo das marcas</li>
- <li xml:lang="pt-BR">Um sistema que pode renomear os arquivos com base no conteúdo das etiquetas</li>
- <li xml:lang="sk">Premenovač súborov, ktorý vie premenovať súbory podľa obsahu tagu</li>
- <li xml:lang="sl">Preimenovalnik datotek, ki preimenuje glede na vsebino oznake</li>
- <li xml:lang="sr">Преименовање фајлова на основу садржаја ознака.</li>
- <li xml:lang="sr-Latn">Preimenovanje fajlova na osnovu sadržaja oznaka.</li>
- <li xml:lang="sr-ijekavian">Преименовање фајлова на основу садржаја ознака.</li>
- <li xml:lang="sr-ijekavianlatin">Preimenovanje fajlova na osnovu sadržaja oznaka.</li>
- <li xml:lang="sv">Byte av filnamn som kan byta namn på filer baserat på tagginnehåll</li>
- <li xml:lang="uk">Засіб перейменування файлів, який може перейменувати файли на основі даних міток.</li>
- <li xml:lang="x-test">xxFile renamer that can rename files based on the tag contentxx</li>
- <li xml:lang="zh-TW">根據標籤內容來重新命名檔案</li>
- <li>Tag reading and editing support for many formats including ID3v1, ID3v2 and Ogg Vorbis</li>
- <li xml:lang="ca">Implementa la lectura i edició de les etiquetes per a molts formats incloent ID3v1, ID3v2 i Ogg Vorbis.</li>
- <li xml:lang="da">Understøttelse af mærkelæsning og -redigering af mange formater inklusiv ID3v1, ID3v2 og Ogg Vorbis</li>
- <li xml:lang="el">Ανάγνωση και εγγραφή ετικέτας με υποστήριξη για πολλούς τύπους αποθήκευσης, για παράδειγμα ID3v1, ID3v2 και Ogg Vorbis</li>
- <li xml:lang="en-GB">Tag reading and editing support for many formats including ID3v1, ID3v2 and Ogg Vorbis</li>
- <li xml:lang="es">Leer y editar metadatos en varios formatos incluyendo ID3v1, ID3v2 y Ogg Vorbis</li>
- <li xml:lang="et">Siltide lugemise ja muutmise toetus paljude vormingute jaoks, sealhulgas ID3v1, ID3v2 ja Ogg Vorbis</li>
- <li xml:lang="hu">Címkeolvasás és szerkesztés támogatás számos formátumhoz, beleértve az ID3v1, az ID3v2 és az Ogg Vorbis formátumokat</li>
- <li xml:lang="it">Supporto per lettura e modifica delle etichette per molti formati, tra cui ID3v1, ID3v2 e Ogg Vorbis</li>
- <li xml:lang="ko">ID3v1, ID3v2, Ogg Vorbis 태그 읽기 및 쓰기 지원</li>
- <li xml:lang="nds">Kann Slötelwöör mit vele Formaten lesen un bewerken, so as ID3v1, ID3v2 un Ogg-Vorbis</li>
- <li xml:lang="nl">Ondersteuning voor lezen van tags en bewerken voor vele formaten inclusief ID3v1, ID3v2 en Ogg Vorbis</li>
- <li xml:lang="pl">Obsługa odczytu i zmieniania znaczników dla wielu formatów zaliczając do nich: ID3v1, ID3v2 oraz Ogg Vorbis</li>
- <li xml:lang="pt">Suporte para a leitura e edição de marcas em vários formatos, incluindo o ID3v1, ID3v2 e Ogg Vorbis</li>
- <li xml:lang="pt-BR">Suporte para leitura e edição de etiquetas em vários formatos, incluindo o ID3v1, ID3v2 e Ogg Vorbis</li>
- <li xml:lang="sk">Podpora čítania a úpravy tagov pre veľa formátov vrátane ID3v1, ID3v2 a Ogg Vorbis</li>
- <li xml:lang="sl">Branje in pisanje oznak ID3v1, ID3v2, Ogg Vorbis ter drugih</li>
- <li xml:lang="sr">Подршка за читање и уређивање ознака за многе формате, укључујући ИД3 в1 и в2, и ОГГ Ворбис.</li>
- <li xml:lang="sr-Latn">Podrška za čitanje i uređivanje oznaka za mnoge formate, uključujući ID3 v1 i v2, i OGG Vorbis.</li>
- <li xml:lang="sr-ijekavian">Подршка за читање и уређивање ознака за многе формате, укључујући ИД3 в1 и в2, и ОГГ Ворбис.</li>
- <li xml:lang="sr-ijekavianlatin">Podrška za čitanje i uređivanje oznaka za mnoge formate, uključujući ID3 v1 i v2, i OGG Vorbis.</li>
- <li xml:lang="sv">Stöd för taggläsning och redigering för många format inklusive ID3v1, ID3v2 och Ogg Vorbis</li>
- <li xml:lang="uk">Підтримка читання та редагування міток у багатьох форматах, зокрема ID3v1, ID3v2 та Ogg Vorbis.</li>
- <li xml:lang="x-test">xxTag reading and editing support for many formats including ID3v1, ID3v2 and Ogg Vorbisxx</li>
- <li xml:lang="zh-TW">標籤讀取與編輯支援許多格式,包括 ID3v1, ID3v2 與 Ogg Vorbis 等</li>
- </ul>
- </description>
- <url type="homepage">http://juk.kde.org/</url>
- <url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?format=guided&product=juk</url>
- <url type="help">http://docs.kde.org/stable/en/kdemultimedia/juk/index.html</url>
- <screenshots>
- <screenshot type="default">
- <image>http://kde.org/images/screenshots/juk.png</image>
- </screenshot>
- </screenshots>
- <project_group>KDE</project_group>
- <provides>
- <binary>juk</binary>
- </provides>
-</component>
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2008, 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "juk.h"
-
-#include <kcmdlineargs.h>
-#include <kstatusbar.h>
-#include <kdebug.h>
-#include <kmessagebox.h>
-#include <kstandarddirs.h>
-#include <kactioncollection.h>
-#include <kstandardaction.h>
-#include <ktoggleaction.h>
-#include <kactionmenu.h>
-#include <kicon.h>
-#include <kaction.h>
-#include <kconfiggroup.h>
-#include <kapplication.h>
-#include <kglobalaccel.h>
-#include <ktoolbarpopupaction.h>
-#include <knotification.h>
-#include <kdeversion.h>
-
-#include <QCoreApplication>
-#include <QKeyEvent>
-#include <QDir>
-#include <QTime>
-#include <QTimer>
-#include <QDesktopWidget>
-
-#include "slideraction.h"
-#include "statuslabel.h"
-#include "splashscreen.h"
-#include "systemtray.h"
-#include "keydialog.h"
-#include "tagguesserconfigdlg.h"
-#include "filerenamerconfigdlg.h"
-#include "scrobbler.h"
-#include "scrobbleconfigdlg.h"
-#include "actioncollection.h"
-#include "cache.h"
-#include "playlistsplitter.h"
-#include "collectionlist.h"
-#include "covermanager.h"
-#include "tagtransactionmanager.h"
-
-using namespace ActionCollection;
-
-JuK* JuK::m_instance;
-
-template<class T>
-void deleteAndClear(T *&ptr)
-{
- delete ptr;
- ptr = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-JuK::JuK(QWidget *parent) :
- KXmlGuiWindow(parent, Qt::WDestructiveClose),
- m_splitter(0),
- m_statusLabel(0),
- m_systemTray(0),
- m_player(new PlayerManager),
- m_scrobbler(0),
- m_shuttingDown(false)
-{
- // Expect segfaults if you change this order.
-
- m_instance = this;
-
- readSettings();
-
- if(m_showSplash && !m_startDocked && Cache::cacheFileExists()) {
- if(SplashScreen* splash = SplashScreen::instance()) {
- splash->show();
- kapp->processEvents();
- }
- }
-
- setupActions();
- setupLayout();
-
- bool firstRun = !KGlobal::config()->hasGroup("MainWindow");
-
- if(firstRun) {
- KConfigGroup mainWindowConfig(KGlobal::config(), "MainWindow");
- KConfigGroup playToolBarConfig(&mainWindowConfig, "Toolbar playToolBar");
- playToolBarConfig.writeEntry("ToolButtonStyle", "IconOnly");
- }
-
- QSize defaultSize(800, 480);
-
- if(QApplication::isRightToLeft())
- setupGUI(defaultSize, ToolBar | Save | Create, "jukui-rtl.rc");
- else
- setupGUI(defaultSize, ToolBar | Save | Create);
-
- // Center the GUI if this is our first run ever.
-
- if(firstRun) {
- QRect r = rect();
- r.moveCenter(KApplication::desktop()->screenGeometry().center());
- move(r.topLeft());
- }
-
- connect(m_splitter, SIGNAL(guiReady()), SLOT(slotSetupSystemTray()));
- readConfig();
- setupGlobalAccels();
- activateScrobblerIfEnabled();
-
- connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), SLOT(slotAboutToQuit()));
-
- // slotCheckCache loads the cached entries first to populate the collection list
-
- QTimer::singleShot(0, this, SLOT(slotClearOldCovers()));
- QTimer::singleShot(0, CollectionList::instance(), SLOT(startLoadingCachedItems()));
- QTimer::singleShot(0, this, SLOT(slotProcessArgs()));
-}
-
-JuK::~JuK()
-{
-}
-
-JuK* JuK::JuKInstance()
-{
- return m_instance;
-}
-
-PlayerManager *JuK::playerManager() const
-{
- return m_player;
-}
-
-void JuK::coverDownloaded(const QPixmap &cover)
-{
- QString event(cover.isNull() ? "coverFailed" : "coverDownloaded");
- KNotification *notification = new KNotification(event, this);
- notification->setPixmap(cover);
- notification->setFlags(KNotification::CloseOnTimeout);
-
- if(cover.isNull())
- notification->setText(i18n("Your album art failed to download."));
- else
- notification->setText(i18n("Your album art has finished downloading."));
-
- notification->sendEvent();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-void JuK::setupLayout()
-{
- new TagTransactionManager(this);
-
- kDebug() << "Creating GUI";
- QTime stopwatch;
- stopwatch.start();
-
- m_splitter = new PlaylistSplitter(m_player, this);
- setCentralWidget(m_splitter);
-
- m_statusLabel = new StatusLabel(m_splitter->playlist(), statusBar());
- connect(CollectionList::instance(), SIGNAL(signalCollectionChanged()),
- m_statusLabel, SLOT(updateData()));
- statusBar()->addWidget(m_statusLabel, 1);
- m_player->setStatusLabel(m_statusLabel);
-
- m_splitter->setFocus();
-
- kDebug() << "GUI created in" << stopwatch.elapsed() << "ms";
-}
-
-void JuK::setupActions()
-{
- KActionCollection *collection = ActionCollection::actions();
-
- // Setup KDE standard actions that JuK uses.
-
- KStandardAction::quit(this, SLOT(slotQuit()), collection);
- KStandardAction::undo(this, SLOT(slotUndo()), collection);
- KStandardAction::cut(collection);
- KStandardAction::copy(collection);
- KStandardAction::paste(collection);
- KAction *clear = KStandardAction::clear(collection);
- KStandardAction::selectAll(collection);
- KStandardAction::keyBindings(this, SLOT(slotEditKeys()), collection);
-
-
- // Setup the menu which handles the random play options.
- KActionMenu *actionMenu = collection->add<KActionMenu>("actionMenu");
- actionMenu->setText(i18n("&Random Play"));
- actionMenu->setIcon(KIcon( QLatin1String( "media-playlist-shuffle" )));
- actionMenu->setDelayed(false);
-
- QActionGroup* randomPlayGroup = new QActionGroup(this);
-
- QAction *act = collection->add<KToggleAction>("disableRandomPlay");
- act->setText(i18n("&Disable Random Play"));
- act->setIcon(KIcon( QLatin1String( "go-down" )));
- act->setActionGroup(randomPlayGroup);
- actionMenu->addAction(act);
-
- m_randomPlayAction = collection->add<KToggleAction>("randomPlay");
- m_randomPlayAction->setText(i18n("Use &Random Play"));
- m_randomPlayAction->setIcon(KIcon( QLatin1String( "media-playlist-shuffle" )));
- m_randomPlayAction->setActionGroup(randomPlayGroup);
- actionMenu->addAction(m_randomPlayAction);
-
- act = collection->add<KToggleAction>("albumRandomPlay");
- act->setText(i18n("Use &Album Random Play"));
- act->setIcon(KIcon( QLatin1String( "media-playlist-shuffle" )));
- act->setActionGroup(randomPlayGroup);
- connect(act, SIGNAL(triggered(bool)), SLOT(slotCheckAlbumNextAction(bool)));
- actionMenu->addAction(act);
-
- act = collection->addAction("removeFromPlaylist", clear, SLOT(clear()));
- act->setText(i18n("Remove From Playlist"));
- act->setIcon(KIcon( QLatin1String( "list-remove" )));
-
- act = collection->add<KToggleAction>("crossfadeTracks");
- act->setText(i18n("Crossfade Between Tracks"));
- connect(act, SIGNAL(triggered(bool)), m_player, SLOT(setCrossfadeEnabled(bool)));
-
- act = collection->addAction("play", m_player, SLOT(play()));
- act->setText(i18n("&Play"));
- act->setIcon(KIcon( QLatin1String( "media-playback-start" )));
-
- act = collection->addAction("pause", m_player, SLOT(pause()));
- act->setText(i18n("P&ause"));
- act->setIcon(KIcon( QLatin1String( "media-playback-pause" )));
-
- act = collection->addAction("stop", m_player, SLOT(stop()));
- act->setText(i18n("&Stop"));
- act->setIcon(KIcon( QLatin1String( "media-playback-stop" )));
-
- act = new KToolBarPopupAction(KIcon( QLatin1String( "media-skip-backward") ), i18nc("previous track", "Previous" ), collection);
- collection->addAction("back", act);
- connect(act, SIGNAL(triggered(bool)), m_player, SLOT(back()));
-
- act = collection->addAction("forward", m_player, SLOT(forward()));
- act->setText(i18nc("next track", "&Next"));
- act->setIcon(KIcon( QLatin1String( "media-skip-forward" )));
-
- act = collection->addAction("loopPlaylist");
- act->setText(i18n("&Loop Playlist"));
- act->setCheckable(true);
-
- act = collection->add<KToggleAction>("resizeColumnsManually");
- act->setText(i18n("&Resize Playlist Columns Manually"));
-
- // the following are not visible by default
-
- act = collection->addAction("mute", m_player, SLOT(mute()));
- act->setText(i18nc("silence playback", "Mute"));
- act->setIcon(KIcon( QLatin1String( "audio-volume-muted" )));
-
- act = collection->addAction("volumeUp", m_player, SLOT(volumeUp()));
- act->setText(i18n("Volume Up"));
- act->setIcon(KIcon( QLatin1String( "audio-volume-high" )));
-
- act = collection->addAction("volumeDown", m_player, SLOT(volumeDown()));
- act->setText(i18n("Volume Down"));
- act->setIcon(KIcon( QLatin1String( "audio-volume-low" )));
-
- act = collection->addAction("playPause", m_player, SLOT(playPause()));
- act->setText(i18n("Play / Pause"));
- act->setIcon(KIcon( QLatin1String( "media-playback-start" )));
-
- act = collection->addAction("seekForward", m_player, SLOT(seekForward()));
- act->setText(i18n("Seek Forward"));
- act->setIcon(KIcon( QLatin1String( "media-seek-forward" )));
-
- act = collection->addAction("seekBack", m_player, SLOT(seekBack()));
- act->setText(i18n("Seek Back"));
- act->setIcon(KIcon( QLatin1String( "media-seek-backward" )));
-
- act = collection->addAction("showHide", this, SLOT(slotShowHide()));
- act->setText(i18n("Show / Hide"));
-
- //////////////////////////////////////////////////
- // settings menu
- //////////////////////////////////////////////////
-
- m_toggleSplashAction = collection->add<KToggleAction>("showSplashScreen");
- m_toggleSplashAction->setText(i18n("Show Splash Screen on Startup"));
-
- m_toggleSystemTrayAction = collection->add<KToggleAction>("toggleSystemTray");
- m_toggleSystemTrayAction->setText(i18n("&Dock in System Tray"));
- connect(m_toggleSystemTrayAction, SIGNAL(triggered(bool)), SLOT(slotToggleSystemTray(bool)));
-
- m_toggleDockOnCloseAction = collection->add<KToggleAction>("dockOnClose");
- m_toggleDockOnCloseAction->setText(i18n("&Stay in System Tray on Close"));
-
- m_togglePopupsAction = collection->add<KToggleAction>("togglePopups");
- m_togglePopupsAction->setText(i18n("Popup &Track Announcement"));
-
- act = collection->add<KToggleAction>("saveUpcomingTracks");
- act->setText(i18n("Save &Play Queue on Exit"));
-
- act = collection->addAction("tagGuesserConfig", this, SLOT(slotConfigureTagGuesser()));
- act->setText(i18n("&Tag Guesser..."));
-
- act = collection->addAction("fileRenamerConfig", this, SLOT(slotConfigureFileRenamer()));
- act->setText(i18n("&File Renamer..."));
-
- act = collection->addAction("scrobblerConfig", this, SLOT(slotConfigureScrobbling()));
- act->setText(i18n("&Configure scrobbling..."));
-
- //////////////////////////////////////////////////
- // just in the toolbar
- //////////////////////////////////////////////////
-
- collection->addAction("trackPositionAction",
- new TrackPositionAction(i18n("Track Position"), this));
- collection->addAction("volumeAction",
- new VolumeAction(i18n("Volume"), this));
-
- ActionCollection::actions()->addAssociatedWidget(this);
- foreach (QAction* action, ActionCollection::actions()->actions())
- action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
-}
-
-void JuK::slotSetupSystemTray()
-{
- if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
- kDebug() << "Setting up systray";
- QTime stopwatch; stopwatch.start();
- m_systemTray = new SystemTray(m_player, this);
- m_systemTray->setObjectName( QLatin1String("systemTray" ));
-
- m_toggleDockOnCloseAction->setEnabled(true);
- m_togglePopupsAction->setEnabled(true);
- kDebug() << "Finished setting up systray, took" << stopwatch.elapsed() << "ms";
- }
- else {
- m_systemTray = 0;
- m_toggleDockOnCloseAction->setEnabled(false);
- m_togglePopupsAction->setEnabled(false);
- }
-}
-
-void JuK::setupGlobalAccels()
-{
- KeyDialog::setupActionShortcut("play");
- KeyDialog::setupActionShortcut("playPause");
- KeyDialog::setupActionShortcut("stop");
- KeyDialog::setupActionShortcut("back");
- KeyDialog::setupActionShortcut("forward");
- KeyDialog::setupActionShortcut("seekBack");
- KeyDialog::setupActionShortcut("seekForward");
- KeyDialog::setupActionShortcut("volumeUp");
- KeyDialog::setupActionShortcut("volumeDown");
- KeyDialog::setupActionShortcut("mute");
- KeyDialog::setupActionShortcut("showHide");
- KeyDialog::setupActionShortcut("forwardAlbum");
-}
-
-void JuK::slotProcessArgs()
-{
- KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
- QStringList files;
-
- for(int i = 0; i < args->count(); i++)
- files.append(args->arg(i));
-
- CollectionList::instance()->addFiles(files);
-}
-
-void JuK::slotClearOldCovers()
-{
- // Find all saved covers from the previous run of JuK and clear them out, in case
- // we find our tracks in a different order this run, which would cause old saved
- // covers to be wrong.
- // See mpris2/mediaplayer2player.cpp
- QStringList oldFiles = KGlobal::dirs()->findAllResources("tmp", "juk-cover-*.png");
-
- foreach(const QString &file, oldFiles) {
- kWarning() << "Removing old cover" << file;
- if(!QFile::remove(file)) {
- kError() << "Failed to remove old cover" << file;
- }
- }
-}
-
-void JuK::keyPressEvent(QKeyEvent *e)
-{
- if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
- e->accept();
- KXmlGuiWindow::keyPressEvent(e);
-}
-
-/**
- * These are settings that need to be know before setting up the GUI.
- */
-
-void JuK::readSettings()
-{
- KConfigGroup config(KGlobal::config(), "Settings");
- m_showSplash = config.readEntry("ShowSplashScreen", true);
- m_startDocked = config.readEntry("StartDocked", false);
-}
-
-void JuK::readConfig()
-{
- // player settings
-
- KConfigGroup playerConfig(KGlobal::config(), "Player");
-
- if(m_player)
- {
- const int maxVolume = 100;
- const int volume = playerConfig.readEntry("Volume", maxVolume);
- m_player->setVolume(volume * 0.01);
- if(ActionCollection::action<VolumeAction>("volumeAction")->button())
- ActionCollection::action<VolumeAction>("volumeAction")->button()->refresh();
-
- bool enableCrossfade = playerConfig.readEntry("CrossfadeTracks", true);
- m_player->setCrossfadeEnabled(enableCrossfade);
- ActionCollection::action<KAction>("crossfadeTracks")->setChecked(enableCrossfade);
- }
-
- // Default to no random play
-
- ActionCollection::action<KToggleAction>("disableRandomPlay")->setChecked(true);
-
- QString randomPlayMode = playerConfig.readEntry("RandomPlay", "Disabled");
- if(randomPlayMode == "true" || randomPlayMode == "Normal")
- m_randomPlayAction->setChecked(true);
- else if(randomPlayMode == "AlbumRandomPlay")
- ActionCollection::action<KAction>("albumRandomPlay")->setChecked(true);
-
- bool loopPlaylist = playerConfig.readEntry("LoopPlaylist", false);
- ActionCollection::action<KAction>("loopPlaylist")->setChecked(loopPlaylist);
-
- // general settings
-
- KConfigGroup settingsConfig(KGlobal::config(), "Settings");
-
- bool dockInSystemTray = settingsConfig.readEntry("DockInSystemTray", true);
- m_toggleSystemTrayAction->setChecked(dockInSystemTray);
-
- bool dockOnClose = settingsConfig.readEntry("DockOnClose", true);
- m_toggleDockOnCloseAction->setChecked(dockOnClose);
-
- bool showPopups = settingsConfig.readEntry("TrackPopup", false);
- m_togglePopupsAction->setChecked(showPopups);
-
- m_toggleSplashAction->setChecked(m_showSplash);
-}
-
-void JuK::saveConfig()
-{
- // player settings
-
- KConfigGroup playerConfig(KGlobal::config(), "Player");
-
- if (m_player)
- {
- playerConfig.writeEntry("Volume", static_cast<int>(100.0 * m_player->volume()));
- }
-
- playerConfig.writeEntry("RandomPlay", m_randomPlayAction->isChecked());
-
- KAction *a = ActionCollection::action<KAction>("loopPlaylist");
- playerConfig.writeEntry("LoopPlaylist", a->isChecked());
-
- a = ActionCollection::action<KAction>("crossfadeTracks");
- playerConfig.writeEntry("CrossfadeTracks", a->isChecked());
-
- a = ActionCollection::action<KAction>("albumRandomPlay");
- if(a->isChecked())
- playerConfig.writeEntry("RandomPlay", "AlbumRandomPlay");
- else if(m_randomPlayAction->isChecked())
- playerConfig.writeEntry("RandomPlay", "Normal");
- else
- playerConfig.writeEntry("RandomPlay", "Disabled");
-
- // general settings
-
- KConfigGroup settingsConfig(KGlobal::config(), "Settings");
- settingsConfig.writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
- settingsConfig.writeEntry("StartDocked", m_startDocked);
- settingsConfig.writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
- settingsConfig.writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
- settingsConfig.writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
-
- KGlobal::config()->sync();
-}
-
-bool JuK::queryClose()
-{
- if(!m_shuttingDown &&
- !kapp->sessionSaving() &&
- m_systemTray &&
- m_toggleDockOnCloseAction->isChecked())
- {
- KMessageBox::information(this,
- i18n("<qt>Closing the main window will keep JuK running in the system tray. "
- "Use Quit from the File menu to quit the application.</qt>"),
- i18n("Docking in System Tray"), "hideOnCloseInfo");
- hide();
- return false;
- }
- else
- {
- // Some phonon backends will crash on shutdown unless we've stopped
- // playback.
- if(m_player->playing())
- m_player->stop();
-
- // Save configuration data.
- m_startDocked = !isVisible();
- saveConfig();
- return true;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slot definitions
-////////////////////////////////////////////////////////////////////////////////
-
-void JuK::slotShowHide()
-{
- setHidden(!isHidden());
-}
-
-void JuK::slotAboutToQuit()
-{
- m_shuttingDown = true;
-
- deleteAndClear(m_systemTray);
- deleteAndClear(m_splitter);
- deleteAndClear(m_player);
- deleteAndClear(m_statusLabel);
-
- // Playlists depend on CoverManager, so CoverManager should shutdown as
- // late as possible
- CoverManager::shutdown();
-}
-
-void JuK::slotQuit()
-{
- m_shuttingDown = true;
-
- kapp->quit();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// settings menu
-////////////////////////////////////////////////////////////////////////////////
-
-void JuK::slotToggleSystemTray(bool enabled)
-{
- if(enabled && !m_systemTray)
- slotSetupSystemTray();
- else if(!enabled && m_systemTray) {
- delete m_systemTray;
- m_systemTray = 0;
- m_toggleDockOnCloseAction->setEnabled(false);
- m_togglePopupsAction->setEnabled(false);
- }
-}
-
-void JuK::slotEditKeys()
-{
- KeyDialog::configure(ActionCollection::actions(), this);
-}
-
-void JuK::slotConfigureTagGuesser()
-{
- TagGuesserConfigDlg(this).exec();
-}
-
-void JuK::slotConfigureFileRenamer()
-{
- FileRenamerConfigDlg(this).exec();
-}
-
-void JuK::slotConfigureScrobbling()
-{
- ScrobbleConfigDlg(this).exec();
- activateScrobblerIfEnabled();
-}
-
-void JuK::activateScrobblerIfEnabled()
-{
- bool isScrobbling = Scrobbler::isScrobblingEnabled();
-
- if (!m_scrobbler && isScrobbling) {
- m_scrobbler = new Scrobbler(this);
- connect (m_player, SIGNAL(signalItemChanged(FileHandle)),
- m_scrobbler, SLOT(nowPlaying(FileHandle)));
- }
- else if (m_scrobbler && !isScrobbling) {
- delete m_scrobbler;
- m_scrobbler = 0;
- }
-}
-
-void JuK::slotUndo()
-{
- TagTransactionManager::instance()->undo();
-}
-
-void JuK::slotCheckAlbumNextAction(bool albumRandomEnabled)
-{
- // If album random play is enabled, then enable the Play Next Album action
- // unless we're not playing right now.
-
- if(albumRandomEnabled && !m_player->playing())
- albumRandomEnabled = false;
-
- action("forwardAlbum")->setEnabled(albumRandomEnabled);
-}
-
-#include "juk.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-# KDE Config File
-[Desktop Entry]
-Type=Application
-Exec=juk -caption %c %i
-Icon=juk
-X-DocPath=juk/index.html
-X-DBUS-StartupType=Unique
-Comment=
-Terminal=false
-Name=JuK
-Name[bg]=JuK
-Name[bs]=JuK
-Name[ca]=JuK
-Name[ca@valencia]=JuK
-Name[cs]=JuK
-Name[da]=JuK
-Name[de]=JuK
-Name[el]=JuK
-Name[en_GB]=JuK
-Name[es]=JuK
-Name[et]=JuK
-Name[fi]=JuK
-Name[fr]=JuK
-Name[ga]=JuK
-Name[gl]=JuK
-Name[hu]=JuK
-Name[ia]=JuK
-Name[is]=JuK
-Name[it]=JuK
-Name[ja]=JuK
-Name[kk]=JuK
-Name[km]=JuK
-Name[ko]=JuK
-Name[lt]=JuK
-Name[mr]=ज्युक
-Name[nb]=JuK
-Name[nds]=JuK
-Name[nl]=JuK
-Name[nn]=JuK
-Name[pa]=ਜੂਕ
-Name[pl]=JuK
-Name[pt]=JuK
-Name[pt_BR]=JuK
-Name[ro]=JuK
-Name[ru]=JuK
-Name[sk]=JuK
-Name[sl]=JuK
-Name[sr]=Џук
-Name[sr@ijekavian]=Џук
-Name[sr@ijekavianlatin]=Juk
-Name[sr@latin]=Juk
-Name[sv]=Juk
-Name[tr]=JuK
-Name[ug]=JuK
-Name[uk]=JuK
-Name[x-test]=xxJuKxx
-Name[zh_CN]=JuK
-Name[zh_TW]=音樂播放_JuK
-GenericName=Music Player
-GenericName[bg]=Слушане на музика
-GenericName[bs]=Muzički program
-GenericName[ca]=Reproductor musical
-GenericName[ca@valencia]=Reproductor musical
-GenericName[cs]=Přehrávač hudby
-GenericName[da]=Musikafspiller
-GenericName[de]=Audio-Wiedergabe
-GenericName[el]=Music Player
-GenericName[en_GB]=Music Player
-GenericName[es]=Reproductor de música
-GenericName[et]=Muusikamängija
-GenericName[fi]=Musiikkisoitin
-GenericName[fr]=Lecteur multimédia
-GenericName[ga]=Seinnteoir Ceoil
-GenericName[gl]=Reprodutor de música
-GenericName[hu]=Zenelejátszó
-GenericName[ia]=Reproductor musical
-GenericName[is]=Tónlistarspilari
-GenericName[it]=Lettore musicale
-GenericName[ja]=ミュージックプレーヤー
-GenericName[kk]=Музыка ойнатқышы
-GenericName[km]=កម្មវិធីចាក់តន្ត្រី
-GenericName[ko]=음악 재생기
-GenericName[lt]=Muzikos grotuvas
-GenericName[mr]=संगीत प्लेयर
-GenericName[nb]=Musikkspiller
-GenericName[nds]=Musikafspeler
-GenericName[nl]=Muziekspeler
-GenericName[nn]=Musikkspelar
-GenericName[pa]=ਸੰਗੀਤ ਪਲੇਅਰ
-GenericName[pl]=Odtwarzacz muzyki
-GenericName[pt]=Leitor de Música
-GenericName[pt_BR]=Reprodutor de músicas
-GenericName[ro]=Program de redare audio
-GenericName[ru]=Музыкальный проигрыватель
-GenericName[sk]=Prehrávač hudby
-GenericName[sl]=Glasbeni predvajalnik
-GenericName[sr]=Музички плејер
-GenericName[sr@ijekavian]=Музички плејер
-GenericName[sr@ijekavianlatin]=Muzički plejer
-GenericName[sr@latin]=Muzički plejer
-GenericName[sv]=Musikspelare
-GenericName[tr]=Müzik Çalar
-GenericName[ug]=نەغمە قويغۇ
-GenericName[uk]=Програвач музики
-GenericName[x-test]=xxMusic Playerxx
-GenericName[zh_CN]=音乐播放器
-GenericName[zh_TW]=音樂播放器
-Categories=Qt;KDE;AudioVideo;Player;
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_H
-#define JUK_H
-
-#include <kxmlguiwindow.h>
-
-#include "playermanager.h"
-#include <QKeyEvent>
-
-
-class KToggleAction;
-class KGlobalAccel;
-
-class SliderAction;
-class StatusLabel;
-class SystemTray;
-class PlayerManager;
-class PlaylistSplitter;
-class Scrobbler;
-
-class JuK : public KXmlGuiWindow
-{
- Q_OBJECT
-
-public:
- JuK(QWidget* parent = 0);
- virtual ~JuK();
-
- static JuK* JuKInstance();
-
- PlayerManager *playerManager() const;
-
- // Use a null cover for failure
- void coverDownloaded(const QPixmap &cover);
-
-private:
- void setupLayout();
- void setupActions();
- void setupGlobalAccels();
-
- void keyPressEvent(QKeyEvent *);
-
- void activateScrobblerIfEnabled();
-
- /**
- * readSettings() is separate from readConfig() in that it contains settings
- * that need to be read before the GUI is setup.
- */
- void readSettings();
- void readConfig();
- void saveConfig();
-
- virtual bool queryClose();
-
-private slots:
- void slotSetupSystemTray();
- void slotShowHide();
- void slotAboutToQuit();
- void slotQuit();
- void slotToggleSystemTray(bool enabled);
- void slotEditKeys();
- void slotConfigureTagGuesser();
- void slotConfigureFileRenamer();
- void slotConfigureScrobbling();
- void slotUndo();
- void slotCheckAlbumNextAction(bool albumRandomEnabled);
- void slotProcessArgs();
- void slotClearOldCovers();
-
-private:
- PlaylistSplitter *m_splitter;
- StatusLabel *m_statusLabel;
- SystemTray *m_systemTray;
-
- KToggleAction *m_randomPlayAction;
- KToggleAction *m_toggleSystemTrayAction;
- KToggleAction *m_toggleDockOnCloseAction;
- KToggleAction *m_togglePopupsAction;
- KToggleAction *m_toggleSplashAction;
-
- PlayerManager *m_player;
- Scrobbler *m_scrobbler;
-
- bool m_startDocked;
- bool m_showSplash;
- bool m_shuttingDown;
-
- static JuK* m_instance;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-[Global]
-IconName=juk
-Comment=Juk Music Player
-Comment[bg]=Слушане на музика (Juk)
-Comment[bs]=Muzički plejer Juk
-Comment[ca]=Reproductor musical Juk
-Comment[ca@valencia]=Reproductor musical Juk
-Comment[cs]=Přehrávač hudby Juk
-Comment[da]=Juk musikafspiller
-Comment[de]=JuK-Audio-Wiedergabe
-Comment[el]=Πρόγραμμα αναπαραγωγής μουσικής JuK
-Comment[en_GB]=Juk Music Player
-Comment[es]=Reproductor de música JuK
-Comment[et]=Muusikamängija Juk
-Comment[fi]=Juk-musiikkisoitin
-Comment[fr]=Lecteur multimédia JuK
-Comment[ga]=Seinnteoir Ceoil Juk
-Comment[gl]=Lector reprodutor de música
-Comment[hu]=Juk zenelejátszó
-Comment[ia]=Juk Music Player (Reproductor musical)
-Comment[is]=JuK tónlistarspilari
-Comment[it]=Lettore musicale Juk
-Comment[ja]=Juk ミュージックプレーヤー
-Comment[kk]=Juk музыка ойнатқышы
-Comment[km]=កម្មវិធីចាក់តន្ត្រី Juk
-Comment[ko]=Juk 음악 재생기
-Comment[lt]=Juk muzikos grotuvas
-Comment[mr]=ज्युक संगीत प्लेयर
-Comment[nb]=Juk musikkspiller
-Comment[nds]=Musikafspeler "Juk"
-Comment[nl]=Juk-muziekspeler
-Comment[pa]=ਜੂਕ ਸੰਗੀਤ ਪਲੇਅਰ
-Comment[pl]=Odtwarzacz muzyki Juk
-Comment[pt]=Leitor de Música
-Comment[pt_BR]=Reprodutor de músicas Juk
-Comment[ro]=Lector de muzică Juk
-Comment[ru]=Музыкальный проигрыватель JuK
-Comment[sk]=Prehrávač hudby Juk
-Comment[sl]=Glasbeni predvajalnik Juk
-Comment[sr]=Музички плејер Џук
-Comment[sr@ijekavian]=Музички плејер Џук
-Comment[sr@ijekavianlatin]=Muzički plejer Juk
-Comment[sr@latin]=Muzički plejer Juk
-Comment[sv]=Juk musikspelare
-Comment[tr]=Juk Müzik Çalar
-Comment[ug]=Juk نەغمە چالغۇچ
-Comment[uk]=Програвач музики JuK
-Comment[x-test]=xxJuk Music Playerxx
-Comment[zh_CN]=Juk 音乐播放器
-Comment[zh_TW]=Juk 音樂播放器
-Name=JuK
-Name[bg]=JuK
-Name[bs]=JuK
-Name[ca]=JuK
-Name[ca@valencia]=JuK
-Name[cs]=JuK
-Name[da]=JuK
-Name[de]=JuK
-Name[el]=JuK
-Name[en_GB]=JuK
-Name[es]=JuK
-Name[et]=JuK
-Name[fi]=JuK
-Name[fr]=JuK
-Name[ga]=JuK
-Name[gl]=JuK
-Name[hu]=JuK
-Name[ia]=JuK
-Name[is]=JuK
-Name[it]=JuK
-Name[ja]=JuK
-Name[kk]=JuK
-Name[km]=JuK
-Name[ko]=JuK
-Name[lt]=JuK
-Name[mr]=ज्युक
-Name[nb]=JuK
-Name[nds]=JuK
-Name[nl]=JuK
-Name[nn]=JuK
-Name[pa]=ਜੂਕ
-Name[pl]=JuK
-Name[pt]=JuK
-Name[pt_BR]=JuK
-Name[ro]=JuK
-Name[ru]=JuK
-Name[sk]=JuK
-Name[sl]=JuK
-Name[sr]=Џук
-Name[sr@ijekavian]=Џук
-Name[sr@ijekavianlatin]=Juk
-Name[sr@latin]=Juk
-Name[sv]=Juk
-Name[tr]=JuK
-Name[ug]=JuK
-Name[uk]=JuK
-Name[x-test]=xxJuKxx
-Name[zh_CN]=JuK
-Name[zh_TW]=音樂播放_JuK
-
-[Event/coverDownloaded]
-Name=Cover Successfully Downloaded
-Name[bg]=Обложката е изтеглена
-Name[bs]=Omot uspješno preuzet
-Name[ca]=La caràtula s'ha baixat correctament
-Name[ca@valencia]=La caràtula s'ha baixat correctament
-Name[cs]=Obal úspěšně stažen
-Name[da]=Download af omslag gennemført
-Name[de]=Titelbild erfolgreich heruntergeladen
-Name[el]=Επιτυχής λήψη εξωφύλλου
-Name[en_GB]=Cover Successfully Downloaded
-Name[es]=Carátula descargada con éxito
-Name[et]=Kaanepilt on edukalt alla laaditud
-Name[fi]=Kansikuva ladattiin onnistuneesti
-Name[fr]=Jaquette téléchargée avec succès
-Name[ga]=D'éirigh le híosluchtú an chlúdaigh
-Name[gl]=Descargouse a portada correctamente
-Name[hu]=A borító sikeresen letöltve
-Name[ia]=Il discargava copertura con successo
-Name[is]=Niðurhal umslags tókst
-Name[it]=Copertina scaricata con successo
-Name[ja]=カバーのダウンロード完了
-Name[kk]=Мұқабасы сәтті жүктеп алынды
-Name[km]=បានទាញយកគម្របដោយជោគជ័យ
-Name[ko]=커버를 다운로드함
-Name[lt]=Viršelis sėkmingai atsiųstas
-Name[mr]=कव्हर यशस्वीपूर्वक डाउनलोड झाले
-Name[nb]=Omslag vellykket lastet ned
-Name[nds]=Titelbild mit Spood daallaadt
-Name[nl]=Hoes is met succes gedownload
-Name[nn]=Omslaget er nedlasta
-Name[pa]=ਕਵਰ ਠੀਕ ਤਰ੍ਹਾਂ ਡਾਊਨਲੋਡ ਹੋ ਗਏ
-Name[pl]=Pomyślnie pobrano okładkę
-Name[pt]=A Capa Foi Obtida com Sucesso
-Name[pt_BR]=Capa baixada com sucesso
-Name[ro]=Copertă descărcată cu succes
-Name[ru]=Обложка успешно загружена
-Name[sk]=Obal bol úspešne stiahnutý
-Name[sl]=Ovitek uspešno prejet
-Name[sr]=Омот успешно преузет
-Name[sr@ijekavian]=Омот успјешно преузет
-Name[sr@ijekavianlatin]=Omot uspješno preuzet
-Name[sr@latin]=Omot uspešno preuzet
-Name[sv]=Omslag nerladdat med lyckat resultat
-Name[tr]=Kapak Başarılı Şekilde İndirildi
-Name[ug]=مۇقاۋا مۇۋەپپەقىيەتلىك چۈشۈرۈلدى
-Name[uk]=Обкладинку успішно звантажено
-Name[x-test]=xxCover Successfully Downloadedxx
-Name[zh_CN]=下载封面成功
-Name[zh_TW]=已成功下載封面
-Comment=A requested cover has been downloaded
-Comment[bg]=Поисканата обложка е изтеглена
-Comment[bs]=Zatraženi omot je preuzet
-Comment[ca]=S'ha baixat la caràtula sol·licitada
-Comment[ca@valencia]=S'ha baixat la caràtula sol·licitada
-Comment[cs]=Vyžádaný obal se byl úspěšně stažen
-Comment[da]=En ønsket omslag er blevet downloadet
-Comment[de]=Ein angefordertes Titelbild wurde heruntergeladen
-Comment[el]=Το εξώφυλλο που ζητήθηκε έχει ληφθεί
-Comment[en_GB]=A requested cover has been downloaded
-Comment[es]=Se ha descargado una carátula solicitada
-Comment[et]=Soovitud kaanepilt on alla laaditud
-Comment[fi]=Pyydetty kansikuva on ladattu
-Comment[fr]=Une jaquette demandée a été téléchargée
-Comment[ga]=Íosluchtaíodh clúdach iarrtha
-Comment[gl]=Descargouse a portada do disco solicitada
-Comment[hu]=A kért borító sikeresen letöltve
-Comment[ia]=Un copertura requirite ha essite discargate
-Comment[is]=Niðurhali á umbeðnu hulstri er lokið
-Comment[it]=Una copertina richiesta è stata scaricata
-Comment[ja]=要求されたカバーをダウンロードしました
-Comment[kk]=Сұралған мұқабасы жүктеп алынды
-Comment[km]=គម្របដែលបានស្នើត្រូវបានទាញយក
-Comment[ko]=요청한 커버가 다운로드됨
-Comment[lt]=Prašytas viršelis buvo atsiųstas
-Comment[mr]=विनंतीकेलेले कव्हर डाउनलोड झाले आहे
-Comment[nb]=Et ønsket omslag er lastet ned
-Comment[nds]=En anfraagt Titelbild wöör daallaadt
-Comment[nl]=Een gevraagde hoes is gedownload
-Comment[nn]=Det førespurde omslaget er nedlasta
-Comment[pa]=ਮੰਗਿਆ ਗਿਆ ਕਵਰ ਡਾਊਨਲੋਡ ਕੀਤਾ ਜਾ ਚੁੱਕਾ ਹੈ
-Comment[pl]=Żądana okładka została pobrana
-Comment[pt]=Foi obtida uma cópia pedida
-Comment[pt_BR]=Uma capa solicitada foi baixada
-Comment[ro]=O copertă cerută a fost descărcată
-Comment[ru]=Запрошенная обложка была загружена
-Comment[sk]=Požadovaný obal bol stiahnutý
-Comment[sl]=Zahtevan ovitek je bil prejet
-Comment[sr]=Затражени омот је преузет
-Comment[sr@ijekavian]=Затражени омот је преузет
-Comment[sr@ijekavianlatin]=Zatraženi omot je preuzet
-Comment[sr@latin]=Zatraženi omot je preuzet
-Comment[sv]=Ett begärt omslag har laddats ner
-Comment[tr]=İstenilen kapak indirildi
-Comment[ug]=ئىلتىماس قىلىنغان مۇقاۋا چۈشۈرۈلدى
-Comment[uk]=Потрібну обкладинку було звантажено
-Comment[x-test]=xxA requested cover has been downloadedxx
-Comment[zh_CN]=已下载请求的封面
-Comment[zh_TW]=要求的封面已下載
-Action=Popup
-
-[Event/coverFailed]
-Name=Cover Failed to Download
-Name[bg]=Грешка при изтегляне на обложката
-Name[bs]=Omot se ne može preuzeti
-Name[ca]=Ha fallat la baixada de la caràtula
-Name[ca@valencia]=Ha fallat la baixada de la caràtula
-Name[cs]=Obal nelze stáhnout
-Name[da]=Download af omslag mislykkedes
-Name[de]=Herunterladen des Titelbildes fehlgeschlagen
-Name[el]=Αποτυχία λήψης εξωφύλλου
-Name[en_GB]=Cover Failed to Download
-Name[es]=La descarga de la carátula ha fallado
-Name[et]=Kaanepildi allalaadimine nurjus
-Name[fi]=Kansikuvan lataus epäonnistui
-Name[fr]=Impossible de télécharger la jaquette
-Name[ga]=Theip ar Íosluchtú Clúdaigh
-Name[gl]=Produciuse un erro ao descargar a portada do disco
-Name[hu]=A borító letöltése sikertelen
-Name[ia]=Il falleva discargar copertura
-Name[is]=Niðurhal umslags mistókst
-Name[it]=Lo scaricamento della copertina non è riuscito
-Name[ja]=カバーのダウンロードに失敗
-Name[kk]=Мұқабасын жүктеу жаңылысы
-Name[km]=បានបរាជ័យក្នុងការទាញយកគម្រប
-Name[ko]=커버 다운로드 실패
-Name[lt]=Nepavyko atsiųsti viršelio
-Name[mr]=कव्हर डाउनलोड अयशस्वी झाले
-Name[nb]=Klarte ikke å laste ned omslaget
-Name[nds]=Titelbild lett sik nich daalladen
-Name[nl]=Downloaden van hoes is mislukt
-Name[nn]=Klarte ikkje lasta ned omslag
-Name[pa]=ਕਵਰ ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਫੇਲ੍ਹ
-Name[pl]=Nieudane pobranie okładki
-Name[pt]=Não Foi Possível Obter a Capa
-Name[pt_BR]=Falha ao baixar a capa
-Name[ro]=Descărcarea coperții a eșuat
-Name[ru]=Не удалось загрузить обложку
-Name[sk]=Obal sa nepodarilo stiahnuť
-Name[sl]=Prejem ovitka ni uspel
-Name[sr]=Омот се не може преузети
-Name[sr@ijekavian]=Омот се не може преузети
-Name[sr@ijekavianlatin]=Omot se ne može preuzeti
-Name[sr@latin]=Omot se ne može preuzeti
-Name[sv]=Nerladdning av omslag misslyckades
-Name[tr]=Kapak İndirilemedi
-Name[ug]=مۇقاۋىنى چۈشۈرەلمىدى
-Name[uk]=Невдала спроба звантаження обкладинки
-Name[x-test]=xxCover Failed to Downloadxx
-Name[zh_CN]=下载封面失败
-Name[zh_TW]=下載封面失敗
-Comment=A requested cover has failed to download
-Comment[bg]=Грешка при изтегляне на поисканата обложка
-Comment[bs]=Preuzimanje zatraženog omota nije uspjelo
-Comment[ca]=Una sol·licitud de baixada de caràtula ha fallat
-Comment[ca@valencia]=Una sol·licitud de baixada de caràtula ha fallat
-Comment[cs]=Vyžádaný obal nelze stáhnout
-Comment[da]=Download af et ønsket omslag mislykkedes
-Comment[de]=Ein angefordertes Titelbild kann nicht heruntergeladen werden
-Comment[el]=Απέτυχε η λήψη του εξωφύλλου που ζητήθηκε
-Comment[en_GB]=A requested cover has failed to download
-Comment[es]=Ha fallado la descarga de una carátula solicitada
-Comment[et]=Soovitud kaanepildi allalaadimine nurjus
-Comment[fi]=Pyydetyn kansikuvan lataus epäonnistui
-Comment[fr]=Une jaquette demandée n'a pas pu être téléchargée
-Comment[ga]=Níorbh fhéidir clúdach iarrtha a íosluchtú
-Comment[gl]=Produciuse un erro ao descargar a portada de disco solicitada
-Comment[hu]=Nem sikerült letölteni a kért borítót
-Comment[ia]=Il falleva discargar un copertura requirite
-Comment[is]=Ekki tókst að ná í umslagið sem beðið var um
-Comment[it]=Lo scaricamento di una copertina richiesta non è riuscito
-Comment[ja]=要求されたカバーをダウンロードできませんでした
-Comment[kk]=Сұралған мұқабасы жүктеп алынбады
-Comment[km]=គម្របដែលបានស្នើបានបរាជ័យក្នុងការទាញយក
-Comment[ko]=요청한 커버를 다운로드할 수 없음
-Comment[lt]=Nepavyko atsiųsti prašyto viršelio
-Comment[mr]=विनंती केलेले कव्हर डाउनलोड अयशस्वी झाले
-Comment[nb]=Et ønsket omslag kunne ikke lastes ned
-Comment[nds]=En anfraagt Titelbild lett sik nich daalladen
-Comment[nl]=Downloaden van een gevraagde hoes is mislukt
-Comment[nn]=Klarte ikkje lasta ned det førespurde omslaget
-Comment[pa]=ਮੰਗੇ ਗਏ ਕਵਰ ਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਫੇਲ੍ਹ
-Comment[pl]=Nieudane pobranie żądanej okładki
-Comment[pt]=Não foi possível obter uma dada capa
-Comment[pt_BR]=Falha ao baixar uma capa solicitada
-Comment[ro]=Descărcarea unei coperți cerute a eșuat
-Comment[ru]=Не удалось загрузить запрошенную обложку
-Comment[sk]=Požadovaný obal sa nepodarilo stiahnuť
-Comment[sl]=Zahtevan ovitek ni bil uspešno prejet
-Comment[sr]=Преузимање затраженог омота није успело
-Comment[sr@ijekavian]=Преузимање затраженог омота није успјело
-Comment[sr@ijekavianlatin]=Preuzimanje zatraženog omota nije uspjelo
-Comment[sr@latin]=Preuzimanje zatraženog omota nije uspelo
-Comment[sv]=Nerladdning av ett begärt omslag har misslyckats
-Comment[tr]=İstenilen kapak indirilemedi
-Comment[ug]=ئىلتىماس قىلىنغان مۇقاۋىنى چۈشۈرەلمىدى
-Comment[uk]=Потрібну обкладинку не вдалося звантажити
-Comment[x-test]=xxA requested cover has failed to downloadxx
-Comment[zh_CN]=请求的封面下载失败
-Comment[zh_TW]=要求的封面無法成功下載
-Action=Popup
-
-[Event/dock_mode]
-Name=JuK running in dock mode
-Name[bs]=JuK radi u sidrišnom režimu
-Name[ca]=El JuK s'està executant en el mode acoblat
-Name[ca@valencia]=El JuK s'està executant en el mode acoblat
-Name[cs]=JuK běží v dokovaném režimu
-Name[da]=JuK kører i doktilstand
-Name[de]=JuK läuft im Systemabschnitt der Kontrollleiste
-Name[el]=Το JuK εκτελείται σε λειτουργία προσάρτησης
-Name[en_GB]=JuK running in dock mode
-Name[es]=Juk se ejecuta en modo anclado
-Name[et]=JuK töötab dokirežiimis
-Name[fi]=JuK on pienennettynä ilmoitusalueelle
-Name[fr]=JuK fonctionne en mode intégré
-Name[gl]=JuK está no modo acoplado
-Name[hu]=A JuK dokkolt módban fut
-Name[ia]=Juck executante de modo dock
-Name[it]=JuK in esecuzione nel vassoio di sistema
-Name[kk]=JuK бүктелген күйде жегілген
-Name[ko]=도킹 모드에서 JuK 실행 중
-Name[nb]=JuK kjører i dokket modus
-Name[nds]=JuK löppt binnen Systeemafsnitt
-Name[nl]=JuK actief in verankerde modus
-Name[pl]=JuK uruchomiono w trybie dokowania
-Name[pt]=JuK em execução no modo acoplado
-Name[pt_BR]=JuK em execução no modo acoplado
-Name[ru]=JuK свёрнут в панели задач
-Name[sk]=JuK beží v dokovanom režime
-Name[sl]=Juk je v zasidranem načinu
-Name[sr]=Џук ради у сидришном режиму
-Name[sr@ijekavian]=Џук ради у сидришном режиму
-Name[sr@ijekavianlatin]=Juk radi u sidrišnom režimu
-Name[sr@latin]=Juk radi u sidrišnom režimu
-Name[sv]=JuK kör i dockningsläge
-Name[tr]=JuK yerleşik kipte çalışıyor
-Name[uk]=JuK запущено у згорнутому режимі
-Name[x-test]=xxJuK running in dock modexx
-Name[zh_TW]=JuK 以嵌入模式執行中
-Comment=Use context menu in system tray to restore.
-Comment[bs]=Koristite kontekstsni meni u sistemskom uglu za obnovu
-Comment[ca]=Useu el menú contextual en la safata del sistema per restaurar.
-Comment[ca@valencia]=Useu el menú contextual en la safata del sistema per restaurar.
-Comment[cs]=Pro návrat použijte kontextovou nabídky v systémové liště.
-Comment[da]=Brug kontekstmenuen i statusområdet til at gendanne.
-Comment[de]=Kontextmenü im Systemabschnitt der Kontrollleiste zum Wiederherstellen verwenden
-Comment[el]=Χρησιμοποιήστε το βοηθητικό μενού στο πλαίσιο συστήματος για επαναφορά.
-Comment[en_GB]=Use context menu in system tray to restore.
-Comment[es]=Use el menú de contexto de la bandeja del sistema para restaurar.
-Comment[et]=Taastamiseks kasuta süsteemisalve kontekstimenüüd.
-Comment[fi]=Palauta käyttämällä ilmoitusalueen kontekstivalikkoa.
-Comment[fr]=utilisez le menu contextuel de la boîte à miniatures pour le restaurer.
-Comment[gl]=Use o menú contextual na bandexa do sistema para restauralo.
-Comment[hu]=Helyi menü használata a rendszertálcán a visszaállításhoz.
-Comment[ia]=Usa menu de contexto in tabuliero de systema pro restabilir.
-Comment[it]=Usa il menu contestuale nel vassoio di sistema per ripristinare.
-Comment[kk]=Қалпына келтіруге жүйелік сөре контекстті мәзірін пайдаланыңыз.
-Comment[ko]=시스템 트레이의 컨텍스트 메뉴를 사용하여 복원하십시오.
-Comment[nb]=Bruk kontekstmenyen i systemkurven for å tilbakestille.
-Comment[nds]=Du kannst dat över't Kontextmenü binnen den Systeemafsnitt wedderherstellen.
-Comment[nl]=Contextmenu in systeemvak gebruiken voor herstellen.
-Comment[pl]=Użyj menu podręcznego na tacce systemowej, aby go przywrócić.
-Comment[pt]=Use o menu de contexto da bandeja para repor.
-Comment[pt_BR]=Use o menu de contexto da área de notificação para restaurar.
-Comment[ru]=Чтобы восстановить его, воспользуйтесь контекстным меню.
-Comment[sk]=Použite kontextovú ponuku v systémovej lište na obnovenie.
-Comment[sl]=Uporabite vsebinski meni v sistemski vrstici za obnovitev.
-Comment[sr]=Употребите контекстни мени у системској касети за обнављање.
-Comment[sr@ijekavian]=Употребите контекстни мени у системској касети за обнављање.
-Comment[sr@ijekavianlatin]=Upotrebite kontekstni meni u sistemskoj kaseti za obnavljanje.
-Comment[sr@latin]=Upotrebite kontekstni meni u sistemskoj kaseti za obnavljanje.
-Comment[sv]=Använd sammanhangsberoende meny i systembrickan för att återställa.
-Comment[tr]=Geri yüklemek için sistem çekmecesindeki bağlam menüsünü kullanın.
-Comment[uk]=Скористайтеся контекстним меню піктограми системного лотка, щоб розгорнути вікно програми.
-Comment[x-test]=xxUse context menu in system tray to restore.xx
-Comment[zh_TW]=用系統匣的內文選單來回復。
-Action=Popup
+++ /dev/null
-/**
- * Copyright (C) 2003 Antonia Larrosa <larrosa@kde.org>
- * Copyright (C) 2003-2006 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2004-2006 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Definition of the DCOP interface for JuK.
- * TODO: Port to DBUS.
- */
-
-#ifndef JUKIFACE_H
-#define JUKIFACE_H
-
-#include <dcopobject.h>
-#include <qstringlist.h>
-#include <qpixmap.h>
-
-class CollectionIface : public DCOPObject
-{
- K_DCOP
-k_dcop:
- void openFile(const QString &file) { open(QStringList(file)); }
- void openFile(const QStringList &files) { open(files); }
- void openFile(const QString &playlist, const QString &file) { open(playlist, QStringList(file)); }
- void openFile(const QString &playlist, const QStringList &files) { open(playlist, files); }
-
- virtual QStringList playlists() const = 0;
- virtual void createPlaylist(const QString &) = 0;
- virtual void remove() = 0;
-
- virtual void removeTrack(const QString &playlist, const QString &file) { removeTrack(playlist, QStringList(file)); }
- virtual void removeTrack(const QString &playlist, const QStringList &files) = 0;
-
- virtual QString playlist() const = 0;
- virtual QString playingPlaylist() const = 0;
- virtual void setPlaylist(const QString &playlist) = 0;
-
- virtual QStringList playlistTracks(const QString &playlist) const = 0;
- virtual QString trackProperty(const QString &file, const QString &property) const = 0;
-
- virtual QPixmap trackCover(const QString &file, const QString &size = "Small") const = 0;
-
-protected:
- CollectionIface() : DCOPObject("Collection") {}
- virtual void open(const QStringList &files) = 0;
- virtual void open(const QString &playlist, const QStringList &files) = 0;
-};
-
-class PlayerIface : public DCOPObject
-{
- K_DCOP
-k_dcop:
- virtual bool playing() const = 0;
- virtual bool paused() const = 0;
- virtual float volume() const = 0;
- virtual int status() const = 0;
-
- virtual QStringList trackProperties() = 0;
- virtual QString trackProperty(const QString &property) const = 0;
- virtual QPixmap trackCover(const QString &size = "Small") const = 0;
-
- virtual QString currentFile() const
- {
- return trackProperty("Path");
- }
-
- virtual void play() = 0;
- virtual void play(const QString &file) = 0;
- virtual void pause() = 0;
- virtual void stop() = 0;
- virtual void playPause() = 0;
-
- virtual void back() = 0;
- virtual void forward() = 0;
- virtual void seekBack() = 0;
- virtual void seekForward() = 0;
-
- virtual void volumeUp() = 0;
- virtual void volumeDown() = 0;
- virtual void mute() = 0;
- virtual void setVolume(float volume) = 0;
- virtual void seek(int time) = 0;
-
- virtual QString playingString() const = 0;
- virtual int currentTime() const = 0;
- virtual int totalTime() const = 0;
-
- /**
- * @return The current player mode.
- * @see setRandomPlayMode()
- */
- virtual QString randomPlayMode() const = 0;
-
- /**
- * Sets the player mode to one of normal, random play, or album
- * random play, depending on @p randomMode.
- * "NoRandom" -> Normal
- * "Random" -> Random
- * "AlbumRandom" -> Album Random
- */
- virtual void setRandomPlayMode(const QString &randomMode) = 0;
-
-protected:
- PlayerIface() : DCOPObject("Player") {}
-};
-
-class SearchIface : public DCOPObject
-{
- K_DCOP
-k_dcop:
- virtual QString searchText() const = 0;
- virtual void setSearchText(const QString &text) = 0;
-
-protected:
- SearchIface() : DCOPObject("Search") {}
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-[Desktop Entry]
-ServiceTypes=KonqPopupMenu/Plugin,application/ogg,audio/x-vorbis+ogg,audio/mpeg,audio/x-flac,audio/x-flac+ogg,audio/x-musepack
-Type=Service
-Actions=addToCollection;
-
-[Desktop Action addToCollection]
-Name=Add to JuK Collection
-Name[bg]=Добавяне към колекцията на Juk
-Name[bs]=Dodaj u JuKovu zbirku
-Name[ca]=Afegeix a la col·lecció del JuK
-Name[ca@valencia]=Afig a la col·lecció del JuK
-Name[cs]=Přidat do sbírky JuK
-Name[da]=Tilføj til JuK-samling
-Name[de]=Zur JuK-Sammlung hinzufügen
-Name[el]=Προσθήκη στη συλλογή του JuK
-Name[en_GB]=Add to JuK Collection
-Name[es]=Añadir a la colección de JuK
-Name[et]=Lisamine JuKi kogusse
-Name[fi]=Lisää JuKin kokoelmalistaan
-Name[fr]=Ajouter à la collection de JuK
-Name[ga]=Cuir le bailiúchán JuK
-Name[gl]=Engadir á colección de JuK
-Name[hu]=Hozzáadás a JuK gyűjteményhez
-Name[ia]=Adde a collection de JuK
-Name[is]=Bæta við JuK safnið
-Name[it]=Aggiungi alla collezione di JuK
-Name[ja]=JuK コレクションに追加
-Name[kk]=JuK жинағына қосу
-Name[km]=បន្ថែមទៅសម្រាំងរបស់ JuK
-Name[ko]=JuK 모음집에 추가
-Name[lt]=Pridėti prie JuK kolekcijos
-Name[mr]=ज्युक संग्रहात जोडा
-Name[nb]=Legg til JuK-samling
-Name[nds]=Na de JuK-Sammeln tofögen
-Name[nl]=Toevoegen aan JuK-collectie
-Name[nn]=Legg til JuK-samlinga
-Name[pa]=ਜੂਕ ਭੰਡਾਰ 'ਚ ਸ਼ਾਮਲ
-Name[pl]=Dodaj do zbioru JuK
-Name[pt]=Adicionar à Colecção do JuK
-Name[pt_BR]=Adicionar à coleção do JuK
-Name[ro]=Adaugă la colecția JuK
-Name[ru]=Добавить в коллекцию JuK
-Name[sk]=Pridať do kolekcie JuK
-Name[sl]=Dodaj v zbirko JuK
-Name[sr]=Додај у Џукову збирку
-Name[sr@ijekavian]=Додај у Џукову збирку
-Name[sr@ijekavianlatin]=Dodaj u Jukovu zbirku
-Name[sr@latin]=Dodaj u Jukovu zbirku
-Name[sv]=Lägg till i Juk-samlingslista
-Name[tr]=JuK Koleksiyonuna Ekle
-Name[ug]=JuK توپلىمىغا قوش
-Name[uk]=Додати до збірки JuK
-Name[x-test]=xxAdd to JuK Collectionxx
-Name[zh_CN]=添加到 Juk 收藏
-Name[zh_TW]=新增到 JuK 收藏清單
-Icon=juk
-Exec=qdbus org.kde.juk /Collection org.kde.juk.collection.openFile %f
+++ /dev/null
-<!DOCTYPE kpartgui>
-<kpartgui name="juk" version="12">
-<MenuBar>
- <Menu name="file" noMerge="1"><text>&File</text>
- <Action name="file_new"/>
- <Action name="file_open"/>
- <Action name="openDirectory"/>
-
- <Separator/>
-
- <Action name="renamePlaylist"/>
- <Action name="editSearch"/>
- <Action name="duplicatePlaylist"/>
- <Action name="reloadPlaylist"/>
- <Action name="deleteItemPlaylist"/>
-
- <Separator/>
-
- <Action name="file_save"/>
- <Action name="file_save_as"/>
-
- <Separator/>
-
- <Action name="file_quit"/>
- </Menu>
- <Menu name="view" noMerge="1"><text>&View</text>
- <Action name="showSearch"/>
- <Action name="showEditor"/>
- <Action name="showLyrics"/>
- <Action name="showHistory"/>
- <Action name="showUpcoming"/>
- <Action name="showColumns"/>
- <Action name="resizeColumnsManually"/>
-
- <Separator/>
-
- <Action name="viewModeMenu"/>
- </Menu>
- <Menu name="player"><text>&Player</text>
- <Action name="actionMenu"/>
-
- <Action name="loopPlaylist"/>
- <Action name="crossfadeTracks"/>
-
- <Separator/>
-
- <Action name="play"/>
- <Action name="pause"/>
- <Action name="stop"/>
- <Action name="forward"/>
- <Action name="back"/>
-
- <Separator/>
-
- <Action name="forwardAlbum"/>
- </Menu>
- <Menu name="playlist"><text>&Tagger</text>
- <Action name="saveItem"/>
- <Action name="removeItem"/>
- <Action name="refresh"/>
-
- <Separator/>
-
- <Action name="guessTag"/>
- <Action name="coverManager"/>
- <Action name="renameFile"/>
- </Menu>
- <Menu name="settings"><text>&Settings</text>
- <Action name="showSplashScreen" append="show_merge"/>
- <Action name="toggleSystemTray" append="show_merge"/>
- <Action name="dockOnClose" append="show_merge"/>
- <Action name="togglePopups" append="show_merge"/>
- <!-- <Action name="saveUpcomingTracks" append="show_merge"/> -->
- <Action name="tagGuesserConfig" append="save_merge"/>
- <Action name="fileRenamerConfig" append="save_merge"/>
- <Action name="scrobblerConfig" append="save_merge"/>
- <Action name="outputSelect" append="save_merge"/>
- </Menu>
-</MenuBar>
-
-<ToolBar name="mainToolBar" hidden="true" noMerge="1"><text>Main Toolbar</text>
- <Action name="file_new"/>
- <Action name="file_open"/>
- <Action name="file_save"/>
-
- <Separator lineSeparator="true"/>
-
- <Action name="edit_cut"/>
- <Action name="edit_copy"/>
- <Action name="edit_paste"/>
-
- <Separator lineSeparator="true"/>
-
- <Action name="showSearch"/>
- <Action name="showEditor"/>
- <Action name="showNowPlaying"/>
-</ToolBar>
-
-<ToolBar name="playToolBar" noMerge="1"><text>Play Toolbar</text>
-
- <Action name="volumeAction"/>
- <Action name="trackPositionAction"/>
- <Action name="forward"/>
- <Action name="back"/>
- <Separator lineSeparator="false"/>
-
-
- <Action name="stop"/>
- <Action name="pause"/>
- <Action name="play"/>
-
-</ToolBar>
-</kpartgui>
+++ /dev/null
-<!-- PLEASE UPDATE jukui-rtl.rc WHEN UPDATING THIS FILE -->
-
-<!DOCTYPE kpartgui>
-<kpartgui name="juk" version="12">
-<MenuBar>
- <Menu name="file" noMerge="1"><text>&File</text>
- <Action name="file_new"/>
- <Action name="file_open"/>
- <Action name="openDirectory"/>
-
- <Separator/>
-
- <Action name="renamePlaylist"/>
- <Action name="editSearch"/>
- <Action name="duplicatePlaylist"/>
- <Action name="reloadPlaylist"/>
- <Action name="deleteItemPlaylist"/>
-
- <Separator/>
-
- <Action name="file_save"/>
- <Action name="file_save_as"/>
-
- <Separator/>
-
- <Action name="file_quit"/>
- </Menu>
- <Menu name="view" noMerge="1"><text>&View</text>
- <Action name="showSearch"/>
- <Action name="showEditor"/>
- <Action name="showLyrics"/>
- <Action name="showHistory"/>
- <Action name="showUpcoming"/>
- <Action name="showColumns"/>
- <Action name="resizeColumnsManually"/>
-
- <Separator/>
-
- <Action name="viewModeMenu"/>
- </Menu>
- <Menu name="player"><text>&Player</text>
- <Action name="actionMenu"/>
-
- <Action name="loopPlaylist"/>
- <Action name="crossfadeTracks"/>
-
- <Separator/>
-
- <Action name="play"/>
- <Action name="pause"/>
- <Action name="stop"/>
- <Action name="forward"/>
- <Action name="back"/>
-
- <Separator/>
-
- <Action name="forwardAlbum"/>
- </Menu>
- <Menu name="playlist"><text>&Tagger</text>
- <Action name="saveItem"/>
- <Action name="removeItem"/>
- <Action name="refresh"/>
-
- <Separator/>
-
- <Action name="guessTag"/>
- <Action name="coverManager"/>
- <Action name="renameFile"/>
- </Menu>
- <Menu name="settings"><text>&Settings</text>
- <Action name="showSplashScreen" append="show_merge"/>
- <Action name="toggleSystemTray" append="show_merge"/>
- <Action name="dockOnClose" append="show_merge"/>
- <Action name="togglePopups" append="show_merge"/>
- <!-- <Action name="saveUpcomingTracks" append="show_merge"/> -->
- <Action name="tagGuesserConfig" append="save_merge"/>
- <Action name="fileRenamerConfig" append="save_merge"/>
- <Action name="scrobblerConfig" append="save_merge"/>
- <Action name="outputSelect" append="save_merge"/>
- </Menu>
-</MenuBar>
-
-<ToolBar name="mainToolBar" hidden="true" noMerge="1"><text>Main Toolbar</text>
- <Action name="file_new"/>
- <Action name="file_open"/>
- <Action name="file_save"/>
-
- <Separator lineSeparator="true"/>
-
- <Action name="edit_cut"/>
- <Action name="edit_copy"/>
- <Action name="edit_paste"/>
-
- <Separator lineSeparator="true"/>
-
- <Action name="showSearch"/>
- <Action name="showEditor"/>
- <Action name="showNowPlaying"/>
-</ToolBar>
-
-<ToolBar name="playToolBar" noMerge="1"><text>Play Toolbar</text>
- <Action name="play"/>
- <Action name="pause"/>
- <Action name="stop"/>
-
- <Separator lineSeparator="false"/>
-
- <Action name="back"/>
- <Action name="forward"/>
- <Action name="trackPositionAction"/>
- <Action name="volumeAction"/>
-</ToolBar>
-</kpartgui>
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "k3bexporter.h"
-
-#include <kprocess.h>
-#include <kmessagebox.h>
-#include <kurl.h>
-#include <klocale.h>
-#include <kaction.h>
-#include <kactioncollection.h>
-#include <kstandarddirs.h>
-#include <kicon.h>
-#include <kiconloader.h>
-#include <kapplication.h>
-
-#include <QMap>
-
-#include "playlistitem.h"
-#include "playlist.h"
-#include "playlistbox.h"
-#include "actioncollection.h"
-
-using ActionCollection::actions;
-
-// static member variable definition
-
-PlaylistAction *K3bExporter::m_action = 0;
-
-// Special KAction subclass used to automatically call a slot when activated,
-// depending on the visible playlist at the time. In other words, use *one*
-// instance of this action for many playlists.
-//
-// This is used to handle some actions in the Playlist context menu.
-
-PlaylistAction::PlaylistAction(const QString &userText,
- const QIcon &pix,
- const char *slot,
- const KShortcut &cut) :
- KAction(userText, actions()),
- m_slot(slot)
-{
- setShortcut(cut);
- QAction::setIcon(pix);
- connect(this, SIGNAL(triggered()), this, SLOT(slotActivated()));
-}
-
-/**
- * Defines a QObject to call (using the m_slot SLOT) when an action is
- * emitted from a Playlist.
- */
-void PlaylistAction::addCallMapping(const Playlist *p, QObject *obj)
-{
- m_playlistRecipient[p] = obj;
-}
-
-void PlaylistAction::slotActivated()
-{
- // Determine current playlist, and call its slot.
- Playlist *p = PlaylistCollection::instance()->visiblePlaylist();
- if(!p)
- return;
- // Make sure we're supposed to notify someone about this playlist.
- QObject *recipient = m_playlistRecipient[p];
- if(!recipient)
- return;
- // Invoke the slot using some trickery.
- recipient->metaObject()->invokeMethod(recipient, m_slot);
-}
-
-K3bExporter::K3bExporter(Playlist *parent) : PlaylistExporter(parent), m_parent(parent)
-{
-}
-
-KAction *K3bExporter::action()
-{
- if(!m_action && !KStandardDirs::findExe("k3b").isNull()) {
- m_action = new PlaylistAction(
- i18n("Add Selected Items to Audio or Data CD"),
- KIcon( QLatin1String( "k3b" )),
- "slotExport"
- );
- m_action->setShortcutConfigurable(false);
- }
- // Tell the action to let us know when it is activated when
- // m_parent is the visible playlist. This allows us to reuse the
- // action to avoid duplicate entries in KActionCollection.
- if(m_action)
- m_action->addCallMapping(m_parent, this);
- return m_action;
-}
-
-void K3bExporter::exportPlaylistItems(const PlaylistItemList &items)
-{
- if(items.empty())
- return;
- exportViaCmdLine(items);
-}
-
-void K3bExporter::slotExport()
-{
- if(m_parent)
- exportPlaylistItems(m_parent->selectedItems());
-}
-
-void K3bExporter::exportViaCmdLine(const PlaylistItemList &items)
-{
- K3bOpenMode mode = openMode();
- QByteArray cmdOption;
-
- switch(mode) {
- case AudioCD:
- cmdOption = "--audiocd";
- break;
-
- case DataCD:
- cmdOption = "--data";
- break;
-
- case Abort:
- return;
- }
-
- KProcess process;
-
- process << "k3b";
- process << cmdOption;
-
- PlaylistItemList::ConstIterator it;
- for(it = items.begin(); it != items.end(); ++it)
- process << (*it)->file().absFilePath();
-
- if(!process.startDetached())
- KMessageBox::error(m_parent, i18n("Unable to start K3b."));
-}
-
-K3bExporter::K3bOpenMode K3bExporter::openMode()
-{
- int reply = KMessageBox::questionYesNoCancel(
- m_parent,
- i18n("Create an audio mode CD suitable for CD players, or a data "
- "mode CD suitable for computers and other digital music "
- "players?"),
- i18n("Create K3b Project"),
- KGuiItem(i18n("Audio Mode")),
- KGuiItem(i18n("Data Mode"))
- );
-
- switch(reply) {
- case KMessageBox::Cancel:
- return Abort;
-
- case KMessageBox::No:
- return DataCD;
-
- case KMessageBox::Yes:
- return AudioCD;
- }
-
- return Abort;
-}
-
-K3bPlaylistExporter::K3bPlaylistExporter(PlaylistBox *parent) : K3bExporter(0),
- m_playlistBox(parent)
-{
-}
-
-KAction *K3bPlaylistExporter::action()
-{
- if(!KStandardDirs::findExe("k3b").isNull()) {
- KAction *action = new KAction(KIcon( QLatin1String( "k3b" )),
- i18n("Add Playlist to Audio or Data CD"),
- actions()
- );
- connect(action, SIGNAL(triggered(bool)), SLOT(slotExport()));
- return action;
- }
-
- return 0;
-}
-
-void K3bPlaylistExporter::slotExport()
-{
- if(m_playlistBox) {
- setPlaylist(m_playlistBox->visiblePlaylist());
- exportPlaylistItems(m_playlistBox->visiblePlaylist()->items());
- }
-}
-
-#include "k3bexporter.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef K3BEXPORTER_H
-#define K3BEXPORTER_H
-
-#include <kaction.h>
-
-#include "playlistexporter.h"
-#include "playlistitem.h"
-
-class PlaylistBox;
-
-class PlaylistAction : public KAction
-{
- Q_OBJECT
-
-public:
- PlaylistAction(const QString &userText, const QIcon &pix, const char *slot, const KShortcut &cut = KShortcut());
-
- typedef QMap<const Playlist *, QObject *> PlaylistRecipientMap;
-
- /**
- * Defines a QObject to call (using the m_slot SLOT) when an action is
- * emitted from a Playlist.
- */
- void addCallMapping(const Playlist *p, QObject *obj);
-
- protected slots:
- void slotActivated();
-
- private:
- QByteArray m_slot;
- PlaylistRecipientMap m_playlistRecipient;
-};
-
-/**
- * Class that will export the selected items of a playlist to K3b.
- */
-class K3bExporter : public PlaylistExporter
-{
- Q_OBJECT
-
-public:
- K3bExporter(Playlist *parent = 0);
-
- /**
- * Returns a KAction that can be used to invoke the export.
- *
- * @return action used to start the export.
- */
- virtual KAction *action();
-
- Playlist *playlist() const { return m_parent; }
- void setPlaylist(Playlist *playlist) { m_parent = playlist; }
-
-protected:
- void exportPlaylistItems(const PlaylistItemList &items);
-
-private slots:
- void slotExport();
-
-private:
- enum K3bOpenMode { AudioCD, DataCD, Abort };
-
- // Private method declarations
- void exportViaCmdLine(const PlaylistItemList &items);
- K3bOpenMode openMode();
-
- // Private member variable declarations
- Playlist *m_parent;
-
- // Static member used to avoid adding more than one action to KDE's
- // action list.
- static PlaylistAction *m_action;
-};
-
-/**
- * Class to export EVERY item in a playlist to K3b. Used with the PlaylistBox
- * class to implement context-menus there.
- *
- * @see PlaylistBox
- */
-class K3bPlaylistExporter : public K3bExporter
-{
- Q_OBJECT
-public:
- K3bPlaylistExporter(PlaylistBox *parent = 0);
-
- virtual KAction *action();
-
-private slots:
- void slotExport();
-
-private:
- PlaylistBox *m_playlistBox;
-};
-
-#endif /* K3BEXPORTER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Stefan Asserhall <stefan.asserhall@telia.com>
- * Copyright (C) 2007, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "keydialog.h"
-#include "actioncollection.h"
-
-#include <kconfig.h>
-#include <klocale.h>
-#include <kshortcutseditor.h>
-#include <kglobal.h>
-#include <kaction.h>
-#include <kvbox.h>
-#include <kconfiggroup.h>
-#include <KShortcut>
-
-#include <QHBoxLayout>
-#include <QTimer>
-#include <QButtonGroup>
-#include <QRadioButton>
-#include <QGroupBox>
-#include <QString>
-
-// Table of shortcut keys for each action, key group and three or four button modifier
-
-struct KeyDialog::KeyInfo {
- QString action;
- KShortcut shortcut[3];
-};
-
-const KeyDialog::KeyInfo KeyDialog::keyInfo[] = {
- { "playPause",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_P),
- KShortcut(Qt::Key_MediaPlay) } },
- { "stop",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_S),
- KShortcut(Qt::Key_MediaStop) } },
- { "back",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_Left),
- KShortcut(Qt::Key_MediaPrevious) } },
- { "forward",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_Right),
- KShortcut(Qt::Key_MediaNext) } },
- { "forwardAlbum",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_Up),
- KShortcut(Qt::CTRL+Qt::Key_MediaNext) } },
- { "seekBack",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::SHIFT+Qt::ALT+Qt::Key_Left),
- KShortcut(Qt::SHIFT+Qt::Key_MediaPrevious) } },
- { "seekForward",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::SHIFT+Qt::ALT+Qt::Key_Right),
- KShortcut(Qt::SHIFT+Qt::Key_MediaNext) } },
- { "volumeUp",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::SHIFT+Qt::Key_Up),
- KShortcut(Qt::Key_VolumeUp) } },
- { "volumeDown",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::SHIFT+Qt::Key_Down),
- KShortcut(Qt::Key_VolumeDown) } },
- { "mute",
- { KShortcut(),
- KShortcut(Qt::CTRL+Qt::ALT+Qt::Key_M),
- KShortcut(Qt::Key_VolumeMute) } },
- { "showHide",
- { KShortcut(),
- KShortcut(),
- KShortcut() } }
-};
-
-const uint KeyDialog::keyInfoCount = sizeof(KeyDialog::keyInfo) / sizeof(KeyDialog::keyInfo[0]);
-
-KeyDialog::KeyDialog(KActionCollection *actionCollection, QWidget *parent)
- : KDialog(parent), m_actionCollection(actionCollection)
-{
- setCaption(i18n("Configure Shortcuts"));
- setButtons(Default | Ok | Cancel);
-
- // Read key group from configuration
-
- KConfigGroup config(KGlobal::config(), "Shortcuts");
- int selectedButton = config.readEntry("GlobalKeys", int(StandardKeys));
-
- // Create widgets for key chooser
-
- KVBox *vbox = new KVBox(this);
- vbox->setSpacing(KDialog::spacingHint());
-
- m_pKeyChooser = new KShortcutsEditor(actionCollection, vbox);
-
- // Create buttons to select key group
-
- QGroupBox *buttonBox = new QGroupBox(i18n("Global Shortcuts"), vbox);
- m_group = new QButtonGroup(buttonBox);
- QHBoxLayout *buttonLayout = new QHBoxLayout;
- buttonBox->setLayout(buttonLayout);
-
- QRadioButton *radioButton = new QRadioButton(i18n("&No keys"), buttonBox);
- m_group->addButton(radioButton, NoKeys);
- buttonLayout->addWidget(radioButton);
-
- radioButton = new QRadioButton(i18n("&Standard keys"), buttonBox);
- m_group->addButton(radioButton, StandardKeys);
- buttonLayout->addWidget(radioButton);
-
- radioButton = new QRadioButton(i18n("&Multimedia keys"), buttonBox);
- m_group->addButton(radioButton, MultimediaKeys);
- buttonLayout->addWidget(radioButton);
-
- connect(m_group, SIGNAL(buttonClicked(int)), this, SLOT(slotKeys(int)));
- buttonBox->setWhatsThis(
- i18n("Here you can select the keys used as global shortcuts to control the player"));
-
- m_group->button(selectedButton)->setChecked(true);
- connect(this, SIGNAL(defaultClicked()), this, SLOT(slotDefault()));
-
- setMainWidget(vbox);
- resize(400, 500); // Make it bigger!
-}
-
-KeyDialog::~KeyDialog()
-{
-}
-
-int KeyDialog::configure()
-{
- // Show the dialog and save configuration if accepted
-
- int retcode = exec();
- if(retcode == Accepted) {
- KConfigGroup config(KGlobal::config(), "Shortcuts");
-
- config.writeEntry("GlobalKeys", m_group->checkedId());
- KGlobal::config()->sync();
-
- m_pKeyChooser->save();
- }
-
- return retcode;
-}
-
-void KeyDialog::slotKeys(int group)
-{
- // Set modifier keys according to key group and modifier keys
-
- for(uint i = 0; i < keyInfoCount; i++) {
- KAction *a = ActionCollection::action<KAction>(keyInfo[i].action);
-
- if(a) {
- KShortcut shortcut(keyInfo[i].shortcut[group]);
-
- a->setGlobalShortcut(shortcut, KAction::ActiveShortcut, KAction::NoAutoloading);
- }
- }
-
- // Update the key chooser widget.
- // TODO: When widget is fixed to note the update remove this bit so that
- // we don't drop user changes for no reason.
-
- m_pKeyChooser->clearCollections();
- m_pKeyChooser->addCollection(m_actionCollection);
-}
-
-void KeyDialog::slotDefault()
-{
- // Select default keys - standard key group
-
- m_group->button(StandardKeys)->setChecked(true);
- slotKeys(StandardKeys);
- m_pKeyChooser->allDefault();
-}
-
-int KeyDialog::configure(KActionCollection *actionCollection, QWidget *parent)
-{
- // Create and show dialog - update connections if accepted
-
- return KeyDialog(actionCollection, parent).configure();
-}
-
-void KeyDialog::setupActionShortcut(const QString &actionName)
-{
- // Find and insert a standard key
- KShortcut shortcut = KShortcut();
-
- // Find out what type is selected so we know what keys to setup.
- KConfigGroup config(KGlobal::config(), "Shortcuts");
- int selectedKeys = config.readEntry("GlobalKeys", int(StandardKeys));
-
- for(uint i = 0; i < keyInfoCount; i++) {
- if(keyInfo[i].action == actionName) {
- shortcut = keyInfo[i].shortcut[selectedKeys];
- break;
- }
- }
-
- if(shortcut.isEmpty())
- return; // We have no shortcut to set.
-
- KAction *a = ActionCollection::action<KAction>(actionName);
- if(a)
- a->setGlobalShortcut(shortcut);
-}
-
-#include "keydialog.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Stefan Asserhall <stefan.asserhall@telia.com>
- * Copyright (C) 2007, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef KEYDIALOG_H
-#define KEYDIALOG_H
-
-#include <KDialog>
-
-class QButtonGroup;
-
-class KActionCollection;
-class KShortcutsEditor;
-
-class KeyDialog : public KDialog
-{
- Q_OBJECT
-
-public:
- /**
- * Constructs a KeyDialog called @p name as a child of @p parent.
- */
- explicit KeyDialog(KActionCollection *actionCollection, QWidget *parent = 0);
-
- /**
- * Destructor. Deletes all resources used by a KeyDialog object.
- */
- virtual ~KeyDialog();
-
- /**
- * This is a member function, provided to allow inserting both global
- * accelerators and actions.
- */
- static int configure(KActionCollection *actionCollection, QWidget *parent = 0);
-
- /**
- * This is a member function, provided to create a global accelerator with
- * standard keys.
- */
- static void setupActionShortcut(const QString &actionName);
-
-private:
-
- /**
- * Groups of keys that can be selected in the dialog. If you add or remove
- * a group you must also adjust struct KeyInfo::shortcut to have enough
- * entries for all groups, and then adjust the keyInfo[] array.
- */
- enum KeyGroup { NoKeys = 0, StandardKeys = 1, MultimediaKeys = 2 };
-
- int configure();
-
-private slots:
- void slotKeys(int group);
- void slotDefault();
-
-private:
- KActionCollection *m_actionCollection;
- KShortcutsEditor *m_pKeyChooser;
- QButtonGroup *m_group;
-
- struct KeyInfo;
-
- static const KeyInfo keyInfo[];
- static const uint keyInfoCount;
-};
-
-#endif // KEYDIALOG_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
- */
-
-/**
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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 "ktrm.h"
-#include <config-juk.h>
-
-#if HAVE_TUNEPIMP > 0
-
-#include <kprotocolmanager.h>
-#include <kurl.h>
-#include <kdebug.h>
-#include <kio/job.h>
-
-#include <QCoreApplication>
-#include <QtAlgorithms>
-#include <QMutex>
-#include <QRegExp>
-#include <QFile>
-#include <QEvent>
-#include <QDomDocument>
-
-#if HAVE_TUNEPIMP >= 5
-#include <tunepimp-0.5/tp_c.h>
-#else
-#include <tunepimp/tp_c.h>
-#endif
-#ifdef Q_WS_X11
-#include <fixx11h.h>
-#endif
-
-#include "ktrm.moc"
-
-class KTRMLookup;
-
-extern "C"
-{
-#if HAVE_TUNEPIMP >= 4
- static void TRMNotifyCallback(tunepimp_t pimp, void *data, TPCallbackEnum type, int fileId, TPFileStatus status);
-#else
- static void TRMNotifyCallback(tunepimp_t pimp, void *data, TPCallbackEnum type, int fileId);
-#endif
-}
-
-/**
- * This represents the main TunePimp instance and handles incoming requests.
- */
-
-class KTRMRequestHandler
-{
-public:
- static KTRMRequestHandler *instance()
- {
- static QMutex mutex;
- mutex.lock();
- static KTRMRequestHandler handler;
- mutex.unlock();
- return &handler;
- }
-
- int startLookup(KTRMLookup *lookup)
- {
- int id;
-
- if(!m_fileMap.contains(lookup->file())) {
-#if HAVE_TUNEPIMP >= 4
- id = tp_AddFile(m_pimp, QFile::encodeName(lookup->file()), 0);
-#else
- id = tp_AddFile(m_pimp, QFile::encodeName(lookup->file()));
-#endif
- m_fileMap.insert(lookup->file(), id);
- }
- else {
- id = m_fileMap[lookup->file()];
- tp_IdentifyAgain(m_pimp, id);
- }
- m_lookupMap[id] = lookup;
- return id;
- }
-
- void endLookup(KTRMLookup *lookup)
- {
- tp_ReleaseTrack(m_pimp, tp_GetTrack(m_pimp, lookup->fileId()));
- tp_Remove(m_pimp, lookup->fileId());
- m_lookupMap.remove(lookup->fileId());
- }
-
- bool lookupMapContains(int fileId) const
- {
- m_lookupMapMutex.lock();
- bool contains = m_lookupMap.contains(fileId);
- m_lookupMapMutex.unlock();
- return contains;
- }
-
- KTRMLookup *lookup(int fileId) const
- {
- m_lookupMapMutex.lock();
- KTRMLookup *l = m_lookupMap[fileId];
- m_lookupMapMutex.unlock();
- return l;
- }
-
- void removeFromLookupMap(int fileId)
- {
- m_lookupMapMutex.lock();
- m_lookupMap.remove(fileId);
- m_lookupMapMutex.unlock();
- }
-
- const tunepimp_t &tunePimp() const
- {
- return m_pimp;
- }
-
-protected:
- KTRMRequestHandler()
- {
- m_pimp = tp_New("KTRM", "0.1");
- //tp_SetDebug(m_pimp, true);
-#if HAVE_TUNEPIMP < 5
- tp_SetTRMCollisionThreshold(m_pimp, 100);
- tp_SetAutoFileLookup(m_pimp,true);
-#endif
- tp_SetAutoSaveThreshold(m_pimp, -1);
- tp_SetMoveFiles(m_pimp, false);
- tp_SetRenameFiles(m_pimp, false);
-#if HAVE_TUNEPIMP >= 4
- tp_SetFileNameEncoding(m_pimp, "UTF-8");
-#else
- tp_SetUseUTF8(m_pimp, true);
-#endif
- tp_SetNotifyCallback(m_pimp, TRMNotifyCallback, 0);
-#if HAVE_TUNEPIMP < 5
- // Re-read proxy config.
- KProtocolManager::reparseConfiguration();
-
- if(KProtocolManager::useProxy()) {
- // split code copied from kcm_kio.
- QString noProxiesFor = KProtocolManager::noProxyFor();
- QStringList noProxies = noProxiesFor.split(QRegExp("[',''\t'' ']"), QString::SkipEmptyParts);
- bool useProxy = true;
-
- // Host that libtunepimp will contact.
- QString tunepimpHost = "www.musicbrainz.org";
- QString tunepimpHostWithPort = "www.musicbrainz.org:80";
-
- // Check what hosts are allowed to proceed without being proxied,
- // or if using reversed proxy, what hosts must be proxied.
- foreach(const QString &host, noProxies) {
- const QString normalizedHost(KUrl::fromAce(KUrl::toAce(host)));
-
- if(normalizedHost == tunepimpHost ||
- tunepimpHost.endsWith('.' + normalizedHost))
- {
- useProxy = false;
- break;
- }
-
- // KDE's proxy mechanism also supports exempting a specific
- // host/port combo, check that also.
- if(normalizedHost == tunepimpHostWithPort ||
- tunepimpHostWithPort.endsWith('.' + normalizedHost))
- {
- useProxy = false;
- break;
- }
- }
-
- // KDE supports a reverse proxy mechanism. Uh, yay.
- if(KProtocolManager::useReverseProxy())
- useProxy = !useProxy;
-
- if(useProxy) {
- KUrl proxy = KProtocolManager::proxyFor("http");
- QString proxyHost = proxy.host();
-
- kDebug() << "Using proxy server " << proxyHost << " for www.musicbrainz.org.\n";
- tp_SetProxy(m_pimp, proxyHost.toAscii(), short(proxy.port()));
- }
- }
-#else
- tp_SetMusicDNSClientId(m_pimp, "0c6019606b1d8a54d0985e448f3603ca");
-#endif
- }
-
- ~KTRMRequestHandler()
- {
- tp_Delete(m_pimp);
- }
-
-private:
- tunepimp_t m_pimp;
- QMap<int, KTRMLookup *> m_lookupMap;
- QMap<QString, int> m_fileMap;
- mutable QMutex m_lookupMapMutex;
-};
-
-
-/**
- * A custom event type used for signalling that a TRM lookup is finished.
- */
-
-class KTRMEvent : public QEvent
-{
-public:
- enum Status {
- Recognized,
- Unrecognized,
- Collision,
- PuidGenerated,
- Error
- };
-
- KTRMEvent(int fileId, Status status) :
- QEvent(static_cast<QEvent::Type>(id)),
- m_fileId(fileId),
- m_status(status)
- {
- }
-
- int fileId() const
- {
- return m_fileId;
- }
-
- Status status() const
- {
- return m_status;
- }
-
- static const int id = User + 1984; // random, unique, event id
-
-private:
- int m_fileId;
- Status m_status;
-};
-
-/**
- * A helper class to intercept KTRMQueryEvents and call recognized() (from the GUI
- * thread) for the lookup.
- */
-
-class KTRMEventHandler : public QObject
-{
-public:
- static void send(int fileId, KTRMEvent::Status status)
- {
- QCoreApplication::postEvent(instance(), new KTRMEvent(fileId, status));
- }
-
-protected:
- KTRMEventHandler() : QObject() {}
-
- static KTRMEventHandler *instance()
- {
- static QMutex mutex;
- mutex.lock();
- static KTRMEventHandler handler;
- mutex.unlock();
- return &handler;
- }
-
- virtual void customEvent(QEvent *event)
- {
- if(event->type() != KTRMEvent::id)
- return;
-
- KTRMEvent *e = static_cast<KTRMEvent *>(event);
-
- static QMutex mutex;
- mutex.lock();
-
- if(!KTRMRequestHandler::instance()->lookupMapContains(e->fileId())) {
- mutex.unlock();
- return;
- }
-
- KTRMLookup *lookup = KTRMRequestHandler::instance()->lookup(e->fileId());
-#if HAVE_TUNEPIMP >= 4
- if ( e->status() != KTRMEvent::Unrecognized)
-#endif
- KTRMRequestHandler::instance()->removeFromLookupMap(e->fileId());
-
- mutex.unlock();
-
- switch(e->status()) {
- case KTRMEvent::Recognized:
- lookup->recognized();
- break;
- case KTRMEvent::Unrecognized:
- lookup->unrecognized();
- break;
- case KTRMEvent::Collision:
- lookup->collision();
- break;
- case KTRMEvent::Error:
- lookup->error();
- break;
- case KTRMEvent::PuidGenerated:
- break; // XXX: Does anything special need done here?
- }
- }
-};
-
-/**
- * Callback function for TunePimp lookup events.
- */
-#if HAVE_TUNEPIMP >= 4
-static void TRMNotifyCallback(tunepimp_t /*pimp*/, void * /*data*/, TPCallbackEnum type, int fileId, TPFileStatus status)
-#else
-static void TRMNotifyCallback(tunepimp_t pimp, void *data, TPCallbackEnum type, int fileId)
-#endif
-{
- if(type != tpFileChanged)
- return;
-
-#if HAVE_TUNEPIMP < 4
- track_t track = tp_GetTrack(pimp, fileId);
- TPFileStatus status = tr_GetStatus(track);
-#endif
-
- switch(status) {
- case eRecognized:
- KTRMEventHandler::send(fileId, KTRMEvent::Recognized);
- break;
- case eUnrecognized:
- KTRMEventHandler::send(fileId, KTRMEvent::Unrecognized);
- break;
-#if HAVE_TUNEPIMP >= 5
- case ePUIDLookup:
- case ePUIDCollision:
- case eFileLookup:
- KTRMEventHandler::send(fileId, KTRMEvent::PuidGenerated);
- break;
-#else
- case eTRMCollision:
-#if HAVE_TUNEPIMP >= 4
- case eUserSelection:
-#endif
- KTRMEventHandler::send(fileId, KTRMEvent::Collision);
- break;
-#endif
- case eError:
- KTRMEventHandler::send(fileId, KTRMEvent::Error);
- break;
- default:
- break;
- }
-#if HAVE_TUNEPIMP < 4
- tp_ReleaseTrack(pimp, track);
-#endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// KTRMResult implementation
-////////////////////////////////////////////////////////////////////////////////
-
-class KTRMResult::KTRMResultPrivate
-{
-public:
- KTRMResultPrivate() : track(0), year(0), relevance(0) {}
- QString title;
- QString artist;
- QString album;
- int track;
- int year;
- int relevance;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// KTRMResult public methods
-////////////////////////////////////////////////////////////////////////////////
-
-KTRMResult::KTRMResult()
-{
- d = new KTRMResultPrivate;
-}
-
-KTRMResult::KTRMResult(const KTRMResult &result)
-{
- d = new KTRMResultPrivate(*result.d);
-}
-
-KTRMResult::~KTRMResult()
-{
- delete d;
-}
-
-QString KTRMResult::title() const
-{
- return d->title;
-}
-
-QString KTRMResult::artist() const
-{
- return d->artist;
-}
-
-QString KTRMResult::album() const
-{
- return d->album;
-}
-
-int KTRMResult::track() const
-{
- return d->track;
-}
-
-int KTRMResult::year() const
-{
- return d->year;
-}
-
-bool KTRMResult::operator<(const KTRMResult &r) const
-{
- return r.d->relevance < d->relevance;
-}
-
-bool KTRMResult::operator>(const KTRMResult &r) const
-{
- return r.d->relevance > d->relevance;
-}
-
-bool KTRMResult::isEmpty() const
-{
- return d->title.isEmpty() && d->artist.isEmpty() && d->album.isEmpty() &&
- d->track == 0 && d->year == 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// KTRMLookup implementation
-////////////////////////////////////////////////////////////////////////////////
-
-class KTRMLookup::KTRMLookupPrivate
-{
-public:
- KTRMLookupPrivate() :
- fileId(-1) {}
- QString file;
- KTRMResultList results;
- int fileId;
- bool autoDelete;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// KTRMLookup public methods
-////////////////////////////////////////////////////////////////////////////////
-
-KTRMLookup::KTRMLookup(const QString &file, bool autoDelete)
-{
- d = new KTRMLookupPrivate;
- d->file = file;
- d->autoDelete = autoDelete;
- d->fileId = KTRMRequestHandler::instance()->startLookup(this);
-}
-
-KTRMLookup::~KTRMLookup()
-{
- KTRMRequestHandler::instance()->endLookup(this);
- delete d;
-}
-
-QString KTRMLookup::file() const
-{
- return d->file;
-}
-
-int KTRMLookup::fileId() const
-{
- return d->fileId;
-}
-
-void KTRMLookup::recognized()
-{
- kDebug() << d->file;
-
- d->results.clear();
-
- metadata_t *metaData = md_New();
- track_t track = tp_GetTrack(KTRMRequestHandler::instance()->tunePimp(), d->fileId);
- tr_Lock(track);
- tr_GetServerMetadata(track, metaData);
-
- KTRMResult result;
-
- result.d->title = QString::fromUtf8(metaData->track);
- result.d->artist = QString::fromUtf8(metaData->artist);
- result.d->album = QString::fromUtf8(metaData->album);
- result.d->track = metaData->trackNum;
- result.d->year = metaData->releaseYear;
-
- d->results.append(result);
-
- md_Delete(metaData);
- tr_Unlock(track);
- finished();
-}
-
-void KTRMLookup::unrecognized()
-{
- kDebug() << d->file;
-#if HAVE_TUNEPIMP >= 4
- char trm[255];
- bool finish = false;
- trm[0] = 0;
- track_t track = tp_GetTrack(KTRMRequestHandler::instance()->tunePimp(), d->fileId);
- tr_Lock(track);
-#if HAVE_TUNEPIMP >= 5
- tr_GetPUID(track, trm, 255);
-#else
- tr_GetTRM(track, trm, 255);
-#endif
-
- if ( !trm[0] ) {
- tr_SetStatus(track, ePending);
- tp_Wake(KTRMRequestHandler::instance()->tunePimp(), track);
- }
- else
- finish = true;
- tr_Unlock(track);
- tp_ReleaseTrack(KTRMRequestHandler::instance()->tunePimp(), track);
- if ( !finish )
- return;
-#endif
- d->results.clear();
- finished();
-}
-
-void KTRMLookup::collision()
-{
-#if HAVE_TUNEPIMP < 5
- kDebug() << d->file;
-
- track_t track = tp_GetTrack(KTRMRequestHandler::instance()->tunePimp(), d->fileId);
-
- if(track <= 0) {
- kDebug() << "invalid track number";
- return;
- }
-
- tr_Lock(track);
- int resultCount = tr_GetNumResults(track);
-
- if(resultCount > 0) {
- TPResultType type;
- result_t *results = new result_t[resultCount];
- tr_GetResults(track, &type, results, &resultCount);
-
- switch(type) {
- case eNone:
- kDebug() << "eNone";
- break;
- case eArtistList:
- kDebug() << "eArtistList";
- break;
- case eAlbumList:
- kDebug() << "eAlbumList";
- break;
- case eTrackList:
- {
- kDebug() << "eTrackList";
- albumtrackresult_t **tracks = (albumtrackresult_t **) results;
- d->results.clear();
-
- for(int i = 0; i < resultCount; i++) {
- KTRMResult result;
-
- result.d->title = QString::fromUtf8(tracks[i]->name);
-#if HAVE_TUNEPIMP >= 4
- result.d->artist = QString::fromUtf8(tracks[i]->artist.name);
- result.d->album = QString::fromUtf8(tracks[i]->album.name);
- result.d->year = tracks[i]->album.releaseYear;
-#else
- result.d->artist = QString::fromUtf8(tracks[i]->artist->name);
- result.d->album = QString::fromUtf8(tracks[i]->album->name);
- result.d->year = tracks[i]->album->releaseYear;
-#endif
- result.d->track = tracks[i]->trackNum;
- result.d->relevance = tracks[i]->relevance;
-
- d->results.append(result);
- }
- break;
- }
- case eMatchedTrack:
- kDebug() << "eMatchedTrack";
- break;
- }
-
- delete [] results;
- }
-
- tr_Unlock(track);
-
- finished();
-#endif
-}
-
-void KTRMLookup::puidGenerated()
-{
-#if HAVE_TUNEPIMP >= 5
- char puid[255] = {0};
- track_t track = tp_GetTrack(KTRMRequestHandler::instance()->tunePimp(), d->fileId);
- tr_Lock(track);
-
- tr_GetPUID(track, puid, 255);
- tr_Unlock(track);
- tp_ReleaseTrack(KTRMRequestHandler::instance()->tunePimp(), track);
- d->results.clear();
-
- KIO::Job *job = KIO::storedGet( QString( "http://musicbrainz.org/ws/1/track/?type=xml&puid=%1" ).arg( puid ) , KIO::NoReload, KIO::HideProgressInfo );
- connect( job, SIGNAL(result(KJob*)), SLOT(lookupResult(KJob*)) );
-#endif
-}
-
-void KTRMLookup::lookupResult( KJob* job )
-{
-#if HAVE_TUNEPIMP >= 5
- if ( job->error() != 0 ) {
- finished();
- return;
- }
- KIO::StoredTransferJob* const storedJob = static_cast<KIO::StoredTransferJob*>( job );
- QString xml = QString::fromUtf8( storedJob->data().data(), storedJob->data().size() );
-
- QDomDocument doc;
- QDomElement e;
-
- if( !doc.setContent( xml ) ) {
- finished();
- return;
- }
-
- e = doc.namedItem( "metadata" ).toElement().namedItem( "track-list" ).toElement();
-
- QStringList strList = d->file.split('/');
-
- QDomNode n = e.namedItem("track");
- for( ; !n.isNull(); n = n.nextSibling() ) {
- QDomElement track = n.toElement();
- KTRMResult result;
-
- result.d->title = track.namedItem( "title" ).toElement().text();
- result.d->artist = track.namedItem( "artist" ).toElement().namedItem( "name" ).toElement().text();
- QDomNode releaseNode = track.namedItem("release-list").toElement().namedItem("release");
- for( ; !releaseNode.isNull(); releaseNode = releaseNode.nextSibling() ) {
- KTRMResult tmpResult( result );
- QDomElement release = releaseNode.toElement();
-
- tmpResult.d->album = release.namedItem( "title" ).toElement().text();
- QDomNode tracklistN = release.namedItem( "track-list" );
- if ( !tracklistN.isNull() ) {
- QDomElement tracklist = tracklistN.toElement();
- if ( !tracklist.attribute( "offset" ).isEmpty() )
- tmpResult.d->track = tracklist.attribute( "offset" ).toInt() + 1;
- }
- //tmpResult.d->year = ???;
- tmpResult.d->relevance = static_cast<int>(
- 4 * stringSimilarity(strList,tmpResult.d->title) +
- 2 * stringSimilarity(strList,tmpResult.d->artist) +
- 1 * stringSimilarity(strList,tmpResult.d->album)
- );
-/*
- if( !d->results.contains( tmpResult ) )
- d->results.append( tmpResult );
- */
- }
- }
-
- qSort(d->results);
-
- finished();
-#else
- Q_UNUSED( job );
-#endif
-}
-
-
-void KTRMLookup::error()
-{
- kDebug() << d->file;
-
- d->results.clear();
- finished();
-}
-
-KTRMResultList KTRMLookup::results() const
-{
- return d->results;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// KTRMLookup protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-void KTRMLookup::finished()
-{
- if(d->autoDelete)
- delete this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Helper Functions used for sorting MusicBrainz results
-////////////////////////////////////////////////////////////////////////////////
-
-double stringSimilarity(const QStringList &l, const QString &s)
-{
- double max = 0, current = 0;
-
- foreach(const QString &string, l) {
- if(max < (current = stringSimilarity(string, s)))
- max = current;
- }
-
- return max;
-}
-
-double stringSimilarity(QString s1, QString s2)
-{
- QRegExp whiteSpace("[\\s\\t\\r\\n]");
-
- s1.remove(whiteSpace);
- s2.remove(whiteSpace);
-
- double nCommon = 0;
- int p1 = 0, p2 = 0, x1 = 0, x2 = 0;
- int l1 = s1.length(), l2 = s2.length(), l3 = l1 + l2;
- QChar c1 = 0, c2 = 0;
-
- while(p1 < l1 && p2 < l2) {
- c1 = s1.at(p1); c2 = s2.at(p2);
-
- if(c1.toUpper() == c2.toUpper()) {
- ++nCommon;
- ++p1; ++p2;
- }
- else {
- x1 = s1.indexOf(c2, p1, Qt::CaseInsensitive);
- x2 = s2.indexOf(c1, p2, Qt::CaseInsensitive);
-
- if( (x1 == x2 || -1 == x1) || (-1 != x2 && x1 > x2) )
- ++p2;
- else
- ++p1;
- }
- }
-
- return l3 ? nCommon * 2.0 / l3 : 1.0;
-}
-
-#endif // (HAVE_TUNEPIMP > 0)
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- */
-
-/**
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version
- * 2.1 as published by the Free Software Foundation.
- *
- * 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
- */
-
-/*
- * At some point this will likely be a library class, as such it's been written
- * as such and is LGPL'ed.
- */
-
-#ifndef KTRM_H
-#define KTRM_H
-
-#include <QObject>
-
-template<class T>
-class QList;
-
-class QString;
-class QStringList;
-
-class KJob;
-
-/**
- * This represents a potential match for a TRM lookup. KTRMResultList is
- * returned from KTRMLookup and will be sorted by relevance (better matches
- * at the beginning of the list).
- */
-
-class KTRMResult
-{
- friend class KTRMLookup;
-
-public:
- KTRMResult();
- KTRMResult(const KTRMResult &result);
- ~KTRMResult();
-
- /**
- * Returns the title of the track for the potential match.
- */
- QString title() const;
-
- /**
- * Returns the artist name of the track for the potential match.
- */
- QString artist() const;
-
- /**
- * Returns the album name of the track for the potential match.
- */
- QString album() const;
-
- /**
- * Returns the track number of the track for the potential match.
- */
- int track() const;
-
- /**
- * Returns the original release year of the track for the potential match.
- */
- int year() const;
-
- /**
- * Returns true if all of the values for the result are empty.
- */
- bool isEmpty() const;
-
- /**
- * Compares to \a r based on the relevance of the match. Better matches
- * will be greater than less accurate matches.
- */
- bool operator<(const KTRMResult &r) const;
-
- /**
- * Compares to \a r based on the relevance of the match. Better matches
- * will be greater than less accurate matches.
- */
- bool operator>(const KTRMResult &r) const;
-
-private:
- class KTRMResultPrivate;
- KTRMResultPrivate *d;
-};
-
-typedef QList<KTRMResult> KTRMResultList;
-
-/**
- * An abstraction for libtunepimp's TRM based lookup and file recognition.
- *
- * A lookup is started when the object is created. One of the virtual methods
- * -- recognized(), unrecognized(), collision() or error(). Those methods
- * should be reimplemented in subclasses to specify what behavior should happen
- * for each result.
- *
- * The lookups themselves happen in a background thread, but the return calls
- * are guaranteed to run in the GUI thread.
- */
-class KTRMLookup : public QObject
-{
-Q_OBJECT
-
-public:
- /**
- * Creates and starts a lookup for \a file. If \a autoDelete is set to
- * true the lookup will delete itself when it has finished.
- */
- explicit KTRMLookup(const QString &file, bool autoDelete = false);
-
- virtual ~KTRMLookup();
-
- /**
- * Returns the file name that was specified in the constructor.
- */
- QString file() const;
-
- /**
- * Returns the TunePimp file ID for the file. This is of no use to the
- * public API.
- *
- * @internal
- */
- int fileId() const;
- /**
- * This method is called when the puid was already generated. It will then do
- * the lookup with MusicBrainz's server. This may be reimplemented to provide
- * specific behavion for the lookup.
- */
- virtual void puidGenerated();
-
- /**
- * This method is called if the track was recognized by the TRM server.
- * results() will return just one value. This may be reimplemented to
- * provide specific behavion in the case of the track being recognized.
- *
- * \note The base class call should happen at the beginning of the subclass
- * reimplementation; it populates the values of results().
- */
- virtual void recognized();
-
- /**
- * This method is called if the track was not recognized by the TRM server.
- * results() will return an empty set. This may be reimplemented to provide
- * specific behavion in the case of the track not being recognized.
- */
- virtual void unrecognized();
-
- /**
- * This method is called if there are multiple potential matches for the TRM
- * value. results() will return a list of the potential matches, sorted by
- * liklihood. This may be reimplemented to provide
- * specific behavion in the case of the track not being recognized.
- *
- * \note The base class call should happen at the beginning of the subclass
- * reimplementation; it populates the values of results().
- */
- virtual void collision();
-
- /**
- * This method is called if the track was not recognized by the TRM server.
- * results() will return an empty set. This may be reimplemented to provide
- * specific behavion in the case of the track not being recognized.
- */
- virtual void error();
-
- /**
- * Returns the list of matches found by the lookup. In the case that there
- * was a TRM collision this list will contain multiple entries. In the case
- * that it was recognized this will only contain one entry. Otherwise it
- * will remain empty.
- */
- KTRMResultList results() const;
-
-protected:
- /**
- * This method is called when any of terminal states (recognized,
- * unrecognized, collision or error) has been reached after the specific
- * method for the result has been called.
- *
- * This should be reimplemented in the case that there is some general
- * processing to be done for all terminal states.
- */
- virtual void finished();
-
-protected slots:
- virtual void lookupResult( KJob* );
-
-signals:
- void sigResult( KTRMResultList, QString );
-
-private:
- class KTRMLookupPrivate;
- KTRMLookupPrivate *d;
-};
-
-/*
- * Helper Functions used for sorting MusicBrainz results
- */
-double stringSimilarity(QString s1, QString s2);
-double stringSimilarity(const QStringList &l, const QString &s);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <QDomDocument>
-#include <QNetworkAccessManager>
-#include <QNetworkReply>
-
-#include <KAction>
-#include <KLocalizedString>
-#include <KActionCollection>
-#include <KToggleAction>
-#include <KConfigGroup>
-#include <KDebug>
-
-#include "lyricswidget.h"
-#include "tag.h"
-#include "actioncollection.h"
-
-
-LyricsWidget::LyricsWidget(QWidget* parent): QTextBrowser(parent),
- m_networkAccessManager(new QNetworkAccessManager),
- m_lyricsCurrent(false)
-{
- setMinimumWidth(200);
- setReadOnly(true);
- setWordWrapMode(QTextOption::WordWrap);
- setOpenExternalLinks(true);
-
- KToggleAction *show = new KToggleAction(KIcon(QLatin1String("view-media-lyrics")),
- i18n("Show &Lyrics"), this);
- ActionCollection::actions()->addAction("showLyrics", show);
- connect(show, SIGNAL(toggled(bool)), this, SLOT(setShown(bool)));
-
- KConfigGroup config(KGlobal::config(), "LyricsWidget");
- bool shown = config.readEntry("Show", true);
- show->setChecked(shown);
- setVisible(shown);
-}
-
-LyricsWidget::~LyricsWidget()
-{
- delete m_networkAccessManager;
- saveConfig();
-}
-
-void LyricsWidget::saveConfig()
-{
- KConfigGroup config(KGlobal::config(), "LyricsWidget");
- config.writeEntry("Show", ActionCollection::action<KToggleAction>("showLyrics")->isChecked());
-}
-
-void LyricsWidget::makeLyricsRequest()
-{
- m_lyricsCurrent = true;
-
- if(m_playingFile.isNull()) {
- setHtml(i18n("<i>No file playing.</i>"));
- return;
- }
-
- setHtml(i18n("<i>Loading...</i>"));
-
- QUrl listUrl("http://lyrics.wikia.com/api.php");
- listUrl.addQueryItem("action", "lyrics");
- listUrl.addQueryItem("func", "getSong");
- listUrl.addQueryItem("fmt", "xml");
- listUrl.addQueryItem("artist", m_playingFile.tag()->artist());
- listUrl.addQueryItem("song", m_playingFile.tag()->title());
- m_title = m_playingFile.tag()->artist() + " – " + m_playingFile.tag()->title();
- connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveListReply(QNetworkReply*)));
- m_networkAccessManager->get(QNetworkRequest(listUrl));
-}
-
-void LyricsWidget::playing(const FileHandle &file)
-{
- m_playingFile = file;
- m_lyricsCurrent = false;
-
- if(isVisible()) {
- makeLyricsRequest();
- }
-}
-
-void LyricsWidget::showEvent(QShowEvent *)
-{
- if(!m_lyricsCurrent) {
- makeLyricsRequest();
- }
-}
-
-void LyricsWidget::receiveListReply(QNetworkReply* reply)
-{
- disconnect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveListReply(QNetworkReply*)));
- if (reply->error() != QNetworkReply::NoError) {
- kWarning() << "Error while fetching lyrics: " << reply->errorString();
- setHtml(i18n("<span style='color:red'>Error while retrieving lyrics!</span>"));
- return;
- }
-
- QDomDocument document;
- document.setContent(reply);
- QString artist = document.elementsByTagName("artist").at(0).toElement().text();
- QString title = document.elementsByTagName("song").at(0).toElement().text();
-
-
- QUrl url("http://lyrics.wikia.com/api.php");
- url.addQueryItem("action", "query");
- url.addQueryItem("prop", "revisions");
- url.addQueryItem("rvprop", "content");
- url.addQueryItem("format", "xml");
- url.addQueryItem("titles", artist + ':' + title);
- connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveLyricsReply(QNetworkReply*)));
- m_networkAccessManager->get(QNetworkRequest(url));
-}
-
-void LyricsWidget::receiveLyricsReply(QNetworkReply* reply)
-{
- disconnect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveLyricsReply(QNetworkReply*)));
- if (reply->error() != QNetworkReply::NoError) {
- kWarning() << "Error while fetching lyrics: " << reply->errorString();
- setHtml(i18n("<span style='color:red'>Error while retrieving lyrics!</span>"));
- return;
- }
-
- QString content = QString::fromUtf8(reply->readAll());
- int lIndex = content.indexOf("<lyrics>");
- int rIndex = content.indexOf("</lyrics>");
- if (lIndex == -1 || rIndex == -1) {
- kWarning() << Q_FUNC_INFO << "Unable to find lyrics in text";
- setText(i18n("No lyrics available."));
- return;
- }
- lIndex += 15; // We skip the tag
- content = content.mid(lIndex, rIndex - lIndex).trimmed();
- content.replace('\n', "<br />");
- //setText(content);
- setHtml("<h1>" + m_title + "</h1>" +
- content +
- i18n("<br /><br /><i>Lyrics provided by <a href='http://lyrics.wikia.com/Lyrics_Wiki'>LyricWiki</a></i>"));
-}
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LYRICSWIDGET_H
-#define LYRICSWIDGET_H
-
-#include <QTextBrowser>
-#include "filehandle.h"
-
-class QNetworkAccessManager;
-class QNetworkReply;
-
-
-class LyricsWidget : public QTextBrowser
-{
- Q_OBJECT
-
-public:
- explicit LyricsWidget(QWidget *parent);
-
- virtual ~LyricsWidget();
-
- QSize minimumSize() const { return QSize(100, 0); }
-
-public Q_SLOTS:
- void playing(const FileHandle &file);
-
-protected:
- virtual void showEvent(QShowEvent*);
-
-private:
- void makeLyricsRequest();
-
-private Q_SLOTS:
- void receiveListReply(QNetworkReply*);
- void receiveLyricsReply(QNetworkReply*);
- void saveConfig();
-
-
-private:
- FileHandle m_playingFile;
- QNetworkAccessManager *m_networkAccessManager;
- QString m_title;
- bool m_lyricsCurrent;
-};
-
-
-#endif//LYRICSWIDGET_H
+++ /dev/null
-/**
- * Copyright (C) 2002-2007 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <kuniqueapplication.h>
-#include <kcmdlineargs.h>
-#include <kaboutdata.h>
-#include <kconfigbase.h>
-#include <kconfig.h>
-#include <klocale.h>
-#include <kglobal.h>
-#include <kconfiggroup.h>
-#include <knotification.h>
-
-#include "juk.h"
-
-static const char description[] = I18N_NOOP("Jukebox and music manager by KDE");
-static const char scott[] = I18N_NOOP("Author, chief dork and keeper of the funk");
-static const char michael[] = I18N_NOOP("Assistant super-hero, fixer of many things");
-static const char georg[] = I18N_NOOP("More KDE Platform 4 porting efforts");
-static const char daniel[] = I18N_NOOP("System tray docking, \"inline\" tag editing,\nbug fixes, evangelism, moral support");
-static const char tim[] = I18N_NOOP("GStreamer port");
-static const char stefan[] = I18N_NOOP("Global keybindings support");
-static const char stephen[] = I18N_NOOP("Track announcement popups");
-static const char frerich[] = I18N_NOOP("Automagic track data guessing, bugfixes");
-static const char zack[] = I18N_NOOP("More automagical things, now using MusicBrainz");
-static const char adam[] = I18N_NOOP("Co-conspirator in MusicBrainz wizardry");
-static const char matthias[] = I18N_NOOP("Friendly, neighborhood aRts guru");
-static const char maks[] = I18N_NOOP("Making JuK friendlier to people with terabytes of music");
-static const char antonio[] = I18N_NOOP("DCOP interface");
-static const char allan[] = I18N_NOOP("FLAC and MPC support");
-static const char nathan[] = I18N_NOOP("Album cover manager");
-static const char pascal[] = I18N_NOOP("Gimper of splash screen");
-static const char laurent[] = I18N_NOOP("Porting to KDE 4 when no one else was around");
-static const char giorgos[] = I18N_NOOP("Badly-needed tag editor bugfixes.");
-static const char sandsmark[] = I18N_NOOP("Last.fm scrobbling support, lyrics, prepping for KDE Frameworks.");
-static const char sho[] = I18N_NOOP("MPRIS2 Interface implementation.");
-
-int main(int argc, char *argv[])
-{
- KAboutData aboutData("juk", 0, ki18n("JuK"),
- "3.12", ki18n(description), KAboutData::License_GPL,
- ki18n("© 2002–2014, Scott Wheeler, Michael Pyne, and others"),
- KLocalizedString(),
- "http://www.kde.org/applications/multimedia/juk/");
-
- aboutData.addAuthor(ki18n("Scott Wheeler"), ki18n(scott), "wheeler@kde.org");
- aboutData.addAuthor(ki18n("Michael Pyne"), ki18n(michael), "mpyne@kde.org");
- aboutData.addCredit(ki18n("Γιώργος Κυλάφας (Giorgos Kylafas)"), ki18n(giorgos), "gekylafas@gmail.com");
- aboutData.addCredit(ki18n("Daniel Molkentin"), ki18n(daniel), "molkentin@kde.org");
- aboutData.addCredit(ki18n("Tim Jansen"), ki18n(tim), "tim@tjansen.de");
- aboutData.addCredit(ki18n("Stefan Asserhäll"), ki18n(stefan), "stefan.asserhall@telia.com");
- aboutData.addCredit(ki18n("Stephen Douglas"), ki18n(stephen), "stephen_douglas@yahoo.com");
- aboutData.addCredit(ki18n("Frerich Raabe"), ki18n(frerich), "raabe@kde.org");
- aboutData.addCredit(ki18n("Zack Rusin"), ki18n(zack), "zack@kde.org");
- aboutData.addCredit(ki18n("Adam Treat"), ki18n(adam), "manyoso@yahoo.com");
- aboutData.addCredit(ki18n("Matthias Kretz"), ki18n(matthias), "kretz@kde.org");
- aboutData.addCredit(ki18n("Maks Orlovich"), ki18n(maks), "maksim@kde.org");
- aboutData.addCredit(ki18n("Antonio Larrosa Jimenez"), ki18n(antonio), "larrosa@kde.org");
- aboutData.addCredit(ki18n("Allan Sandfeld Jensen"), ki18n(allan), "kde@carewolf.com");
- aboutData.addCredit(ki18n("Nathan Toone"), ki18n(nathan), "nathan@toonetown.com");
- aboutData.addCredit(ki18n("Pascal Klein"), ki18n(pascal), "4pascal@tpg.com.au");
- aboutData.addCredit(ki18n("Laurent Montel"), ki18n(laurent), "montel@kde.org");
- aboutData.addCredit(ki18n("Georg Grabler"), ki18n(georg), "georg@grabler.net");
- aboutData.addCredit(ki18n("Martin Sandsmark"), ki18n(sandsmark), "martin.sandsmark@kde.org");
- aboutData.addCredit(ki18n("Eike Hein"), ki18n(sho), "hein@kde.org");
-
- KCmdLineArgs::init(argc, argv, &aboutData);
-
- KCmdLineOptions options;
- options.add("+[file(s)]", ki18n("File(s) to open"));
- KCmdLineArgs::addCmdLineOptions(options);
-
- KUniqueApplication::addCmdLineOptions();
-
- KUniqueApplication a;
-
- // If this flag gets set then JuK will quit if you click the cover on the track
- // announcement popup when JuK is only in the system tray (the systray has no widget).
-
- a.setQuitOnLastWindowClosed(false);
-
- // Create the main window and such
-
- JuK *juk = new JuK;
-
- if(a.isSessionRestored() && KMainWindow::canBeRestored(1))
- juk->restore(1, false /* don't show */);
-
- KConfigGroup config(KGlobal::config(), "Settings");
- if(!config.readEntry("StartDocked", false)) {
- juk->show();
- }
- else if(!a.isSessionRestored()) {
- QString message = i18n("JuK running in docked mode\nUse context menu in system tray to restore.");
- KNotification::event("dock_mode",i18n("JuK Docked"), message);
- }
-
- return a.exec();
-}
-
-// vim: set et sw=4 tw=0 sta fileencoding=utf8:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "mediafiles.h"
-
-#include <kfiledialog.h>
-#include <kdebug.h>
-#include <klocale.h>
-#include <kurl.h>
-#include <kio/netaccess.h>
-
-#include <QtGui/QWidget>
-#include <QtCore/QFile>
-
-#include <taglib.h>
-#include <taglib_config.h>
-#include <tag.h>
-#include <mpegfile.h>
-#include <vorbisfile.h>
-#include <flacfile.h>
-#include <xiphcomment.h>
-#include <oggflacfile.h>
-#include <mpcfile.h>
-
-#include "config-juk.h"
-#if TAGLIB_HAS_OPUSFILE
-# include <opusfile.h>
-#endif
-
-#ifdef TAGLIB_WITH_ASF
-#include <asffile.h>
-#endif
-
-#ifdef TAGLIB_WITH_MP4
-#include <mp4file.h>
-#endif
-
-namespace MediaFiles {
- static QStringList savedMimeTypes;
-
- static const char mp3Type[] = "audio/mpeg";
- static const char oggType[] = "audio/ogg";
- static const char flacType[] = "audio/x-flac";
- static const char mpcType[] = "audio/x-musepack";
- static const char m3uType[] = "audio/x-mpegurl";
-
- static const char vorbisType[] = "audio/x-vorbis+ogg";
- static const char oggflacType[] = "audio/x-flac+ogg";
-
-#ifdef TAGLIB_WITH_ASF
- static const char asfType[] = "video/x-ms-asf";
-#endif
-
-#ifdef TAGLIB_WITH_MP4
- static const char mp4Type[] = "audio/mp4";
- static const char mp4AudiobookType[] = "audio/x-m4b";
-#endif
-
-#if TAGLIB_HAS_OPUSFILE
- static const char oggopusType[] = "audio/x-opus+ogg";
-#endif
-
- static const char *const mediaTypes[] = {
- mp3Type, oggType, flacType, mpcType, vorbisType, oggflacType
-#ifdef TAGLIB_WITH_ASF
- ,asfType
-#endif
-#ifdef TAGLIB_WITH_MP4
- ,mp4Type
- ,mp4AudiobookType
-#endif
-#if TAGLIB_HAS_OPUSFILE
- ,oggopusType
-#endif
- };
-
- static const char playlistExtension[] = ".m3u";
-}
-
-#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
-
-QStringList MediaFiles::openDialog(QWidget *parent)
-{
- KFileDialog *dialog = new KFileDialog(KUrl(), QString(), parent);
-
- dialog->setOperationMode(KFileDialog::Opening);
-
- dialog->setCaption(i18nc("open audio file", "Open"));
- dialog->setMode(KFile::Files | KFile::LocalOnly);
- // dialog.ops->clearHistory();
- dialog->setMimeFilter(mimeTypes());
-
- dialog->exec();
-
- // Only local files included in this list.
- QStringList selectedFiles = dialog->selectedFiles();
-
- delete dialog;
-
- return selectedFiles;
-}
-
-QString MediaFiles::savePlaylistDialog(const QString &playlistName, QWidget *parent)
-{
- QString fileName = KFileDialog::getSaveFileName(playlistName + playlistExtension,
- QString("*").append(playlistExtension),
- parent,
- i18n("Playlists"));
- if(!fileName.isEmpty() && !fileName.endsWith(playlistExtension))
- fileName.append(playlistExtension);
-
- return fileName;
-}
-
-TagLib::File *MediaFiles::fileFactoryByType(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- if(!result->isValid())
- return 0;
-
- TagLib::File *file(0);
- QByteArray encodedFileName(QFile::encodeName(fileName));
-
- if(result->is(mp3Type))
- file = new TagLib::MPEG::File(encodedFileName.constData());
- else if(result->is(flacType))
- file = new TagLib::FLAC::File(encodedFileName.constData());
- else if(result->is(vorbisType))
- file = new TagLib::Vorbis::File(encodedFileName.constData());
-#ifdef TAGLIB_WITH_ASF
- else if(result->is(asfType))
- file = new TagLib::ASF::File(encodedFileName.constData());
-#endif
-#ifdef TAGLIB_WITH_MP4
- else if(result->is(mp4Type) || result->is(mp4AudiobookType))
- file = new TagLib::MP4::File(encodedFileName.constData());
-#endif
- else if(result->is(mpcType))
- file = new TagLib::MPC::File(encodedFileName.constData());
- else if(result->is(oggflacType))
- file = new TagLib::Ogg::FLAC::File(encodedFileName.constData());
-#if TAGLIB_HAS_OPUSFILE
- else if(result->is(oggopusType) ||
- (result->is(oggType) && fileName.endsWith(QLatin1String(".opus")))
- )
- {
- file = new TagLib::Ogg::Opus::File(encodedFileName.constData());
- }
-#endif
-
- return file;
-}
-
-bool MediaFiles::isMediaFile(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- if(!result->isValid())
- return false;
-
- // Search through our table of media types for a match
- for(unsigned i = 0; i < ARRAY_SIZE(mediaTypes); ++i) {
- if(result->is(mediaTypes[i]))
- return true;
- }
-
- return false;
-}
-
-bool MediaFiles::isPlaylistFile(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(m3uType);
-}
-
-bool MediaFiles::isMP3(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(mp3Type);
-}
-
-bool MediaFiles::isOgg(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(oggType);
-}
-
-bool MediaFiles::isFLAC(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(flacType);
-}
-
-bool MediaFiles::isMPC(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(mpcType);
-}
-
-bool MediaFiles::isVorbis(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(vorbisType);
-}
-
-#ifdef TAGLIB_WITH_ASF
-bool MediaFiles::isASF(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(asfType);
-}
-#endif
-
-#ifdef TAGLIB_WITH_MP4
-bool MediaFiles::isMP4(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(mp4Type) || result->is(mp4AudiobookType);
-}
-#endif
-
-bool MediaFiles::isOggFLAC(const QString &fileName)
-{
- KMimeType::Ptr result = KMimeType::findByPath(fileName);
- return result->is(oggflacType);
-}
-
-QStringList MediaFiles::mimeTypes()
-{
- if(!savedMimeTypes.isEmpty())
- return savedMimeTypes;
-
- for(unsigned i = 0; i < ARRAY_SIZE(mediaTypes); ++i) {
- savedMimeTypes << QLatin1String(mediaTypes[i]);
- }
-
- return savedMimeTypes;
-}
-
-QStringList MediaFiles::convertURLsToLocal(const KUrl::List &urlList, QWidget *w)
-{
- QStringList result;
- KUrl localUrl;
-
- foreach(const KUrl &url, urlList) {
- localUrl = KIO::NetAccess::mostLocalUrl(url, w);
-
- if(!localUrl.isLocalFile())
- kDebug() << localUrl << " is not a local file, skipping.\n";
- else
- result.append(localUrl.path());
- }
-
- return result;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MEDIAFILES_H
-#define MEDIAFILES_H
-
-class QWidget;
-class QString;
-class QStringList;
-
-namespace TagLib {
- class File;
-}
-
-#include <kurl.h>
-#include <taglib_config.h>
-
-/**
- * A namespace for file JuK's file related functions. The goal is to hide
- * all specific knowledge of mimetypes and file extensions here.
- */
-namespace MediaFiles
-{
- /**
- * Creates a JuK specific KFileDialog with the specified parent.
- */
- QStringList openDialog(QWidget *parent = 0);
-
- /**
- * Creates a JuK specific KFileDialog for saving a playlist with the name
- * playlistName and the specified parent and returns the file name.
- */
- QString savePlaylistDialog(const QString &playlistName, QWidget *parent = 0);
-
- /**
- * Returns a pointer to a new appropriate subclass of TagLib::File, or
- * a null pointer if there is no appropriate subclass for the given
- * file.
- */
- TagLib::File *fileFactoryByType(const QString &fileName);
-
- /**
- * Returns true if fileName is a supported media file.
- */
- bool isMediaFile(const QString &fileName);
-
- /**
- * Returns true if fileName is a supported playlist file.
- */
- bool isPlaylistFile(const QString &fileName);
-
- /**
- * Returns a list of all supported mimetypes.
- */
- QStringList mimeTypes();
-
- /**
- * Returns true if fileName is a mp3 file.
- */
- bool isMP3(const QString &fileName);
-
- /**
- * Returns true if fileName is a mpc (aka musepack) file.
- */
- bool isMPC(const QString &fileName);
-
- /**
- * Returns true if fileName is an Ogg file.
- */
- bool isOgg(const QString &fileName);
-
- /**
- * Returns true if fileName is a FLAC file.
- */
- bool isFLAC(const QString &fileName);
-
- /**
- * Returns true if fileName is an Ogg/Vorbis file.
- */
- bool isVorbis(const QString &fileName);
-
-#ifdef TAGLIB_WITH_ASF
- /**
- * Returns true if fileName is an ASF file.
- */
- bool isASF(const QString &fileName);
-#endif
-
-#ifdef TAGLIB_WITH_MP4
- /**
- * Returns true if fileName is a MP4 file.
- */
- bool isMP4(const QString &fileName);
-#endif
-
- /**
- * Returns true if fileName is an Ogg/FLAC file.
- */
- bool isOggFLAC(const QString &fileName);
-
- /**
- * Returns a list of absolute local filenames, mapped from \p urlList.
- * Any URLs in urlList that aren't really local files will be stripped
- * from the result (so result.size() may be < urlList.size()).
- *
- * @param urlList list of file names or URLs to convert.
- * @param w KIO may need the widget to handle user interaction.
- * @return list of all local files in urlList, converted to absolute paths.
- */
- QStringList convertURLsToLocal(const KUrl::List &urlList, QWidget *w = 0);
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#include "mpris2/mediaplayer2.h"
-#include "juk.h"
-#include "mediafiles.h"
-
-#include <KAboutData>
-#include <KApplication>
-#include <KCmdLineArgs>
-#include <KWindowSystem>
-
-#include <QDBusConnection>
-#include <QDBusMessage>
-#include <QWidget>
-
-MediaPlayer2::MediaPlayer2(QObject* parent) : QDBusAbstractAdaptor(parent)
-{
-}
-
-MediaPlayer2::~MediaPlayer2()
-{
-}
-
-bool MediaPlayer2::CanRaise() const
-{
- return true;
-}
-
-void MediaPlayer2::Raise() const
-{
- JuK::JuKInstance()->show();
- KWindowSystem::forceActiveWindow(JuK::JuKInstance()->effectiveWinId());
-}
-
-bool MediaPlayer2::CanQuit() const
-{
- return true;
-}
-
-void MediaPlayer2::Quit() const
-{
- kapp->quit();
-}
-
-bool MediaPlayer2::CanSetFullscreen() const
-{
- return false;
-}
-
-bool MediaPlayer2::Fullscreen() const
-{
- return false;
-}
-
-bool MediaPlayer2::HasTrackList() const
-{
- return false;
-}
-
-QString MediaPlayer2::Identity() const
-{
- return KCmdLineArgs::aboutData()->programName();
-}
-
-QString MediaPlayer2::DesktopEntry() const
-{
- return QLatin1String("kde4-juk");
-}
-
-QStringList MediaPlayer2::SupportedUriSchemes() const
-{
- return QStringList(QLatin1String("file"));
-}
-
-QStringList MediaPlayer2::SupportedMimeTypes() const
-{
- QStringList mimeTable = MediaFiles::mimeTypes();
-
- // Add whitelist hacks
-
- // technically, "audio/flac" is not a valid mimetype (not on IANA list), but some things expect it
- if( mimeTable.contains( "audio/x-flac" ) && !mimeTable.contains( "audio/flac" ) )
- mimeTable << "audio/flac";
-
- bool canPlayMp3 = mimeTable.contains( "audio/mpeg" ) || mimeTable.contains( "audio/x-mp3" );
- // We special case this, as otherwise the users would hate us
- // Again, "audio/mp3" is not a valid mimetype, but is widely used
- // (the proper one is "audio/mpeg", but that is also for .mp1 and .mp2 files)
- if( canPlayMp3 && !mimeTable.contains( "audio/mp3" ) )
- mimeTable << "audio/mp3";
- if( canPlayMp3 && !mimeTable.contains( "audio/x-mp3" ) )
- mimeTable << "audio/x-mp3";
-
- return mimeTable;
-}
-
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#ifndef JUK_MEDIAPLAYER2_H
-#define JUK_MEDIAPLAYER2_H
-
-#include <QDBusAbstractAdaptor>
-#include <QStringList>
-
-class MediaPlayer2 : public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2") // Docs: http://www.mpris.org/2.1/spec/Root_Node.html
-
- Q_PROPERTY(bool CanRaise READ CanRaise)
- Q_PROPERTY(bool CanQuit READ CanQuit)
- Q_PROPERTY(bool CanSetFullscreen READ CanSetFullscreen)
- Q_PROPERTY(bool Fullscreen READ Fullscreen)
-
- Q_PROPERTY(bool HasTrackList READ HasTrackList)
-
- Q_PROPERTY(QString Identity READ Identity)
- Q_PROPERTY(QString DesktopEntry READ DesktopEntry)
-
- Q_PROPERTY(QStringList SupportedUriSchemes READ SupportedUriSchemes)
- Q_PROPERTY(QStringList SupportedMimeTypes READ SupportedMimeTypes)
-
- public:
- explicit MediaPlayer2(QObject* parent);
- ~MediaPlayer2();
-
- bool CanRaise() const;
- bool CanQuit() const;
- bool CanSetFullscreen() const;
- bool Fullscreen() const;
-
- bool HasTrackList() const;
-
- QString Identity() const;
- QString DesktopEntry() const;
-
- QStringList SupportedUriSchemes() const;
- QStringList SupportedMimeTypes() const;
-
- public slots:
- Q_NOREPLY void Raise() const;
- Q_NOREPLY void Quit() const;
-};
-
-#endif
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#include "mpris2/mediaplayer2player.h"
-#include "juk.h"
-#include "playermanager.h"
-#include "coverinfo.h"
-#include "playlist.h"
-#include "playlistitem.h"
-#include "tag.h"
-#include "filehandle.h"
-
-#include <QCryptographicHash>
-#include <QDBusConnection>
-#include <QDBusMessage>
-#include <QVariant>
-#include <QFile>
-
-#include <KUrl>
-#include <KStandardDirs>
-
-static QByteArray idFromPlaylistItem(const PlaylistItem *item)
-{
- return QByteArray("/org/kde/juk/tid_") +
- QByteArray::number(item->trackId(), 16).rightJustified(8, '0');
-}
-
-MediaPlayer2Player::MediaPlayer2Player(QObject* parent)
- : QDBusAbstractAdaptor(parent)
- , m_player(JuK::JuKInstance()->playerManager())
-{
- connect(m_player, SIGNAL(signalItemChanged(FileHandle)), this, SLOT(currentSourceChanged()));
- connect(m_player, SIGNAL(signalPlay()), this, SLOT(stateUpdated()));
- connect(m_player, SIGNAL(signalPause()), this, SLOT(stateUpdated()));
- connect(m_player, SIGNAL(signalStop()), this, SLOT(stateUpdated()));
- connect(m_player, SIGNAL(totalTimeChanged(int)), this, SLOT(totalTimeChanged()));
- connect(m_player, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
- connect(m_player, SIGNAL(volumeChanged(float)), this, SLOT(volumeChanged(float)));
- connect(m_player, SIGNAL(seeked(int)), this, SLOT(seeked(int)));
-}
-
-MediaPlayer2Player::~MediaPlayer2Player()
-{
-}
-
-bool MediaPlayer2Player::CanGoNext() const
-{
- return true;
-}
-
-void MediaPlayer2Player::Next() const
-{
- m_player->forward();
-}
-
-bool MediaPlayer2Player::CanGoPrevious() const
-{
- return true;
-}
-
-void MediaPlayer2Player::Previous() const
-{
- m_player->back();
-}
-
-bool MediaPlayer2Player::CanPause() const
-{
- return true;
-}
-
-void MediaPlayer2Player::Pause() const
-{
- m_player->pause();
-}
-
-void MediaPlayer2Player::PlayPause() const
-{
- m_player->playPause();
-}
-
-void MediaPlayer2Player::Stop() const
-{
- m_player->stop();
-}
-
-bool MediaPlayer2Player::CanPlay() const
-{
- return true;
-}
-
-void MediaPlayer2Player::Play() const
-{
- m_player->play();
-}
-
-void MediaPlayer2Player::SetPosition(const QDBusObjectPath& TrackId, qlonglong Position) const
-{
- PlaylistItem *playingItem = Playlist::playingItem();
-
- if (!playingItem) {
- return;
- }
-
- // Verify the SetPosition call is against the currently playing track
- QByteArray currentTrackId = idFromPlaylistItem(playingItem);
-
- if (TrackId.path().toLatin1() == currentTrackId) {
- m_player->seek(Position / 1000);
- }
-}
-
-void MediaPlayer2Player::OpenUri(QString Uri) const
-{
- KUrl url(Uri);
-
- // JuK does not yet support KIO
- if (url.isLocalFile()) {
- m_player->play(url.toLocalFile());
- }
-}
-
-QString MediaPlayer2Player::PlaybackStatus() const
-{
- if (m_player->playing()) {
- return QLatin1String("Playing");
- }
- else if (m_player->paused()) {
- return QLatin1String("Paused");
- }
-
- return QLatin1String("Stopped");
-}
-
-QString MediaPlayer2Player::LoopStatus() const
-{
- // TODO: Implement, although this is orthogonal to the PlayerManager
- return "None";
-}
-
-void MediaPlayer2Player::setLoopStatus(const QString& loopStatus) const
-{
- Q_UNUSED(loopStatus)
-}
-
-double MediaPlayer2Player::Rate() const
-{
- return 1.0;
-}
-
-void MediaPlayer2Player::setRate(double rate) const
-{
- Q_UNUSED(rate)
-}
-
-bool MediaPlayer2Player::Shuffle() const
-{
- // TODO: Implement
- return false;
-}
-
-void MediaPlayer2Player::setShuffle(bool shuffle) const
-{
- Q_UNUSED(shuffle)
- // TODO: Implement
-}
-
-QVariantMap MediaPlayer2Player::Metadata() const
-{
- QVariantMap metaData;
-
- // The track ID is annoying since it must result in a valid DBus object
- // path, and the regex for that is, and I quote: [a-zA-Z0-9_]*, along with
- // the normal / delimiters for paths.
- PlaylistItem *item = Playlist::playingItem();
- if (!item)
- return metaData;
-
- FileHandle playingFile = item->file();
- QByteArray playingTrackFileId = idFromPlaylistItem(item);
-
- metaData["mpris:trackid"] =
- QVariant::fromValue<QDBusObjectPath>(
- QDBusObjectPath(playingTrackFileId.constData()));
-
- metaData["xesam:album"] = playingFile.tag()->album();
- metaData["xesam:title"] = playingFile.tag()->title();
- metaData["xesam:artist"] = QStringList(playingFile.tag()->artist());
- metaData["xesam:genre"] = QStringList(playingFile.tag()->genre());
-
- metaData["mpris:length"] = qint64(playingFile.tag()->seconds() * 1000000);
- metaData["xesam:url"] = QString::fromLatin1(
- KUrl::fromLocalFile(playingFile.absFilePath()).toEncoded());
-
- if(playingFile.coverInfo()->hasCover()) {
- QString fallbackFileName = KStandardDirs::locateLocal("tmp",
- QString("juk-cover-%1.png").arg(item->trackId()));
-
- QString path = fallbackFileName;
- if(!QFile::exists(path)) {
- path = playingFile.coverInfo()->localPathToCover(fallbackFileName);
- }
-
- metaData["mpris:artUrl"] = QString::fromLatin1(QUrl::fromLocalFile(
- path).toEncoded());
- }
-
- return metaData;
-}
-
-double MediaPlayer2Player::Volume() const
-{
- return m_player->volume();
-}
-
-void MediaPlayer2Player::setVolume(double volume) const
-{
- if (volume < 0.0)
- volume = 0.0;
- if (volume > 1.0)
- volume = 1.0;
- m_player->setVolume(volume);
-}
-
-qlonglong MediaPlayer2Player::Position() const
-{
- return m_player->currentTimeMSecs() * 1000;
-}
-
-double MediaPlayer2Player::MinimumRate() const
-{
- return 1.0;
-}
-
-double MediaPlayer2Player::MaximumRate() const
-{
- return 1.0;
-}
-
-bool MediaPlayer2Player::CanSeek() const
-{
- return m_player->seekable();
-}
-
-void MediaPlayer2Player::Seek(qlonglong Offset) const
-{
- m_player->seek(((m_player->currentTimeMSecs() * 1000) + Offset) / 1000);
-}
-
-bool MediaPlayer2Player::CanControl() const
-{
- return true;
-}
-
-void MediaPlayer2Player::currentSourceChanged() const
-{
- QVariantMap properties;
- properties["Metadata"] = Metadata();
- properties["CanSeek"] = CanSeek();
- signalPropertiesChange(properties);
-}
-
-void MediaPlayer2Player::stateUpdated() const
-{
- QVariantMap properties;
- properties["PlaybackStatus"] = PlaybackStatus();
- signalPropertiesChange(properties);
-}
-
-void MediaPlayer2Player::totalTimeChanged() const
-{
- QVariantMap properties;
- properties["Metadata"] = Metadata();
- signalPropertiesChange(properties);
-}
-
-void MediaPlayer2Player::seekableChanged(bool seekable) const
-{
- QVariantMap properties;
- properties["CanSeek"] = seekable;
- signalPropertiesChange(properties);
-}
-
-void MediaPlayer2Player::volumeChanged(float newVol) const
-{
- Q_UNUSED(newVol)
-
- QVariantMap properties;
- properties["Volume"] = Volume();
- signalPropertiesChange(properties);
-}
-
-void MediaPlayer2Player::seeked(int newPos) const
-{
- // casts int to uint64
- emit Seeked(newPos);
-}
-
-void MediaPlayer2Player::signalPropertiesChange(const QVariantMap& properties) const
-{
- QDBusMessage msg = QDBusMessage::createSignal("/org/mpris/MediaPlayer2",
- "org.freedesktop.DBus.Properties", "PropertiesChanged" );
-
- msg << "org.mpris.MediaPlayer2.Player";
- msg << properties;
- msg << QStringList();
-
- QDBusConnection::sessionBus().send(msg);
-}
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#ifndef JUK_MEDIAPLAYRER2PLAYER_H
-#define JUK_MEDIAPLAYRER2PLAYER_H
-
-#include <QDBusAbstractAdaptor>
-#include <QDBusObjectPath>
-#include <QPointer>
-
-#include <Phonon/MediaSource>
-
-#include "playermanager.h"
-
-class MediaPlayer2Player : public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.Player") // Docs: http://www.mpris.org/2.1/spec/Player_Node.html
-
- Q_PROPERTY(QString PlaybackStatus READ PlaybackStatus)
- Q_PROPERTY(QString LoopStatus READ LoopStatus WRITE setLoopStatus)
- Q_PROPERTY(double Rate READ Rate WRITE setRate)
- Q_PROPERTY(bool Shuffle READ Shuffle WRITE setShuffle)
- Q_PROPERTY(QVariantMap Metadata READ Metadata)
- Q_PROPERTY(double Volume READ Volume WRITE setVolume)
- Q_PROPERTY(qlonglong Position READ Position)
- Q_PROPERTY(double MinimumRate READ MinimumRate)
- Q_PROPERTY(double MaximumRate READ MaximumRate)
- Q_PROPERTY(bool CanGoNext READ CanGoNext)
- Q_PROPERTY(bool CanGoPrevious READ CanGoPrevious)
- Q_PROPERTY(bool CanPlay READ CanPlay)
- Q_PROPERTY(bool CanPause READ CanPause)
- Q_PROPERTY(bool CanSeek READ CanSeek)
- Q_PROPERTY(bool CanControl READ CanControl)
-
- public:
- explicit MediaPlayer2Player(QObject* parent);
- ~MediaPlayer2Player();
-
- QString PlaybackStatus() const;
- QString LoopStatus() const;
- Q_NOREPLY void setLoopStatus(const QString& loopStatus) const;
- double Rate() const;
- Q_NOREPLY void setRate(double rate) const;
- bool Shuffle() const;
- void setShuffle(bool shuffle) const;
- QVariantMap Metadata() const;
- double Volume() const;
- Q_NOREPLY void setVolume(double volume) const;
- qlonglong Position() const;
- double MinimumRate() const;
- double MaximumRate() const;
- bool CanGoNext() const;
- bool CanGoPrevious() const;
- bool CanPlay() const;
- bool CanPause() const;
- bool CanSeek() const;
- bool CanControl() const;
-
- signals:
- void Seeked(qlonglong Position) const;
-
- public slots:
- Q_NOREPLY void Next() const;
- Q_NOREPLY void Previous() const;
- Q_NOREPLY void Pause() const;
- Q_NOREPLY void PlayPause() const;
- Q_NOREPLY void Stop() const;
- Q_NOREPLY void Play() const;
- Q_NOREPLY void Seek(qlonglong Offset) const;
- Q_NOREPLY void SetPosition(const QDBusObjectPath& TrackId, qlonglong Position) const;
- Q_NOREPLY void OpenUri(QString Uri) const;
-
- private slots:
- void currentSourceChanged() const;
- void stateUpdated() const;
- void totalTimeChanged() const;
- void seekableChanged(bool seekable) const;
- void volumeChanged(float newVol) const;
- void seeked(int newPos) const;
-
- private:
- void signalPropertiesChange(const QVariantMap& properties) const;
-
- int oldPos;
- QPointer<PlayerManager> m_player;
-};
-
-#endif
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#include "mpris2/mpris2.h"
-#include "mpris2/mediaplayer2.h"
-#include "mpris2/mediaplayer2player.h"
-#include "unistd.h"
-
-#include <QDBusConnection>
-
-Mpris2::Mpris2(QObject* parent) : QObject(parent)
-{
- QString mspris2Name("org.mpris.MediaPlayer2." + QLatin1String("juk"));
-
- bool success = QDBusConnection::sessionBus().registerService(mspris2Name);
-
- // If the above failed, it's likely because we're not the first instance
- // and the name is already taken. In that event the MPRIS2 spec wants the
- // following:
- if (!success)
- success = QDBusConnection::sessionBus().registerService(mspris2Name + ".instance" + QString::number(getpid()));
-
- if (success)
- {
- new MediaPlayer2(this);
- new MediaPlayer2Player(this);
- QDBusConnection::sessionBus().registerObject("/org/mpris/MediaPlayer2", this, QDBusConnection::ExportAdaptors);
- }
-}
-
-Mpris2::~Mpris2()
-{
-}
+++ /dev/null
-/***********************************************************************
- * Copyright 2012 Eike Hein <hein@kde.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License or (at your option) version 3 or any later version
- * accepted by the membership of KDE e.V. (or its successor approved
- * by the membership of KDE e.V.), which shall act as a proxy
- * defined in Section 14 of version 3 of the license.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
-
-#ifndef JUK_MPRIS2_H
-#define JUK_MPRIS2_H
-
-#include <QObject>
-
-class Mpris2 : public QObject
-{
- Q_OBJECT
-
- public:
- explicit Mpris2(QObject* parent);
- ~Mpris2();
-};
-
-#endif
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "musicbrainzquery.h"
-
-#if HAVE_TUNEPIMP > 0
-
-#include "juk.h"
-#include "trackpickerdialog.h"
-#include "tag.h"
-#include "collectionlist.h"
-#include "tagtransactionmanager.h"
-
-#include <kxmlguiwindow.h>
-#include <kstatusbar.h>
-#include <klocale.h>
-#include <kdebug.h>
-
-#include <QList>
-#include <QFileInfo>
-
-MusicBrainzLookup::MusicBrainzLookup(const FileHandle &file) :
- KTRMLookup(file.absFilePath()),
- m_file(file)
-{
- message(i18n("Querying MusicBrainz server..."));
-}
-
-void MusicBrainzLookup::recognized()
-{
- KTRMLookup::recognized();
- confirmation();
- delete this;
-}
-
-void MusicBrainzLookup::unrecognized()
-{
- KTRMLookup::unrecognized();
- message(i18n("No matches found."));
- delete this;
-}
-
-void MusicBrainzLookup::collision()
-{
- KTRMLookup::collision();
- confirmation();
- delete this;
-}
-
-void MusicBrainzLookup::error()
-{
- KTRMLookup::error();
- message(i18n("Error connecting to MusicBrainz server."));
- delete this;
-}
-
-void MusicBrainzLookup::message(const QString &s) const
-{
- QString message = QString("%1 (%2)").arg(s).arg(m_file.fileInfo().fileName());
- JuK::JuKInstance()->statusBar()->showMessage(message, 3000);
-}
-
-void MusicBrainzLookup::confirmation()
-{
- // Here we do a bit of queuing to make sure that we don't pop up multiple
- // instances of the confirmation dialog at once.
-
- static QList< QPair<FileHandle, KTRMResultList> > queue;
-
- if(results().isEmpty())
- return;
-
- if(!queue.isEmpty()) {
- queue.append(qMakePair(m_file, results()));
- return;
- }
-
- queue.append(qMakePair(m_file, results()));
-
- while(!queue.isEmpty()) {
- QPair<FileHandle, KTRMResultList> item = queue.first();
- FileHandle file = item.first;
- KTRMResultList results = item.second;
- TrackPickerDialog dialog(file.fileInfo().fileName(), results);
-
- if(dialog.exec() == QDialog::Accepted && !dialog.result().isEmpty()) {
- KTRMResult result = dialog.result();
- Tag *tag = TagTransactionManager::duplicateTag(file.tag());
-
- if(!result.title().isEmpty())
- tag->setTitle(result.title());
- if(!result.artist().isEmpty())
- tag->setArtist(result.artist());
- if(!result.album().isEmpty())
- tag->setAlbum(result.album());
- if(result.track() != 0)
- tag->setTrack(result.track());
- if(result.year() != 0)
- tag->setYear(result.year());
-
- PlaylistItem *item = CollectionList::instance()->lookup(file.absFilePath());
- TagTransactionManager::instance()->changeTagOnItem(item, tag);
- TagTransactionManager::instance()->commit();
- }
-
- queue.pop_front();
- }
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MUSICBRAINZQUERY_H
-#define MUSICBRAINZQUERY_H
-
-#include <config-juk.h>
-
-#if HAVE_TUNEPIMP
-
-#include "ktrm.h"
-#include "filehandle.h"
-
-class MusicBrainzLookup : public KTRMLookup
-{
-public:
- MusicBrainzLookup(const FileHandle &file);
- virtual void recognized();
- virtual void unrecognized();
- virtual void collision();
- virtual void error();
-
-private:
- void message(const QString &s) const;
- void confirmation();
-
- FileHandle m_file;
-};
-
-#endif
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "nowplaying.h"
-
-#include <kiconloader.h>
-#include <klocale.h>
-#include <kdebug.h>
-#include <krandom.h>
-#include <kglobalsettings.h>
-#include <kio/netaccess.h>
-
-#include <QImage>
-#include <QLayout>
-#include <QEvent>
-#include <QDrag>
-#include <QTimer>
-#include <QPoint>
-#include <QFrame>
-#include <QDropEvent>
-#include <QLabel>
-#include <QVBoxLayout>
-#include <QDragEnterEvent>
-#include <QMouseEvent>
-#include <QUrl>
-#include <QList>
-#include <QTextDocument>
-
-#include "playlistcollection.h"
-#include "playlistitem.h"
-#include "coverinfo.h"
-#include "covermanager.h"
-#include "tag.h"
-#include "collectionlist.h"
-
-static const int imageSize = 64;
-
-struct Line : public QFrame
-{
- Line(QWidget *parent) : QFrame(parent) { setFrameShape(VLine); }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// NowPlaying
-////////////////////////////////////////////////////////////////////////////////
-
-NowPlaying::NowPlaying(QWidget *parent, PlaylistCollection *collection) :
- QWidget(parent),
- m_observer(this, collection),
- // Also watch the collection
- m_collectionListObserver(this, CollectionList::instance()),
- m_collection(collection)
-{
- setObjectName(QLatin1String("NowPlaying"));
-
- QHBoxLayout *layout = new QHBoxLayout(this);
- setLayout(layout);
-
- layout->setMargin(0);
- layout->setSpacing(3);
- setFixedHeight(imageSize + 2);
-
- layout->addWidget(new CoverItem(this), 0);
- layout->addWidget(new TrackItem(this), 2);
- layout->addWidget(new Line(this), 0);
-
- hide();
-}
-
-void NowPlaying::addItem(NowPlayingItem *item)
-{
- m_items.append(item);
-}
-
-PlaylistCollection *NowPlaying::collection() const
-{
- return m_collection;
-}
-
-void NowPlaying::slotUpdate(const FileHandle &file)
-{
- m_file = file;
- if(file.isNull()) {
- hide();
- emit nowPlayingHidden();
- return;
- }
- else
- show();
-
- foreach(NowPlayingItem *item, m_items)
- item->update(file);
-}
-
-void NowPlaying::slotReloadCurrentItem()
-{
- foreach(NowPlayingItem *item, m_items)
- item->update(m_file);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CoverItem
-////////////////////////////////////////////////////////////////////////////////
-
-CoverItem::CoverItem(NowPlaying *parent) :
- QLabel(parent),
- NowPlayingItem(parent)
-{
- setObjectName( QLatin1String("CoverItem" ));
- setFixedHeight(parent->height() - parent->layout()->margin() * 2);
- setMargin(1);
- setAcceptDrops(true);
-}
-
-void CoverItem::update(const FileHandle &file)
-{
- m_file = file;
-
- if(!file.isNull() && file.coverInfo()->hasCover()) {
- show();
- setPixmap(
- file.coverInfo()->pixmap(CoverInfo::Thumbnail)
- .scaled(imageSize, imageSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
- }
- else
- hide();
-}
-
-void CoverItem::mouseReleaseEvent(QMouseEvent *event)
-{
- if(m_dragging) {
- m_dragging = false;
- return;
- }
-
- if(event->x() >= 0 && event->y() >= 0 &&
- event->x() < width() && event->y() < height() &&
- event->button() == Qt::LeftButton &&
- m_file.coverInfo()->hasCover())
- {
- m_file.coverInfo()->popup();
- }
-
- QLabel::mousePressEvent(event);
-}
-
-void CoverItem::mousePressEvent(QMouseEvent *e)
-{
- m_dragging = false;
- m_dragStart = e->globalPos();
-}
-
-void CoverItem::mouseMoveEvent(QMouseEvent *e)
-{
- if(m_dragging)
- return;
-
- QPoint diff = m_dragStart - e->globalPos();
- if(diff.manhattanLength() > KGlobalSettings::dndEventDelay()) {
-
- // Start a drag.
-
- m_dragging = true;
-
- QDrag *drag = new QDrag(this);
- CoverDrag *data = new CoverDrag(m_file.coverInfo()->coverId());
-
- drag->setMimeData(data);
- drag->exec(Qt::CopyAction);
- }
-}
-
-void CoverItem::dragEnterEvent(QDragEnterEvent *e)
-{
- e->setAccepted(CoverDrag::isCover(e->mimeData()) || e->mimeData()->hasUrls());
-}
-
-void CoverItem::dropEvent(QDropEvent *e)
-{
- QImage image;
- QList<QUrl> urls;
- coverKey key;
-
- if(e->source() == this)
- return;
-
- key = CoverDrag::idFromData(e->mimeData());
- if(key != CoverManager::NoMatch) {
- m_file.coverInfo()->setCoverId(key);
- update(m_file);
- }
- else if(e->mimeData()->hasImage()) {
- m_file.coverInfo()->setCover(qvariant_cast<QImage>(e->mimeData()->imageData()));
- update(m_file);
- }
- else {
- urls = e->mimeData()->urls();
- if(urls.isEmpty())
- return;
-
- QString fileName;
-
- if(KIO::NetAccess::download(urls.front(), fileName, this)) {
- if(image.load(fileName)) {
- m_file.coverInfo()->setCover(image);
- update(m_file);
- }
- else
- kError() << "Unable to load image from " << urls.front() << endl;
-
- KIO::NetAccess::removeTempFile(fileName);
- }
- else
- kError() << "Unable to download " << urls.front() << endl;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TrackItem
-////////////////////////////////////////////////////////////////////////////////
-
-TrackItem::TrackItem(NowPlaying *parent) :
- QWidget(parent),
- NowPlayingItem(parent)
-{
- setObjectName( QLatin1String("TrackItem" ));
- setFixedHeight(parent->height() - parent->layout()->margin() * 2);
- setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
-
- QVBoxLayout *layout = new QVBoxLayout(this);
-
- m_label = new QLabel(this);
- m_label->setWordWrap(true);
-
- m_label->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::LinksAccessibleByKeyboard);
-
- layout->addStretch();
- layout->addWidget(m_label);
- layout->addStretch();
-
- connect(m_label, SIGNAL(linkActivated(QString)), this,
- SLOT(slotOpenLink(QString)));
-
- // Ensure that if we're filtering results, that the filtering is cleared if we
- // hide the now playing bar so that the user can select tracks normally.
-
- connect(parent, SIGNAL(nowPlayingHidden()), SLOT(slotClearShowMore()));
-}
-
-void TrackItem::update(const FileHandle &file)
-{
- m_file = file;
- QTimer::singleShot(0, this, SLOT(slotUpdate()));
-}
-
-void TrackItem::slotOpenLink(const QString &link)
-{
- PlaylistCollection *collection = NowPlayingItem::parent()->collection();
-
- if(link == "artist")
- collection->showMore(m_file.tag()->artist());
- else if(link == "album")
- collection->showMore(m_file.tag()->artist(), m_file.tag()->album());
- else if(link == "clear")
- collection->clearShowMore();
-
- update(m_file);
-}
-
-void TrackItem::slotUpdate()
-{
- if(m_file.isNull()) {
- m_label->setText(QString());
- return;
- }
-
- QString title = Qt::escape(m_file.tag()->title());
- QString artist = Qt::escape(m_file.tag()->artist());
- QString album = Qt::escape(m_file.tag()->album());
- QString separator = (artist.isNull() || album.isNull()) ? QString::null : QString(" - "); //krazy:exclude=nullstrassign for old broken gcc
-
- // This block-o-nastiness makes the font smaller and smaller until it actually fits.
-
- int size = 4;
- QString format =
- "<font size=\"+%1\"><b>%2</b></font>"
- "<br />"
- "<font size=\"+%3\"><b><a href=\"artist\">%4</a>%5<a href=\"album\">%6</a></b>";
-
- if(NowPlayingItem::parent()->collection()->showMoreActive())
- format.append(QString(" (<a href=\"clear\">%1</a>)").arg(i18n("back to playlist")));
-
- format.append("</font>");
-
- do {
- m_label->setText(format.arg(size).arg(title).arg(size - 2)
- .arg(artist).arg(separator).arg(album));
- --size;
- } while(m_label->heightForWidth(m_label->width()) > imageSize && size >= 0);
-
- m_label->setFixedHeight(qMin(imageSize, m_label->heightForWidth(m_label->width())));
-}
-
-void TrackItem::slotClearShowMore()
-{
- PlaylistCollection *collection = NowPlayingItem::parent()->collection();
- Q_ASSERT(collection);
- collection->clearShowMore();
-}
-
-#include "nowplaying.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NOWPLAYING_H
-#define NOWPLAYING_H
-
-#include <QWidget>
-#include <QLabel>
-#include <QPointer>
-#include <QList>
-
-#include "filehandle.h"
-#include "playlistinterface.h"
-
-class QTimer;
-class QPoint;
-
-class NowPlayingItem;
-class PlaylistCollection;
-class Playlist;
-
-/**
- * This is the widget that holds all of the other items and handles updating them
- * when the playing item changes.
- */
-
-class NowPlaying : public QWidget
-{
- Q_OBJECT
-
-public:
- NowPlaying(QWidget *parent, PlaylistCollection *collection);
- void addItem(NowPlayingItem *item);
- PlaylistCollection *collection() const;
-
-public slots:
- void slotUpdate(const FileHandle &file);
- void slotReloadCurrentItem();
-
-signals:
- void nowPlayingHidden();
-
-private:
- struct Observer : public PlaylistObserver
- {
- Observer(NowPlaying *parent, PlaylistInterface *playlist) :
- PlaylistObserver(playlist),
- m_parent(parent) {}
- virtual void updateCurrent() {}
- virtual void updateData() { m_parent->slotReloadCurrentItem(); }
- NowPlaying *m_parent;
- };
- friend struct Observer;
-
- Observer m_observer;
- Observer m_collectionListObserver;
- PlaylistCollection *m_collection;
- QList<NowPlayingItem *> m_items;
- FileHandle m_file;
-};
-
-/**
- * Abstract base for the other NowPlaying items.
- */
-
-class NowPlayingItem
-{
-public:
- virtual ~NowPlayingItem() {}
- virtual void update(const FileHandle &file) = 0;
- NowPlaying *parent() const { return m_parent; }
-protected:
- NowPlayingItem(NowPlaying *parent) : m_parent(parent) { parent->addItem(this); }
-private:
- NowPlaying *m_parent;
-};
-
-/**
- * Displays the cover of the currently playing file if available, or hides
- * itself if not.
- */
-
-class CoverItem : public QLabel, public NowPlayingItem
-{
-public:
- CoverItem(NowPlaying *parent);
- virtual void update(const FileHandle &file);
- virtual void mouseReleaseEvent(QMouseEvent *event);
-
-protected:
- virtual void dragEnterEvent(QDragEnterEvent *e);
- virtual void dropEvent(QDropEvent *e);
-
- virtual void mousePressEvent(QMouseEvent *e);
- virtual void mouseMoveEvent(QMouseEvent *e);
-
-private:
- FileHandle m_file;
- bool m_dragging;
- QPoint m_dragStart;
-};
-
-/**
- * Show the text information on the current track and provides links to the
- * album and artist of the currently playing item.
- */
-
-class TrackItem : public QWidget, public NowPlayingItem
-{
- Q_OBJECT
-
-public:
- TrackItem(NowPlaying *parent);
- virtual void update(const FileHandle &file);
-
-private slots:
- void slotOpenLink(const QString &link);
- void slotUpdate();
- void slotClearShowMore();
-
-private:
- FileHandle m_file;
- QLabel *m_label;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.kde.juk.collection">
- <method name="openFile">
- <arg name="file" type="s" direction="in"/>
- </method>
- <method name="openFile">
- <arg name="files" type="as" direction="in"/>
- </method>
- <method name="openFile">
- <arg name="playlist" type="s" direction="in"/>
- <arg name="file" type="s" direction="in"/>
- </method>
- <method name="openFile">
- <arg name="playlist" type="s" direction="in"/>
- <arg name="files" type="as" direction="in"/>
- </method>
- <method name="visiblePlaylist">
- <arg type="s" direction="out"/>
- </method>
- <method name="playingPlaylist">
- <arg type="s" direction="out"/>
- </method>
- <method name="playlists">
- <arg type="as" direction="out"/>
- </method>
- <method name="playlistTracks">
- <arg type="as" direction="out"/>
- <arg name="playlist" type="s" direction="in"/>
- </method>
- <method name="trackProperty">
- <arg type="s" direction="out"/>
- <arg name="file" type="s" direction="in"/>
- <arg name="property" type="s" direction="in"/>
- </method>
- <method name="createPlaylist">
- <arg name="name" type="s" direction="in"/>
- </method>
- <method name="setPlaylist">
- <arg name="name" type="s" direction="in"/>
- </method>
- <method name="remove">
- </method>
- <method name="removeTrack">
- <arg name="playlist" type="s" direction="in"/>
- <arg name="files" type="as" direction="in"/>
- </method>
- <method name="trackCover">
- <arg type="s" direction="out"/>
- <arg name="track" type="s" direction="in"/>
- </method>
- </interface>
-</node>
+++ /dev/null
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.kde.juk.player">
- <method name="playing">
- <arg type="b" direction="out"/>
- </method>
- <method name="paused">
- <arg type="b" direction="out"/>
- </method>
- <method name="volume">
- <arg type="d" direction="out"/>
- </method>
- <method name="status">
- <arg type="i" direction="out"/>
- </method>
- <method name="trackProperties">
- <arg type="as" direction="out"/>
- </method>
- <method name="trackProperty">
- <arg type="s" direction="out"/>
- <arg name="property" type="s" direction="in"/>
- </method>
- <method name="play"/>
- <method name="play">
- <arg name="file" type="s" direction="in"/>
- </method>
- <method name="pause"/>
- <method name="stop"/>
- <method name="playPause"/>
- <method name="back"/>
- <method name="forward"/>
- <method name="seekBack"/>
- <method name="seekForward"/>
- <method name="volumeUp"/>
- <method name="volumeDown"/>
- <method name="mute"/>
- <method name="setVolume">
- <arg name="volume" type="d" direction="in"/>
- </method>
- <!-- I can't make this work reliably, so remove the capability
- <method name="seek">
- <arg name="time" type="i" direction="in"/>
- </method>-->
- <method name="playingString">
- <arg type="s" direction="out"/>
- </method>
- <method name="currentTime">
- <arg type="i" direction="out"/>
- </method>
- <method name="totalTime">
- <arg type="i" direction="out"/>
- </method>
- <method name="currentTimeMSecs">
- <arg type="i" direction="out"/>
- </method>
- <method name="totalTimeMSecs">
- <arg type="i" direction="out"/>
- </method>
- <method name="randomPlayMode">
- <arg type="s" direction="out"/>
- </method>
- <method name="setRandomPlayMode">
- <arg name="randomMode" type="s" direction="in"/>
- </method>
- </interface>
-</node>
+++ /dev/null
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.kde.juk.search">
- <method name="searchText">
- <arg type="s" direction="out"/>
- </method>
- <method name="setSearchText">
- <arg name="text" type="s" direction="in"/>
- </method>
- </interface>
-</node>
+++ /dev/null
-
-install( FILES theme.svg playing.png splash.png DESTINATION ${DATA_INSTALL_DIR}/juk/pics )
-
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<!-- Manually reduced from Amarok's default-theme-clean.svg by
- Michael Pyne <mpyne@kde.org>.
- The original license is the GNU GPL v2 (based on the COPYING file in the
- Amarok source)
- -->
-
-<svg
- xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
- xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="2551.1226"
- height="1380.9272"
- id="svg6830"
- sodipodi:version="0.32"
- inkscape:version="0.47 r22583"
- version="1.0"
- sodipodi:docname="juk-theme.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape">
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- gridtolerance="10000"
- guidetolerance="10"
- objecttolerance="10"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="1.4142136"
- inkscape:cx="2035.649"
- inkscape:cy="223.19126"
- inkscape:document-units="px"
- inkscape:current-layer="PLAYpause"
- showgrid="true"
- inkscape:window-width="1204"
- inkscape:window-height="922"
- inkscape:window-x="180"
- inkscape:window-y="154"
- inkscape:window-maximized="0"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid11130"
- empspacing="5"
- visible="true"
- enabled="true"
- snapvisiblegridlinesonly="true" />
- </sodipodi:namedview>
- <defs
- id="defs6832">
- <linearGradient
- id="linearGradient5851-1">
- <stop
- id="stop5853-5"
- offset="0"
- style="stop-color:#000000;stop-opacity:0.44705883;" />
- <stop
- style="stop-color:#000000;stop-opacity:0.22134387;"
- offset="0.09"
- id="stop5855-9" />
- <stop
- id="stop5857-8"
- offset="1"
- style="stop-color:#000000;stop-opacity:0.08695652" />
- </linearGradient>
- <linearGradient
- y2="1002.8258"
- x2="-131.98988"
- y1="987.82581"
- x1="-131.98988"
- gradientTransform="translate(25,64.989702)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient11679"
- xlink:href="#linearGradient5851-1"
- inkscape:collect="always" />
- <linearGradient
- y2="1002.8258"
- x2="-131.98988"
- y1="987.82581"
- x1="-131.98988"
- gradientTransform="matrix(-1,0,0,1,-3.97976,64.989744)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient11720"
- xlink:href="#linearGradient5851-1"
- inkscape:collect="always" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5851-1"
- id="linearGradient11884"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.33333333,0,0,0.33333289,-82.993253,750.21083)"
- x1="-86.989883"
- y1="1012.8258"
- x2="-86.989883"
- y2="982.82581" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5851-1"
- id="linearGradient4559"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(-0.33333333,0,0,0.33333289,95.01349,750.21083)"
- x1="-86.989883"
- y1="1012.8258"
- x2="-86.989883"
- y2="982.82581" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient5851-1"
- id="linearGradient11898"
- x1="730"
- y1="1220.9272"
- x2="730"
- y2="1235.9272"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(23.5,0,0,1,-17144.49,-168.10144)" />
- <linearGradient
- y2="1235.9272"
- x2="730"
- y1="1220.9272"
- x1="730"
- gradientTransform="matrix(23.5,0,0,0.6666667,-17149.49,-1901.7773)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient11921"
- xlink:href="#linearGradient5851-1"
- inkscape:collect="always" />
- <linearGradient
- id="linearGradient6773">
- <stop
- id="stop6775"
- offset="0"
- style="stop-color:#000000;stop-opacity:1;" />
- <stop
- id="stop6777"
- offset="1"
- style="stop-color:#000000;stop-opacity:0;" />
- </linearGradient>
- <radialGradient
- r="19"
- fy="124"
- fx="885"
- cy="124"
- cx="885"
- gradientTransform="matrix(0.999999,2.0609768e-7,-2.0609785e-7,0.9999998,9.2955617e-4,-1.647123e-4)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient8574"
- xlink:href="#linearGradient6773"
- inkscape:collect="always" />
- <linearGradient
- id="linearGradient3958">
- <stop
- id="stop3960"
- offset="0"
- style="stop-color:#ffffff;stop-opacity:1;" />
- <stop
- id="stop3962"
- offset="1"
- style="stop-color:#000000;stop-opacity:1;" />
- </linearGradient>
- <radialGradient
- r="19"
- fy="124"
- fx="885"
- cy="124"
- cx="885"
- gradientTransform="matrix(0.999999,2.0609768e-7,-2.0609785e-7,0.9999998,9.2955617e-4,-1.647123e-4)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient8574"
- xlink:href="#linearGradient6773"
- inkscape:collect="always" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3958"
- id="linearGradient6743"
- gradientUnits="userSpaceOnUse"
- x1="891.17303"
- y1="143.45389"
- x2="891.17303"
- y2="104.99113" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3958"
- id="linearGradient6745"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)"
- x1="904"
- y1="105"
- x2="904"
- y2="186.5" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient9636"
- id="radialGradient9674"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.39473645,8.1354347e-8,-8.1354416e-8,0.39473676,565.65826,1269.4798)"
- cx="885"
- cy="124"
- fx="885"
- fy="124"
- r="19" />
- <linearGradient
- id="linearGradient9636">
- <stop
- style="stop-color:#66ffff;stop-opacity:1;"
- offset="0"
- id="stop9638" />
- <stop
- style="stop-color:#66ffff;stop-opacity:0.39215687;"
- offset="1"
- id="stop9640" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3958"
- id="linearGradient9909"
- gradientUnits="userSpaceOnUse"
- x1="891.17303"
- y1="142.29079"
- x2="891.17303"
- y2="103.73747" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3958"
- id="linearGradient9911"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)"
- x1="904"
- y1="110.16653"
- x2="904"
- y2="167.90259" />
- </defs>
- <metadata
- id="metadata6835">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(846.98988,218.10144)">
-
- <path
- style="opacity:0.54000004999999995;fill:url(#linearGradient11679);fill-opacity:1.0;fill-rule:nonzero"
- d="m -116.48988,1052.8258 c -3.047,0 -5.5,2.6455 -5.5,5 l 0,5.75 c 0,2.3545 2.453,4.25 5.5,4.25 l 9.5,0 0,-15 -9.5,0 z"
- id="progress_slider_left"
- sodipodi:nodetypes="ccccccc">
- <title
- id="title11743"
- style="fill-opacity:1.0">progress_slider_left</title>
- </path>
- <path
- style="opacity:0.54000005;fill:url(#linearGradient11720);fill-opacity:1;fill-rule:nonzero"
- d="m 137.51012,1052.8258 c 3.047,0 5.5,1.8955 5.5,4.25 l 0,6.5 c 0,2.3545 -2.453,4.25 -5.5,4.25 l -9.5,0 0,-15 9.5,0 z"
- id="progress_slider_right">
- <title
- id="title11745">progress_slider_right</title>
- </path>
- <path
- style="opacity:0.7;fill:url(#linearGradient11884);fill-opacity:1;fill-rule:nonzero"
- d="m -116.98988,1077.8258 c -2.77,0 -5,2.23 -5,5 0,2.77 2.23,5 5,5 l 5,0 0,-10 -5,0 z m 0,1.6667 c 1.84095,0 3.33333,1.4924 3.33333,3.3333 0,1.8409 -1.49238,3.3333 -3.33333,3.3333 -1.84095,0 -3.33333,-1.4924 -3.33333,-3.3333 0,-1.8409 1.49238,-3.3333 3.33333,-3.3333 z"
- id="progress_slider_played_left">
- <title
- id="title11886"
- style="fill-opacity:1.0">progress_slider_played_left</title>
- </path>
- <path
- id="progress_slider_played_right"
- d="m 129.01012,1077.8258 c 2.77,0 5,2.23 5,5 0,2.77 -2.23,5 -5,5 l -5,0 0,-10 5,0 z m 0,1.6667 c -1.84095,0 -3.33333,1.4924 -3.33333,3.3333 0,1.8409 1.49238,3.3333 3.33333,3.3333 1.84095,0 3.33333,-1.4924 3.33333,-3.3333 0,-1.8409 -1.49238,-3.3333 -3.33333,-3.3333 z"
- style="opacity:0.7;fill:url(#linearGradient4559);fill-opacity:1;fill-rule:nonzero">
- <title
- id="title4557">progress_slider_played_left</title>
- </path>
- <rect
- style="opacity:0.54000005;fill:url(#linearGradient11898);fill-opacity:1;fill-rule:nonzero"
- id="progress_slider_mid"
- width="235"
- height="15"
- x="-106.98988"
- y="1052.8258">
- <title
- id="title11900">progress_slider_mid</title>
- </rect>
- <rect
- style="opacity:0.7;fill:url(#linearGradient11921);fill-opacity:1;fill-rule:nonzero"
- id="progress_slider_played_mid"
- width="235"
- height="10"
- x="-111.98988"
- y="-1087.8258"
- transform="scale(1,-1)">
- <title
- id="title11900-9"
- style="fill-opacity:1.0">progress_slider_played_mid</title>
- </rect>
- <g
- transform="matrix(0.8004071,0,0,0.8004071,-125.86255,1093.7014)"
- id="slider_knob_200911">
- <path
- transform="matrix(0.4931701,0,0,0.4931701,-219.22524,-52.876797)"
- d="m 904,124 c 0,10.49341 -8.50659,19 -19,19 -10.49341,0 -19,-8.50659 -19,-19 0,-10.49341 8.50659,-19 19,-19 10.49341,0 19,8.50659 19,19 z"
- sodipodi:ry="19"
- sodipodi:rx="19"
- sodipodi:cy="124"
- sodipodi:cx="885"
- id="path6791"
- style="opacity:0.75609753;fill:url(#radialGradient8574);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <g
- transform="matrix(1.0120555,0,0,1.0120555,22.919418,3.4559159)"
- id="g6725">
- <path
- sodipodi:type="arc"
- style="fill:#f0f0f0;fill-opacity:1;stroke:none"
- id="path9913"
- sodipodi:cx="885"
- sodipodi:cy="124"
- sodipodi:rx="19"
- sodipodi:ry="19"
- d="m 904,124 c 0,10.49341 -8.50659,19 -19,19 -10.49341,0 -19,-8.50659 -19,-19 0,-10.49341 8.50659,-19 19,-19 10.49341,0 19,8.50659 19,19 z"
- transform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)" />
- <path
- transform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)"
- d="m 904,124 c 0,10.49341 -8.50659,19 -19,19 -10.49341,0 -19,-8.50659 -19,-19 0,-10.49341 8.50659,-19 19,-19 10.49341,0 19,8.50659 19,19 z"
- sodipodi:ry="19"
- sodipodi:rx="19"
- sodipodi:cy="124"
- sodipodi:cx="885"
- id="path3538"
- style="opacity:0.25;fill:url(#linearGradient6743);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- id="path8715"
- d="m 191.98562,-2.5499892 c -4.09036,0 -7.40626,3.3159032 -7.40626,7.4062751 0,4.0903732 3.3159,7.4062741 7.40626,7.4062741 4.09038,0 7.40629,-3.3159009 7.40629,-7.4062741 0,-4.0903719 -3.31591,-7.4062751 -7.40629,-7.4062751 z m 0,0.718702 c 3.69676,0 6.68759,2.990829 6.68759,6.6875731 0,3.696743 -2.99083,6.6997561 -6.68759,6.6997561 -3.69673,0 -6.69973,-3.0030131 -6.69973,-6.6997561 0,-3.6967441 3.003,-6.6875731 6.69973,-6.6875731 z"
- style="fill:url(#linearGradient6745);fill-opacity:1;stroke:none" />
- </g>
- </g>
- <g
- transform="matrix(0.8004071,0,0,0.80040708,-152.29776,1098.9362)"
- id="slider_knob_200911_active">
- <path
- style="opacity:0.6;fill:url(#radialGradient9674);fill-opacity:1;stroke:none"
- d="M 915 1310.9375 C 910.85786 1310.9375 907.5 1314.2954 907.5 1318.4375 C 907.5 1322.5796 910.85786 1325.9375 915 1325.9375 C 919.14214 1325.9375 922.5 1322.5796 922.5 1318.4375 C 922.5 1314.2954 919.14214 1310.9375 915 1310.9375 z "
- id="path9228"
- transform="matrix(1.2493642,0,0,1.2493643,-867.92349,-1645.4598)" />
- <g
- id="g9246"
- transform="matrix(1.0120555,0,0,1.0119205,81.027658,-3.1233233)">
- <path
- transform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)"
- d="m 904,124 c 0,10.49341 -8.50659,19 -19,19 -10.49341,0 -19,-8.50659 -19,-19 0,-10.49341 8.50659,-19 19,-19 10.49341,0 19,8.50659 19,19 z"
- sodipodi:ry="19"
- sodipodi:rx="19"
- sodipodi:cy="124"
- sodipodi:cx="885"
- id="path9907"
- style="fill:#f0f0f0;fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="opacity:0.25;fill:url(#linearGradient9909);fill-opacity:1;stroke:none"
- id="path9248"
- sodipodi:cx="885"
- sodipodi:cy="124"
- sodipodi:rx="19"
- sodipodi:ry="19"
- d="m 904,124 c 0,10.49341 -8.50659,19 -19,19 -10.49341,0 -19,-8.50659 -19,-19 0,-10.49341 8.50659,-19 19,-19 10.49341,0 19,8.50659 19,19 z"
- transform="matrix(0.3898039,0,0,0.3898039,-152.99205,-43.476187)" />
- <path
- style="opacity:0.75;fill:url(#linearGradient9911);fill-opacity:1;stroke:none"
- d="m 191.98562,-2.5499892 c -4.09036,0 -7.40626,3.3159032 -7.40626,7.4062751 0,4.0903732 3.3159,7.4062741 7.40626,7.4062741 4.09038,0 7.40629,-3.3159009 7.40629,-7.4062741 0,-4.0903719 -3.31591,-7.4062751 -7.40629,-7.4062751 z m 0,0.718702 c 3.69676,0 6.68759,2.990829 6.68759,6.6875731 0,3.696743 -2.99083,6.6997561 -6.68759,6.6997561 -3.69673,0 -6.69973,-3.0030131 -6.69973,-6.6997561 0,-3.6967441 3.003,-6.6875731 6.69973,-6.6875731 z"
- id="path9250" />
- </g>
- </g>
- </g>
-</svg>
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
- * Copyright (C) 2008, 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playermanager.h"
-
-#include <kdebug.h>
-#include <kmessagebox.h>
-#include <klocale.h>
-#include <kactioncollection.h>
-#include <kselectaction.h>
-#include <ktoggleaction.h>
-#include <kurl.h>
-
-#include <Phonon/AudioOutput>
-#include <Phonon/MediaObject>
-#include <Phonon/VolumeFaderEffect>
-
-#include <QPixmap>
-#include <QTimer>
-
-#include <math.h>
-
-#include "playlistinterface.h"
-#include "playeradaptor.h"
-#include "slideraction.h"
-#include "statuslabel.h"
-#include "actioncollection.h"
-#include "collectionlist.h"
-#include "coverinfo.h"
-#include "tag.h"
-#include "scrobbler.h"
-#include "juk.h"
-
-using namespace ActionCollection;
-
-enum PlayerManagerStatus { StatusStopped = -1, StatusPaused = 1, StatusPlaying = 2 };
-
-////////////////////////////////////////////////////////////////////////////////
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
-PlayerManager::PlayerManager() :
- QObject(),
- m_playlistInterface(0),
- m_statusLabel(0),
- m_setup(false),
- m_crossfadeTracks(true),
- m_curOutputPath(0)
-{
-// This class is the first thing constructed during program startup, and
-// therefore has no access to the widgets needed by the setup() method.
-// Since the setup() method will be called indirectly by the player() method
-// later, just disable it here. -- mpyne
-// setup();
- new PlayerAdaptor( this );
-}
-
-PlayerManager::~PlayerManager()
-{
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-bool PlayerManager::playing() const
-{
- if(!m_setup)
- return false;
-
- Phonon::State state = m_media[m_curOutputPath]->state();
- return (state == Phonon::PlayingState || state == Phonon::BufferingState);
-}
-
-bool PlayerManager::paused() const
-{
- if(!m_setup)
- return false;
-
- return m_media[m_curOutputPath]->state() == Phonon::PausedState;
-}
-
-bool PlayerManager::muted() const
-{
- if(!m_setup)
- return false;
-
- return m_output[m_curOutputPath]->isMuted();
-}
-
-float PlayerManager::volume() const
-{
- if(!m_setup)
- return 1.0;
-
- return m_output[m_curOutputPath]->volume();
-}
-
-int PlayerManager::status() const
-{
- if(!m_setup)
- return StatusStopped;
-
- if(paused())
- return StatusPaused;
-
- if(playing())
- return StatusPlaying;
-
- return 0;
-}
-
-int PlayerManager::totalTime() const
-{
- return totalTimeMSecs() / 1000;
-}
-
-int PlayerManager::currentTime() const
-{
- return currentTimeMSecs() / 1000;
-}
-
-int PlayerManager::totalTimeMSecs() const
-{
- if(!m_setup)
- return 0;
-
- return m_media[m_curOutputPath]->totalTime();
-}
-
-int PlayerManager::currentTimeMSecs() const
-{
- if(!m_setup)
- return 0;
-
- return m_media[m_curOutputPath]->currentTime();
-}
-
-bool PlayerManager::seekable() const
-{
- if(!m_setup)
- return false;
-
- return m_media[m_curOutputPath]->isSeekable();
-}
-
-QStringList PlayerManager::trackProperties()
-{
- return FileHandle::properties();
-}
-
-QString PlayerManager::trackProperty(const QString &property) const
-{
- if(!playing() && !paused())
- return QString();
-
- return m_file.property(property);
-}
-
-QPixmap PlayerManager::trackCover(const QString &size) const
-{
- if(!playing() && !paused())
- return QPixmap();
-
- if(size.toLower() == "small")
- return m_file.coverInfo()->pixmap(CoverInfo::Thumbnail);
- if(size.toLower() == "large")
- return m_file.coverInfo()->pixmap(CoverInfo::FullSize);
-
- return QPixmap();
-}
-
-FileHandle PlayerManager::playingFile() const
-{
- return m_file;
-}
-
-QString PlayerManager::playingString() const
-{
- if(!playing() || m_file.isNull())
- return QString();
-
- return m_file.tag()->playingString();
-}
-
-void PlayerManager::setPlaylistInterface(PlaylistInterface *interface)
-{
- m_playlistInterface = interface;
-}
-
-void PlayerManager::setStatusLabel(StatusLabel *label)
-{
- m_statusLabel = label;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlayerManager::play(const FileHandle &file)
-{
- if(!m_setup)
- setup();
-
- if(!m_media[0] || !m_media[1] || !m_playlistInterface)
- return;
-
- stopCrossfade();
-
- // The "currently playing" media object.
- Phonon::MediaObject *mediaObject = m_media[m_curOutputPath];
-
- if(file.isNull()) {
- if(paused())
- mediaObject->play();
- else if(playing()) {
- mediaObject->seek(0);
- emit seeked(0);
- }
- else {
- m_playlistInterface->playNext();
- m_file = m_playlistInterface->currentFile();
-
- if(!m_file.isNull())
- {
- mediaObject->setCurrentSource(KUrl::fromPath(m_file.absFilePath()));
- mediaObject->play();
-
- emit signalItemChanged(m_file);
- }
- }
- }
- else {
- mediaObject->setCurrentSource(KUrl::fromPath(file.absFilePath()));
- mediaObject->play();
-
- if(m_file != file)
- emit signalItemChanged(file);
-
- m_file = file;
- }
-
- // Our state changed handler will perform the follow up actions necessary
- // once we actually start playing.
-}
-
-void PlayerManager::play(const QString &file)
-{
- CollectionListItem *item = CollectionList::instance()->lookup(file);
- if(item) {
- Playlist::setPlaying(item);
- play(item->file());
- }
-}
-
-void PlayerManager::play()
-{
- play(FileHandle::null());
-}
-
-void PlayerManager::pause()
-{
- if(!m_setup)
- return;
-
- if(paused()) {
- play();
- return;
- }
-
- action("pause")->setEnabled(false);
-
- m_media[m_curOutputPath]->pause();
-}
-
-void PlayerManager::stop()
-{
- if(!m_setup || !m_playlistInterface)
- return;
-
- action("pause")->setEnabled(false);
- action("stop")->setEnabled(false);
- action("back")->setEnabled(false);
- action("forward")->setEnabled(false);
- action("forwardAlbum")->setEnabled(false);
-
- // Fading out playback is for chumps.
- stopCrossfade();
- m_media[0]->stop();
- m_media[1]->stop();
-
- if(!m_file.isNull()) {
- m_file = FileHandle::null();
- emit signalItemChanged(m_file);
- }
-}
-
-void PlayerManager::setVolume(float volume)
-{
- if(!m_setup)
- setup();
-
- m_output[0]->setVolume(volume);
- m_output[1]->setVolume(volume);
-}
-
-void PlayerManager::seek(int seekTime)
-{
- if(!m_setup || m_media[m_curOutputPath]->currentTime() == seekTime)
- return;
-
- kDebug() << "Stopping crossfade to seek from" << m_media[m_curOutputPath]->currentTime()
- << "to" << seekTime;
- stopCrossfade();
- m_media[m_curOutputPath]->seek(seekTime);
- emit seeked(seekTime);
-}
-
-void PlayerManager::seekForward()
-{
- Phonon::MediaObject *mediaObject = m_media[m_curOutputPath];
- const qint64 total = mediaObject->totalTime();
- const qint64 newtime = mediaObject->currentTime() + total / 100;
- const qint64 seekTo = qMin(total, newtime);
-
- stopCrossfade();
- mediaObject->seek(seekTo);
- emit seeked(seekTo);
-}
-
-void PlayerManager::seekBack()
-{
- Phonon::MediaObject *mediaObject = m_media[m_curOutputPath];
- const qint64 total = mediaObject->totalTime();
- const qint64 newtime = mediaObject->currentTime() - total / 100;
- const qint64 seekTo = qMax(qint64(0), newtime);
-
- stopCrossfade();
- mediaObject->seek(seekTo);
- emit seeked(seekTo);
-}
-
-void PlayerManager::playPause()
-{
- playing() ? action("pause")->trigger() : action("play")->trigger();
-}
-
-void PlayerManager::forward()
-{
- m_playlistInterface->playNext();
- FileHandle file = m_playlistInterface->currentFile();
-
- if(!file.isNull())
- play(file);
- else
- stop();
-}
-
-void PlayerManager::back()
-{
- m_playlistInterface->playPrevious();
- FileHandle file = m_playlistInterface->currentFile();
-
- if(!file.isNull())
- play(file);
- else
- stop();
-}
-
-void PlayerManager::volumeUp()
-{
- if(!m_setup)
- return;
-
- setVolume(volume() + 0.04); // 4% up
-}
-
-void PlayerManager::volumeDown()
-{
- if(!m_output)
- return;
-
- setVolume(volume() - 0.04); // 4% down
-}
-
-void PlayerManager::setMuted(bool m)
-{
- if(!m_setup)
- return;
-
- m_output[m_curOutputPath]->setMuted(m);
-}
-
-bool PlayerManager::mute()
-{
- if(!m_setup)
- return false;
-
- bool newState = !muted();
- setMuted(newState);
- return newState;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlayerManager::slotNeedNextUrl()
-{
- if(m_file.isNull() || !m_crossfadeTracks)
- return;
-
- m_playlistInterface->playNext();
- FileHandle nextFile = m_playlistInterface->currentFile();
-
- if(!nextFile.isNull()) {
- m_file = nextFile;
- crossfadeToFile(m_file);
- }
-}
-
-void PlayerManager::slotFinished()
-{
- // It is possible to end up in this function if a file simply fails to play or if the
- // user moves the slider all the way to the end, therefore see if we can keep playing
- // and if we can, do so. Otherwise, stop. Note that this slot should
- // only be called by the currently "main" output path (i.e. not from the
- // crossfading one). However life isn't always so nice apparently, so do some
- // sanity-checking.
-
- Phonon::MediaObject *mediaObject = qobject_cast<Phonon::MediaObject *>(sender());
- if(mediaObject != m_media[m_curOutputPath])
- return;
-
- m_playlistInterface->playNext();
- m_file = m_playlistInterface->currentFile();
-
- if(m_file.isNull()) {
- stop();
- }
- else {
- emit signalItemChanged(m_file);
- m_media[m_curOutputPath]->setCurrentSource(QUrl::fromLocalFile(m_file.absFilePath()));
- m_media[m_curOutputPath]->play();
- }
-}
-
-void PlayerManager::slotLength(qint64 msec)
-{
- m_statusLabel->setItemTotalTime(msec / 1000);
- emit totalTimeChanged(msec);
-}
-
-void PlayerManager::slotTick(qint64 msec)
-{
- if(!m_setup || !m_playlistInterface)
- return;
-
- if(m_statusLabel)
- m_statusLabel->setItemCurrentTime(msec / 1000);
-
- emit tick(msec);
-}
-
-void PlayerManager::slotStateChanged(Phonon::State newstate, Phonon::State oldstate)
-{
- // Use sender() since either media object may have sent the signal.
- Phonon::MediaObject *mediaObject = qobject_cast<Phonon::MediaObject *>(sender());
- if(!mediaObject)
- return;
-
- // Handle errors for either media object
- if(newstate == Phonon::ErrorState) {
- QString errorMessage =
- i18nc(
- "%1 will be the /path/to/file, %2 will be some string from Phonon describing the error",
- "JuK is unable to play the audio file<nl/><filename>%1</filename><nl/>"
- "for the following reason:<nl/><message>%2</message>",
- m_file.absFilePath(),
- mediaObject->errorString()
- );
-
- switch(mediaObject->errorType()) {
- case Phonon::NoError:
- kDebug() << "received a state change to ErrorState but errorType is NoError!?";
- break;
-
- case Phonon::NormalError:
- forward();
- KMessageBox::information(0, errorMessage);
- break;
-
- case Phonon::FatalError:
- stop();
- KMessageBox::sorry(0, errorMessage);
- break;
- }
- }
-
- // Now bail out if we're not dealing with the currently playing media
- // object.
-
- if(mediaObject != m_media[m_curOutputPath])
- return;
-
- // Handle state changes for the playing media object.
- if(newstate == Phonon::StoppedState && oldstate != Phonon::LoadingState) {
- // If this occurs it should be due to a transitory shift (i.e. playing a different
- // song when one is playing now), since it didn't occur in the error handler. Just
- // in case we really did abruptly stop, handle that case in a couple of seconds.
- QTimer::singleShot(2000, this, SLOT(slotUpdateGuiIfStopped()));
-
- JuK::JuKInstance()->setWindowTitle(i18n("JuK"));
-
- emit signalStop();
- }
- else if(newstate == Phonon::PausedState) {
- emit signalPause();
- }
- else { // PlayingState or BufferingState
- action("pause")->setEnabled(true);
- action("stop")->setEnabled(true);
- action("forward")->setEnabled(true);
- if(action<KToggleAction>("albumRandomPlay")->isChecked())
- action("forwardAlbum")->setEnabled(true);
- action("back")->setEnabled(true);
-
- JuK::JuKInstance()->setWindowTitle(i18nc(
- "%1 is the artist and %2 is the title of the currently playing track.",
- "%1 - %2 :: JuK",
- m_file.tag()->artist(),
- m_file.tag()->title()));
-
- emit signalPlay();
- }
-}
-
-void PlayerManager::slotSeekableChanged(bool isSeekable)
-{
- // Use sender() since either media object may have sent the signal.
- Phonon::MediaObject *mediaObject = qobject_cast<Phonon::MediaObject *>(sender());
- if(!mediaObject)
- return;
- if(mediaObject != m_media[m_curOutputPath])
- return;
-
- emit seekableChanged(isSeekable);
-}
-
-void PlayerManager::slotMutedChanged(bool muted)
-{
- // Use sender() since either output object may have sent the signal.
- Phonon::AudioOutput *output = qobject_cast<Phonon::AudioOutput *>(sender());
- if(!output)
- return;
-
- if(output != m_output[m_curOutputPath])
- return;
-
- emit mutedChanged(muted);
-}
-
-void PlayerManager::slotVolumeChanged(qreal volume)
-{
- // Use sender() since either output object may have sent the signal.
- Phonon::AudioOutput *output = qobject_cast<Phonon::AudioOutput *>(sender());
- if(!output)
- return;
-
- if(output != m_output[m_curOutputPath])
- return;
-
- emit volumeChanged(volume);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-void PlayerManager::setup()
-{
- // All of the actions required by this class should be listed here.
-
- if(!action("pause") ||
- !action("stop") ||
- !action("back") ||
- !action("forwardAlbum") ||
- !action("forward") ||
- !action("trackPositionAction"))
- {
- kWarning() << "Could not find all of the required actions.";
- return;
- }
-
- if(m_setup)
- return;
- m_setup = true;
-
- // We use two audio paths at all times to make cross fading easier (and to also easily
- // support not using cross fading with the same code). The currently playing audio
- // path is controlled using m_curOutputPath.
-
- for(int i = 0; i < 2; ++i) {
- m_output[i] = new Phonon::AudioOutput(Phonon::MusicCategory, this);
- connect(m_output[i], SIGNAL(mutedChanged(bool)), SLOT(slotMutedChanged(bool)));
- connect(m_output[i], SIGNAL(volumeChanged(qreal)), SLOT(slotVolumeChanged(qreal)));
-
- m_media[i] = new Phonon::MediaObject(this);
- m_audioPath[i] = Phonon::createPath(m_media[i], m_output[i]);
- m_media[i]->setTickInterval(200);
- m_media[i]->setPrefinishMark(2000);
-
- // Pre-cache a volume fader object
- m_fader[i] = new Phonon::VolumeFaderEffect(m_media[i]);
- m_audioPath[i].insertEffect(m_fader[i]);
- m_fader[i]->setVolume(1.0f);
-
- connect(m_media[i], SIGNAL(stateChanged(Phonon::State,Phonon::State)), SLOT(slotStateChanged(Phonon::State,Phonon::State)));
- connect(m_media[i], SIGNAL(prefinishMarkReached(qint32)), SLOT(slotNeedNextUrl()));
- connect(m_media[i], SIGNAL(totalTimeChanged(qint64)), SLOT(slotLength(qint64)));
- connect(m_media[i], SIGNAL(tick(qint64)), SLOT(slotTick(qint64)));
- connect(m_media[i], SIGNAL(finished()), SLOT(slotFinished()));
- connect(m_media[i], SIGNAL(seekableChanged(bool)), SLOT(slotSeekableChanged(bool)));
- }
-
- // initialize action states
-
- action("pause")->setEnabled(false);
- action("stop")->setEnabled(false);
- action("back")->setEnabled(false);
- action("forward")->setEnabled(false);
- action("forwardAlbum")->setEnabled(false);
-
- QDBusConnection::sessionBus().registerObject("/Player", this);
-}
-
-void PlayerManager::slotUpdateGuiIfStopped()
-{
- if(m_media[0]->state() == Phonon::StoppedState && m_media[1]->state() == Phonon::StoppedState)
- stop();
-}
-
-void PlayerManager::crossfadeToFile(const FileHandle &newFile)
-{
- int nextOutputPath = 1 - m_curOutputPath;
-
- // Don't need this anymore
- disconnect(m_media[m_curOutputPath], SIGNAL(finished()), this, 0);
- connect(m_media[nextOutputPath], SIGNAL(finished()), SLOT(slotFinished()));
-
- m_fader[nextOutputPath]->setVolume(0.0f);
-
- emit signalItemChanged(newFile);
- m_media[nextOutputPath]->setCurrentSource(QUrl::fromLocalFile(newFile.absFilePath()));
- m_media[nextOutputPath]->play();
-
- m_fader[m_curOutputPath]->setVolume(1.0f);
- m_fader[m_curOutputPath]->fadeTo(0.0f, 2000);
-
- m_fader[nextOutputPath]->fadeTo(1.0f, 2000);
-
- m_curOutputPath = nextOutputPath;
-}
-
-void PlayerManager::stopCrossfade()
-{
- // According to the Phonon docs, setVolume immediately takes effect,
- // which is "good enough for government work" ;)
-
- // 1 - curOutputPath is the other output path...
- m_fader[m_curOutputPath]->setVolume(1.0f);
- m_fader[1 - m_curOutputPath]->setVolume(0.0f);
-
- // We don't actually need to physically stop crossfading as the playback
- // code will call ->play() when necessary anyways. If we hit stop()
- // here instead of pause() then we will trick our stateChanged handler
- // into thinking Phonon had a spurious stop and we'll switch tracks
- // unnecessarily. (This isn't a problem after crossfade completes due to
- // the signals being disconnected).
-
- m_media[1 - m_curOutputPath]->pause();
-}
-
-QString PlayerManager::randomPlayMode() const
-{
- if(action<KToggleAction>("randomPlay")->isChecked())
- return "Random";
- if(action<KToggleAction>("albumRandomPlay")->isChecked())
- return "AlbumRandom";
- return "NoRandom";
-}
-
-void PlayerManager::setCrossfadeEnabled(bool crossfadeEnabled)
-{
- m_crossfadeTracks = crossfadeEnabled;
-}
-
-void PlayerManager::setRandomPlayMode(const QString &randomMode)
-{
- if(randomMode.toLower() == "random")
- action<KToggleAction>("randomPlay")->setChecked(true);
- if(randomMode.toLower() == "albumrandom")
- action<KToggleAction>("albumRandomPlay")->setChecked(true);
- if(randomMode.toLower() == "norandom")
- action<KToggleAction>("disableRandomPlay")->setChecked(true);
-}
-
-#include "playermanager.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
- * Copyright (C) 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYERMANAGER_H
-#define PLAYERMANAGER_H
-
-#include <QObject>
-
-#include "filehandle.h"
-
-#include <Phonon/Global>
-#include <Phonon/Path>
-
-class KSelectAction;
-class StatusLabel;
-class PlaylistInterface;
-class QPixmap;
-
-namespace Phonon
-{
- class AudioOutput;
- class MediaObject;
- class VolumeFaderEffect;
-}
-
-/**
- * This class serves as a proxy to the Player interface and handles managing
- * the actions from the top-level mainwindow.
- */
-
-class PlayerManager : public QObject
-{
- Q_OBJECT
-
-public:
- PlayerManager();
- virtual ~PlayerManager();
-
- bool playing() const;
- bool paused() const;
- bool muted() const;
- float volume() const;
- int status() const;
-
- // These two have been part of the prior public DBus interface so they have
- // been retained. You should use the MSecs versions below. These return in units
- // of seconds instead.
- int totalTime() const;
- int currentTime() const;
-
- int totalTimeMSecs() const;
- int currentTimeMSecs() const;
-
- bool seekable() const;
- //int position() const;
-
- QStringList trackProperties();
- QString trackProperty(const QString &property) const;
- QPixmap trackCover(const QString &size) const;
-
- FileHandle playingFile() const;
- QString playingString() const;
-
- KSelectAction* outputDeviceSelectAction();
-
- void setPlaylistInterface(PlaylistInterface *interface);
- void setStatusLabel(StatusLabel *label);
-
- QString randomPlayMode() const;
-
-public slots:
- void play(const FileHandle &file);
- void play(const QString &file);
- void play();
- void pause();
- void stop();
- void setVolume(float volume = 1.0);
- void seek(int seekTime);
- //void seekPosition(int position);
- void seekForward();
- void seekBack();
- void playPause();
- void forward();
- void back();
- void volumeUp();
- void volumeDown();
- void setMuted(bool m);
- bool mute();
-
- void setRandomPlayMode(const QString &randomMode);
- void setCrossfadeEnabled(bool enableCrossfade);
-
-signals:
- void tick(int time);
- void totalTimeChanged(int time);
- void mutedChanged(bool muted);
- void volumeChanged(float volume);
- void seeked(int newPos);
- void seekableChanged(bool muted);
-
- void signalPlay();
- void signalPause();
- void signalStop();
- void signalItemChanged(const FileHandle &file);
-
-private:
- void setup();
- void crossfadeToFile(const FileHandle &newFile);
- void stopCrossfade();
-
-private slots:
- void slotNeedNextUrl();
- void slotFinished();
- void slotLength(qint64);
- void slotTick(qint64);
- void slotStateChanged(Phonon::State, Phonon::State);
- /// Updates the GUI to reflect stopped playback if we're stopped at this point.
- void slotUpdateGuiIfStopped();
- void slotSeekableChanged(bool);
- void slotMutedChanged(bool);
- void slotVolumeChanged(qreal);
-
-private:
- FileHandle m_file;
- PlaylistInterface *m_playlistInterface;
- StatusLabel *m_statusLabel;
- bool m_muted;
- bool m_setup;
- bool m_crossfadeTracks;
-
- static const int m_pollInterval = 800;
-
- int m_curOutputPath; ///< Either 0 or 1 depending on which output path is in use.
- Phonon::AudioOutput *m_output[2];
- Phonon::Path m_audioPath[2];
- Phonon::MediaObject *m_media[2];
- Phonon::VolumeFaderEffect *m_fader[2];
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlist.h"
-#include "juk-exception.h"
-
-#include <q3header.h>
-#include <kconfig.h>
-#include <kapplication.h>
-#include <kmessagebox.h>
-#include <k3urldrag.h>
-#include <kiconloader.h>
-#include <klineedit.h>
-#include <k3popupmenu.h>
-#include <klocale.h>
-#include <kdebug.h>
-#include <kfiledialog.h>
-#include <kglobalsettings.h>
-#include <kurl.h>
-#include <kio/netaccess.h>
-#include <kio/copyjob.h>
-#include <kmenu.h>
-#include <kactioncollection.h>
-#include <kconfiggroup.h>
-#include <ktoolbarpopupaction.h>
-#include <kactionmenu.h>
-#include <ktoggleaction.h>
-#include <kselectaction.h>
-
-#include <QCursor>
-#include <QDir>
-#include <QDirIterator>
-#include <QToolTip>
-#include <QFile>
-#include <QResizeEvent>
-#include <QMouseEvent>
-#include <QKeyEvent>
-#include <QMimeData>
-#include <QTimer>
-#include <QClipboard>
-#include <QTextStream>
-#include <QDropEvent>
-#include <QDragEnterEvent>
-#include <QPixmap>
-#include <QStackedWidget>
-#include <id3v1genres.h>
-
-#include <time.h>
-#include <cmath>
-
-#include "playlistitem.h"
-#include "playlistcollection.h"
-#include "playlistsearch.h"
-#include "mediafiles.h"
-#include "collectionlist.h"
-#include "filerenamer.h"
-#include "actioncollection.h"
-#include "tracksequencemanager.h"
-#include "tag.h"
-#include "k3bexporter.h"
-#include "upcomingplaylist.h"
-#include "deletedialog.h"
-#include "webimagefetcher.h"
-#include "coverinfo.h"
-#include "coverdialog.h"
-#include "tagtransactionmanager.h"
-#include "cache.h"
-
-using namespace ActionCollection;
-
-/**
- * Used to give every track added in the program a unique identifier. See
- * PlaylistItem
- */
-quint32 g_trackID = 0;
-
-/**
- * Just a shortcut of sorts.
- */
-
-static bool manualResize()
-{
- return action<KToggleAction>("resizeColumnsManually")->isChecked();
-}
-
-/**
- * A tooltip specialized to show full filenames over the file name column.
- */
-
-#ifdef __GNUC__
-#warning disabling the tooltip for now
-#endif
-#if 0
-class PlaylistToolTip : public QToolTip
-{
-public:
- PlaylistToolTip(QWidget *parent, Playlist *playlist) :
- QToolTip(parent), m_playlist(playlist) {}
-
- virtual void maybeTip(const QPoint &p)
- {
- PlaylistItem *item = static_cast<PlaylistItem *>(m_playlist->itemAt(p));
-
- if(!item)
- return;
-
- QPoint contentsPosition = m_playlist->viewportToContents(p);
-
- int column = m_playlist->header()->sectionAt(contentsPosition.x());
-
- if(column == m_playlist->columnOffset() + PlaylistItem::FileNameColumn ||
- item->cachedWidths()[column] > m_playlist->columnWidth(column) ||
- (column == m_playlist->columnOffset() + PlaylistItem::CoverColumn &&
- item->file().coverInfo()->hasCover()))
- {
- QRect r = m_playlist->itemRect(item);
- int headerPosition = m_playlist->header()->sectionPos(column);
- r.setLeft(headerPosition);
- r.setRight(headerPosition + m_playlist->header()->sectionSize(column));
-
- if(column == m_playlist->columnOffset() + PlaylistItem::FileNameColumn)
- tip(r, item->file().absFilePath());
- else if(column == m_playlist->columnOffset() + PlaylistItem::CoverColumn) {
- Q3MimeSourceFactory *f = Q3MimeSourceFactory::defaultFactory();
- f->setImage("coverThumb",
- QImage(item->file().coverInfo()->pixmap(CoverInfo::Thumbnail).convertToImage()));
- tip(r, "<center><img source=\"coverThumb\"/></center>");
- }
- else
- tip(r, item->text(column));
- }
- }
-
-private:
- Playlist *m_playlist;
-};
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-// Playlist::SharedSettings definition
-////////////////////////////////////////////////////////////////////////////////
-
-bool Playlist::m_visibleChanged = false;
-bool Playlist::m_shuttingDown = false;
-
-/**
- * Shared settings between the playlists.
- */
-
-class Playlist::SharedSettings
-{
-public:
- static SharedSettings *instance();
- /**
- * Sets the default column order to that of Playlist @param p.
- */
- void setColumnOrder(const Playlist *l);
- void toggleColumnVisible(int column);
- void setInlineCompletionMode(KGlobalSettings::Completion mode);
-
- /**
- * Apply the settings.
- */
- void apply(Playlist *l) const;
- void sync() { writeConfig(); }
-
-protected:
- SharedSettings();
- ~SharedSettings() {}
-
-private:
- void writeConfig();
-
- static SharedSettings *m_instance;
- QList<int> m_columnOrder;
- QVector<bool> m_columnsVisible;
- KGlobalSettings::Completion m_inlineCompletion;
-};
-
-Playlist::SharedSettings *Playlist::SharedSettings::m_instance = 0;
-
-////////////////////////////////////////////////////////////////////////////////
-// Playlist::SharedSettings public members
-////////////////////////////////////////////////////////////////////////////////
-
-Playlist::SharedSettings *Playlist::SharedSettings::instance()
-{
- static SharedSettings settings;
- return &settings;
-}
-
-void Playlist::SharedSettings::setColumnOrder(const Playlist *l)
-{
- if(!l)
- return;
-
- m_columnOrder.clear();
-
- for(int i = l->columnOffset(); i < l->columns(); ++i)
- m_columnOrder.append(l->header()->mapToIndex(i));
-
- writeConfig();
-}
-
-void Playlist::SharedSettings::toggleColumnVisible(int column)
-{
- if(column >= m_columnsVisible.size())
- m_columnsVisible.fill(true, column + 1);
-
- m_columnsVisible[column] = !m_columnsVisible[column];
-
- writeConfig();
-}
-
-void Playlist::SharedSettings::setInlineCompletionMode(KGlobalSettings::Completion mode)
-{
- m_inlineCompletion = mode;
- writeConfig();
-}
-
-
-void Playlist::SharedSettings::apply(Playlist *l) const
-{
- if(!l)
- return;
-
- int offset = l->columnOffset();
- int i = 0;
- foreach(int column, m_columnOrder)
- l->header()->moveSection(i++ + offset, column + offset);
-
- for(int i = 0; i < m_columnsVisible.size(); i++) {
- if(m_columnsVisible[i] && !l->isColumnVisible(i + offset))
- l->showColumn(i + offset, false);
- else if(!m_columnsVisible[i] && l->isColumnVisible(i + offset))
- l->hideColumn(i + offset, false);
- }
-
- l->updateLeftColumn();
- l->renameLineEdit()->setCompletionMode(m_inlineCompletion);
- l->slotColumnResizeModeChanged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Playlist::ShareSettings protected members
-////////////////////////////////////////////////////////////////////////////////
-
-Playlist::SharedSettings::SharedSettings()
-{
- KConfigGroup config(KGlobal::config(), "PlaylistShared");
-
- bool resizeColumnsManually = config.readEntry("ResizeColumnsManually", false);
- action("resizeColumnsManually")->setChecked(resizeColumnsManually);
-
- // Preallocate spaces so we don't need to check later.
- m_columnsVisible.fill(true, PlaylistItem::lastColumn() + 1);
-
- // save column order
- m_columnOrder = config.readEntry("ColumnOrder", QList<int>());
-
- QList<int> l = config.readEntry("VisibleColumns", QList<int>());
-
- if(l.isEmpty()) {
-
- // Provide some default values for column visibility if none were
- // read from the configuration file.
-
- m_columnsVisible[PlaylistItem::BitrateColumn] = false;
- m_columnsVisible[PlaylistItem::CommentColumn] = false;
- m_columnsVisible[PlaylistItem::FileNameColumn] = false;
- m_columnsVisible[PlaylistItem::FullPathColumn] = false;
- }
- else {
- // Convert the int list into a bool list.
-
- m_columnsVisible.fill(false);
- for(int i = 0; i < l.size() && i < m_columnsVisible.size(); ++i)
- m_columnsVisible[i] = bool(l[i]);
- }
-
- m_inlineCompletion = KGlobalSettings::Completion(
- config.readEntry("InlineCompletionMode", int(KGlobalSettings::CompletionAuto)));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Playlist::SharedSettings private members
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::SharedSettings::writeConfig()
-{
- KConfigGroup config(KGlobal::config(), "PlaylistShared");
- config.writeEntry("ColumnOrder", m_columnOrder);
-
- QList<int> l;
- for(int i = 0; i < m_columnsVisible.size(); i++)
- l.append(int(m_columnsVisible[i]));
-
- config.writeEntry("VisibleColumns", l);
- config.writeEntry("InlineCompletionMode", int(m_inlineCompletion));
-
- config.writeEntry("ResizeColumnsManually", manualResize());
-
- KGlobal::config()->sync();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistItemList Playlist::m_history;
-QVector<PlaylistItem *> Playlist::m_backMenuItems;
-int Playlist::m_leftColumn = 0;
-
-Playlist::Playlist(PlaylistCollection *collection, const QString &name,
- const QString &iconName) :
- K3ListView(collection->playlistStack()),
- m_collection(collection),
- m_fetcher(new WebImageFetcher(this)),
- m_selectedCount(0),
- m_allowDuplicates(false),
- m_applySharedSettings(true),
- m_columnWidthModeChanged(false),
- m_disableColumnWidthUpdates(true),
- m_time(0),
- m_widthsDirty(true),
- m_searchEnabled(true),
- m_lastSelected(0),
- m_playlistName(name),
- m_rmbMenu(0),
- m_toolTip(0),
- m_blockDataChanged(false)
-{
- setup();
- collection->setupPlaylist(this, iconName);
-}
-
-Playlist::Playlist(PlaylistCollection *collection, const PlaylistItemList &items,
- const QString &name, const QString &iconName) :
- K3ListView(collection->playlistStack()),
- m_collection(collection),
- m_fetcher(new WebImageFetcher(this)),
- m_selectedCount(0),
- m_allowDuplicates(false),
- m_applySharedSettings(true),
- m_columnWidthModeChanged(false),
- m_disableColumnWidthUpdates(true),
- m_time(0),
- m_widthsDirty(true),
- m_searchEnabled(true),
- m_lastSelected(0),
- m_playlistName(name),
- m_rmbMenu(0),
- m_toolTip(0),
- m_blockDataChanged(false)
-{
- setup();
- collection->setupPlaylist(this, iconName);
- createItems(items);
-}
-
-Playlist::Playlist(PlaylistCollection *collection, const QFileInfo &playlistFile,
- const QString &iconName) :
- K3ListView(collection->playlistStack()),
- m_collection(collection),
- m_fetcher(new WebImageFetcher(this)),
- m_selectedCount(0),
- m_allowDuplicates(false),
- m_applySharedSettings(true),
- m_columnWidthModeChanged(false),
- m_disableColumnWidthUpdates(true),
- m_time(0),
- m_widthsDirty(true),
- m_searchEnabled(true),
- m_lastSelected(0),
- m_fileName(playlistFile.canonicalFilePath()),
- m_rmbMenu(0),
- m_toolTip(0),
- m_blockDataChanged(false)
-{
- setup();
- loadFile(m_fileName, playlistFile);
- collection->setupPlaylist(this, iconName);
-}
-
-Playlist::Playlist(PlaylistCollection *collection, bool delaySetup, int extraColumns) :
- K3ListView(collection->playlistStack()),
- m_collection(collection),
- m_fetcher(new WebImageFetcher(this)),
- m_selectedCount(0),
- m_allowDuplicates(false),
- m_applySharedSettings(true),
- m_columnWidthModeChanged(false),
- m_disableColumnWidthUpdates(true),
- m_time(0),
- m_widthsDirty(true),
- m_searchEnabled(true),
- m_lastSelected(0),
- m_rmbMenu(0),
- m_toolTip(0),
- m_blockDataChanged(false)
-{
- for(int i = 0; i < extraColumns; ++i) {
- addColumn(i18n("JuK")); // Placeholder text!
- }
-
- setup();
-
- if(!delaySetup)
- collection->setupPlaylist(this, "audio-midi");
-}
-
-Playlist::~Playlist()
-{
- // In some situations the dataChanged signal from clearItems will cause observers to
- // subsequently try to access a deleted item. Since we're going away just remove all
- // observers.
-
- clearObservers();
-
- // clearItem() will take care of removing the items from the history,
- // so call clearItems() to make sure it happens.
-
- clearItems(items());
-
- /* delete m_toolTip; */
-
- if(!m_shuttingDown)
- m_collection->removePlaylist(this);
-}
-
-QString Playlist::name() const
-{
- if(m_playlistName.isEmpty())
- return m_fileName.section(QDir::separator(), -1).section('.', 0, -2);
- else
- return m_playlistName;
-}
-
-FileHandle Playlist::currentFile() const
-{
- return playingItem() ? playingItem()->file() : FileHandle::null();
-}
-
-int Playlist::time() const
-{
- // Since this method gets a lot of traffic, let's optimize for such.
-
- if(!m_addTime.isEmpty()) {
- foreach(const PlaylistItem *item, m_addTime) {
- if(item)
- m_time += item->file().tag()->seconds();
- }
-
- m_addTime.clear();
- }
-
- if(!m_subtractTime.isEmpty()) {
- foreach(const PlaylistItem *item, m_subtractTime) {
- if(item)
- m_time -= item->file().tag()->seconds();
- }
-
- m_subtractTime.clear();
- }
-
- return m_time;
-}
-
-void Playlist::playFirst()
-{
- TrackSequenceManager::instance()->setNextItem(static_cast<PlaylistItem *>(
- Q3ListViewItemIterator(const_cast<Playlist *>(this), Q3ListViewItemIterator::Visible).current()));
- action("forward")->trigger();
-}
-
-void Playlist::playNextAlbum()
-{
- PlaylistItem *current = TrackSequenceManager::instance()->currentItem();
- if(!current)
- return; // No next album if we're not already playing.
-
- QString currentAlbum = current->file().tag()->album();
- current = TrackSequenceManager::instance()->nextItem();
-
- while(current && current->file().tag()->album() == currentAlbum)
- current = TrackSequenceManager::instance()->nextItem();
-
- TrackSequenceManager::instance()->setNextItem(current);
- action("forward")->trigger();
-}
-
-void Playlist::playNext()
-{
- TrackSequenceManager::instance()->setCurrentPlaylist(this);
- setPlaying(TrackSequenceManager::instance()->nextItem());
-}
-
-void Playlist::stop()
-{
- m_history.clear();
- setPlaying(0);
-}
-
-void Playlist::playPrevious()
-{
- if(!playingItem())
- return;
-
- bool random = action("randomPlay") && action<KToggleAction>("randomPlay")->isChecked();
-
- PlaylistItem *previous = 0;
-
- if(random && !m_history.isEmpty()) {
- PlaylistItemList::Iterator last = --m_history.end();
- previous = *last;
- m_history.erase(last);
- }
- else {
- m_history.clear();
- previous = TrackSequenceManager::instance()->previousItem();
- }
-
- if(!previous)
- previous = static_cast<PlaylistItem *>(playingItem()->itemAbove());
-
- setPlaying(previous, false);
-}
-
-void Playlist::setName(const QString &n)
-{
- m_collection->addNameToDict(n);
- m_collection->removeNameFromDict(m_playlistName);
-
- m_playlistName = n;
- emit signalNameChanged(m_playlistName);
-}
-
-void Playlist::save()
-{
- if(m_fileName.isEmpty())
- return saveAs();
-
- QFile file(m_fileName);
-
- if(!file.open(QIODevice::WriteOnly))
- return KMessageBox::error(this, i18n("Could not save to file %1.", m_fileName));
-
- QTextStream stream(&file);
-
- QStringList fileList = files();
-
- foreach(const QString &file, fileList)
- stream << file << endl;
-
- file.close();
-}
-
-void Playlist::saveAs()
-{
- m_collection->removeFileFromDict(m_fileName);
-
- m_fileName = MediaFiles::savePlaylistDialog(name(), this);
-
- if(!m_fileName.isEmpty()) {
- m_collection->addFileToDict(m_fileName);
-
- // If there's no playlist name set, use the file name.
- if(m_playlistName.isEmpty())
- emit signalNameChanged(name());
- save();
- }
-}
-
-void Playlist::updateDeletedItem(PlaylistItem *item)
-{
- m_members.remove(item->file().absFilePath());
- m_search.clearItem(item);
-
- m_history.removeAll(item);
- m_addTime.removeAll(item);
- m_subtractTime.removeAll(item);
-}
-
-void Playlist::clearItem(PlaylistItem *item)
-{
- // Automatically updates internal structs via updateDeletedItem
- delete item;
-
- dataChanged();
-}
-
-void Playlist::clearItems(const PlaylistItemList &items)
-{
- foreach(PlaylistItem *item, items)
- delete item;
-
- dataChanged();
-}
-
-PlaylistItem *Playlist::playingItem() // static
-{
- return PlaylistItem::playingItems().isEmpty() ? 0 : PlaylistItem::playingItems().front();
-}
-
-QStringList Playlist::files() const
-{
- QStringList list;
-
- for(Q3ListViewItemIterator it(const_cast<Playlist *>(this)); it.current(); ++it)
- list.append(static_cast<PlaylistItem *>(*it)->file().absFilePath());
-
- return list;
-}
-
-PlaylistItemList Playlist::items()
-{
- return items(Q3ListViewItemIterator::IteratorFlag(0));
-}
-
-PlaylistItemList Playlist::visibleItems()
-{
- return items(Q3ListViewItemIterator::Visible);
-}
-
-PlaylistItemList Playlist::selectedItems()
-{
- PlaylistItemList list;
-
- switch(m_selectedCount) {
- case 0:
- break;
- // case 1:
- // list.append(m_lastSelected);
- // break;
- default:
- list = items(Q3ListViewItemIterator::IteratorFlag(Q3ListViewItemIterator::Selected |
- Q3ListViewItemIterator::Visible));
- break;
- }
-
- return list;
-}
-
-PlaylistItem *Playlist::firstChild() const
-{
- return static_cast<PlaylistItem *>(K3ListView::firstChild());
-}
-
-void Playlist::updateLeftColumn()
-{
- int newLeftColumn = leftMostVisibleColumn();
-
- if(m_leftColumn != newLeftColumn) {
- updatePlaying();
- m_leftColumn = newLeftColumn;
- }
-}
-
-void Playlist::setItemsVisible(const PlaylistItemList &items, bool visible) // static
-{
- m_visibleChanged = true;
-
- foreach(PlaylistItem *playlistItem, items)
- playlistItem->setVisible(visible);
-}
-
-void Playlist::setSearch(const PlaylistSearch &s)
-{
- m_search = s;
-
- if(!m_searchEnabled)
- return;
-
- setItemsVisible(s.matchedItems(), true);
- setItemsVisible(s.unmatchedItems(), false);
-
- TrackSequenceManager::instance()->iterator()->playlistChanged();
-}
-
-void Playlist::setSearchEnabled(bool enabled)
-{
- if(m_searchEnabled == enabled)
- return;
-
- m_searchEnabled = enabled;
-
- if(enabled) {
- setItemsVisible(m_search.matchedItems(), true);
- setItemsVisible(m_search.unmatchedItems(), false);
- }
- else
- setItemsVisible(items(), true);
-}
-
-void Playlist::markItemSelected(PlaylistItem *item, bool selected)
-{
- if(selected && !item->isSelected()) {
- m_selectedCount++;
- m_lastSelected = item;
- }
- else if(!selected && item->isSelected())
- m_selectedCount--;
-}
-
-void Playlist::synchronizePlayingItems(const PlaylistList &sources, bool setMaster)
-{
- foreach(const Playlist *p, sources) {
- if(p->playing()) {
- CollectionListItem *base = playingItem()->collectionItem();
- for(Q3ListViewItemIterator itemIt(this); itemIt.current(); ++itemIt) {
- PlaylistItem *item = static_cast<PlaylistItem *>(itemIt.current());
- if(base == item->collectionItem()) {
- item->setPlaying(true, setMaster);
- PlaylistItemList playing = PlaylistItem::playingItems();
- TrackSequenceManager::instance()->setCurrent(item);
- return;
- }
- }
- return;
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::copy()
-{
- PlaylistItemList items = selectedItems();
- KUrl::List urls;
-
- foreach(PlaylistItem *item, items) {
- urls << KUrl::fromPath(item->file().absFilePath());
- }
-
- QMimeData *mimeData = new QMimeData;
- urls.populateMimeData(mimeData);
-
- QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
-}
-
-void Playlist::paste()
-{
- decode(QApplication::clipboard()->mimeData(), static_cast<PlaylistItem *>(currentItem()));
-}
-
-void Playlist::clear()
-{
- PlaylistItemList l = selectedItems();
- if(l.isEmpty())
- l = items();
-
- clearItems(l);
-}
-
-void Playlist::slotRefresh()
-{
- PlaylistItemList l = selectedItems();
- if(l.isEmpty())
- l = visibleItems();
-
- KApplication::setOverrideCursor(Qt::waitCursor);
- foreach(PlaylistItem *item, l) {
- item->refreshFromDisk();
-
- if(!item->file().tag() || !item->file().fileInfo().exists()) {
- kDebug() << "Error while trying to refresh the tag. "
- << "This file has probably been removed."
- << endl;
- delete item->collectionItem();
- }
-
- processEvents();
- }
- KApplication::restoreOverrideCursor();
-}
-
-void Playlist::slotRenameFile()
-{
- FileRenamer renamer;
- PlaylistItemList items = selectedItems();
-
- if(items.isEmpty())
- return;
-
- emit signalEnableDirWatch(false);
-
- m_blockDataChanged = true;
- renamer.rename(items);
- m_blockDataChanged = false;
- dataChanged();
-
- emit signalEnableDirWatch(true);
-}
-
-void Playlist::slotViewCover()
-{
- const PlaylistItemList items = selectedItems();
- if (items.isEmpty())
- return;
- foreach(const PlaylistItem *item, items)
- item->file().coverInfo()->popup();
-}
-
-void Playlist::slotRemoveCover()
-{
- PlaylistItemList items = selectedItems();
- if(items.isEmpty())
- return;
- int button = KMessageBox::warningContinueCancel(this,
- i18n("Are you sure you want to delete these covers?"),
- QString(),
- KGuiItem(i18n("&Delete Covers")));
- if(button == KMessageBox::Continue)
- refreshAlbums(items);
-}
-
-void Playlist::slotShowCoverManager()
-{
- static CoverDialog *managerDialog = 0;
-
- if(!managerDialog)
- managerDialog = new CoverDialog(this);
-
- managerDialog->show();
-}
-
-void Playlist::slotAddCover(bool retrieveLocal)
-{
- PlaylistItemList items = selectedItems();
-
- if(items.isEmpty())
- return;
-
- if(!retrieveLocal) {
- m_fetcher->setFile((*items.begin())->file());
- m_fetcher->searchCover();
- return;
- }
-
- KUrl file = KFileDialog::getImageOpenUrl(
- KUrl( "kfiledialog://homedir" ), this, i18n("Select Cover Image File"));
-
- if(file.isEmpty())
- return;
-
- QString artist = items.front()->file().tag()->artist();
- QString album = items.front()->file().tag()->album();
-
- coverKey newId = CoverManager::addCover(file, artist, album);
-
- if(newId != CoverManager::NoMatch)
- refreshAlbums(items, newId);
-}
-
-// Called when image fetcher has added a new cover.
-void Playlist::slotCoverChanged(int coverId)
-{
- kDebug() << "Refreshing information for newly changed covers.\n";
- refreshAlbums(selectedItems(), coverId);
-}
-
-void Playlist::slotGuessTagInfo(TagGuesser::Type type)
-{
- KApplication::setOverrideCursor(Qt::waitCursor);
- const PlaylistItemList items = selectedItems();
- setDynamicListsFrozen(true);
-
- m_blockDataChanged = true;
-
- foreach(PlaylistItem *item, items) {
- item->guessTagInfo(type);
- processEvents();
- }
-
- // MusicBrainz queries automatically commit at this point. What would
- // be nice is having a signal emitted when the last query is completed.
-
- if(type == TagGuesser::FileName)
- TagTransactionManager::instance()->commit();
-
- m_blockDataChanged = false;
-
- dataChanged();
- setDynamicListsFrozen(false);
- KApplication::restoreOverrideCursor();
-}
-
-void Playlist::slotReload()
-{
- QFileInfo fileInfo(m_fileName);
- if(!fileInfo.exists() || !fileInfo.isFile() || !fileInfo.isReadable())
- return;
-
- clearItems(items());
- loadFile(m_fileName, fileInfo);
-}
-
-void Playlist::slotWeightDirty(int column)
-{
- if(column < 0) {
- m_weightDirty.clear();
- for(int i = 0; i < columns(); i++) {
- if(isColumnVisible(i))
- m_weightDirty.append(i);
- }
- return;
- }
-
- if(!m_weightDirty.contains(column))
- m_weightDirty.append(column);
-}
-
-void Playlist::slotShowPlaying()
-{
- if(!playingItem())
- return;
-
- Playlist *l = playingItem()->playlist();
-
- l->clearSelection();
-
- // Raise the playlist before selecting the items otherwise the tag editor
- // will not update when it gets the selectionChanged() notification
- // because it will think the user is choosing a different playlist but not
- // selecting a different item.
-
- m_collection->raise(l);
-
- l->setSelected(playingItem(), true);
- l->ensureItemVisible(playingItem());
-}
-
-void Playlist::slotColumnResizeModeChanged()
-{
- if(manualResize())
- setHScrollBarMode(Auto);
- else
- setHScrollBarMode(AlwaysOff);
-
- if(!manualResize())
- slotUpdateColumnWidths();
-
- SharedSettings::instance()->sync();
-}
-
-void Playlist::dataChanged()
-{
- if(m_blockDataChanged)
- return;
- PlaylistInterface::dataChanged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::removeFromDisk(const PlaylistItemList &items)
-{
- if(isVisible() && !items.isEmpty()) {
-
- QStringList files;
- foreach(const PlaylistItem *item, items)
- files.append(item->file().absFilePath());
-
- DeleteDialog dialog(this);
-
- m_blockDataChanged = true;
-
- if(dialog.confirmDeleteList(files)) {
- bool shouldDelete = dialog.shouldDelete();
- QStringList errorFiles;
-
- foreach(PlaylistItem *item, items) {
- if(playingItem() == item)
- action("forward")->trigger();
-
- QString removePath = item->file().absFilePath();
- if((!shouldDelete && KIO::NetAccess::synchronousRun(KIO::trash(removePath), this)) ||
- (shouldDelete && QFile::remove(removePath)))
- {
- delete item->collectionItem();
- }
- else
- errorFiles.append(item->file().absFilePath());
- }
-
- if(!errorFiles.isEmpty()) {
- QString errorMsg = shouldDelete ?
- i18n("Could not delete these files") :
- i18n("Could not move these files to the Trash");
- KMessageBox::errorList(this, errorMsg, errorFiles);
- }
- }
-
- m_blockDataChanged = false;
-
- dataChanged();
- }
-}
-
-Q3DragObject *Playlist::dragObject(QWidget *parent)
-{
- PlaylistItemList items = selectedItems();
- KUrl::List urls;
-
- foreach(PlaylistItem *item, items) {
- urls << KUrl::fromPath(item->file().absFilePath());
- }
-
- K3URLDrag *urlDrag = new K3URLDrag(urls, parent);
-
- urlDrag->setPixmap(BarIcon("audio-x-generic"));
-
- return urlDrag;
-}
-
-void Playlist::contentsDragEnterEvent(QDragEnterEvent *e)
-{
- K3ListView::contentsDragEnterEvent(e);
-
- if(CoverDrag::isCover(e->mimeData())) {
- setDropHighlighter(true);
- setDropVisualizer(false);
-
- e->accept();
- return;
- }
-
- setDropHighlighter(false);
- setDropVisualizer(true);
-
- const KUrl::List urls = KUrl::List::fromMimeData(e->mimeData());
-
- if (urls.isEmpty()) {
- e->ignore();
- return;
- }
-
- e->accept();
- return;
-}
-
-bool Playlist::acceptDrag(QDropEvent *e) const
-{
- return CoverDrag::isCover(e->mimeData()) || KUrl::List::canDecode(e->mimeData());
-}
-
-void Playlist::decode(const QMimeData *s, PlaylistItem *item)
-{
- if(!KUrl::List::canDecode(s))
- return;
-
- const KUrl::List urls = KUrl::List::fromMimeData(s);
-
- if(urls.isEmpty())
- return;
-
- // handle dropped images
-
- if(!MediaFiles::isMediaFile(urls.front().path())) {
-
- QString file;
-
- if(urls.front().isLocalFile())
- file = urls.front().path();
- else
- KIO::NetAccess::download(urls.front(), file, 0);
-
- KMimeType::Ptr mimeType = KMimeType::findByPath(file);
-
- if(item && mimeType->name().startsWith(QLatin1String("image/"))) {
- item->file().coverInfo()->setCover(QImage(file));
- refreshAlbum(item->file().tag()->artist(),
- item->file().tag()->album());
- }
-
- KIO::NetAccess::removeTempFile(file);
- }
-
- QStringList fileList = MediaFiles::convertURLsToLocal(urls, this);
-
- addFiles(fileList, item);
-}
-
-bool Playlist::eventFilter(QObject *watched, QEvent *e)
-{
- if(watched == header()) {
- switch(e->type()) {
- case QEvent::MouseMove:
- {
- if((static_cast<QMouseEvent *>(e)->modifiers() & Qt::LeftButton) == Qt::LeftButton &&
- !action<KToggleAction>("resizeColumnsManually")->isChecked())
- {
- m_columnWidthModeChanged = true;
-
- action<KToggleAction>("resizeColumnsManually")->setChecked(true);
- slotColumnResizeModeChanged();
- }
-
- break;
- }
- case QEvent::MouseButtonPress:
- {
- if(static_cast<QMouseEvent *>(e)->button() == Qt::RightButton)
- m_headerMenu->popup(QCursor::pos());
-
- break;
- }
- case QEvent::MouseButtonRelease:
- {
- if(m_columnWidthModeChanged) {
- m_columnWidthModeChanged = false;
- notifyUserColumnWidthModeChanged();
- }
-
- if(!manualResize() && m_widthsDirty)
- QTimer::singleShot(0, this, SLOT(slotUpdateColumnWidths()));
- break;
- }
- default:
- break;
- }
- }
-
- return K3ListView::eventFilter(watched, e);
-}
-
-void Playlist::keyPressEvent(QKeyEvent *event)
-{
- if(event->key() == Qt::Key_Up) {
- Q3ListViewItemIterator selected(this, Q3ListViewItemIterator::IteratorFlag(
- Q3ListViewItemIterator::Selected |
- Q3ListViewItemIterator::Visible));
- if(selected.current()) {
- Q3ListViewItemIterator visible(this, Q3ListViewItemIterator::IteratorFlag(
- Q3ListViewItemIterator::Visible));
- if(selected.current() == visible.current())
- KApplication::postEvent(parent(), new FocusUpEvent);
- }
-
- }
-
- K3ListView::keyPressEvent(event);
-}
-
-void Playlist::contentsDropEvent(QDropEvent *e)
-{
- QPoint vp = contentsToViewport(e->pos());
- PlaylistItem *item = static_cast<PlaylistItem *>(itemAt(vp));
-
- // First see if we're dropping a cover, if so we can get it out of the
- // way early.
- if(item && CoverDrag::isCover(e->mimeData())) {
- coverKey id = CoverDrag::idFromData(e->mimeData());
-
- // If the item we dropped on is selected, apply cover to all selected
- // items, otherwise just apply to the dropped item.
-
- if(item->isSelected()) {
- const PlaylistItemList selItems = selectedItems();
- foreach(PlaylistItem *playlistItem, selItems) {
- playlistItem->file().coverInfo()->setCoverId(id);
- playlistItem->refresh();
- }
- }
- else {
- item->file().coverInfo()->setCoverId(id);
- item->refresh();
- }
-
- return;
- }
-
- // When dropping on the toUpper half of an item, insert before this item.
- // This is what the user expects, and also allows the insertion at
- // top of the list
-
- if(!item)
- item = static_cast<PlaylistItem *>(lastItem());
- else if(vp.y() < item->itemPos() + item->height() / 2)
- item = static_cast<PlaylistItem *>(item->itemAbove());
-
- m_blockDataChanged = true;
-
- if(e->source() == this) {
-
- // Since we're trying to arrange things manually, turn off sorting.
-
- setSorting(columns() + 1);
-
- const QList<Q3ListViewItem *> items = K3ListView::selectedItems();
-
- foreach(Q3ListViewItem *listViewItem, items) {
- if(!item) {
-
- // Insert the item at the top of the list. This is a bit ugly,
- // but I don't see another way.
-
- takeItem(listViewItem);
- insertItem(listViewItem);
- }
- else
- listViewItem->moveItem(item);
-
- item = static_cast<PlaylistItem *>(listViewItem);
- }
- }
- else
- decode(e->mimeData(), item);
-
- m_blockDataChanged = false;
-
- dataChanged();
- emit signalPlaylistItemsDropped(this);
- K3ListView::contentsDropEvent(e);
-}
-
-void Playlist::contentsMouseDoubleClickEvent(QMouseEvent *e)
-{
- // Filter out non left button double clicks, that way users don't have the
- // weird experience of switching songs from a double right-click.
-
- if(e->button() == Qt::LeftButton)
- K3ListView::contentsMouseDoubleClickEvent(e);
-}
-
-void Playlist::showEvent(QShowEvent *e)
-{
- if(m_applySharedSettings) {
- SharedSettings::instance()->apply(this);
- m_applySharedSettings = false;
- }
-
- K3ListView::showEvent(e);
-}
-
-void Playlist::applySharedSettings()
-{
- m_applySharedSettings = true;
-}
-
-void Playlist::read(QDataStream &s)
-{
- s >> m_playlistName
- >> m_fileName;
-
- // m_fileName is probably empty.
- if(m_playlistName.isEmpty())
- throw BICStreamException();
-
- // Do not sort. Add the files in the order they were saved.
- setSorting(columns() + 1);
-
- QStringList files;
- s >> files;
-
- Q3ListViewItem *after = 0;
-
- m_blockDataChanged = true;
-
- foreach(const QString &file, files) {
- if(file.isEmpty())
- throw BICStreamException();
-
- after = createItem(FileHandle(file), after, false);
- }
-
- m_blockDataChanged = false;
-
- dataChanged();
- m_collection->setupPlaylist(this, "audio-midi");
-}
-
-void Playlist::viewportPaintEvent(QPaintEvent *pe)
-{
- // If there are columns that need to be updated, well, update them.
-
- if(!m_weightDirty.isEmpty() && !manualResize())
- {
- calculateColumnWeights();
- slotUpdateColumnWidths();
- }
-
- K3ListView::viewportPaintEvent(pe);
-}
-
-void Playlist::viewportResizeEvent(QResizeEvent *re)
-{
- // If the width of the view has changed, manually update the column
- // widths.
-
- if(re->size().width() != re->oldSize().width() && !manualResize())
- slotUpdateColumnWidths();
-
- K3ListView::viewportResizeEvent(re);
-}
-
-void Playlist::insertItem(Q3ListViewItem *item)
-{
- // Because we're called from the PlaylistItem ctor, item may not be a
- // PlaylistItem yet (it would be QListViewItem when being inserted. But,
- // it will be a PlaylistItem by the time it matters, but be careful if
- // you need to use the PlaylistItem from here.
-
- m_addTime.append(static_cast<PlaylistItem *>(item));
- K3ListView::insertItem(item);
-}
-
-void Playlist::takeItem(Q3ListViewItem *item)
-{
- // See the warning in Playlist::insertItem.
-
- m_subtractTime.append(static_cast<PlaylistItem *>(item));
- K3ListView::takeItem(item);
-}
-
-int Playlist::addColumn(const QString &label, int)
-{
- int newIndex = K3ListView::addColumn(label, 30);
- slotWeightDirty(newIndex);
- return newIndex;
-}
-
-PlaylistItem *Playlist::createItem(const FileHandle &file,
- Q3ListViewItem *after, bool emitChanged)
-{
- return createItem<PlaylistItem>(file, after, emitChanged);
-}
-
-void Playlist::createItems(const PlaylistItemList &siblings, PlaylistItem *after)
-{
- createItems<PlaylistItem, PlaylistItem>(siblings, after);
-}
-
-void Playlist::addFiles(const QStringList &files, PlaylistItem *after)
-{
- if(!after)
- after = static_cast<PlaylistItem *>(lastItem());
-
- KApplication::setOverrideCursor(Qt::waitCursor);
-
- m_blockDataChanged = true;
-
- FileHandleList queue;
-
- foreach(const QString &file, files)
- addFile(file, queue, true, &after);
-
- addFileHelper(queue, &after, true);
-
- m_blockDataChanged = false;
-
- slotWeightDirty();
- dataChanged();
-
- KApplication::restoreOverrideCursor();
-}
-
-void Playlist::refreshAlbums(const PlaylistItemList &items, coverKey id)
-{
- QList< QPair<QString, QString> > albums;
- bool setAlbumCovers = items.count() == 1;
-
- foreach(const PlaylistItem *item, items) {
- QString artist = item->file().tag()->artist();
- QString album = item->file().tag()->album();
-
- if(!albums.contains(qMakePair(artist, album)))
- albums.append(qMakePair(artist, album));
-
- item->file().coverInfo()->setCoverId(id);
- if(setAlbumCovers)
- item->file().coverInfo()->applyCoverToWholeAlbum(true);
- }
-
- for(QList< QPair<QString, QString> >::ConstIterator it = albums.constBegin();
- it != albums.constEnd(); ++it)
- {
- refreshAlbum((*it).first, (*it).second);
- }
-}
-
-void Playlist::updatePlaying() const
-{
- foreach(const PlaylistItem *item, PlaylistItem::playingItems())
- item->listView()->triggerUpdate();
-}
-
-void Playlist::refreshAlbum(const QString &artist, const QString &album)
-{
- ColumnList columns;
- columns.append(PlaylistItem::ArtistColumn);
- PlaylistSearch::Component artistComponent(artist, false, columns,
- PlaylistSearch::Component::Exact);
-
- columns.clear();
- columns.append(PlaylistItem::AlbumColumn);
- PlaylistSearch::Component albumComponent(album, false, columns,
- PlaylistSearch::Component::Exact);
-
- PlaylistSearch::ComponentList components;
- components.append(artist);
- components.append(album);
-
- PlaylistList playlists;
- playlists.append(CollectionList::instance());
-
- PlaylistSearch search(playlists, components);
- const PlaylistItemList matches = search.matchedItems();
-
- foreach(PlaylistItem *item, matches)
- item->refresh();
-}
-
-void Playlist::hideColumn(int c, bool updateSearch)
-{
- foreach (QAction *action, m_headerMenu->actions()) {
- if(!action)
- continue;
-
- if (action->data().toInt() == c) {
- action->setChecked(false);
- break;
- }
- }
-
- if(!isColumnVisible(c))
- return;
-
- setColumnWidthMode(c, Manual);
- setColumnWidth(c, 0);
-
- // Moving the column to the end seems to prevent it from randomly
- // popping up.
-
- header()->moveSection(c, header()->count());
- header()->setResizeEnabled(false, c);
-
- if(c == m_leftColumn) {
- updatePlaying();
- m_leftColumn = leftMostVisibleColumn();
- }
-
- if(!manualResize()) {
- slotUpdateColumnWidths();
- triggerUpdate();
- }
-
- if(this != CollectionList::instance())
- CollectionList::instance()->hideColumn(c, false);
-
- if(updateSearch)
- redisplaySearch();
-}
-
-void Playlist::showColumn(int c, bool updateSearch)
-{
- foreach (QAction *action, m_headerMenu->actions()) {
- if(!action)
- continue;
-
- if (action->data().toInt() == c) {
- action->setChecked(true);
- break;
- }
- }
-
- if(isColumnVisible(c))
- return;
-
- // Just set the width to one to mark the column as visible -- we'll update
- // the real size in the next call.
-
- if(manualResize())
- setColumnWidth(c, 35); // Make column at least slightly visible.
- else
- setColumnWidth(c, 1);
-
- header()->setResizeEnabled(true, c);
- header()->moveSection(c, c); // Approximate old position
-
- if(c == leftMostVisibleColumn()) {
- updatePlaying();
- m_leftColumn = leftMostVisibleColumn();
- }
-
- if(!manualResize()) {
- slotUpdateColumnWidths();
- triggerUpdate();
- }
-
- if(this != CollectionList::instance())
- CollectionList::instance()->showColumn(c, false);
-
- if(updateSearch)
- redisplaySearch();
-}
-
-bool Playlist::isColumnVisible(int c) const
-{
- return columnWidth(c) != 0;
-}
-
-void Playlist::slotInitialize()
-{
- addColumn(i18n("Track Name"));
- addColumn(i18n("Artist"));
- addColumn(i18n("Album"));
- addColumn(i18n("Cover"));
- addColumn(i18nc("cd track number", "Track"));
- addColumn(i18n("Genre"));
- addColumn(i18n("Year"));
- addColumn(i18n("Length"));
- addColumn(i18n("Bitrate"));
- addColumn(i18n("Comment"));
- addColumn(i18n("File Name"));
- addColumn(i18n("File Name (full path)"));
-
- setRenameable(PlaylistItem::TrackColumn, true);
- setRenameable(PlaylistItem::ArtistColumn, true);
- setRenameable(PlaylistItem::AlbumColumn, true);
- setRenameable(PlaylistItem::TrackNumberColumn, true);
- setRenameable(PlaylistItem::GenreColumn, true);
- setRenameable(PlaylistItem::YearColumn, true);
-
- setAllColumnsShowFocus(true);
- setSelectionMode(Q3ListView::Extended);
- setShowSortIndicator(true);
- setDropVisualizer(true);
-
- m_columnFixedWidths.resize(columns());
-
- //////////////////////////////////////////////////
- // setup header RMB menu
- //////////////////////////////////////////////////
-
-#ifdef __GNUC__
- #warning should be fixed...
-#endif
- /* m_headerMenu->insertTitle(i18n("Show")); */
-
- QAction *showAction;
-
- for(int i = 0; i < header()->count(); ++i) {
- if(i - columnOffset() == PlaylistItem::FileNameColumn)
- m_headerMenu->addSeparator();
-
- showAction = new QAction(header()->label(i), m_headerMenu);
- showAction->setData(i);
- showAction->setCheckable(true);
- showAction->setChecked(true);
- m_headerMenu->addAction(showAction);
-
- adjustColumn(i);
- }
-
- connect(m_headerMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotToggleColumnVisible(QAction*)));
-
- connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)),
- this, SLOT(slotShowRMBMenu(Q3ListViewItem*,QPoint,int)));
- connect(this, SIGNAL(itemRenamed(Q3ListViewItem*,QString,int)),
- this, SLOT(slotInlineEditDone(Q3ListViewItem*,QString,int)));
- connect(this, SIGNAL(doubleClicked(Q3ListViewItem*)),
- this, SLOT(slotPlayCurrent()));
- connect(this, SIGNAL(returnPressed(Q3ListViewItem*)),
- this, SLOT(slotPlayCurrent()));
-
- connect(header(), SIGNAL(sizeChange(int,int,int)),
- this, SLOT(slotColumnSizeChanged(int,int,int)));
-
- connect(renameLineEdit(), SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
- this, SLOT(slotInlineCompletionModeChanged(KGlobalSettings::Completion)));
-
- connect(action("resizeColumnsManually"), SIGNAL(activated()),
- this, SLOT(slotColumnResizeModeChanged()));
-
- if(action<KToggleAction>("resizeColumnsManually")->isChecked())
- setHScrollBarMode(Auto);
- else
- setHScrollBarMode(AlwaysOff);
-
- setAcceptDrops(true);
- setDropVisualizer(true);
-
- m_disableColumnWidthUpdates = false;
-
- setShowToolTips(false);
- /* m_toolTip = new PlaylistToolTip(viewport(), this); */
-}
-
-void Playlist::setupItem(PlaylistItem *item)
-{
- item->setTrackId(g_trackID);
- g_trackID++;
-
- if(!m_search.isEmpty())
- item->setVisible(m_search.checkItem(item));
-
- if(childCount() <= 2 && !manualResize()) {
- slotWeightDirty();
- slotUpdateColumnWidths();
- triggerUpdate();
- }
-}
-
-void Playlist::setDynamicListsFrozen(bool frozen)
-{
- m_collection->setDynamicListsFrozen(frozen);
-}
-
-CollectionListItem *Playlist::collectionListItem(const FileHandle &file)
-{
- if(!QFile::exists(file.absFilePath())) {
- kError() << "File" << file.absFilePath() << "does not exist.";
- return 0;
- }
-
- CollectionListItem *item = CollectionList::instance()->lookup(file.absFilePath());
-
- if(!item) {
- item = CollectionList::instance()->createItem(file);
- }
-
- return item;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected slots
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::slotPopulateBackMenu() const
-{
- if(!playingItem())
- return;
-
- QMenu *menu = action<KToolBarPopupAction>("back")->menu();
- menu->clear();
- m_backMenuItems.clear();
- m_backMenuItems.reserve(10);
-
- int count = 0;
- PlaylistItemList::ConstIterator it = m_history.constEnd();
-
- QAction *action;
-
- while(it != m_history.constBegin() && count < 10) {
- ++count;
- --it;
- action = new QAction((*it)->file().tag()->title(), menu);
- action->setData(count - 1);
- menu->addAction(action);
- m_backMenuItems << *it;
- }
-}
-
-void Playlist::slotPlayFromBackMenu(QAction *backAction) const
-{
- int number = backAction->data().toInt();
-
- if(number >= m_backMenuItems.size())
- return;
-
- TrackSequenceManager::instance()->setNextItem(m_backMenuItems[number]);
- action("forward")->trigger();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::setup()
-{
- setItemMargin(3);
-
- connect(header(), SIGNAL(indexChange(int,int,int)), this, SLOT(slotColumnOrderChanged(int,int,int)));
-
- connect(m_fetcher, SIGNAL(signalCoverChanged(int)), this, SLOT(slotCoverChanged(int)));
-
- // Prevent list of selected items from changing while internet search is in
- // progress.
- connect(this, SIGNAL(selectionChanged()), m_fetcher, SLOT(abortSearch()));
-
- setSorting(1);
-
- // This apparently must be created very early in initialization for other
- // Playlist code requiring m_headerMenu.
- m_columnVisibleAction = new KActionMenu(i18n("&Show Columns"), this);
- ActionCollection::actions()->addAction("showColumns", m_columnVisibleAction);
-
- m_headerMenu = m_columnVisibleAction->menu();
-
- // TODO: Determine if other stuff in setup must happen before slotInitialize().
-
- // Explicitly call slotInitialize() so that the columns are added before
- // SharedSettings::apply() sets the visible and hidden ones.
- slotInitialize();
-}
-
-void Playlist::loadFile(const QString &fileName, const QFileInfo &fileInfo)
-{
- QFile file(fileName);
- if(!file.open(QIODevice::ReadOnly))
- return;
-
- QTextStream stream(&file);
-
- // Turn off non-explicit sorting.
-
- setSorting(PlaylistItem::lastColumn() + columnOffset() + 1);
-
- PlaylistItem *after = 0;
-
- m_disableColumnWidthUpdates = true;
-
- m_blockDataChanged = true;
-
- while(!stream.atEnd()) {
- QString itemName = stream.readLine().trimmed();
-
- QFileInfo item(itemName);
-
- if(item.isRelative())
- item.setFile(QDir::cleanPath(fileInfo.absolutePath() + '/' + itemName));
-
- if(item.exists() && item.isFile() && item.isReadable() &&
- MediaFiles::isMediaFile(item.fileName()))
- {
- if(after)
- after = createItem(FileHandle(item, item.absoluteFilePath()), after, false);
- else
- after = createItem(FileHandle(item, item.absoluteFilePath()), 0, false);
- }
- }
-
- m_blockDataChanged = false;
-
- file.close();
-
- dataChanged();
-
- m_disableColumnWidthUpdates = false;
-}
-
-void Playlist::setPlaying(PlaylistItem *item, bool addToHistory)
-{
- if(playingItem() == item)
- return;
-
- if(playingItem()) {
- if(addToHistory) {
- if(playingItem()->playlist() ==
- playingItem()->playlist()->m_collection->upcomingPlaylist())
- m_history.append(playingItem()->collectionItem());
- else
- m_history.append(playingItem());
- }
- playingItem()->setPlaying(false);
- }
-
- TrackSequenceManager::instance()->setCurrent(item);
-#ifdef __GNUC__
-#warning "kde4: port it"
-#endif
- //kapp->dcopClient()->emitDCOPSignal("Player", "trackChanged()", data);
-
- if(!item)
- return;
-
- item->setPlaying(true);
-
- bool enableBack = !m_history.isEmpty();
- action<KToolBarPopupAction>("back")->menu()->setEnabled(enableBack);
-}
-
-bool Playlist::playing() const
-{
- return playingItem() && this == playingItem()->playlist();
-}
-
-int Playlist::leftMostVisibleColumn() const
-{
- int i = 0;
- while(!isColumnVisible(header()->mapToSection(i)) && i < PlaylistItem::lastColumn())
- i++;
-
- return header()->mapToSection(i);
-}
-
-PlaylistItemList Playlist::items(Q3ListViewItemIterator::IteratorFlag flags)
-{
- PlaylistItemList list;
-
- for(Q3ListViewItemIterator it(this, flags); it.current(); ++it)
- list.append(static_cast<PlaylistItem *>(it.current()));
-
- return list;
-}
-
-void Playlist::calculateColumnWeights()
-{
- if(m_disableColumnWidthUpdates)
- return;
-
- PlaylistItemList l = items();
- QList<int>::Iterator columnIt;
-
- QVector<double> averageWidth(columns());
- double itemCount = l.size();
-
- QVector<int> cachedWidth;
-
- // Here we're not using a real average, but averaging the squares of the
- // column widths and then using the square root of that value. This gives
- // a nice weighting to the longer columns without doing something arbitrary
- // like adding a fixed amount of padding.
-
- foreach(PlaylistItem *item, l) {
- cachedWidth = item->cachedWidths();
-
- // Extra columns start at 0, but those weights aren't shared with all
- // items.
- for(int i = 0; i < columnOffset(); ++i) {
- averageWidth[i] +=
- std::pow(double(item->width(fontMetrics(), this, i)), 2.0) / itemCount;
- }
-
- for(int column = columnOffset(); column < columns(); ++column) {
- averageWidth[column] +=
- std::pow(double(cachedWidth[column - columnOffset()]), 2.0) / itemCount;
- }
- }
-
- if(m_columnWeights.isEmpty())
- m_columnWeights.fill(-1, columns());
-
- foreach(int column, m_weightDirty) {
- m_columnWeights[column] = int(std::sqrt(averageWidth[column]) + 0.5);
- }
-
- m_weightDirty.clear();
-}
-
-void Playlist::addFile(const QString &file, FileHandleList &files, bool importPlaylists,
- PlaylistItem **after)
-{
- if(hasItem(file) && !m_allowDuplicates)
- return;
-
- addFileHelper(files, after);
-
- // Our biggest thing that we're fighting during startup is too many stats
- // of files. Make sure that we don't do one here if it's not needed.
-
- const CollectionListItem *item = CollectionList::instance()->lookup(file);
-
- if(item && !item->file().isNull()) {
- FileHandle cached(item->file());
- cached.tag();
- files.append(cached);
- return;
- }
-
- const QFileInfo fileInfo(QDir::cleanPath(file));
- if(!fileInfo.exists())
- return;
-
- const QString canonicalPath = fileInfo.canonicalFilePath();
-
- if(fileInfo.isFile() && fileInfo.isReadable()) {
- if(MediaFiles::isMediaFile(file)) {
- FileHandle f(fileInfo, canonicalPath);
- f.tag();
- files.append(f);
- }
- }
-
- if(importPlaylists && MediaFiles::isPlaylistFile(file) &&
- !m_collection->containsPlaylistFile(canonicalPath))
- {
- new Playlist(m_collection, fileInfo);
- return;
- }
-
- if(fileInfo.isDir()) {
- foreach(const QString &directory, m_collection->excludedFolders()) {
- if(canonicalPath.startsWith(directory))
- return; // Exclude it
- }
-
- QDirIterator dirIterator(canonicalPath, QDir::AllEntries | QDir::NoDotAndDotDot);
-
- while(dirIterator.hasNext()) {
- // We set importPlaylists to the value from the add directories
- // dialog as we want to load all of the ones that the user has
- // explicitly asked for, but not those that we find in toLower
- // directories.
-
- addFile(dirIterator.next(), files,
- m_collection->importPlaylists(), after);
- }
- }
-}
-
-void Playlist::addFileHelper(FileHandleList &files, PlaylistItem **after, bool ignoreTimer)
-{
- static QTime time = QTime::currentTime();
-
- // Process new items every 10 seconds, when we've loaded 1000 items, or when
- // it's been requested in the API.
-
- if(ignoreTimer || time.elapsed() > 10000 ||
- (files.count() >= 1000 && time.elapsed() > 1000))
- {
- time.restart();
-
- const bool focus = hasFocus();
- const bool visible = isVisible() && files.count() > 20;
-
- if(visible)
- m_collection->raiseDistraction();
-
- foreach(const FileHandle &fileHandle, files)
- *after = createItem(fileHandle, *after, false);
-
- files.clear();
-
- if(visible)
- m_collection->lowerDistraction();
-
- if(focus)
- setFocus();
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void Playlist::slotUpdateColumnWidths()
-{
- if(m_disableColumnWidthUpdates || manualResize())
- return;
-
- // Make sure that the column weights have been initialized before trying to
- // update the columns.
-
- QList<int> visibleColumns;
- for(int i = 0; i < columns(); i++) {
- if(isColumnVisible(i))
- visibleColumns.append(i);
- }
-
- if(count() == 0) {
- foreach(int column, visibleColumns)
- setColumnWidth(column, header()->fontMetrics().width(header()->label(column)) + 10);
-
- return;
- }
-
- if(m_columnWeights.isEmpty())
- return;
-
- // First build a list of minimum widths based on the strings in the listview
- // header. We won't let the width of the column go below this width.
-
- QVector<int> minimumWidth(columns(), 0);
- int minimumWidthTotal = 0;
-
- // Also build a list of either the minimum *or* the fixed width -- whichever is
- // greater.
-
- QVector<int> minimumFixedWidth(columns(), 0);
- int minimumFixedWidthTotal = 0;
-
- foreach(int column, visibleColumns) {
- minimumWidth[column] = header()->fontMetrics().width(header()->label(column)) + 10;
- minimumWidthTotal += minimumWidth[column];
-
- minimumFixedWidth[column] = qMax(minimumWidth[column], m_columnFixedWidths[column]);
- minimumFixedWidthTotal += minimumFixedWidth[column];
- }
-
- // Make sure that the width won't get any smaller than this. We have to
- // account for the scrollbar as well. Since this method is called from the
- // resize event this will set a pretty hard toLower bound on the size.
-
- setMinimumWidth(minimumWidthTotal + verticalScrollBar()->width());
-
- // If we've got enough room for the fixed widths (larger than the minimum
- // widths) then instead use those for our "minimum widths".
-
- if(minimumFixedWidthTotal < visibleWidth()) {
- minimumWidth = minimumFixedWidth;
- minimumWidthTotal = minimumFixedWidthTotal;
- }
-
- // We've got a list of columns "weights" based on some statistics gathered
- // about the widths of the items in that column. We need to find the total
- // useful weight to use as a divisor for each column's weight.
-
- double totalWeight = 0;
- foreach(int column, visibleColumns)
- totalWeight += m_columnWeights[column];
-
- // Computed a "weighted width" for each visible column. This would be the
- // width if we didn't have to handle the cases of minimum and maximum widths.
-
- QVector<int> weightedWidth(columns(), 0);
- foreach(int column, visibleColumns)
- weightedWidth[column] = int(double(m_columnWeights[column]) / totalWeight * visibleWidth() + 0.5);
-
- // The "extra" width for each column. This is the weighted width less the
- // minimum width or zero if the minimum width is greater than the weighted
- // width.
-
- QVector<int> extraWidth(columns(), 0);
-
- // This is used as an indicator if we have any columns where the weighted
- // width is less than the minimum width. If this is false then we can
- // just use the weighted width with no problems, otherwise we have to
- // "readjust" the widths.
-
- bool readjust = false;
-
- // If we have columns where the weighted width is less than the minimum width
- // we need to steal that space from somewhere. The amount that we need to
- // steal is the "neededWidth".
-
- int neededWidth = 0;
-
- // While we're on the topic of stealing -- we have to have somewhere to steal
- // from. availableWidth is the sum of the amount of space beyond the minimum
- // width that each column has been allocated -- the sum of the values of
- // extraWidth[].
-
- int availableWidth = 0;
-
- // Fill in the values discussed above.
-
- foreach(int column, visibleColumns) {
- if(weightedWidth[column] < minimumWidth[column]) {
- readjust = true;
- extraWidth[column] = 0;
- neededWidth += minimumWidth[column] - weightedWidth[column];
- }
- else {
- extraWidth[column] = weightedWidth[column] - minimumWidth[column];
- availableWidth += extraWidth[column];
- }
- }
-
- // The adjustmentRatio is the amount of the "extraWidth[]" that columns will
- // actually be given.
-
- double adjustmentRatio = (double(availableWidth) - double(neededWidth)) / double(availableWidth);
-
- // This will be the sum of the total space that we actually use. Because of
- // rounding error this won't be the exact available width.
-
- int usedWidth = 0;
-
- // Now set the actual column widths. If the weighted widths are all greater
- // than the minimum widths, just use those, otherwise use the "reajusted
- // weighted width".
-
- foreach(int column, visibleColumns) {
- int width;
- if(readjust) {
- int adjustedExtraWidth = int(double(extraWidth[column]) * adjustmentRatio + 0.5);
- width = minimumWidth[column] + adjustedExtraWidth;
- }
- else
- width = weightedWidth[column];
-
- setColumnWidth(column, width);
- usedWidth += width;
- }
-
- // Fill the remaining gap for a clean fit into the available space.
-
- int remainingWidth = visibleWidth() - usedWidth;
- setColumnWidth(visibleColumns.back(), columnWidth(visibleColumns.back()) + remainingWidth);
-
- m_widthsDirty = false;
-}
-
-void Playlist::slotAddToUpcoming()
-{
- m_collection->setUpcomingPlaylistEnabled(true);
- m_collection->upcomingPlaylist()->appendItems(selectedItems());
-}
-
-void Playlist::slotShowRMBMenu(Q3ListViewItem *item, const QPoint &point, int column)
-{
- if(!item)
- return;
-
- // Create the RMB menu on demand.
-
- if(!m_rmbMenu) {
-
- // Probably more of these actions should be ported over to using KActions.
-
- m_rmbMenu = new KMenu(this);
-
- m_rmbMenu->addAction(SmallIcon("go-jump-today"),
- i18n("Add to Play Queue"), this, SLOT(slotAddToUpcoming()));
- m_rmbMenu->addSeparator();
-
- if(!readOnly()) {
- m_rmbMenu->addAction( action("edit_cut") );
- m_rmbMenu->addAction( action("edit_copy") );
- m_rmbMenu->addAction( action("edit_paste") );
- m_rmbMenu->addSeparator();
- m_rmbMenu->addAction( action("removeFromPlaylist") );
- }
- else
- m_rmbMenu->addAction( action("edit_copy") );
-
- m_rmbEdit = m_rmbMenu->addAction(i18n("Edit"), this, SLOT(slotRenameTag()));
-
- m_rmbMenu->addAction( action("refresh") );
- m_rmbMenu->addAction( action("removeItem") );
-
- m_rmbMenu->addSeparator();
-
- m_rmbMenu->addAction( action("guessTag") );
- m_rmbMenu->addAction( action("renameFile") );
-
- m_rmbMenu->addAction( action("coverManager") );
-
- m_rmbMenu->addSeparator();
-
- m_rmbMenu->addAction(
- SmallIcon("folder-new"), i18n("Create Playlist From Selected Items..."), this, SLOT(slotCreateGroup()));
-
- K3bExporter *exporter = new K3bExporter(this);
- KAction *k3bAction = exporter->action();
- if(k3bAction)
- m_rmbMenu->addAction( k3bAction );
- }
-
- // Ignore any columns added by subclasses.
-
- column -= columnOffset();
-
- bool showEdit =
- (column == PlaylistItem::TrackColumn) ||
- (column == PlaylistItem::ArtistColumn) ||
- (column == PlaylistItem::AlbumColumn) ||
- (column == PlaylistItem::TrackNumberColumn) ||
- (column == PlaylistItem::GenreColumn) ||
- (column == PlaylistItem::YearColumn);
-
- if(showEdit)
- m_rmbEdit->setText(i18n("Edit '%1'", columnText(column + columnOffset())));
-
- m_rmbEdit->setVisible(showEdit);
-
- // Disable edit menu if only one file is selected, and it's read-only
-
- FileHandle file = static_cast<PlaylistItem*>(item)->file();
-
- m_rmbEdit->setEnabled(file.fileInfo().isWritable() || selectedItems().count() > 1);
-
- // View cover is based on if there is a cover to see. We should only have
- // the remove cover option if the cover is in our database (and not directly
- // embedded in the file, for instance).
-
- action("viewCover")->setEnabled(file.coverInfo()->hasCover());
- action("removeCover")->setEnabled(file.coverInfo()->coverId() != CoverManager::NoMatch);
-
- m_rmbMenu->popup(point);
- m_currentColumn = column + columnOffset();
-}
-
-void Playlist::slotRenameTag()
-{
- // setup completions and validators
-
- CollectionList *list = CollectionList::instance();
-
- KLineEdit *edit = renameLineEdit();
-
- switch(m_currentColumn - columnOffset())
- {
- case PlaylistItem::ArtistColumn:
- edit->completionObject()->setItems(list->uniqueSet(CollectionList::Artists));
- break;
- case PlaylistItem::AlbumColumn:
- edit->completionObject()->setItems(list->uniqueSet(CollectionList::Albums));
- break;
- case PlaylistItem::GenreColumn:
- {
- QStringList genreList;
- TagLib::StringList genres = TagLib::ID3v1::genreList();
- for(TagLib::StringList::Iterator it = genres.begin(); it != genres.end(); ++it)
- genreList.append(TStringToQString((*it)));
- edit->completionObject()->setItems(genreList);
- break;
- }
- default:
- edit->completionObject()->clear();
- break;
- }
-
- m_editText = currentItem()->text(m_currentColumn);
-
- rename(currentItem(), m_currentColumn);
-}
-
-bool Playlist::editTag(PlaylistItem *item, const QString &text, int column)
-{
- Tag *newTag = TagTransactionManager::duplicateTag(item->file().tag());
-
- switch(column - columnOffset())
- {
- case PlaylistItem::TrackColumn:
- newTag->setTitle(text);
- break;
- case PlaylistItem::ArtistColumn:
- newTag->setArtist(text);
- break;
- case PlaylistItem::AlbumColumn:
- newTag->setAlbum(text);
- break;
- case PlaylistItem::TrackNumberColumn:
- {
- bool ok;
- int value = text.toInt(&ok);
- if(ok)
- newTag->setTrack(value);
- break;
- }
- case PlaylistItem::GenreColumn:
- newTag->setGenre(text);
- break;
- case PlaylistItem::YearColumn:
- {
- bool ok;
- int value = text.toInt(&ok);
- if(ok)
- newTag->setYear(value);
- break;
- }
- }
-
- TagTransactionManager::instance()->changeTagOnItem(item, newTag);
- return true;
-}
-
-void Playlist::slotInlineEditDone(Q3ListViewItem *, const QString &, int column)
-{
- QString text = renameLineEdit()->text();
- bool changed = false;
-
- PlaylistItemList l = selectedItems();
-
- // See if any of the files have a tag different from the input.
-
- for(PlaylistItemList::ConstIterator it = l.constBegin(); it != l.constEnd() && !changed; ++it)
- if((*it)->text(column - columnOffset()) != text)
- changed = true;
-
- if(!changed ||
- (l.count() > 1 && KMessageBox::warningContinueCancel(
- 0,
- i18n("This will edit multiple files. Are you sure?"),
- QString(),
- KGuiItem(i18n("Edit")),
- KStandardGuiItem::cancel(),
- "DontWarnMultipleTags") == KMessageBox::Cancel))
- {
- return;
- }
-
- foreach(PlaylistItem *item, l)
- editTag(item, text, column);
-
- TagTransactionManager::instance()->commit();
-
- CollectionList::instance()->dataChanged();
- dataChanged();
- update();
-}
-
-void Playlist::slotColumnOrderChanged(int, int from, int to)
-{
- if(from == 0 || to == 0) {
- updatePlaying();
- m_leftColumn = header()->mapToSection(0);
- }
-
- SharedSettings::instance()->setColumnOrder(this);
-}
-
-void Playlist::slotToggleColumnVisible(QAction *action)
-{
- int column = action->data().toInt();
-
- if(!isColumnVisible(column)) {
- int fileNameColumn = PlaylistItem::FileNameColumn + columnOffset();
- int fullPathColumn = PlaylistItem::FullPathColumn + columnOffset();
-
- if(column == fileNameColumn && isColumnVisible(fullPathColumn)) {
- hideColumn(fullPathColumn, false);
- SharedSettings::instance()->toggleColumnVisible(fullPathColumn);
- }
- if(column == fullPathColumn && isColumnVisible(fileNameColumn)) {
- hideColumn(fileNameColumn, false);
- SharedSettings::instance()->toggleColumnVisible(fileNameColumn);
- }
- }
-
- if(isColumnVisible(column))
- hideColumn(column);
- else
- showColumn(column);
-
- if(column >= columnOffset()) {
- SharedSettings::instance()->toggleColumnVisible(column - columnOffset());
- }
-}
-
-void Playlist::slotCreateGroup()
-{
- QString name = m_collection->playlistNameDialog(i18n("Create New Playlist"));
-
- if(!name.isEmpty())
- new Playlist(m_collection, selectedItems(), name);
-}
-
-void Playlist::notifyUserColumnWidthModeChanged()
-{
- KMessageBox::information(this,
- i18n("Manual column widths have been enabled. You can "
- "switch back to automatic column sizes in the view "
- "menu."),
- i18n("Manual Column Widths Enabled"),
- "ShowManualColumnWidthInformation");
-}
-
-void Playlist::slotColumnSizeChanged(int column, int, int newSize)
-{
- m_widthsDirty = true;
- m_columnFixedWidths[column] = newSize;
-}
-
-void Playlist::slotInlineCompletionModeChanged(KGlobalSettings::Completion mode)
-{
- SharedSettings::instance()->setInlineCompletionMode(mode);
-}
-
-void Playlist::slotPlayCurrent()
-{
- Q3ListViewItemIterator it(this, Q3ListViewItemIterator::Selected);
- PlaylistItem *next = static_cast<PlaylistItem *>(it.current());
- TrackSequenceManager::instance()->setNextItem(next);
- action("forward")->trigger();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// helper functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const Playlist &p)
-{
- s << p.name();
- s << p.fileName();
- s << p.files();
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, Playlist &p)
-{
- p.read(s);
- return s;
-}
-
-bool processEvents()
-{
- static QTime time = QTime::currentTime();
-
- if(time.elapsed() > 100) {
- time.restart();
- kapp->processEvents();
- return true;
- }
- return false;
-}
-
-#include "playlist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLIST_H
-#define PLAYLIST_H
-
-#include <k3listview.h>
-#include <kglobalsettings.h>
-#include <kdebug.h>
-
-#include <QVector>
-#include <QEvent>
-#include <QList>
-
-#include "covermanager.h"
-#include "stringhash.h"
-#include "playlistsearch.h"
-#include "tagguesser.h"
-#include "playlistinterface.h"
-#include "filehandle.h"
-
-class KMenu;
-class KActionMenu;
-
-class QFileInfo;
-class QMimeData;
-class QDrag;
-class QAction;
-
-class WebImageFetcher;
-class PlaylistItem;
-class PlaylistCollection;
-class PlaylistToolTip;
-class CollectionListItem;
-
-typedef QList<PlaylistItem *> PlaylistItemList;
-
-class Playlist : public K3ListView, public PlaylistInterface
-{
- Q_OBJECT
-
-public:
-
- explicit Playlist(PlaylistCollection *collection, const QString &name = QString(),
- const QString &iconName = "audio-midi");
- Playlist(PlaylistCollection *collection, const PlaylistItemList &items,
- const QString &name = QString(), const QString &iconName = "audio-midi");
- Playlist(PlaylistCollection *collection, const QFileInfo &playlistFile,
- const QString &iconName = "audio-midi");
-
- /**
- * This constructor should generally only be used either by the cache
- * restoration methods or by subclasses that want to handle calls to
- * PlaylistCollection::setupPlaylist() differently.
- *
- * @param extraColumns is used to preallocate columns for subclasses that
- * need them (since extra columns are assumed to start from 0). extraColumns
- * should be equal to columnOffset() (we can't use columnOffset until the
- * ctor has run).
- */
- Playlist(PlaylistCollection *collection, bool delaySetup, int extraColumns = 0);
-
- virtual ~Playlist();
-
-
- // The following group of functions implement the PlaylistInterface API.
-
- virtual QString name() const;
- virtual FileHandle currentFile() const;
- virtual int count() const { return childCount(); }
- virtual int time() const;
- virtual void playNext();
- virtual void playPrevious();
- virtual void stop();
-
- /**
- * Plays the top item of the playlist.
- */
- void playFirst();
-
- /**
- * Plays the next album in the playlist. Only useful when in album random
- * play mode.
- */
- void playNextAlbum();
-
- /**
- * Saves the file to the currently set file name. If there is no filename
- * currently set, the default behavior is to prompt the user for a file
- * name.
- */
- virtual void save();
-
- /**
- * Standard "save as". Prompts the user for a location where to save the
- * playlist to.
- */
- virtual void saveAs();
-
- /**
- * Removes \a item from the Playlist, but not from the disk.
- *
- * Since the GUI updates after an item is cleared, you should use clearItems() if you have
- * a list of items to remove, as that will remove the whole batch before updating
- * other components/GUI to the change.
- */
- virtual void clearItem(PlaylistItem *item);
-
- /**
- * Remove \a items from the playlist and emit a signal indicating
- * that the number of items in the list has changed.
- */
- virtual void clearItems(const PlaylistItemList &items);
-
- /**
- * Accessor function to return a pointer to the currently playing file.
- *
- * @return 0 if no file is playing, otherwise a pointer to the PlaylistItem
- * of the track that is currently playing.
- */
- static PlaylistItem *playingItem();
-
- /**
- * All of the (media) files in the list.
- */
- QStringList files() const;
-
- /**
- * Returns a list of all of the items in the playlist.
- */
- virtual PlaylistItemList items();
-
- /**
- * Returns a list of all of the \e visible items in the playlist.
- */
- PlaylistItemList visibleItems();
-
- /**
- * Returns a list of the currently selected items.
- */
- PlaylistItemList selectedItems();
-
- /**
- * Returns properly casted first child item in list.
- */
- PlaylistItem *firstChild() const;
-
- /**
- * Allow duplicate files in the playlist.
- */
- void setAllowDuplicates(bool allow) { m_allowDuplicates = allow; }
-
- /**
- * This is being used as a mini-factory of sorts to make the construction
- * of PlaylistItems virtual. In this case it allows for the creation of
- * both PlaylistItems and CollectionListItems.
- */
- virtual PlaylistItem *createItem(const FileHandle &file,
- Q3ListViewItem *after = 0,
- bool emitChanged = true);
-
- /**
- * This is implemented as a template method to allow subclasses to
- * instantiate their PlaylistItem subclasses using the same method.
- */
- template <class ItemType>
- ItemType *createItem(const FileHandle &file,
- Q3ListViewItem *after = 0,
- bool emitChanged = true);
-
- virtual void createItems(const PlaylistItemList &siblings, PlaylistItem *after = 0);
-
- /**
- * This handles adding files of various types -- music, playlist or directory
- * files. Music files that are found will be added to this playlist. New
- * playlist files that are found will result in new playlists being created.
- *
- * Note that this should not be used in the case of adding *only* playlist
- * items since it has the overhead of checking to see if the file is a playlist
- * or directory first.
- */
- virtual void addFiles(const QStringList &files, PlaylistItem *after = 0);
-
- /**
- * Returns the file name associated with this playlist (an m3u file) or
- * an empty QString if no such file exists.
- */
- QString fileName() const { return m_fileName; }
-
- /**
- * Sets the file name to be associated with this playlist; this file should
- * have the "m3u" extension.
- */
- void setFileName(const QString &n) { m_fileName = n; }
-
- /**
- * Hides column \a c. If \a updateSearch is true then a signal that the
- * visible columns have changed will be emitted and things like the search
- * will be udated.
- */
- void hideColumn(int c, bool updateSearch = true);
-
- /**
- * Shows column \a c. If \a updateSearch is true then a signal that the
- * visible columns have changed will be emitted and things like the search
- * will be udated.
- */
- void showColumn(int c, bool updateSearch = true);
- bool isColumnVisible(int c) const;
-
- /**
- * This sets a name for the playlist that is \e different from the file name.
- */
- void setName(const QString &n);
-
- /**
- * Returns the KActionMenu that allows this to be embedded in menus outside
- * of the playlist.
- */
- KActionMenu *columnVisibleAction() const { return m_columnVisibleAction; }
-
- /**
- * Set item to be the playing item. If \a item is null then this will clear
- * the playing indicator.
- */
- static void setPlaying(PlaylistItem *item, bool addToHistory = true);
-
- /**
- * Returns true if this playlist is currently playing.
- */
- bool playing() const;
-
- /**
- * This forces an update of the left most visible column, but does not save
- * the settings for this.
- */
- void updateLeftColumn();
-
- /**
- * Returns the leftmost visible column of the listview.
- */
- int leftColumn() const { return m_leftColumn; }
-
- /**
- * Sets the items in the list to be either visible based on the value of
- * visible. This is useful for search operations and such.
- */
- static void setItemsVisible(const PlaylistItemList &items, bool visible = true);
-
- /**
- * Returns the search associated with this list, or an empty search if one
- * has not yet been set.
- */
- PlaylistSearch search() const { return m_search; }
-
- /**
- * Set the search associtated with this playlist.
- */
- void setSearch(const PlaylistSearch &s);
-
- /**
- * If the search is disabled then all items will be shown, not just those that
- * match the current search.
- */
- void setSearchEnabled(bool searchEnabled);
-
- /**
- * Marks \a item as either selected or deselected based.
- */
- void markItemSelected(PlaylistItem *item, bool selected);
-
- /**
- * Subclasses of Playlist which add new columns will set this value to
- * specify how many of those columns exist. This allows the Playlist
- * class to do some internal calculations on the number and positions
- * of columns.
- */
- virtual int columnOffset() const { return 0; }
-
- /**
- * Some subclasses of Playlist will be "read only" lists (i.e. the history
- * playlist). This is a way for those subclasses to indicate that to the
- * Playlist internals.
- */
- virtual bool readOnly() const { return false; }
-
- /**
- * Returns true if it's possible to reload this playlist.
- */
- virtual bool canReload() const { return !m_fileName.isEmpty(); }
-
- /**
- * Returns true if the playlist is a search playlist and the search should be
- * editable.
- */
- virtual bool searchIsEditable() const { return false; }
-
- /**
- * Synchronizes the playing item in this playlist with the playing item
- * in \a sources. If \a setMaster is true, this list will become the source
- * for determining the next item.
- */
- void synchronizePlayingItems(const PlaylistList &sources, bool setMaster);
-
- /**
- * Playlists have a common set of shared settings such as visible columns
- * that should be applied just before the playlist is shown. Calling this
- * method applies those.
- */
- void applySharedSettings();
-
- void read(QDataStream &s);
-
- static void setShuttingDown() { m_shuttingDown = true; }
-
-public slots:
- /**
- * Remove the currently selected items from the playlist and disk.
- */
- void slotRemoveSelectedItems() { removeFromDisk(selectedItems()); }
-
- /*
- * The edit slots are required to use the canonical names so that they are
- * detected by the application wide framework.
- */
- virtual void cut() { copy(); clear(); }
-
- /**
- * Puts a list of URLs pointing to the files in the current selection on the
- * clipboard.
- */
- virtual void copy();
-
- /**
- * Checks the clipboard for local URLs to be inserted into this playlist.
- */
- virtual void paste();
-
- /**
- * Removes the selected items from the list, but not the disk.
- *
- * @see clearItem()
- * @see clearItems()
- */
- virtual void clear();
- virtual void selectAll() { K3ListView::selectAll(true); }
-
- /**
- * Refreshes the tags of the selection from disk, or all of the files in the
- * list if there is no selection.
- */
- virtual void slotRefresh();
-
- void slotGuessTagInfo(TagGuesser::Type type);
-
- /**
- * Renames the selected items' files based on their tags contents.
- *
- * @see PlaylistItem::renameFile()
- */
- void slotRenameFile();
-
- /**
- * Sets the cover of the selected items, pass in true if you want to load from the local system,
- * false if you want to load from the internet.
- */
- void slotAddCover(bool fromLocal);
-
- /**
- * Shows a large image of the cover
- */
- void slotViewCover();
-
- /**
- * Removes covers from the selected items
- */
- void slotRemoveCover();
-
- /**
- * Shows the cover manager GUI dialog
- */
- void slotShowCoverManager();
-
- /**
- * Reload the playlist contents from the m3u file.
- */
- virtual void slotReload();
-
- /**
- * Tells the listview that the next time that it paints that the weighted
- * column widths must be recalculated. If this is called without a column
- * all visible columns are marked as dirty.
- */
- void slotWeightDirty(int column = -1);
-
- void slotShowPlaying();
-
- void slotColumnResizeModeChanged();
-
- virtual void dataChanged();
-
-protected:
- /**
- * Remove \a items from the playlist and disk. This will ignore items that
- * are not actually in the list.
- */
- void removeFromDisk(const PlaylistItemList &items);
-
- // the following are all reimplemented from base classes
-
- virtual bool eventFilter(QObject *watched, QEvent *e);
- virtual void keyPressEvent(QKeyEvent *e);
- virtual Q3DragObject *dragObject(QWidget *parent);
- virtual Q3DragObject *dragObject() { return dragObject(this); }
- virtual void decode(const QMimeData *s, PlaylistItem *item = 0);
- virtual void contentsDropEvent(QDropEvent *e);
- virtual void contentsMouseDoubleClickEvent(QMouseEvent *e);
- virtual void contentsDragEnterEvent(QDragEnterEvent *e);
- virtual void showEvent(QShowEvent *e);
- virtual bool acceptDrag(QDropEvent *e) const;
- virtual void viewportPaintEvent(QPaintEvent *pe);
- virtual void viewportResizeEvent(QResizeEvent *re);
-
- virtual void insertItem(Q3ListViewItem *item);
- virtual void takeItem(Q3ListViewItem *item);
-
- virtual bool hasItem(const QString &file) const { return m_members.contains(file); }
-
- virtual int addColumn(const QString &label, int width = -1);
- using K3ListView::addColumn;
-
- /**
- * Do some finial initialization of created items. Notably ensure that they
- * are shown or hidden based on the contents of the current PlaylistSearch.
- *
- * This is called by the PlaylistItem constructor.
- */
- void setupItem(PlaylistItem *item);
-
- /**
- * Forwards the call to the parent to enable or disable automatic deletion
- * of tree view playlists. Used by CollectionListItem.
- */
- void setDynamicListsFrozen(bool frozen);
-
- template <class ItemType, class SiblingType>
- ItemType *createItem(SiblingType *sibling, ItemType *after = 0);
-
- /**
- * As a template this allows us to use the same code to initialize the items
- * in subclasses. ItemType should be a PlaylistItem subclass.
- */
- template <class ItemType, class SiblingType>
- void createItems(const QList<SiblingType *> &siblings, ItemType *after = 0);
-
-protected slots:
- void slotPopulateBackMenu() const;
- void slotPlayFromBackMenu(QAction *) const;
-
-signals:
-
- /**
- * This is connected to the PlaylistBox::Item to let it know when the
- * playlist's name has changed.
- */
- void signalNameChanged(const QString &name);
-
- /**
- * This signal is emitted just before a playlist item is removed from the
- * list allowing for any cleanup that needs to happen. Typically this
- * is used to remove the item from the history and safeguard against
- * dangling pointers.
- */
- void signalAboutToRemove(PlaylistItem *item);
-
- void signalEnableDirWatch(bool enable);
-
- void signalPlaylistItemsDropped(Playlist *p);
-
-private:
- void setup();
-
- /**
- * This function is called to let the user know that JuK has automatically enabled
- * manual column width adjust mode.
- */
- void notifyUserColumnWidthModeChanged();
-
- /**
- * Load the playlist from a file. \a fileName should be the absolute path.
- * \a fileInfo should point to the same file as \a fileName. This is a
- * little awkward API-wise, but keeps us from throwing away useful
- * information.
- */
- void loadFile(const QString &fileName, const QFileInfo &fileInfo);
-
- /**
- * Writes \a text to \a item in \a column. This is used by the inline tag
- * editor. Returns false if the tag update failed.
- */
- bool editTag(PlaylistItem *item, const QString &text, int column);
-
- /**
- * Returns the index of the left most visible column in the playlist.
- *
- * \see isColumnVisible()
- */
- int leftMostVisibleColumn() const;
-
- /**
- * This method is used internally to provide the backend to the other item
- * lists.
- *
- * \see items()
- * \see visibleItems()
- * \see selectedItems()
- */
- PlaylistItemList items(Q3ListViewItemIterator::IteratorFlag flags);
-
- /**
- * Build the column "weights" for the weighted width mode.
- */
- void calculateColumnWeights();
-
- void addFile(const QString &file, FileHandleList &files, bool importPlaylists,
- PlaylistItem **after);
- void addFileHelper(FileHandleList &files, PlaylistItem **after,
- bool ignoreTimer = false);
-
- void redisplaySearch() { setSearch(m_search); }
-
- /**
- * Sets the cover for items to the cover identified by id.
- */
- void refreshAlbums(const PlaylistItemList &items, coverKey id = CoverManager::NoMatch);
-
- void refreshAlbum(const QString &artist, const QString &album);
-
- void updatePlaying() const;
-
- /**
- * This function should be called when item is deleted to ensure that any
- * internal bookkeeping is performed. It is automatically called by
- * PlaylistItem::~PlaylistItem and by clearItem() and clearItems().
- */
- void updateDeletedItem(PlaylistItem *item);
-
- /**
- * Used as a helper to implement template<> createItem(). This grabs the
- * CollectionListItem for file if it exists, otherwise it creates a new one and
- * returns that. If 0 is returned then some kind of error occurred, such as file not
- * found and probably nothing should be done with the FileHandle you have.
- */
- CollectionListItem *collectionListItem(const FileHandle &file);
-
- /**
- * This class is used internally to store settings that are shared by all
- * of the playlists, such as column order. It is implemented as a singleton.
- */
- class SharedSettings;
-
- using K3ListView::selectAll; // Avoid warning about hiding this function.
-
-private slots:
-
- /**
- * Handle the necessary tasks needed to create and setup the playlist that
- * don't need to happen in the ctor, such as setting up the columns,
- * initializing the RMB menu, and setting up signal/slot connections.
- *
- * Used to be a subclass of K3ListView::polish() but the timing of the
- * call is not consistent and therefore lead to crashes.
- */
- void slotInitialize();
-
- void slotUpdateColumnWidths();
-
- void slotAddToUpcoming();
-
- /**
- * Show the RMB menu. Matches the signature for the signal
- * QListView::contextMenuRequested().
- */
- void slotShowRMBMenu(Q3ListViewItem *item, const QPoint &point, int column);
-
- /**
- * This slot is called when the inline tag editor has completed its editing
- * and starts the process of renaming the values.
- *
- * \see editTag()
- */
- void slotInlineEditDone(Q3ListViewItem *, const QString &, int column);
-
- /**
- * This starts the renaming process by displaying a line edit if the mouse is in
- * an appropriate position.
- */
- void slotRenameTag();
-
- /**
- * The image fetcher will update the cover asynchronously, this internal
- * slot is called when it happens.
- */
- void slotCoverChanged(int coverId);
-
- /**
- * Moves the column \a from to the position \a to. This matches the signature
- * for the signal QHeader::indexChange().
- */
- void slotColumnOrderChanged(int, int from, int to);
-
- /**
- * Toggles a columns visible status. Useful for KActions.
- *
- * \see hideColumn()
- * \see showColumn()
- */
- void slotToggleColumnVisible(QAction *action);
-
- /**
- * Prompts the user to create a new playlist with from the selected items.
- */
- void slotCreateGroup();
-
- /**
- * This slot is called when the user drags the slider in the listview header
- * to manually set the size of the column.
- */
- void slotColumnSizeChanged(int column, int oldSize, int newSize);
-
- /**
- * The slot is called when the completion mode for the line edit in the
- * inline tag editor is changed. It saves the settings and through the
- * magic of the SharedSettings class will apply it to the other playlists as
- * well.
- */
- void slotInlineCompletionModeChanged(KGlobalSettings::Completion mode);
-
- void slotPlayCurrent();
-
-private:
- friend class PlaylistItem;
-
- PlaylistCollection *m_collection;
-
- StringHash m_members;
-
- WebImageFetcher *m_fetcher;
-
- int m_currentColumn;
- QAction *m_rmbEdit;
- int m_selectedCount;
-
- bool m_allowDuplicates;
- bool m_applySharedSettings;
- bool m_columnWidthModeChanged;
-
- QList<int> m_weightDirty;
- bool m_disableColumnWidthUpdates;
-
- mutable int m_time;
- mutable PlaylistItemList m_addTime;
- mutable PlaylistItemList m_subtractTime;
-
- /**
- * The average minimum widths of columns to be used in balancing calculations.
- */
- QVector<int> m_columnWeights;
- QVector<int> m_columnFixedWidths;
- bool m_widthsDirty;
-
- static PlaylistItemList m_history;
- PlaylistSearch m_search;
-
- bool m_searchEnabled;
-
- PlaylistItem *m_lastSelected;
-
- /**
- * Used to store the text for inline editing before it is changed so that
- * we can know if something actually changed and as such if we need to save
- * the tag.
- */
- QString m_editText;
-
- /**
- * This is only defined if the playlist name is something other than the
- * file name.
- */
- QString m_playlistName;
- QString m_fileName;
-
- KMenu *m_rmbMenu;
- KMenu *m_headerMenu;
- KActionMenu *m_columnVisibleAction;
- PlaylistToolTip *m_toolTip;
-
- /**
- * This is used to indicate if the list of visible items has changed (via a
- * call to setVisibleItems()) while random play is playing.
- */
- static bool m_visibleChanged;
- static bool m_shuttingDown;
- static int m_leftColumn;
- static QVector<PlaylistItem *> m_backMenuItems;
-
- bool m_blockDataChanged;
-};
-
-typedef QList<Playlist *> PlaylistList;
-
-bool processEvents();
-
-class FocusUpEvent : public QEvent
-{
-public:
- FocusUpEvent() : QEvent(id) {}
- Type type() const { return id; }
-
- static const Type id = static_cast<Type>(QEvent::User + 1);
-};
-
-QDataStream &operator<<(QDataStream &s, const Playlist &p);
-QDataStream &operator>>(QDataStream &s, Playlist &p);
-
-// template method implementations
-
-template <class ItemType>
-ItemType *Playlist::createItem(const FileHandle &file, Q3ListViewItem *after,
- bool emitChanged)
-{
- CollectionListItem *item = collectionListItem(file);
- if(item && (!m_members.insert(file.absFilePath()) || m_allowDuplicates)) {
-
- ItemType *i = after ? new ItemType(item, this, after) : new ItemType(item, this);
- setupItem(i);
-
- if(emitChanged)
- dataChanged();
-
- return i;
- }
- else
- return 0;
-}
-
-template <class ItemType, class SiblingType>
-ItemType *Playlist::createItem(SiblingType *sibling, ItemType *after)
-{
- m_disableColumnWidthUpdates = true;
-
- if(!m_members.insert(sibling->file().absFilePath()) || m_allowDuplicates) {
- after = new ItemType(sibling->collectionItem(), this, after);
- setupItem(after);
- }
-
- m_disableColumnWidthUpdates = false;
-
- return after;
-}
-
-template <class ItemType, class SiblingType>
-void Playlist::createItems(const QList<SiblingType *> &siblings, ItemType *after)
-{
- if(siblings.isEmpty())
- return;
-
- foreach(SiblingType *sibling, siblings)
- after = createItem(sibling, after);
-
- dataChanged();
- slotWeightDirty();
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistbox.h"
-
-#include <kicon.h>
-#include <kiconloader.h>
-#include <kmessagebox.h>
-#include <kmenu.h>
-#include <kaction.h>
-#include <kactioncollection.h>
-#include <kdebug.h>
-#include <ktoggleaction.h>
-#include <kselectaction.h>
-#include <kconfiggroup.h>
-
-#include <Q3Header>
-#include <QPainter>
-#include <QTimer>
-#include <QDragLeaveEvent>
-#include <QList>
-#include <QDragMoveEvent>
-#include <QKeyEvent>
-#include <QDropEvent>
-#include <QMouseEvent>
-#include <QFileInfo>
-#include <QTime>
-#include <QApplication>
-#include <QClipboard>
-
-#include "playlist.h"
-#include "collectionlist.h"
-#include "dynamicplaylist.h"
-#include "upcomingplaylist.h"
-#include "historyplaylist.h"
-#include "viewmode.h"
-#include "searchplaylist.h"
-#include "treeviewitemplaylist.h"
-#include "actioncollection.h"
-#include "cache.h"
-#include "k3bexporter.h"
-#include "tracksequencemanager.h"
-#include "tagtransactionmanager.h"
-#include "playermanager.h"
-#include "dbuscollectionproxy.h"
-
-using namespace ActionCollection;
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistBox::PlaylistBox(PlayerManager *player, QWidget *parent, QStackedWidget *playlistStack) :
- K3ListView(parent),
- PlaylistCollection(player, playlistStack),
- m_viewModeIndex(0),
- m_hasSelection(false),
- m_doingMultiSelect(false),
- m_dropItem(0),
- m_showTimer(0)
-{
- readConfig();
- addColumn("Playlists", width());
-
- header()->blockSignals(true);
- header()->hide();
- header()->blockSignals(false);
-
- setSorting(0);
- setFullWidth(true);
- setItemMargin(3);
-
- setAcceptDrops(true);
- setSelectionModeExt(Extended);
-
- m_contextMenu = new KMenu(this);
-
- K3bPlaylistExporter *exporter = new K3bPlaylistExporter(this);
- m_k3bAction = exporter->action();
-
- m_contextMenu->addAction( action("file_new") );
- m_contextMenu->addAction( action("renamePlaylist") );
- m_contextMenu->addAction( action("editSearch") );
- m_contextMenu->addAction( action("duplicatePlaylist") );
- m_contextMenu->addAction( action("reloadPlaylist") );
- m_contextMenu->addAction( action("deleteItemPlaylist") );
- m_contextMenu->addAction( action("file_save") );
- m_contextMenu->addAction( action("file_save_as") );
- if(m_k3bAction)
- m_contextMenu->addAction( m_k3bAction );
-
- m_contextMenu->addSeparator();
-
- // add the view modes stuff
-
- KSelectAction *viewModeAction =
- new KSelectAction( KIcon("view-choose"), i18n("View Modes"), ActionCollection::actions());
- ActionCollection::actions()->addAction("viewModeMenu", viewModeAction);
-
- ViewMode* viewmode = new ViewMode(this);
- m_viewModes.append(viewmode);
- viewModeAction->addAction(KIcon("view-list-details"), viewmode->name());
-
- CompactViewMode* compactviewmode = new CompactViewMode(this);
- m_viewModes.append(compactviewmode);
- viewModeAction->addAction(KIcon("view-list-text"), compactviewmode->name());
-
- TreeViewMode* treeviewmode = new TreeViewMode(this);
- m_viewModes.append(treeviewmode);
- viewModeAction->addAction(KIcon("view-list-tree"), treeviewmode->name());
-
- CollectionList::initialize(this);
-
- viewModeAction->setCurrentItem(m_viewModeIndex);
- m_viewModes[m_viewModeIndex]->setShown(true);
-
- TrackSequenceManager::instance()->setCurrentPlaylist(CollectionList::instance());
- raise(CollectionList::instance());
-
- m_contextMenu->addAction( viewModeAction );
- connect(viewModeAction, SIGNAL(triggered(int)), this, SLOT(slotSetViewMode(int)));
-
- connect(this, SIGNAL(selectionChanged()),
- this, SLOT(slotPlaylistChanged()));
-
- connect(this, SIGNAL(doubleClicked(Q3ListViewItem*)),
- this, SLOT(slotDoubleClicked(Q3ListViewItem*)));
-
- connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)),
- this, SLOT(slotShowContextMenu(Q3ListViewItem*,QPoint,int)));
-
- TagTransactionManager *tagManager = TagTransactionManager::instance();
- connect(tagManager, SIGNAL(signalAboutToModifyTags()), SLOT(slotFreezePlaylists()));
- connect(tagManager, SIGNAL(signalDoneModifyingTags()), SLOT(slotUnfreezePlaylists()));
-
- setupUpcomingPlaylist();
-
- connect(CollectionList::instance(), SIGNAL(signalNewTag(QString,uint)),
- this, SLOT(slotAddItem(QString,uint)));
- connect(CollectionList::instance(), SIGNAL(signalRemovedTag(QString,uint)),
- this, SLOT(slotRemoveItem(QString,uint)));
- connect(CollectionList::instance(), SIGNAL(cachedItemsLoaded()),
- this, SLOT(slotLoadCachedPlaylists()));
-
- m_savePlaylistTimer = 0;
-
- KToggleAction *historyAction =
- new KToggleAction(KIcon("view-history"), i18n("Show &History"), ActionCollection::actions());
- ActionCollection::actions()->addAction("showHistory", historyAction);
- connect(historyAction, SIGNAL(triggered(bool)),
- this, SLOT(slotSetHistoryPlaylistEnabled(bool)));
-
- m_showTimer = new QTimer(this);
- connect(m_showTimer, SIGNAL(timeout()), SLOT(slotShowDropTarget()));
-
- // hook up to the D-Bus
- (void) new DBusCollectionProxy(this, this);
-}
-
-PlaylistBox::~PlaylistBox()
-{
- PlaylistList l;
- CollectionList *collection = CollectionList::instance();
- for(Q3ListViewItem *i = firstChild(); i; i = i->nextSibling()) {
- Item *item = static_cast<Item *>(i);
- if(item->playlist() && item->playlist() != collection)
- l.append(item->playlist());
- }
-
- Cache::savePlaylists(l);
- saveConfig();
-}
-
-void PlaylistBox::raise(Playlist *playlist)
-{
- if(!playlist)
- return;
-
- Item *i = m_playlistDict.value(playlist, 0);
-
- if(i) {
- clearSelection();
- setSelected(i, true);
-
- setSingleItem(i);
- ensureItemVisible(currentItem());
- }
- else
- PlaylistCollection::raise(playlist);
-
- slotPlaylistChanged();
-}
-
-void PlaylistBox::duplicate()
-{
- Item *item = static_cast<Item *>(currentItem());
- if(!item || !item->playlist())
- return;
-
- QString name = playlistNameDialog(i18nc("verb, copy the playlist", "Duplicate"), item->text(0));
-
- if(name.isNull())
- return;
-
- Playlist *p = new Playlist(this, name);
- p->createItems(item->playlist()->items());
-}
-
-void PlaylistBox::scanFolders()
-{
- kDebug() << "Starting folder scan";
- QTime stopwatch; stopwatch.start();
-
- PlaylistCollection::scanFolders();
-
- kDebug() << "Folder scan complete, took" << stopwatch.elapsed() << "ms";
- kDebug() << "Startup complete!";
- emit startupComplete();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::paste()
-{
- Item *i = static_cast<Item *>(currentItem());
- decode(QApplication::clipboard()->mimeData(), i);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::slotFreezePlaylists()
-{
- setDynamicListsFrozen(true);
-}
-
-void PlaylistBox::slotUnfreezePlaylists()
-{
- setDynamicListsFrozen(false);
-}
-
-void PlaylistBox::slotPlaylistDataChanged()
-{
- if(m_savePlaylistTimer)
- m_savePlaylistTimer->start(); // Restarts the timer if it's already running.
-}
-
-void PlaylistBox::slotSetHistoryPlaylistEnabled(bool enable)
-{
- setHistoryPlaylistEnabled(enable);
-}
-
-void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName)
-{
- setupPlaylist(playlist, iconName, 0);
-}
-
-void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName, Item *parentItem)
-{
- connect(playlist, SIGNAL(signalPlaylistItemsDropped(Playlist*)),
- SLOT(slotPlaylistItemsDropped(Playlist*)));
-
- PlaylistCollection::setupPlaylist(playlist, iconName);
-
- if(parentItem)
- new Item(parentItem, iconName, playlist->name(), playlist);
- else
- new Item(this, iconName, playlist->name(), playlist);
-}
-
-void PlaylistBox::removePlaylist(Playlist *playlist)
-{
- // Could be false if setup() wasn't run yet.
- if(m_playlistDict.contains(playlist)) {
- removeNameFromDict(m_playlistDict[playlist]->text(0));
- delete m_playlistDict[playlist]; // Delete the Item*
- }
-
- removeFileFromDict(playlist->fileName());
- m_playlistDict.remove(playlist);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::readConfig()
-{
- KConfigGroup config(KGlobal::config(), "PlaylistBox");
- m_viewModeIndex = config.readEntry("ViewMode", 0);
-}
-
-void PlaylistBox::saveConfig()
-{
- KConfigGroup config(KGlobal::config(), "PlaylistBox");
- config.writeEntry("ViewMode", action<KSelectAction>("viewModeMenu")->currentItem());
- KGlobal::config()->sync();
-}
-
-void PlaylistBox::remove()
-{
- ItemList items = selectedBoxItems();
-
- if(items.isEmpty())
- return;
-
- QStringList files;
- QStringList names;
-
- foreach(Item *item, items) {
- if(item && item->playlist())
- {
- if (!item->playlist()->fileName().isEmpty() &&
- QFileInfo(item->playlist()->fileName()).exists())
- {
- files.append(item->playlist()->fileName());
- }
-
- names.append(item->playlist()->name());
- }
- }
-
- if(!files.isEmpty()) {
- int remove = KMessageBox::warningYesNoCancelList(
- this, i18n("Do you want to delete these files from the disk as well?"), files, QString(), KStandardGuiItem::del(), KGuiItem(i18n("Keep")));
-
- if(remove == KMessageBox::Yes) {
- QStringList couldNotDelete;
- for(QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
- if(!QFile::remove(*it))
- couldNotDelete.append(*it);
- }
-
- if(!couldNotDelete.isEmpty())
- KMessageBox::errorList(this, i18n("Could not delete these files."), couldNotDelete);
- }
- else if(remove == KMessageBox::Cancel)
- return;
- }
- else if(items.count() > 1 || items.front()->playlist() != upcomingPlaylist()) {
- if(KMessageBox::warningContinueCancelList(this,
- i18n("Are you sure you want to remove these "
- "playlists from your collection?"),
- names,
- i18n("Remove Items?"),
- KGuiItem(i18n("&Remove"), "user-trash")) == KMessageBox::Cancel)
- {
- return;
- }
- }
-
- PlaylistList removeQueue;
-
- for(ItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
- if(*it != Item::collectionItem() &&
- (*it)->playlist() &&
- (!(*it)->playlist()->readOnly()))
- {
- removeQueue.append((*it)->playlist());
- }
- }
-
- if(items.back()->nextSibling() && static_cast<Item *>(items.back()->nextSibling())->playlist())
- setSingleItem(items.back()->nextSibling());
- else {
- Item *i = static_cast<Item *>(items.front()->itemAbove());
- while(i && !i->playlist())
- i = static_cast<Item *>(i->itemAbove());
-
- if(!i)
- i = Item::collectionItem();
-
- setSingleItem(i);
- }
-
- for(PlaylistList::ConstIterator it = removeQueue.constBegin(); it != removeQueue.constEnd(); ++it) {
- if(*it != upcomingPlaylist())
- delete *it;
- else {
- action<KToggleAction>("showUpcoming")->setChecked(false);
- setUpcomingPlaylistEnabled(false);
- }
- }
-}
-
-void PlaylistBox::setDynamicListsFrozen(bool frozen)
-{
- for(QList<ViewMode *>::Iterator it = m_viewModes.begin();
- it != m_viewModes.end();
- ++it)
- {
- (*it)->setDynamicListsFrozen(frozen);
- }
-}
-
-void PlaylistBox::slotSavePlaylists()
-{
- kDebug() << "Auto-saving playlists.\n";
-
- PlaylistList l;
- CollectionList *collection = CollectionList::instance();
- for(Q3ListViewItem *i = firstChild(); i; i = i->nextSibling()) {
- Item *item = static_cast<Item *>(i);
- if(item->playlist() && item->playlist() != collection)
- l.append(item->playlist());
- }
-
- Cache::savePlaylists(l);
-}
-
-void PlaylistBox::slotShowDropTarget()
-{
- if(!m_dropItem) {
- kError() << "Trying to show the playlist of a null item!\n";
- return;
- }
-
- raise(m_dropItem->playlist());
-}
-
-void PlaylistBox::slotAddItem(const QString &tag, unsigned column)
-{
- for(QList<ViewMode *>::Iterator it = m_viewModes.begin(); it != m_viewModes.end(); ++it)
- (*it)->addItems(QStringList(tag), column);
-}
-
-void PlaylistBox::slotRemoveItem(const QString &tag, unsigned column)
-{
- for(QList<ViewMode *>::Iterator it = m_viewModes.begin(); it != m_viewModes.end(); ++it)
- (*it)->removeItem(tag, column);
-}
-
-void PlaylistBox::decode(const QMimeData *s, Item *item)
-{
- if(!s || (item && item->playlist() && item->playlist()->readOnly()))
- return;
-
- const KUrl::List urls = KUrl::List::fromMimeData(s);
-
- if(!urls.isEmpty()) {
- QStringList files;
- for(KUrl::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it)
- files.append((*it).path());
-
- if(item) {
- TreeViewItemPlaylist *playlistItem;
- playlistItem = dynamic_cast<TreeViewItemPlaylist *>(item->playlist());
- if(playlistItem) {
- playlistItem->retag(files, currentPlaylist());
- TagTransactionManager::instance()->commit();
- currentPlaylist()->update();
- return;
- }
- }
-
- if(item && item->playlist())
- item->playlist()->addFiles(files);
- else {
- QString name = playlistNameDialog();
- if(!name.isNull()) {
- Playlist *p = new Playlist(this, name);
- p->addFiles(files);
- }
- }
- }
-}
-
-void PlaylistBox::contentsDropEvent(QDropEvent *e)
-{
- m_showTimer->stop();
-
- Item *i = static_cast<Item *>(itemAt(contentsToViewport(e->pos())));
- decode(e->mimeData(), i);
-
- if(m_dropItem) {
- Item *old = m_dropItem;
- m_dropItem = 0;
- old->repaint();
- }
-}
-
-void PlaylistBox::contentsDragMoveEvent(QDragMoveEvent *e)
-{
- // If we can decode the input source, there is a non-null item at the "move"
- // position, the playlist for that Item is non-null, is not the
- // selected playlist and is not the CollectionList, then accept the event.
- //
- // Otherwise, do not accept the event.
-
- if (!KUrl::List::canDecode(e->mimeData())) {
- e->setAccepted(false);
- return;
- }
-
- Item *target = static_cast<Item *>(itemAt(contentsToViewport(e->pos())));
-
- if(target) {
-
- if(target->playlist() && target->playlist()->readOnly())
- return;
-
- // This is a semi-dirty hack to check if the items are coming from within
- // JuK. If they are not coming from a Playlist (or subclass) then the
- // dynamic_cast will fail and we can safely assume that the item is
- // coming from outside of JuK.
-
- if(dynamic_cast<Playlist *>(e->source())) {
- if(target->playlist() &&
- target->playlist() != CollectionList::instance() &&
- !target->isSelected())
- {
- e->setAccepted(true);
- }
- else
- e->setAccepted(false);
- }
- else // the dropped items are coming from outside of JuK
- e->setAccepted(true);
-
- if(m_dropItem != target) {
- Item *old = m_dropItem;
- m_showTimer->stop();
-
- if(e->isAccepted()) {
- m_dropItem = target;
- target->repaint();
- m_showTimer->setSingleShot(true);
- m_showTimer->start(1500);
- }
- else
- m_dropItem = 0;
-
- if(old)
- old->repaint();
- }
- }
- else {
-
- // We're dragging over the whitespace. We'll use this case to make it
- // possible to create new lists.
-
- e->setAccepted(true);
- }
-}
-
-void PlaylistBox::contentsDragLeaveEvent(QDragLeaveEvent *e)
-{
- if(m_dropItem) {
- Item *old = m_dropItem;
- m_dropItem = 0;
- old->repaint();
- }
- K3ListView::contentsDragLeaveEvent(e);
-}
-
-void PlaylistBox::contentsMousePressEvent(QMouseEvent *e)
-{
- if(e->button() == Qt::LeftButton)
- m_doingMultiSelect = true;
- K3ListView::contentsMousePressEvent(e);
-}
-
-void PlaylistBox::contentsMouseReleaseEvent(QMouseEvent *e)
-{
- if(e->button() == Qt::LeftButton) {
- m_doingMultiSelect = false;
- slotPlaylistChanged();
- }
- K3ListView::contentsMouseReleaseEvent(e);
-}
-
-void PlaylistBox::keyPressEvent(QKeyEvent *e)
-{
- if((e->key() == Qt::Key_Up || e->key() == Qt::Key_Down) && e->modifiers() == Qt::ShiftButton)
- m_doingMultiSelect = true;
- K3ListView::keyPressEvent(e);
-}
-
-void PlaylistBox::keyReleaseEvent(QKeyEvent *e)
-{
- if(m_doingMultiSelect && e->key() == Qt::Key_Shift) {
- m_doingMultiSelect = false;
- slotPlaylistChanged();
- }
- K3ListView::keyReleaseEvent(e);
-}
-
-PlaylistBox::ItemList PlaylistBox::selectedBoxItems() const
-{
- ItemList l;
-
- for(Q3ListViewItemIterator it(const_cast<PlaylistBox *>(this),
- Q3ListViewItemIterator::Selected); it.current(); ++it)
- l.append(static_cast<Item *>(*it));
-
- return l;
-}
-
-void PlaylistBox::setSingleItem(Q3ListViewItem *item)
-{
- setSelectionModeExt(Single);
- K3ListView::setCurrentItem(item);
- setSelectionModeExt(Extended);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::slotPlaylistChanged()
-{
- // Don't update while the mouse is pressed down.
-
- if(m_doingMultiSelect)
- return;
-
- ItemList items = selectedBoxItems();
- m_hasSelection = !items.isEmpty();
-
- bool allowReload = false;
-
- PlaylistList playlists;
- for(ItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
-
- Playlist *p = (*it)->playlist();
- if(p) {
- if(p->canReload())
- allowReload = true;
- playlists.append(p);
- }
- }
-
- bool singlePlaylist = playlists.count() == 1;
-
- if(playlists.isEmpty() ||
- (singlePlaylist &&
- (playlists.front() == CollectionList::instance() ||
- playlists.front()->readOnly())))
- {
- action("file_save")->setEnabled(false);
- action("file_save_as")->setEnabled(false);
- action("renamePlaylist")->setEnabled(false);
- action("deleteItemPlaylist")->setEnabled(false);
- }
- else {
- action("file_save")->setEnabled(true);
- action("file_save_as")->setEnabled(true);
- action("renamePlaylist")->setEnabled(playlists.count() == 1);
- action("deleteItemPlaylist")->setEnabled(true);
- }
- action("reloadPlaylist")->setEnabled(allowReload);
- action("duplicatePlaylist")->setEnabled(!playlists.isEmpty());
-
- if(m_k3bAction)
- m_k3bAction->setEnabled(!playlists.isEmpty());
-
- action("editSearch")->setEnabled(singlePlaylist &&
- playlists.front()->searchIsEditable());
-
- if(singlePlaylist) {
- PlaylistCollection::raise(playlists.front());
-
- if(playlists.front() == upcomingPlaylist())
- action("deleteItemPlaylist")->setText(i18n("Hid&e"));
- else
- action("deleteItemPlaylist")->setText(i18n("R&emove"));
- }
- else if(!playlists.isEmpty())
- createDynamicPlaylist(playlists);
-}
-
-void PlaylistBox::slotDoubleClicked(Q3ListViewItem *item)
-{
- if(!item)
- return;
-
- TrackSequenceManager *manager = TrackSequenceManager::instance();
- Item *playlistItem = static_cast<Item *>(item);
-
- manager->setCurrentPlaylist(playlistItem->playlist());
-
- manager->setCurrent(0); // Reset playback
- PlaylistItem *next = manager->nextItem(); // Allow manager to choose
-
- if(next) {
- emit startFilePlayback(next->file());
- playlistItem->playlist()->setPlaying(next);
- }
- else
- action("stop")->trigger();
-}
-
-void PlaylistBox::slotShowContextMenu(Q3ListViewItem *, const QPoint &point, int)
-{
- m_contextMenu->popup(point);
-}
-
-void PlaylistBox::slotPlaylistItemsDropped(Playlist *p)
-{
- raise(p);
-}
-
-void PlaylistBox::slotSetViewMode(int index)
-{
- if(index == m_viewModeIndex)
- return;
-
- viewMode()->setShown(false);
- m_viewModeIndex = index;
- viewMode()->setShown(true);
-}
-
-void PlaylistBox::setupItem(Item *item)
-{
- m_playlistDict.insert(item->playlist(), item);
- viewMode()->queueRefresh();
-}
-
-void PlaylistBox::setupUpcomingPlaylist()
-{
- KConfigGroup config(KGlobal::config(), "Playlists");
- bool enable = config.readEntry("showUpcoming", false);
-
- setUpcomingPlaylistEnabled(enable);
- action<KToggleAction>("showUpcoming")->setChecked(enable);
-}
-
-
-void PlaylistBox::slotLoadCachedPlaylists()
-{
- kDebug() << "Loading cached playlists.";
- QTime stopwatch;
- stopwatch.start();
-
- Cache::loadPlaylists(this);
-
- kDebug() << "Cached playlists loaded, took" << stopwatch.elapsed() << "ms";
-
- // Auto-save playlists after they change.
- m_savePlaylistTimer = new QTimer(this);
- m_savePlaylistTimer->setInterval(3000); // 3 seconds with no change? -> commit
- m_savePlaylistTimer->setSingleShot(true);
- connect(m_savePlaylistTimer, SIGNAL(timeout()), SLOT(slotSavePlaylists()));
-
- clearSelection();
- setSelected(m_playlistDict[CollectionList::instance()], true);
-
- QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
- QTimer::singleShot(0, object(), SLOT(slotScanFolders()));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox::Item protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistBox::Item *PlaylistBox::Item::m_collectionItem = 0;
-
-PlaylistBox::Item::Item(PlaylistBox *listBox, const QString &icon, const QString &text, Playlist *l)
- : QObject(listBox), K3ListViewItem(listBox, 0, text),
- PlaylistObserver(l),
- m_playlist(l), m_text(text), m_iconName(icon), m_sortedFirst(false)
-{
- init();
-}
-
-PlaylistBox::Item::Item(Item *parent, const QString &icon, const QString &text, Playlist *l)
- : QObject(parent->listView()), K3ListViewItem(parent, text),
- PlaylistObserver(l),
- m_playlist(l), m_text(text), m_iconName(icon), m_sortedFirst(false)
-{
- init();
-}
-
-PlaylistBox::Item::~Item()
-{
-
-}
-
-int PlaylistBox::Item::compare(Q3ListViewItem *i, int col, bool) const
-{
- Item *otherItem = static_cast<Item *>(i);
- PlaylistBox *playlistBox = static_cast<PlaylistBox *>(listView());
-
- if(m_playlist == playlistBox->upcomingPlaylist() && otherItem->m_playlist != CollectionList::instance())
- return -1;
- if(otherItem->m_playlist == playlistBox->upcomingPlaylist() && m_playlist != CollectionList::instance())
- return 1;
-
- if(m_sortedFirst && !otherItem->m_sortedFirst)
- return -1;
- else if(otherItem->m_sortedFirst && !m_sortedFirst)
- return 1;
-
- return text(col).toLower().localeAwareCompare(i->text(col).toLower());
-}
-
-void PlaylistBox::Item::paintCell(QPainter *painter, const QColorGroup &colorGroup, int column, int width, int align)
-{
- PlaylistBox *playlistBox = static_cast<PlaylistBox *>(listView());
- playlistBox->viewMode()->paintCell(this, painter, colorGroup, column, width, align);
-}
-
-void PlaylistBox::Item::setText(int column, const QString &text)
-{
- m_text = text;
- K3ListViewItem::setText(column, text);
-}
-
-void PlaylistBox::Item::setup()
-{
- listView()->viewMode()->setupItem(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox::Item protected slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::Item::slotSetName(const QString &name)
-{
- if(listView()) {
- setText(0, name);
- setSelected(true);
-
- listView()->sort();
- listView()->ensureItemVisible(listView()->currentItem());
- listView()->viewMode()->queueRefresh();
- }
-}
-
-void PlaylistBox::Item::updateCurrent()
-{
-}
-
-void PlaylistBox::Item::updateData()
-{
- listView()->slotPlaylistDataChanged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistBox::Item private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistBox::Item::init()
-{
- PlaylistBox *list = listView();
-
- list->setupItem(this);
-
- int iconSize = list->viewModeIndex() == 0 ? 32 : 16;
- setPixmap(0, SmallIcon(m_iconName, iconSize));
- list->addNameToDict(m_text);
-
- if(m_playlist) {
- connect(m_playlist, SIGNAL(signalNameChanged(QString)),
- this, SLOT(slotSetName(QString)));
- connect(m_playlist, SIGNAL(signalEnableDirWatch(bool)),
- list->object(), SLOT(slotEnableDirWatch(bool)));
- }
-
- if(m_playlist == CollectionList::instance()) {
- m_sortedFirst = true;
- m_collectionItem = this;
- list->viewMode()->setupDynamicPlaylists();
- }
-
- if(m_playlist == list->historyPlaylist() || m_playlist == list->upcomingPlaylist())
- m_sortedFirst = true;
-}
-
-#include "playlistbox.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTBOX_H
-#define PLAYLISTBOX_H
-
-#include "playlistcollection.h"
-
-#include <k3listview.h>
-
-#include <QHash>
-
-class Playlist;
-class PlaylistItem;
-class ViewMode;
-
-class KMenu;
-
-template<class T>
-class QList;
-
-typedef QList<Playlist *> PlaylistList;
-
-/**
- * This is the play list selection box that is by default on the left side of
- * JuK's main widget (PlaylistSplitter).
- */
-
-class PlaylistBox : public K3ListView, public PlaylistCollection
-{
- Q_OBJECT
-
-public:
- class Item;
- typedef QList<Item *> ItemList;
-
- friend class Item;
-
- PlaylistBox(PlayerManager *player, QWidget *parent, QStackedWidget *playlistStack);
- virtual ~PlaylistBox();
-
- virtual void raise(Playlist *playlist);
- virtual void duplicate();
- virtual void remove();
-
- // Called after files loaded to pickup any new files that might be present
- // in managed directories.
- virtual void scanFolders();
-
- /**
- * For view modes that have dynamic playlists, this freezes them from
- * removing playlists.
- */
- virtual void setDynamicListsFrozen(bool frozen);
-
- Item *dropItem() const { return m_dropItem; }
-
- void setupPlaylist(Playlist *playlist, const QString &iconName, Item *parentItem = 0);
-
-public slots:
- void paste();
- void clear() {}
-
- void slotFreezePlaylists();
- void slotUnfreezePlaylists();
- void slotPlaylistDataChanged();
- void slotSetHistoryPlaylistEnabled(bool enable);
-
-protected:
- virtual void setupPlaylist(Playlist *playlist, const QString &iconName);
- virtual void removePlaylist(Playlist *playlist);
-
-signals:
- void signalPlaylistDestroyed(Playlist *);
- void startupComplete(); ///< Emitted after playlists are loaded.
- void startFilePlayback(const FileHandle &file);
-
-private:
- void readConfig();
- void saveConfig();
-
- virtual void decode(const QMimeData *s, Item *item);
- virtual void contentsDropEvent(QDropEvent *e);
- virtual void contentsDragMoveEvent(QDragMoveEvent *e);
- virtual void contentsDragLeaveEvent(QDragLeaveEvent *e);
- virtual void contentsMousePressEvent(QMouseEvent *e);
- virtual void contentsMouseReleaseEvent(QMouseEvent *e);
- virtual void keyPressEvent(QKeyEvent *e);
- virtual void keyReleaseEvent(QKeyEvent *e);
-
- // selectedItems already used for something different
-
- ItemList selectedBoxItems() const;
- void setSingleItem(Q3ListViewItem *item);
-
- void setupItem(Item *item);
- void setupUpcomingPlaylist();
- int viewModeIndex() const { return m_viewModeIndex; }
- ViewMode *viewMode() const { return m_viewModes[m_viewModeIndex]; }
-
-private slots:
- /**
- * Catches QListBox::currentChanged(QListBoxItem *), does a cast and then re-emits
- * the signal as currentChanged(Item *).
- */
- void slotPlaylistChanged();
- void slotDoubleClicked(Q3ListViewItem *);
- void slotShowContextMenu(Q3ListViewItem *, const QPoint &point, int);
- void slotSetViewMode(int index);
- void slotSavePlaylists();
- void slotShowDropTarget();
-
- void slotPlaylistItemsDropped(Playlist *p);
-
- void slotAddItem(const QString &tag, unsigned column);
- void slotRemoveItem(const QString &tag, unsigned column);
-
- // Used to load the playlists after GUI setup.
- void slotLoadCachedPlaylists();
-
-private:
- KMenu *m_contextMenu;
- QHash<Playlist *, Item*> m_playlistDict;
- int m_viewModeIndex;
- QList<ViewMode *> m_viewModes;
- KAction *m_k3bAction;
- bool m_hasSelection;
- bool m_doingMultiSelect;
- Item *m_dropItem;
- QTimer *m_showTimer;
- QTimer *m_savePlaylistTimer;
-};
-
-class PlaylistBox::Item : public QObject, public K3ListViewItem, public PlaylistObserver
-{
- friend class PlaylistBox;
- friend class ViewMode;
- friend class CompactViewMode;
- friend class TreeViewMode;
-
- Q_OBJECT
-
- // moc won't let me create private QObject subclasses and Qt won't let me
- // make the destructor protected, so here's the closest hack that will
- // compile.
-
-public:
- virtual ~Item();
-
-protected:
- Item(PlaylistBox *listBox, const QString &icon, const QString &text, Playlist *l = 0);
- Item(Item *parent, const QString &icon, const QString &text, Playlist *l = 0);
-
- Playlist *playlist() const { return m_playlist; }
- PlaylistBox *listView() const { return static_cast<PlaylistBox *>(K3ListViewItem::listView()); }
- QString iconName() const { return m_iconName; }
- QString text() const { return m_text; }
- void setSortedFirst(bool first = true) { m_sortedFirst = first; }
-
- virtual int compare(Q3ListViewItem *i, int col, bool) const;
- virtual void paintCell(QPainter *p, const QColorGroup &colorGroup, int column, int width, int align);
- virtual void paintFocus(QPainter *, const QColorGroup &, const QRect &) {}
- virtual void setText(int column, const QString &text);
-
- virtual QString text(int column) const { return K3ListViewItem::text(column); }
-
- virtual void setup();
-
- static Item *collectionItem() { return m_collectionItem; }
- static void setCollectionItem(Item *item) { m_collectionItem = item; }
-
- //
- // Reimplemented from PlaylistObserver
- //
-
- virtual void updateCurrent();
-
- // Used to post a timer in PlaylistBox to save playlists.
- virtual void updateData();
-
-
-protected slots:
- void slotSetName(const QString &name);
-
-private:
- // setup() was already taken.
- void init();
-
- Playlist *m_playlist;
- QString m_text;
- QString m_iconName;
- bool m_sortedFirst;
- static Item *m_collectionItem;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistcollection.h"
-
-#include <kurl.h>
-#include <kicon.h>
-#include <kiconloader.h>
-#include <kapplication.h>
-#include <kinputdialog.h>
-#include <kmessagebox.h>
-#include <kfiledialog.h>
-#include <kaction.h>
-#include <kactioncollection.h>
-#include <ktoggleaction.h>
-#include <kactionmenu.h>
-#include <kconfiggroup.h>
-#include <kfileitem.h>
-
-#include <config-juk.h>
-
-#include <QObject>
-#include <QPixmap>
-#include <QStackedWidget>
-#include <QMutableListIterator>
-
-#include <sys/types.h>
-#include <dirent.h>
-
-#include "collectionlist.h"
-#include "actioncollection.h"
-#include "advancedsearchdialog.h"
-#include "coverinfo.h"
-#include "searchplaylist.h"
-#include "folderplaylist.h"
-#include "historyplaylist.h"
-#include "upcomingplaylist.h"
-#include "directorylist.h"
-#include "mediafiles.h"
-#include "playermanager.h"
-#include "tracksequencemanager.h"
-#include "juk.h"
-
-//Laurent: readd it
-//#include "collectionadaptor.h"
-
-using namespace ActionCollection;
-
-////////////////////////////////////////////////////////////////////////////////
-// static methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistCollection *PlaylistCollection::m_instance = 0;
-
-// Returns all folders in input list with their canonical path, if available, or
-// unchanged if not.
-static QStringList canonicalizeFolderPaths(const QStringList &folders)
-{
- QStringList result;
-
- foreach(const QString &folder, folders) {
- QString canonicalFolder = QDir(folder).canonicalPath();
- result << (!canonicalFolder.isEmpty() ? canonicalFolder : folder);
- }
-
- return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistCollection::PlaylistCollection(PlayerManager *player, QStackedWidget *playlistStack) :
- m_playlistStack(playlistStack),
- m_historyPlaylist(0),
- m_upcomingPlaylist(0),
- m_playerManager(player),
- m_importPlaylists(true),
- m_searchEnabled(true),
- m_playing(false),
- m_showMorePlaylist(0),
- m_belowShowMorePlaylist(0),
- m_dynamicPlaylist(0),
- m_belowDistraction(0),
- m_distraction(0)
-{
- //new CollectionAdaptor( this );
- //QDBus::sessionBus().registerObject("/Collection",this );
- m_instance = this;
-
- m_actionHandler = new ActionHandler(this);
-
- // KDirLister's auto error handling seems to crash JuK during startup in
- // readConfig().
-
- m_dirLister.setAutoErrorHandlingEnabled(false, playlistStack);
- readConfig();
-}
-
-PlaylistCollection::~PlaylistCollection()
-{
- saveConfig();
- CollectionList::instance()->saveItemsToCache();
- delete m_actionHandler;
- Playlist::setShuttingDown();
-}
-
-QString PlaylistCollection::name() const
-{
- return currentPlaylist()->name();
-}
-
-FileHandle PlaylistCollection::currentFile() const
-{
- return currentPlaylist()->currentFile();
-}
-
-int PlaylistCollection::count() const
-{
- return currentPlaylist()->count();
-}
-
-int PlaylistCollection::time() const
-{
- return currentPlaylist()->time();
-}
-
-void PlaylistCollection::playFirst()
-{
- m_playing = true;
- currentPlaylist()->playFirst();
- currentChanged();
-}
-
-void PlaylistCollection::playNextAlbum()
-{
- m_playing = true;
- currentPlaylist()->playNextAlbum();
- currentChanged();
-}
-
-void PlaylistCollection::playPrevious()
-{
- m_playing = true;
- currentPlaylist()->playPrevious();
- currentChanged();
-}
-
-void PlaylistCollection::playNext()
-{
- m_playing = true;
- currentPlaylist()->playNext();
- currentChanged();
-}
-
-void PlaylistCollection::stop()
-{
- m_playing = false;
- currentPlaylist()->stop();
- dataChanged();
-}
-
-bool PlaylistCollection::playing() const
-{
- return m_playing;
-}
-
-QStringList PlaylistCollection::playlists() const
-{
- QStringList l;
-
- //(or qFindChildren() if you need MSVC 6 compatibility)
- const QList<Playlist *> childList = m_playlistStack->findChildren<Playlist *>("Playlist");
- foreach(Playlist *p, childList) {
- l.append(p->name());
- }
-
- return l;
-}
-
-void PlaylistCollection::createPlaylist(const QString &name)
-{
- raise(new Playlist(this, name));
-}
-
-void PlaylistCollection::createDynamicPlaylist(const PlaylistList &playlists)
-{
- if(m_dynamicPlaylist)
- m_dynamicPlaylist->setPlaylists(playlists);
- else {
- m_dynamicPlaylist =
- new DynamicPlaylist(playlists, this, i18n("Dynamic List"), "audio-midi", false, true);
- PlaylistCollection::setupPlaylist(m_dynamicPlaylist, QString());
- }
-
- PlaylistCollection::raise(m_dynamicPlaylist);
-}
-
-void PlaylistCollection::showMore(const QString &artist, const QString &album)
-{
-
- PlaylistList playlists;
- PlaylistSearch::ComponentList components;
-
- if(currentPlaylist() != CollectionList::instance() &&
- currentPlaylist() != m_showMorePlaylist)
- {
- playlists.append(currentPlaylist());
- }
-
- playlists.append(CollectionList::instance());
-
- if(!artist.isNull())
- { // Just setting off the artist stuff in its own block.
- ColumnList columns;
- columns.append(PlaylistItem::ArtistColumn);
- PlaylistSearch::Component c(artist, false, columns,
- PlaylistSearch::Component::Exact);
- components.append(c);
- }
-
- if(!album.isNull()) {
- ColumnList columns;
- columns.append(PlaylistItem::AlbumColumn);
- PlaylistSearch::Component c(album, false, columns,
- PlaylistSearch::Component::Exact);
- components.append(c);
- }
-
- PlaylistSearch search(playlists, components, PlaylistSearch::MatchAll);
-
- if(m_showMorePlaylist)
- m_showMorePlaylist->setPlaylistSearch(search);
- else
- m_showMorePlaylist = new SearchPlaylist(this, search, i18n("Now Playing"), false, true);
-
- // The call to raise() below will end up clearing m_belowShowMorePlaylist,
- // so cache the value we want it to have now.
- Playlist *belowShowMore = visiblePlaylist();
-
- PlaylistCollection::setupPlaylist(m_showMorePlaylist, QString());
- PlaylistCollection::raise(m_showMorePlaylist);
-
- m_belowShowMorePlaylist = belowShowMore;
-}
-
-void PlaylistCollection::removeTrack(const QString &playlist, const QStringList &files)
-{
- Playlist *p = playlistByName(playlist);
- PlaylistItemList itemList;
- if(!p)
- return;
-
- QStringList::ConstIterator it;
- for(it = files.begin(); it != files.end(); ++it) {
- CollectionListItem *item = CollectionList::instance()->lookup(*it);
-
- if(item) {
- PlaylistItem *playlistItem = item->itemForPlaylist(p);
- if(playlistItem)
- itemList.append(playlistItem);
- }
- }
-
- p->clearItems(itemList);
-}
-
-QString PlaylistCollection::playlist() const
-{
- return visiblePlaylist() ? visiblePlaylist()->name() : QString();
-}
-
-QString PlaylistCollection::playingPlaylist() const
-{
- return currentPlaylist() && m_playing ? currentPlaylist()->name() : QString();
-}
-
-void PlaylistCollection::setPlaylist(const QString &playlist)
-{
- Playlist *p = playlistByName(playlist);
- if(p)
- raise(p);
-}
-
-QStringList PlaylistCollection::playlistTracks(const QString &playlist) const
-{
- Playlist *p = playlistByName(playlist);
-
- if(p)
- return p->files();
- return QStringList();
-}
-
-QString PlaylistCollection::trackProperty(const QString &file, const QString &property) const
-{
- CollectionList *l = CollectionList::instance();
- CollectionListItem *item = l->lookup(file);
-
- return item ? item->file().property(property) : QString();
-}
-
-QPixmap PlaylistCollection::trackCover(const QString &file, const QString &size) const
-{
- if(size.toLower() != "small" && size.toLower() != "large")
- return QPixmap();
-
- CollectionList *l = CollectionList::instance();
- CollectionListItem *item = l->lookup(file);
-
- if(!item)
- return QPixmap();
-
- if(size.toLower() == "small")
- return item->file().coverInfo()->pixmap(CoverInfo::Thumbnail);
- else
- return item->file().coverInfo()->pixmap(CoverInfo::FullSize);
-}
-
-void PlaylistCollection::open(const QStringList &l)
-{
- QStringList files = l;
-
- if(files.isEmpty())
- files = MediaFiles::openDialog(JuK::JuKInstance());
-
- if(files.isEmpty())
- return;
-
- bool justPlaylists = true;
-
- for(QStringList::ConstIterator it = files.constBegin(); it != files.constEnd() && justPlaylists; ++it)
- justPlaylists = !MediaFiles::isPlaylistFile(*it);
-
- if(visiblePlaylist() == CollectionList::instance() || justPlaylists ||
- KMessageBox::questionYesNo(
- JuK::JuKInstance(),
- i18n("Do you want to add these items to the current list or to the collection list?"),
- QString(),
- KGuiItem(i18nc("current playlist", "Current")),
- KGuiItem(i18n("Collection"))) == KMessageBox::No)
- {
- CollectionList::instance()->addFiles(files);
- }
- else {
- visiblePlaylist()->addFiles(files);
- }
-
- dataChanged();
-}
-
-void PlaylistCollection::open(const QString &playlist, const QStringList &files)
-{
- Playlist *p = playlistByName(playlist);
-
- if(p)
- p->addFiles(files);
-}
-
-void PlaylistCollection::addFolder()
-{
- DirectoryList l(m_folderList, m_excludedFolderList, m_importPlaylists, JuK::JuKInstance());
- DirectoryList::Result result = l.exec();
-
- if(result.status == QDialog::Accepted) {
-
- m_dirLister.blockSignals(true);
-
- const bool reload = m_importPlaylists != result.addPlaylists;
-
- m_importPlaylists = result.addPlaylists;
- m_excludedFolderList = canonicalizeFolderPaths(result.excludedDirs);
-
- foreach(const QString &dir, result.addedDirs) {
- m_dirLister.openUrl(KUrl::fromPath(dir), KDirLister::Keep);
- m_folderList.append(dir);
- }
-
- foreach(const QString &dir, result.removedDirs) {
- m_dirLister.stop(KUrl::fromPath(dir));
- m_folderList.removeAll(dir);
- }
-
- if(reload) {
- open(m_folderList);
- }
- else if(!result.addedDirs.isEmpty()) {
- open(result.addedDirs);
- }
-
- saveConfig();
-
- m_dirLister.blockSignals(false);
- }
-}
-
-void PlaylistCollection::rename()
-{
- QString old = visiblePlaylist()->name();
- QString name = playlistNameDialog(i18n("Rename"), old, false);
-
- m_playlistNames.remove(old);
-
- if(name.isEmpty())
- return;
-
- visiblePlaylist()->setName(name);
-}
-
-void PlaylistCollection::duplicate()
-{
- QString name = playlistNameDialog(i18nc("verb, copy the playlist", "Duplicate"),
- visiblePlaylist()->name());
- if(name.isEmpty())
- return;
-
- raise(new Playlist(this, visiblePlaylist()->items(), name));
-}
-
-void PlaylistCollection::save()
-{
- visiblePlaylist()->save();
-}
-
-void PlaylistCollection::saveAs()
-{
- visiblePlaylist()->saveAs();
-}
-
-void PlaylistCollection::reload()
-{
- if(visiblePlaylist() == CollectionList::instance())
- CollectionList::instance()->addFiles(m_folderList);
- else
- visiblePlaylist()->slotReload();
-
-}
-
-void PlaylistCollection::editSearch()
-{
- SearchPlaylist *p = dynamic_cast<SearchPlaylist *>(visiblePlaylist());
-
- if(!p)
- return;
-
- AdvancedSearchDialog::Result r =
- AdvancedSearchDialog(p->name(), p->playlistSearch(), JuK::JuKInstance()).exec();
-
- if(r.result == AdvancedSearchDialog::Accepted) {
- p->setPlaylistSearch(r.search);
- p->setName(r.playlistName);
- }
-}
-
-void PlaylistCollection::removeItems()
-{
- visiblePlaylist()->slotRemoveSelectedItems();
-}
-
-void PlaylistCollection::refreshItems()
-{
- visiblePlaylist()->slotRefresh();
-}
-
-void PlaylistCollection::renameItems()
-{
- visiblePlaylist()->slotRenameFile();
-}
-
-void PlaylistCollection::addCovers(bool fromFile)
-{
- visiblePlaylist()->slotAddCover(fromFile);
- dataChanged();
-}
-
-void PlaylistCollection::removeCovers()
-{
- visiblePlaylist()->slotRemoveCover();
- dataChanged();
-}
-
-void PlaylistCollection::viewCovers()
-{
- visiblePlaylist()->slotViewCover();
-}
-
-void PlaylistCollection::showCoverManager()
-{
- visiblePlaylist()->slotShowCoverManager();
-}
-
-PlaylistItemList PlaylistCollection::selectedItems()
-{
- return visiblePlaylist()->selectedItems();
-}
-
-void PlaylistCollection::scanFolders()
-{
- CollectionList::instance()->addFiles(m_folderList);
-
- if(CollectionList::instance()->count() == 0)
- addFolder();
-
- enableDirWatch(true);
-}
-
-void PlaylistCollection::createPlaylist()
-{
- QString name = playlistNameDialog();
- if(!name.isEmpty())
- raise(new Playlist(this, name));
-}
-
-void PlaylistCollection::createSearchPlaylist()
-{
- QString name = uniquePlaylistName(i18n("Search Playlist"));
-
- AdvancedSearchDialog::Result r =
- AdvancedSearchDialog(name, PlaylistSearch(), JuK::JuKInstance()).exec();
-
- if(r.result == AdvancedSearchDialog::Accepted)
- raise(new SearchPlaylist(this, r.search, r.playlistName));
-}
-
-void PlaylistCollection::createFolderPlaylist()
-{
- QString folder = KFileDialog::getExistingDirectory();
-
- if(folder.isEmpty())
- return;
-
- QString name = uniquePlaylistName(folder.mid(folder.lastIndexOf('/') + 1));
- name = playlistNameDialog(i18n("Create Folder Playlist"), name);
-
- if(!name.isEmpty())
- raise(new FolderPlaylist(this, folder, name));
-}
-
-void PlaylistCollection::guessTagFromFile()
-{
- visiblePlaylist()->slotGuessTagInfo(TagGuesser::FileName);
-}
-
-void PlaylistCollection::guessTagFromInternet()
-{
- visiblePlaylist()->slotGuessTagInfo(TagGuesser::MusicBrainz);
-}
-
-void PlaylistCollection::setSearchEnabled(bool enable)
-{
- if(enable == m_searchEnabled)
- return;
-
- m_searchEnabled = enable;
-
- visiblePlaylist()->setSearchEnabled(enable);
-}
-
-HistoryPlaylist *PlaylistCollection::historyPlaylist() const
-{
- return m_historyPlaylist;
-}
-
-void PlaylistCollection::setHistoryPlaylistEnabled(bool enable)
-{
- if((enable && m_historyPlaylist) || (!enable && !m_historyPlaylist))
- return;
-
- if(enable) {
- action<KToggleAction>("showHistory")->setChecked(true);
- m_historyPlaylist = new HistoryPlaylist(this);
- m_historyPlaylist->setName(i18n("History"));
- setupPlaylist(m_historyPlaylist, "view-history");
-
- QObject::connect(m_playerManager, SIGNAL(signalItemChanged(FileHandle)),
- historyPlaylist(), SLOT(appendProposedItem(FileHandle)));
- }
- else {
- delete m_historyPlaylist;
- m_historyPlaylist = 0;
- }
-}
-
-UpcomingPlaylist *PlaylistCollection::upcomingPlaylist() const
-{
- return m_upcomingPlaylist;
-}
-
-void PlaylistCollection::setUpcomingPlaylistEnabled(bool enable)
-{
- if((enable && m_upcomingPlaylist) || (!enable && !m_upcomingPlaylist))
- return;
-
- if(enable) {
- action<KToggleAction>("showUpcoming")->setChecked(true);
- if(!m_upcomingPlaylist)
- m_upcomingPlaylist = new UpcomingPlaylist(this);
-
- setupPlaylist(m_upcomingPlaylist, "go-jump-today");
- }
- else {
- action<KToggleAction>("showUpcoming")->setChecked(false);
- bool raiseCollection = visiblePlaylist() == m_upcomingPlaylist;
-
- if(raiseCollection) {
- raise(CollectionList::instance());
- }
-
- m_upcomingPlaylist->deleteLater();
- m_upcomingPlaylist = 0;
- }
-}
-
-QObject *PlaylistCollection::object() const
-{
- return m_actionHandler;
-}
-
-Playlist *PlaylistCollection::currentPlaylist() const
-{
- if(m_belowDistraction)
- return m_belowDistraction;
-
- if(m_upcomingPlaylist && m_upcomingPlaylist->active())
- return m_upcomingPlaylist;
-
- if(Playlist::playingItem())
- return Playlist::playingItem()->playlist();
- else
- return visiblePlaylist();
-}
-
-Playlist *PlaylistCollection::visiblePlaylist() const
-{
- return qobject_cast<Playlist *>(m_playlistStack->currentWidget());
-}
-
-void PlaylistCollection::raise(Playlist *playlist)
-{
- if(m_showMorePlaylist && currentPlaylist() == m_showMorePlaylist)
- m_showMorePlaylist->lower(playlist);
- if(m_dynamicPlaylist && currentPlaylist() == m_dynamicPlaylist)
- m_dynamicPlaylist->lower(playlist);
-
- TrackSequenceManager::instance()->setCurrentPlaylist(playlist);
- playlist->applySharedSettings();
- playlist->setSearchEnabled(m_searchEnabled);
- m_playlistStack->setCurrentWidget(playlist);
- clearShowMore(false);
- dataChanged();
-}
-
-void PlaylistCollection::raiseDistraction()
-{
- if(m_belowDistraction)
- return;
-
- m_belowDistraction = currentPlaylist();
-
- if(!m_distraction) {
- m_distraction = new QWidget(m_playlistStack);
- m_playlistStack->addWidget(m_distraction);
- }
-
- m_playlistStack->setCurrentWidget(m_distraction);
-}
-
-void PlaylistCollection::lowerDistraction()
-{
- if(!m_distraction)
- return;
-
- if(m_belowDistraction)
- m_playlistStack->setCurrentWidget(m_belowDistraction);
-
- m_belowDistraction = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-QStackedWidget *PlaylistCollection::playlistStack() const
-{
- return m_playlistStack;
-}
-
-void PlaylistCollection::setupPlaylist(Playlist *playlist, const QString &)
-{
- if(!playlist->fileName().isEmpty())
- m_playlistFiles.insert(playlist->fileName());
-
- if(!playlist->name().isEmpty())
- m_playlistNames.insert(playlist->name());
-
- m_playlistStack->addWidget(playlist);
- QObject::connect(playlist, SIGNAL(selectionChanged()),
- object(), SIGNAL(signalSelectedItemsChanged()));
-}
-
-bool PlaylistCollection::importPlaylists() const
-{
- return m_importPlaylists;
-}
-
-bool PlaylistCollection::containsPlaylistFile(const QString &file) const
-{
- return m_playlistFiles.contains(file);
-}
-
-bool PlaylistCollection::showMoreActive() const
-{
- return visiblePlaylist() == m_showMorePlaylist;
-}
-
-void PlaylistCollection::clearShowMore(bool raisePlaylist)
-{
- if(!m_showMorePlaylist)
- return;
-
- if(raisePlaylist) {
- if(m_belowShowMorePlaylist)
- raise(m_belowShowMorePlaylist);
- else
- raise(CollectionList::instance());
- }
-
- m_belowShowMorePlaylist = 0;
-}
-
-void PlaylistCollection::enableDirWatch(bool enable)
-{
- QObject *collection = CollectionList::instance();
-
- m_dirLister.disconnect(object());
- if(enable) {
- QObject::connect(&m_dirLister, SIGNAL(newItems(KFileItemList)),
- object(), SLOT(slotNewItems(KFileItemList)));
- QObject::connect(&m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem,KFileItem> >)),
- collection, SLOT(slotRefreshItems(QList<QPair<KFileItem,KFileItem> >)));
- QObject::connect(&m_dirLister, SIGNAL(deleteItem(KFileItem)),
- collection, SLOT(slotDeleteItem(KFileItem)));
- }
-}
-
-QString PlaylistCollection::playlistNameDialog(const QString &caption,
- const QString &suggest,
- bool forceUnique) const
-{
- bool ok;
-
- QString name = KInputDialog::getText(
- caption,
- i18n("Please enter a name for this playlist:"),
- forceUnique ? uniquePlaylistName(suggest) : suggest,
- &ok);
-
- return ok ? uniquePlaylistName(name) : QString();
-}
-
-
-QString PlaylistCollection::uniquePlaylistName(const QString &suggest) const
-{
- if(suggest.isEmpty())
- return uniquePlaylistName();
-
- if(!m_playlistNames.contains(suggest))
- return suggest;
-
- QString base = suggest;
- base.remove(QRegExp("\\s\\([0-9]+\\)$"));
-
- int count = 1;
- QString s = QString("%1 (%2)").arg(base).arg(count);
-
- while(m_playlistNames.contains(s)) {
- count++;
- s = QString("%1 (%2)").arg(base).arg(count);
- }
-
- return s;
-}
-
-void PlaylistCollection::addNameToDict(const QString &name)
-{
- m_playlistNames.insert(name);
-}
-
-void PlaylistCollection::addFileToDict(const QString &file)
-{
- m_playlistFiles.insert(file);
-}
-
-void PlaylistCollection::removeNameFromDict(const QString &name)
-{
- m_playlistNames.remove(name);
-}
-
-void PlaylistCollection::removeFileFromDict(const QString &file)
-{
- m_playlistFiles.remove(file);
-}
-
-void PlaylistCollection::dirChanged(const QString &path)
-{
- QString canonicalPath = QDir(path).canonicalPath();
- if(canonicalPath.isEmpty())
- return;
-
- foreach(const QString &excludedFolder, m_excludedFolderList) {
- if(canonicalPath.startsWith(excludedFolder))
- return;
- }
-
- CollectionList::instance()->addFiles(QStringList(canonicalPath));
-}
-
-Playlist *PlaylistCollection::playlistByName(const QString &name) const
-{
- for(int i = 0; i < m_playlistStack->count(); ++i) {
- Playlist *p = qobject_cast<Playlist *>(m_playlistStack->widget(i));
- if(p && p->name() == name)
- return p;
- }
-
- return 0;
-}
-
-void PlaylistCollection::newItems(const KFileItemList &list) const
-{
- // Make fast-path for the normal case
- if(m_excludedFolderList.isEmpty()) {
- CollectionList::instance()->slotNewItems(list);
- return;
- }
-
- // Slow case: Directories to exclude from consideration
-
- KFileItemList filteredList(list);
-
- foreach(const QString &excludedFolder, m_excludedFolderList) {
- QMutableListIterator<KFileItem> filteredListIterator(filteredList);
-
- while(filteredListIterator.hasNext()) {
- const KFileItem fileItem = filteredListIterator.next();
-
- if(fileItem.url().path().startsWith(excludedFolder))
- filteredListIterator.remove();
- }
- }
-
- CollectionList::instance()->slotNewItems(filteredList);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistCollection::readConfig()
-{
- KConfigGroup config(KGlobal::config(), "Playlists");
-
- m_importPlaylists = config.readEntry("ImportPlaylists", true);
- m_folderList = config.readEntry("DirectoryList", QStringList());
- m_excludedFolderList = canonicalizeFolderPaths(
- config.readEntry("ExcludeDirectoryList", QStringList()));
-
- foreach(const QString &folder, m_folderList) {
- m_dirLister.openUrl(folder, KDirLister::Keep);
- }
-}
-
-void PlaylistCollection::saveConfig()
-{
- KConfigGroup config(KGlobal::config(), "Playlists");
- config.writeEntry("ImportPlaylists", m_importPlaylists);
- config.writeEntry("showUpcoming", action("showUpcoming")->isChecked());
- config.writePathEntry("DirectoryList", m_folderList);
- config.writePathEntry("ExcludeDirectoryList", m_excludedFolderList);
-
- config.sync();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ActionHanlder implementation
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistCollection::ActionHandler::ActionHandler(PlaylistCollection *collection) :
- QObject(0),
- m_collection(collection)
-{
- setObjectName( QLatin1String("ActionHandler" ));
-
- KActionMenu *menu;
-
- // "New" menu
-
- menu = new KActionMenu(KIcon("document-new"), i18nc("new playlist", "&New"), actions());
- actions()->addAction("file_new", menu);
-
- menu->addAction(createAction(i18n("&Empty Playlist..."), SLOT(slotCreatePlaylist()),
- "newPlaylist", "window-new", KShortcut(Qt::CTRL + Qt::Key_N)));
- menu->addAction(createAction(i18n("&Search Playlist..."), SLOT(slotCreateSearchPlaylist()),
- "newSearchPlaylist", "edit-find", KShortcut(Qt::CTRL + Qt::Key_F)));
- menu->addAction(createAction(i18n("Playlist From &Folder..."), SLOT(slotCreateFolderPlaylist()),
- "newDirectoryPlaylist", "document-open", KShortcut(Qt::CTRL + Qt::Key_D)));
-
- // Guess tag info menu
-
-#if HAVE_TUNEPIMP
- menu = new KActionMenu(i18n("&Guess Tag Information"), actions());
- actions()->addAction("guessTag", menu);
-
- /* menu->setIcon(SmallIcon("wizard")); */
-
- menu->addAction(createAction(i18n("From &File Name"), SLOT(slotGuessTagFromFile()),
- "guessTagFile", "document-import", KShortcut(Qt::CTRL + Qt::Key_G)));
- menu->addAction(createAction(i18n("From &Internet"), SLOT(slotGuessTagFromInternet()),
- "guessTagInternet", "network-server", KShortcut(Qt::CTRL + Qt::Key_I)));
-#else
- createAction(i18n("Guess Tag Information From &File Name"), SLOT(slotGuessTagFromFile()),
- "guessTag", "document-import", KShortcut(Qt::CTRL + Qt::Key_F));
-#endif
-
-
- createAction(i18n("Play First Track"),SLOT(slotPlayFirst()), "playFirst");
- createAction(i18n("Play Next Album"), SLOT(slotPlayNextAlbum()), "forwardAlbum", "go-down-search");
-
- KStandardAction::open(this, SLOT(slotOpen()), actions());
- KStandardAction::save(this, SLOT(slotSave()), actions());
- KStandardAction::saveAs(this, SLOT(slotSaveAs()), actions());
-
- createAction(i18n("Manage &Folders..."), SLOT(slotManageFolders()), "openDirectory", "folder-new");
- createAction(i18n("&Rename..."), SLOT(slotRename()), "renamePlaylist", "edit-rename");
- createAction(i18nc("verb, copy the playlist", "D&uplicate..."),
- SLOT(slotDuplicate()), "duplicatePlaylist", "edit-copy");
- createAction(i18n("R&emove"), SLOT(slotRemove()), "deleteItemPlaylist", "user-trash");
- createAction(i18n("Reload"), SLOT(slotReload()), "reloadPlaylist", "view-refresh");
- createAction(i18n("Edit Search..."), SLOT(slotEditSearch()), "editSearch");
-
- createAction(i18n("&Delete"), SLOT(slotRemoveItems()), "removeItem", "edit-delete");
- createAction(i18n("Refresh"), SLOT(slotRefreshItems()), "refresh", "view-refresh");
- createAction(i18n("&Rename File"), SLOT(slotRenameItems()), "renameFile", "document-save-as", KShortcut(Qt::CTRL + Qt::Key_R));
-
- menu = new KActionMenu(i18n("Cover Manager"), actions());
- actions()->addAction("coverManager", menu);
- /* menu->setIcon(SmallIcon("image-x-generic")); */
- menu->addAction(createAction(i18n("&View Cover"),
- SLOT(slotViewCovers()), "viewCover", "document-preview"));
- menu->addAction(createAction(i18n("Get Cover From &File..."),
- SLOT(slotAddLocalCover()), "addCover", "document-import", KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_F)));
- menu->addAction(createAction(i18n("Get Cover From &Internet..."),
- SLOT(slotAddInternetCover()), "webImageCover", "network-server", KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_G)));
- menu->addAction(createAction(i18n("&Delete Cover"),
- SLOT(slotRemoveCovers()), "removeCover", "edit-delete"));
- menu->addAction(createAction(i18n("Show Cover &Manager"),
- SLOT(slotShowCoverManager()), "showCoverManager"));
-
- KToggleAction *upcomingAction =
- new KToggleAction(KIcon("go-jump-today"), i18n("Show &Play Queue"), actions());
- actions()->addAction("showUpcoming", upcomingAction);
-
- connect(upcomingAction, SIGNAL(triggered(bool)),
- this, SLOT(slotSetUpcomingPlaylistEnabled(bool)));
-}
-
-KAction *PlaylistCollection::ActionHandler::createAction(const QString &text,
- const char *slot,
- const char *name,
- const QString &icon,
- const KShortcut &shortcut)
-{
- KAction *action;
- if(icon.isNull())
- action = new KAction(text, actions());
- else
- action = new KAction(KIcon(icon), text, actions());
- actions()->addAction(name, action);
- connect( action, SIGNAL(triggered(bool)), slot);
- action->setShortcut(shortcut);
- return action;
-}
-
-#include "playlistcollection.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLIST_COLLECTION_H
-#define PLAYLIST_COLLECTION_H
-
-#include "stringhash.h"
-#include "playlistinterface.h"
-
-#include <kshortcut.h>
-#include <klocale.h>
-#include <kdirlister.h>
-
-#include <QPointer>
-
-class QPixmap;
-class QStackedWidget;
-
-class KAction;
-
-class HistoryPlaylist;
-class UpcomingPlaylist;
-class SearchPlaylist;
-class DynamicPlaylist;
-class PlaylistItem;
-class Playlist;
-class PlayerManager;
-class FileHandle;
-
-template<class T>
-class QList;
-
-typedef QList<PlaylistItem *> PlaylistItemList;
-typedef QList<Playlist *> PlaylistList;
-
-class PlaylistCollection : public PlaylistInterface
-{
- friend class Playlist;
- friend class CollectionList;
- friend class DynamicPlaylist;
-
-public:
- PlaylistCollection(PlayerManager *player, QStackedWidget *playlistStack);
- virtual ~PlaylistCollection();
-
- static PlaylistCollection *instance() { return m_instance; }
-
- virtual QString name() const;
- virtual FileHandle currentFile() const;
- virtual int count() const;
- virtual int time() const;
- virtual void playNext();
- virtual void playPrevious();
- virtual void stop();
- virtual bool playing() const;
-
- void playFirst();
- void playNextAlbum();
-
- virtual QStringList playlists() const;
- virtual void createPlaylist(const QString &name);
- virtual void createDynamicPlaylist(const PlaylistList &playlists);
- virtual void showMore(const QString &artist, const QString &album = QString());
- virtual void removeTrack(const QString &playlist, const QStringList &files);
-
- virtual QString playlist() const;
- virtual QString playingPlaylist() const;
- virtual void setPlaylist(const QString &playlist);
-
- virtual QStringList playlistTracks(const QString &playlist) const;
- virtual QString trackProperty(const QString &file, const QString &property) const;
- virtual QPixmap trackCover(const QString &file, const QString &size = "Small") const;
-
- virtual void open(const QStringList &files = QStringList());
- virtual void open(const QString &playlist, const QStringList &files);
- virtual void addFolder();
- virtual void rename();
- virtual void duplicate();
- virtual void save();
- virtual void saveAs();
- virtual void remove() = 0;
- virtual void reload();
- virtual void editSearch();
- virtual void setDynamicListsFrozen(bool) = 0;
-
- bool showMoreActive() const;
- void clearShowMore(bool raise = true);
- void enableDirWatch(bool enable);
-
- void removeItems();
- void refreshItems();
- void renameItems();
- void addCovers(bool fromFile);
- void removeCovers();
- void viewCovers();
- void showCoverManager();
-
- virtual PlaylistItemList selectedItems();
-
- // virtual to allow our QWidget subclass to emit a signal after we're done
- virtual void scanFolders();
-
- void createPlaylist();
- void createSearchPlaylist();
- void createFolderPlaylist();
-
- void guessTagFromFile();
- void guessTagFromInternet();
-
- void setSearchEnabled(bool enable);
-
- HistoryPlaylist *historyPlaylist() const;
- void setHistoryPlaylistEnabled(bool enable);
-
- UpcomingPlaylist *upcomingPlaylist() const;
- void setUpcomingPlaylistEnabled(bool enable);
-
- void dirChanged(const QString &path);
-
- /**
- * Returns a pointer to the action handler.
- */
- QObject *object() const;
-
- void newItems(const KFileItemList &list) const;
-
- /**
- * This is the current playlist in all things relating to the player. It
- * represents the playlist that either should be played from or is currently
- * playing.
- */
- virtual Playlist *currentPlaylist() const;
-
- /**
- * This is the currently visible playlist and should be used for all user
- * interaction elements.
- */
- virtual Playlist *visiblePlaylist() const;
-
- /**
- * Makes \a playlist the currently visible playlist.
- */
- virtual void raise(Playlist *playlist);
-
- /**
- * @return true, if a playlist with the file name given in @p file is
- * already loaded into this collection, or false otherwise.
- *
- * @note @p file should be the "canonical" full path to the file to avoid
- * problems with duplicates and symlinks.
- */
- bool containsPlaylistFile(const QString &file) const;
-
- /**
- * @return list of folders to exclude from automatic searching (whether
- * by directory-change watchers or the startup folder scan). The user should
- * still be able to manually add files even under an excluded folder.
- */
- QStringList excludedFolders() const { return m_excludedFolderList; }
-
- /**
- * This is used to put up a temporary widget over the top of the playlist
- * stack. This is part of a trick to significantly speed up painting by
- * hiding the playlist to which items are being added.
- */
- void raiseDistraction();
- void lowerDistraction();
-
- class ActionHandler;
-
-protected:
- virtual QStackedWidget *playlistStack() const;
- virtual void setupPlaylist(Playlist *playlist, const QString &iconName);
- virtual void removePlaylist(Playlist *playlist) = 0;
-
- bool importPlaylists() const;
-
- QString playlistNameDialog(const QString &caption = i18n("Create New Playlist"),
- const QString &suggest = QString(),
- bool forceUnique = true) const;
- QString uniquePlaylistName(const QString &suggest = i18n("Playlist")) const;
-
- void addNameToDict(const QString &name);
- void addFileToDict(const QString &file);
- void removeNameFromDict(const QString &name);
- void removeFileFromDict(const QString &file);
-
- Playlist *playlistByName(const QString &name) const;
-
-private:
- void readConfig();
- void saveConfig();
-
- QStackedWidget *m_playlistStack;
- HistoryPlaylist *m_historyPlaylist;
- UpcomingPlaylist *m_upcomingPlaylist;
- ActionHandler *m_actionHandler;
- PlayerManager *m_playerManager;
-
- KDirLister m_dirLister;
- StringHash m_playlistNames;
- StringHash m_playlistFiles;
- QStringList m_folderList;
- QStringList m_excludedFolderList;
- bool m_importPlaylists;
- bool m_searchEnabled;
- bool m_playing;
-
- QPointer<SearchPlaylist> m_showMorePlaylist;
- QPointer<Playlist> m_belowShowMorePlaylist;
- QPointer<DynamicPlaylist> m_dynamicPlaylist;
- QPointer<Playlist> m_belowDistraction;
-
- QWidget *m_distraction;
-
- static PlaylistCollection *m_instance;
-};
-
-/**
- * This class is just used as a proxy to handle the signals coming from action
- * activations without requiring PlaylistCollection to be a QObject.
- */
-
-class PlaylistCollection::ActionHandler : public QObject
-{
- Q_OBJECT
-public:
- ActionHandler(PlaylistCollection *collection);
-
-private:
- KAction *createAction(const QString &text,
- const char *slot,
- const char *name,
- const QString &icon = QString(),
- const KShortcut &shortcut = KShortcut());
-private slots:
- void slotPlayFirst() { m_collection->playFirst(); }
- void slotPlayNextAlbum() { m_collection->playNextAlbum(); }
-
- void slotOpen() { m_collection->open(); }
- void slotManageFolders() { m_collection->addFolder(); }
- void slotRename() { m_collection->rename(); }
- void slotDuplicate() { m_collection->duplicate(); }
- void slotSave() { m_collection->save(); }
- void slotSaveAs() { m_collection->saveAs(); }
- void slotReload() { m_collection->reload(); }
- void slotRemove() { m_collection->remove(); }
- void slotEditSearch() { m_collection->editSearch(); }
-
- void slotRemoveItems() { m_collection->removeItems(); }
- void slotRefreshItems() { m_collection->refreshItems(); }
- void slotRenameItems() { m_collection->renameItems(); }
- void slotScanFolders() { m_collection->scanFolders(); }
-
- void slotViewCovers() { m_collection->viewCovers(); }
- void slotRemoveCovers() { m_collection->removeCovers(); }
- void slotAddLocalCover() { m_collection->addCovers(true); }
- void slotAddInternetCover() { m_collection->addCovers(false); }
-
- void slotCreatePlaylist() { m_collection->createPlaylist(); }
- void slotCreateSearchPlaylist() { m_collection->createSearchPlaylist(); }
- void slotCreateFolderPlaylist() { m_collection->createFolderPlaylist(); }
-
- void slotGuessTagFromFile() { m_collection->guessTagFromFile(); }
- void slotGuessTagFromInternet() { m_collection->guessTagFromInternet(); }
-
- void slotSetSearchEnabled(bool enable) { m_collection->setSearchEnabled(enable); }
- void slotSetUpcomingPlaylistEnabled(bool enable) { m_collection->setUpcomingPlaylistEnabled(enable); }
- void slotShowCoverManager() { m_collection->showCoverManager(); }
- void slotEnableDirWatch(bool enable) { m_collection->enableDirWatch(enable); }
- void slotDirChanged(const QString &path) { m_collection->dirChanged(path); }
-
- void slotNewItems(const KFileItemList &list) { m_collection->newItems(list); }
-
-signals:
- void signalSelectedItemsChanged();
- void signalCountChanged();
-
-private:
- PlaylistCollection *m_collection;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Just a quick hack to get Q_OBJECT to work in playlistexporter.h --amth
-
-#include "playlistexporter.h"
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTEXPORTER_H
-#define PLAYLISTEXPORTER_H
-
-#include <QtCore/QObject>
-
-class KAction;
-
-/**
- * Abstract base class to define an interface for classes that export
- * PlaylistItem data.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see K3bExporter
- */
-class PlaylistExporter : public QObject
-{
- Q_OBJECT
-
-public:
- PlaylistExporter(QObject *parent = 0) : QObject(parent) { }
- virtual ~PlaylistExporter() { }
-
- /**
- * Returns a KAction that can be used to invoke the export.
- * Returns 0 if it is not possible.
- *
- * @return pointer to a KAction that can invoke the export, or 0 on
- * failure.
- */
- virtual KAction *action() = 0;
-};
-
-#endif /* PLAYLISTEXPORTER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistinterface.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// Watched implementation
-////////////////////////////////////////////////////////////////////////////////
-
-void Watched::currentChanged()
-{
- foreach(PlaylistObserver *observer, m_observers)
- observer->updateCurrent();
-}
-
-void Watched::dataChanged()
-{
- foreach(PlaylistObserver *observer, m_observers)
- observer->updateData();
-}
-
-void Watched::addObserver(PlaylistObserver *observer)
-{
- m_observers.append(observer);
-}
-
-void Watched::removeObserver(PlaylistObserver *observer)
-{
- if(observer)
- observer->clearWatched();
-
- m_observers.removeAll(observer);
-}
-
-void Watched::clearObservers()
-{
- foreach(PlaylistObserver *observer, m_observers)
- observer->clearWatched();
-
- m_observers.clear();
-}
-
-Watched::~Watched()
-{
- clearObservers();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistObserver implementation
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistObserver::~PlaylistObserver()
-{
- if(m_playlist)
- m_playlist->removeObserver(this);
-}
-
-PlaylistObserver::PlaylistObserver(PlaylistInterface *playlist) :
- m_playlist(playlist)
-{
- if(m_playlist)
- playlist->addObserver(this);
-}
-
-const PlaylistInterface *PlaylistObserver::playlist() const
-{
- return m_playlist;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTINTERFACE_H
-#define PLAYLISTINTERFACE_H
-
-#include <QList>
-
-class FileHandle;
-class PlaylistObserver;
-
-/**
- * An interface implemented by PlaylistInterface to make it possible to watch
- * for changes in the PlaylistInterface. This is a semi-standard observer
- * pattern from i.e. Design Patterns.
- */
-
-class Watched
-{
-public:
- void addObserver(PlaylistObserver *observer);
- void removeObserver(PlaylistObserver *observer);
-
- /**
- * Call this to remove all objects observing this class unconditionally (for example, when
- * you're being destructed).
- */
- void clearObservers();
-
- /**
- * This is triggered when the currently playing item has been changed.
- */
- virtual void currentChanged();
-
- /**
- * This is triggered when the data in the playlist -- i.e. the tag content
- * changes.
- */
- virtual void dataChanged();
-
-protected:
- virtual ~Watched();
-
-private:
- QList<PlaylistObserver *> m_observers;
-};
-
-/**
- * This is a simple interface that should be used by things that implement a
- * playlist-like API.
- */
-
-class PlaylistInterface : public Watched
-{
-public:
- virtual QString name() const = 0;
- virtual FileHandle currentFile() const = 0;
- virtual int time() const = 0;
- virtual int count() const = 0;
-
- virtual void playNext() = 0;
- virtual void playPrevious() = 0;
- virtual void stop() = 0;
-
- virtual bool playing() const = 0;
-};
-
-class PlaylistObserver
-{
-public:
- virtual ~PlaylistObserver();
-
- /**
- * This method must be implemented in concrete implementations; it should
- * define what action should be taken in the observer when the currently
- * playing item changes.
- */
- virtual void updateCurrent() = 0;
-
- /**
- * This method must be implemented in concrete implementations; it should
- * define what action should be taken when the data of the PlaylistItems in
- * the playlist changes.
- */
- virtual void updateData() = 0;
-
- void clearWatched() { m_playlist = 0; }
-
-protected:
- PlaylistObserver(PlaylistInterface *playlist);
- const PlaylistInterface *playlist() const;
-
-private:
- PlaylistInterface *m_playlist;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistitem.h"
-
-#include <config-juk.h>
-#include <kdebug.h>
-#include <kiconloader.h>
-
-#include <QPixmap>
-#include <QFileInfo>
-
-#include "collectionlist.h"
-#include "musicbrainzquery.h"
-#include "tag.h"
-#include "coverinfo.h"
-#include "covermanager.h"
-#include "tagtransactionmanager.h"
-
-PlaylistItemList PlaylistItem::m_playingItems; // static
-
-static void startMusicBrainzQuery(const FileHandle &file)
-{
-#if HAVE_TUNEPIMP
- // This deletes itself when finished.
- new MusicBrainzLookup(file);
-#else
- Q_UNUSED(file)
-#endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistItem public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistItem::~PlaylistItem()
-{
- // Although this isn't the most efficient way to accomplish the task of
- // stopping playback when deleting the item being played, it has the
- // stark advantage of working reliably. I'll tell anyone who tries to
- // optimize this, the timing issues can be *hard*. -- mpyne
-
- m_collectionItem->removeChildItem(this);
-
- if(m_playingItems.contains(this)) {
- m_playingItems.removeAll(this);
- if(m_playingItems.isEmpty())
- playlist()->setPlaying(0);
- }
-
- playlist()->updateDeletedItem(this);
- emit playlist()->signalAboutToRemove(this);
-
- if(m_watched)
- Pointer::clear(this);
-}
-
-void PlaylistItem::setFile(const FileHandle &file)
-{
- m_collectionItem->updateCollectionDict(d->fileHandle.absFilePath(), file.absFilePath());
- d->fileHandle = file;
- refresh();
-}
-
-void PlaylistItem::setFile(const QString &file)
-{
- QString oldPath = d->fileHandle.absFilePath();
- d->fileHandle.setFile(file);
- m_collectionItem->updateCollectionDict(oldPath, d->fileHandle.absFilePath());
- refresh();
-}
-
-FileHandle PlaylistItem::file() const
-{
- return d->fileHandle;
-}
-
-K_GLOBAL_STATIC_WITH_ARGS(QPixmap, globalGenericImage, (SmallIcon("image-x-generic")))
-K_GLOBAL_STATIC_WITH_ARGS(QPixmap, globalPlayingImage, (UserIcon("playing")))
-
-const QPixmap *PlaylistItem::pixmap(int column) const
-{
- int offset = playlist()->columnOffset();
-
- // Don't use hasCover here because that may dig into the track itself.
- // Besides, we really just want to know if the cover manager has a cover
- // for the track.
-
- if((column - offset) == CoverColumn &&
- d->fileHandle.coverInfo()->coverId() != CoverManager::NoMatch)
- {
- return globalGenericImage;
- }
-
- if(column == playlist()->leftColumn() &&
- m_playingItems.contains(const_cast<PlaylistItem *>(this)))
- {
- return globalPlayingImage;
- }
-
- return K3ListViewItem::pixmap(column);
-}
-
-QString PlaylistItem::text(int column) const
-{
- if(!d->fileHandle.tag())
- return QString();
-
- int offset = playlist()->columnOffset();
-
- switch(column - offset) {
- case TrackColumn:
- return d->fileHandle.tag()->title();
- case ArtistColumn:
- return d->fileHandle.tag()->artist();
- case AlbumColumn:
- return d->fileHandle.tag()->album();
- case CoverColumn:
- return QString();
- case TrackNumberColumn:
- return d->fileHandle.tag()->track() > 0
- ? QString::number(d->fileHandle.tag()->track())
- : QString();
- case GenreColumn:
- return d->fileHandle.tag()->genre();
- case YearColumn:
- return d->fileHandle.tag()->year() > 0
- ? QString::number(d->fileHandle.tag()->year())
- : QString();
- case LengthColumn:
- return d->fileHandle.tag()->lengthString();
- case BitrateColumn:
- return QString::number(d->fileHandle.tag()->bitrate());
- case CommentColumn:
- return d->fileHandle.tag()->comment();
- case FileNameColumn:
- return d->fileHandle.fileInfo().fileName();
- case FullPathColumn:
- return d->fileHandle.fileInfo().absoluteFilePath();
- default:
- return K3ListViewItem::text(column);
- }
-}
-
-void PlaylistItem::setText(int column, const QString &text)
-{
- int offset = playlist()->columnOffset();
- if(column - offset >= 0 && column + offset <= lastColumn()) {
- K3ListViewItem::setText(column, QString());
- return;
- }
-
- K3ListViewItem::setText(column, text);
- playlist()->slotWeightDirty(column);
-}
-
-void PlaylistItem::setPlaying(bool playing, bool master)
-{
- m_playingItems.removeAll(this);
-
- if(playing) {
- if(master)
- m_playingItems.prepend(this);
- else
- m_playingItems.append(this);
- }
- else {
-
- // This is a tricky little recursion, but it
- // in fact does clear the list.
-
- if(!m_playingItems.isEmpty())
- m_playingItems.front()->setPlaying(false);
- }
-
- listView()->triggerUpdate();
-}
-
-void PlaylistItem::setSelected(bool selected)
-{
- playlist()->markItemSelected(this, selected);
- K3ListViewItem::setSelected(selected);
-}
-
-void PlaylistItem::guessTagInfo(TagGuesser::Type type)
-{
- switch(type) {
- case TagGuesser::FileName:
- {
- TagGuesser guesser(d->fileHandle.absFilePath());
- Tag *tag = TagTransactionManager::duplicateTag(d->fileHandle.tag());
-
- if(!guesser.title().isNull())
- tag->setTitle(guesser.title());
- if(!guesser.artist().isNull())
- tag->setArtist(guesser.artist());
- if(!guesser.album().isNull())
- tag->setAlbum(guesser.album());
- if(!guesser.track().isNull())
- tag->setTrack(guesser.track().toInt());
- if(!guesser.comment().isNull())
- tag->setComment(guesser.comment());
-
- TagTransactionManager::instance()->changeTagOnItem(this, tag);
- break;
- }
- case TagGuesser::MusicBrainz:
- startMusicBrainzQuery(d->fileHandle);
- break;
- }
-}
-
-Playlist *PlaylistItem::playlist() const
-{
- return static_cast<Playlist *>(listView());
-}
-
-QVector<int> PlaylistItem::cachedWidths() const
-{
- return d->cachedWidths;
-}
-
-void PlaylistItem::refresh()
-{
- m_collectionItem->refresh();
-}
-
-void PlaylistItem::refreshFromDisk()
-{
- d->fileHandle.refresh();
- refresh();
-}
-
-void PlaylistItem::clear()
-{
- playlist()->clearItem(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistItem protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistItem::PlaylistItem(CollectionListItem *item, Playlist *parent) :
- K3ListViewItem(parent),
- d(0),
- m_watched(0)
-{
- setup(item);
-}
-
-PlaylistItem::PlaylistItem(CollectionListItem *item, Playlist *parent, Q3ListViewItem *after) :
- K3ListViewItem(parent, after),
- d(0),
- m_watched(0)
-{
- setup(item);
-}
-
-
-// This constructor should only be used by the CollectionList subclass.
-
-PlaylistItem::PlaylistItem(CollectionList *parent) :
- K3ListViewItem(parent),
- m_watched(0)
-{
- d = new Data;
- m_collectionItem = static_cast<CollectionListItem *>(this);
- setDragEnabled(true);
-}
-
-void PlaylistItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
-{
- if(!m_playingItems.contains(this))
- return K3ListViewItem::paintCell(p, cg, column, width, align);
-
- QPalette colorGroup = cg;
-
- QColor base = colorGroup.color( QPalette::Base );
- QColor selection = colorGroup.color( QPalette::Highlight );
-
- int r = (base.red() + selection.red()) / 2;
- int b = (base.blue() + selection.blue()) / 2;
- int g = (base.green() + selection.green()) / 2;
-
- QColor c(r, g, b);
-
- colorGroup.setColor(QPalette::Base, c);
- Q3ListViewItem::paintCell(p, colorGroup, column, width, align);
-}
-
-int PlaylistItem::compare(Q3ListViewItem *item, int column, bool ascending) const
-{
- // reimplemented from QListViewItem
-
- int offset = playlist()->columnOffset();
-
- if(!item)
- return 0;
-
- PlaylistItem *playlistItem = static_cast<PlaylistItem *>(item);
-
- // The following statments first check to see if you can sort based on the
- // specified column. If the values for the two PlaylistItems are the same
- // in that column it then tries to sort based on columns 1, 2, 3 and 0,
- // (artist, album, track number, track name) in that order.
-
- int c = compare(this, playlistItem, column, ascending);
-
- if(c != 0)
- return c;
- else {
- // Loop through the columns doing comparisons until something is differnt.
- // If all else is the same, compare the track name.
-
- int last = playlist()->isColumnVisible(AlbumColumn + offset) ? TrackNumberColumn : ArtistColumn;
-
- for(int i = ArtistColumn; i <= last; i++) {
- if(playlist()->isColumnVisible(i + offset)) {
- c = compare(this, playlistItem, i, ascending);
- if(c != 0)
- return c;
- }
- }
- return compare(this, playlistItem, TrackColumn + offset, ascending);
- }
-}
-
-int PlaylistItem::compare(const PlaylistItem *firstItem, const PlaylistItem *secondItem, int column, bool) const
-{
- int offset = playlist()->columnOffset();
-
- if(column < 0 || column > lastColumn() + offset || !firstItem->d || !secondItem->d)
- return 0;
-
- if(column < offset) {
- QString first = firstItem->text(column).toLower();
- QString second = secondItem->text(column).toLower();
- return first.localeAwareCompare(second);
- }
-
- switch(column - offset) {
- case TrackNumberColumn:
- if(firstItem->d->fileHandle.tag()->track() > secondItem->d->fileHandle.tag()->track())
- return 1;
- else if(firstItem->d->fileHandle.tag()->track() < secondItem->d->fileHandle.tag()->track())
- return -1;
- else
- return 0;
- break;
- case LengthColumn:
- if(firstItem->d->fileHandle.tag()->seconds() > secondItem->d->fileHandle.tag()->seconds())
- return 1;
- else if(firstItem->d->fileHandle.tag()->seconds() < secondItem->d->fileHandle.tag()->seconds())
- return -1;
- else
- return 0;
- break;
- case BitrateColumn:
- if(firstItem->d->fileHandle.tag()->bitrate() > secondItem->d->fileHandle.tag()->bitrate())
- return 1;
- else if(firstItem->d->fileHandle.tag()->bitrate() < secondItem->d->fileHandle.tag()->bitrate())
- return -1;
- else
- return 0;
- break;
- case CoverColumn:
- if(firstItem->d->fileHandle.coverInfo()->coverId() == secondItem->d->fileHandle.coverInfo()->coverId())
- return 0;
- else if (firstItem->d->fileHandle.coverInfo()->coverId() != CoverManager::NoMatch)
- return -1;
- else
- return 1;
- break;
- default:
- return QString::localeAwareCompare(firstItem->d->metadata[column - offset],
- secondItem->d->metadata[column - offset]);
- }
-}
-
-bool PlaylistItem::isValid() const
-{
- return bool(d->fileHandle.tag());
-}
-
-void PlaylistItem::setTrackId(quint32 id)
-{
- m_trackId = id;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistItem private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistItem::setup(CollectionListItem *item)
-{
- m_collectionItem = item;
-
- d = item->d;
- item->addChildItem(this);
- setDragEnabled(true);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PlaylistItem::Pointer implementation
-////////////////////////////////////////////////////////////////////////////////
-
-QMap<PlaylistItem *, QList<PlaylistItem::Pointer *> > PlaylistItem::Pointer::m_map; // static
-
-PlaylistItem::Pointer::Pointer(PlaylistItem *item) :
- m_item(item)
-{
- if(!m_item)
- return;
-
- m_item->m_watched = true;
- m_map[m_item].append(this);
-}
-
-PlaylistItem::Pointer::Pointer(const Pointer &p) :
- m_item(p.m_item)
-{
- m_map[m_item].append(this);
-}
-
-PlaylistItem::Pointer::~Pointer()
-{
- if(!m_item)
- return;
-
- m_map[m_item].removeAll(this);
- if(m_map[m_item].isEmpty()) {
- m_map.remove(m_item);
- m_item->m_watched = false;
- }
-}
-
-PlaylistItem::Pointer &PlaylistItem::Pointer::operator=(PlaylistItem *item)
-{
- if(item == m_item)
- return *this;
-
- if(m_item) {
- m_map[m_item].removeAll(this);
- if(m_map[m_item].isEmpty()) {
- m_map.remove(m_item);
- m_item->m_watched = false;
- }
- }
-
- if(item) {
- m_map[item].append(this);
- item->m_watched = true;
- }
-
- m_item = item;
-
- return *this;
-}
-
-void PlaylistItem::Pointer::clear(PlaylistItem *item) // static
-{
- if(!item)
- return;
-
- QList<Pointer *> l = m_map[item];
- foreach(Pointer *pointer, l)
- pointer->m_item = 0;
- m_map.remove(item);
- item->m_watched = false;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTITEM_H
-#define PLAYLISTITEM_H
-
-#include <k3listview.h>
-#include <ksharedptr.h>
-#include <kdebug.h>
-
-#include <QVector>
-#include <QPixmap>
-#include <QList>
-
-#include "tagguesser.h"
-#include "filehandle.h"
-
-class Playlist;
-class PlaylistItem;
-class CollectionListItem;
-class CollectionList;
-
-typedef QList<PlaylistItem *> PlaylistItemList;
-
-/**
- * Items for the Playlist and the baseclass for CollectionListItem.
- * The constructors and destructor are protected and new items should be
- * created via Playlist::createItem(). Items should be removed by
- * Playlist::clear(), Playlist::deleteFromDisk(), Playlist::clearItem() or
- * Playlist::clearItem().
- */
-
-class PlaylistItem : public K3ListViewItem
-{
- friend class Playlist;
- friend class SearchPlaylist;
- friend class UpcomingPlaylist;
- friend class CollectionList;
- friend class CollectionListItem;
- friend class Pointer;
-
-public:
- enum ColumnType { TrackColumn = 0,
- ArtistColumn = 1,
- AlbumColumn = 2,
- CoverColumn = 3,
- TrackNumberColumn = 4,
- GenreColumn = 5,
- YearColumn = 6,
- LengthColumn = 7,
- BitrateColumn = 8,
- CommentColumn = 9,
- FileNameColumn = 10,
- FullPathColumn = 11 };
-
- /**
- * A helper class to implement guarded pointer semantics.
- */
-
- class Pointer
- {
- public:
- Pointer() : m_item(0) {}
- Pointer(PlaylistItem *item);
- Pointer(const Pointer &p);
- ~Pointer();
- Pointer &operator=(PlaylistItem *item);
- bool operator==(const Pointer &p) const { return m_item == p.m_item; }
- bool operator!=(const Pointer &p) const { return m_item != p.m_item; }
- PlaylistItem *operator->() const { return m_item; }
- PlaylistItem &operator*() const { return *m_item; }
- operator PlaylistItem*() const { return m_item; }
- static void clear(PlaylistItem *item);
-
- private:
- PlaylistItem *m_item;
- static QMap<PlaylistItem *, QList<Pointer *> > m_map;
- };
- friend class Pointer;
-
- static int lastColumn() { return FullPathColumn; }
-
- void setFile(const FileHandle &file);
- void setFile(const QString &file);
- FileHandle file() const;
-
- virtual const QPixmap *pixmap(int column) const;
- virtual QString text(int column) const;
- virtual void setText(int column, const QString &text);
-
- void setPlaying(bool playing = true, bool master = true);
-
- virtual void setSelected(bool selected);
- void guessTagInfo(TagGuesser::Type type);
-
- Playlist *playlist() const;
-
- virtual CollectionListItem *collectionItem() { return m_collectionItem; }
-
- /**
- * This is an identifier for the playlist item which will remain unique
- * throughout the process lifetime. It stays constant once the PlaylistItem
- * is created.
- */
- quint32 trackId() const { return m_trackId; }
-
- /**
- * The widths of items are cached when they're updated for us in computations
- * in the "weighted" listview column width mode.
- */
- QVector<int> cachedWidths() const;
-
- /**
- * This just refreshes from the in memory data. This may seem pointless at
- * first, but this data is shared between all of the list view items that are
- * based on the same file, so if another one of those items changes its data
- * it is important to refresh the others.
- */
- virtual void refresh();
-
- /**
- * This rereads the tag from disk. This affects all PlaylistItems based on
- * the same file.
- */
- virtual void refreshFromDisk();
-
- /**
- * Asks the item's playlist to remove the item (which uses deleteLater()).
- */
- virtual void clear();
-
- /**
- * Returns properly casted item below this one.
- */
- PlaylistItem *itemBelow() { return static_cast<PlaylistItem *>(K3ListViewItem::itemBelow()); }
-
- /**
- * Returns properly casted item above this one.
- */
- PlaylistItem *itemAbove() { return static_cast<PlaylistItem *>(K3ListViewItem::itemAbove()); }
-
- /**
- * Returns a reference to the list of the currnetly playing items, with the
- * first being the "master" item (i.e. the item from which the next track is
- * chosen).
- */
- static const PlaylistItemList &playingItems() { return m_playingItems; }
-
-protected:
- /**
- * Items should always be created using Playlist::createItem() or through a
- * subclass or friend class.
- */
- PlaylistItem(CollectionListItem *item, Playlist *parent);
- PlaylistItem(CollectionListItem *item, Playlist *parent, Q3ListViewItem *after);
-
- /**
- * This is the constructor that shold be used by subclasses.
- */
- PlaylistItem(CollectionList *parent);
-
- /**
- * See the class documentation for an explanation of construction and deletion
- * of PlaylistItems.
- */
- virtual ~PlaylistItem();
-
- virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align);
- virtual void paintFocus(QPainter *, const QColorGroup &, const QRect &) {}
-
- virtual int compare(Q3ListViewItem *item, int column, bool ascending) const;
- int compare(const PlaylistItem *firstItem, const PlaylistItem *secondItem, int column, bool ascending) const;
-
- bool isValid() const;
-
- void setTrackId(quint32 id);
-
- /**
- * Shared data between all PlaylistItems from the same track (incl. the CollectionItem
- * representing said track.
- */
- struct Data : public KShared
- {
- Data() {}
- Data(const QFileInfo &info, const QString &path) : fileHandle(info, path) {}
- Data(const QString &path) : fileHandle(path) {}
-
- FileHandle fileHandle;
- QVector<QString> metadata; ///< Artist, album, or genre tags. Other columns unfilled
- QVector<int> cachedWidths;
- };
-
- KSharedPtr<Data> data() const { return d; }
-
-private:
- KSharedPtr<Data> d;
-
- void setup(CollectionListItem *item);
- using Q3ListViewItem::setup; // Avoid warning about hidden function.
-
- CollectionListItem *m_collectionItem;
- quint32 m_trackId;
- bool m_watched;
- static PlaylistItemList m_playingItems;
-};
-
-inline QDebug operator<<(QDebug s, const PlaylistItem &item)
-{
- if(&item == 0)
- s << "(nil)";
- else
- s << item.text(PlaylistItem::TrackColumn);
-
- return s;
-}
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistsearch.h"
-#include "playlist.h"
-#include "playlistitem.h"
-#include "collectionlist.h"
-#include "juk-exception.h"
-
-#include <kdebug.h>
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistSearch::PlaylistSearch() :
- m_mode(MatchAny)
-{
-
-}
-
-PlaylistSearch::PlaylistSearch(const PlaylistList &playlists,
- const ComponentList &components,
- SearchMode mode,
- bool searchNow) :
- m_playlists(playlists),
- m_components(components),
- m_mode(mode)
-{
- if(searchNow)
- search();
-}
-
-void PlaylistSearch::search()
-{
- m_items.clear();
- m_matchedItems.clear();
- m_unmatchedItems.clear();
-
- // This really isn't as bad as it looks. Despite the four nexted loops
- // most of the time this will be searching one playlist for one search
- // component -- possibly for one column.
-
- // Also there should be some caching of previous searches in here and
- // allowance for appending and removing chars. If one is added it
- // should only search the current list. If one is removed it should
- // pop the previous search results off of a stack.
-
- foreach(Playlist *playlist, m_playlists) {
- if(!isEmpty()) {
- for(Q3ListViewItemIterator it(playlist); it.current(); ++it)
- checkItem(static_cast<PlaylistItem *>(*it));
- }
- else {
- m_items += playlist->items();
- m_matchedItems += playlist->items();
- }
- }
-}
-
-bool PlaylistSearch::checkItem(PlaylistItem *item)
-{
- m_items.append(item);
-
- // set our default
- bool match = bool(m_mode);
-
- ComponentList::Iterator componentIt = m_components.begin();
- for(; componentIt != m_components.end(); ++componentIt) {
-
- bool componentMatches = (*componentIt).matches(item);
-
- if(componentMatches && m_mode == MatchAny) {
- match = true;
- break;
- }
-
- if(!componentMatches && m_mode == MatchAll) {
- match = false;
- break;
- }
- }
-
- if(match)
- m_matchedItems.append(item);
- else
- m_unmatchedItems.append(item);
-
- return match;
-}
-
-void PlaylistSearch::addComponent(const Component &c)
-{
- m_components.append(c);
-}
-
-void PlaylistSearch::clearComponents()
-{
- m_components.clear();
-}
-
-PlaylistSearch::ComponentList PlaylistSearch::components() const
-{
- return m_components;
-}
-
-bool PlaylistSearch::isNull() const
-{
- return m_components.isEmpty();
-}
-
-bool PlaylistSearch::isEmpty() const
-{
- if(isNull())
- return true;
-
- ComponentList::ConstIterator it = m_components.begin();
- for(; it != m_components.end(); ++it) {
- if(!(*it).query().isEmpty() || !(*it).pattern().isEmpty())
- return false;
- }
-
- return true;
-}
-
-void PlaylistSearch::clearItem(PlaylistItem *item)
-{
- m_items.removeAll(item);
- m_matchedItems.removeAll(item);
- m_unmatchedItems.removeAll(item);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Component public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistSearch::Component::Component() :
- m_mode(Contains),
- m_searchAllVisible(true),
- m_caseSensitive(false)
-{
-
-}
-
-PlaylistSearch::Component::Component(const QString &query,
- bool caseSensitive,
- const ColumnList &columns,
- MatchMode mode) :
- m_query(query),
- m_columns(columns),
- m_mode(mode),
- m_searchAllVisible(columns.isEmpty()),
- m_caseSensitive(caseSensitive),
- m_re(false)
-{
-
-}
-
-PlaylistSearch::Component::Component(const QRegExp &query, const ColumnList& columns) :
- m_queryRe(query),
- m_columns(columns),
- m_mode(Exact),
- m_searchAllVisible(columns.isEmpty()),
- m_caseSensitive(false),
- m_re(true)
-{
-
-}
-
-bool PlaylistSearch::Component::matches(PlaylistItem *item) const
-{
- if((m_re && m_queryRe.isEmpty()) || (!m_re && m_query.isEmpty()))
- return false;
-
- if(m_columns.isEmpty()) {
- Playlist *p = static_cast<Playlist *>(item->listView());
- for(int i = 0; i < p->columns(); i++) {
- if(p->isColumnVisible(i))
- m_columns.append(i);
- }
- }
-
-
- for(ColumnList::Iterator it = m_columns.begin(); it != m_columns.end(); ++it) {
-
- if(m_re) {
- if(item->text(*it).contains(m_queryRe))
- return true;
- else
- break;
- }
-
- switch(m_mode) {
- case Contains:
- if(item->text(*it).contains(m_query, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive))
- return true;
- break;
- case Exact:
- if(item->text(*it).length() == m_query.length()) {
- if(m_caseSensitive) {
- if(item->text(*it) == m_query)
- return true;
- }
- else if(item->text(*it).toLower() == m_query.toLower())
- return true;
- }
- break;
- case ContainsWord:
- {
- QString s = item->text(*it);
- int i = s.indexOf(m_query, 0, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
-
- if(i >= 0) {
-
- // If we found the pattern and the lengths are the same, then
- // this is a match.
-
- if(s.length() == m_query.length())
- return true;
-
- // First: If the match starts at the beginning of the text or the
- // character before the match is not a word character
-
- // AND
-
- // Second: Either the pattern was found at the end of the text,
- // or the text following the match is a non-word character
-
- // ...then we have a match
-
- if((i == 0 || !s.at(i - 1).isLetterOrNumber()) &&
- (i + m_query.length() == s.length() || !s.at(i + m_query.length()).isLetterOrNumber()))
- return true;
- break;
- }
- }
- }
- }
- return false;
-}
-
-bool PlaylistSearch::Component::operator==(const Component &v) const
-{
- return m_query == v.m_query &&
- m_queryRe == v.m_queryRe &&
- m_columns == v.m_columns &&
- m_mode == v.m_mode &&
- m_searchAllVisible == v.m_searchAllVisible &&
- m_caseSensitive == v.m_caseSensitive &&
- m_re == v.m_re;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// helper functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const PlaylistSearch &search)
-{
- s << search.components()
- << qint32(search.searchMode());
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, PlaylistSearch &search)
-{
- search.clearPlaylists();
- search.addPlaylist(CollectionList::instance());
-
- search.clearComponents();
- PlaylistSearch::ComponentList components;
- s >> components;
- PlaylistSearch::ComponentList::ConstIterator it = components.constBegin();
- for(; it != components.constEnd(); ++it)
- search.addComponent(*it);
-
- qint32 mode;
- s >> mode;
- search.setSearchMode(PlaylistSearch::SearchMode(mode));
-
- return s;
-}
-
-QDataStream &operator<<(QDataStream &s, const PlaylistSearch::Component &c)
-{
- s << c.isPatternSearch()
- << (c.isPatternSearch() ? c.pattern().pattern() : c.query())
- << c.isCaseSensitive()
- << c.columns()
- << qint32(c.matchMode());
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, PlaylistSearch::Component &c)
-{
- bool patternSearch;
- QString pattern;
- bool caseSensitive;
- ColumnList columns;
- qint32 mode;
-
- s >> patternSearch
- >> pattern
- >> caseSensitive
- >> columns
- >> mode;
-
- if(patternSearch)
- c = PlaylistSearch::Component(QRegExp(pattern), columns);
- else
- c = PlaylistSearch::Component(pattern, caseSensitive, columns, PlaylistSearch::Component::MatchMode(mode));
-
- return s;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTSEARCH_H
-#define PLAYLISTSEARCH_H
-
-#include <QRegExp>
-#include <QList>
-
-class Playlist;
-class PlaylistItem;
-
-typedef QList<int> ColumnList;
-typedef QList<PlaylistItem *> PlaylistItemList;
-typedef QList<Playlist *> PlaylistList;
-
-class PlaylistSearch
-{
-public:
- class Component;
- typedef QList<Component> ComponentList;
-
- enum SearchMode { MatchAny = 0, MatchAll = 1 };
-
- PlaylistSearch();
- PlaylistSearch(const PlaylistList &playlists,
- const ComponentList &components,
- SearchMode mode = MatchAny,
- bool searchNow = true);
-
- void search();
- bool checkItem(PlaylistItem *item);
-
- PlaylistItemList searchedItems() const { return m_items; }
- PlaylistItemList matchedItems() const { return m_matchedItems; }
- PlaylistItemList unmatchedItems() const { return m_unmatchedItems; }
-
- void addPlaylist(Playlist *p) { m_playlists.append(p); }
- void clearPlaylists() { m_playlists.clear(); }
- PlaylistList playlists() const { return m_playlists; }
-
- void addComponent(const Component &c);
- void clearComponents();
- ComponentList components() const;
-
- void setSearchMode(SearchMode m) { m_mode = m; }
- SearchMode searchMode() const { return m_mode; }
-
- bool isNull() const;
- bool isEmpty() const;
-
- /**
- * This is used to clear an item from the matched and unmatched lists. This
- * is useful because it can prevent keeping a dangling pointer around without
- * requiring invalidating the search.
- */
- void clearItem(PlaylistItem *item);
-
-private:
- PlaylistList m_playlists;
- ComponentList m_components;
- SearchMode m_mode;
-
- PlaylistItemList m_items;
- PlaylistItemList m_matchedItems;
- PlaylistItemList m_unmatchedItems;
-};
-
-/**
- * A search is built from several search components. These corespond to to lines
- * in the search bar.
- */
-
-class PlaylistSearch::Component
-{
-public:
- enum MatchMode { Contains = 0, Exact = 1, ContainsWord = 2 };
-
- /**
- * Create an empty search component. This is only provided for use by
- * QValueList and should not be used in any other context.
- */
- Component();
-
- /**
- * Create a query component. This defaults to searching all visible coulumns.
- */
- Component(const QString &query,
- bool caseSensitive = false,
- const ColumnList &columns = ColumnList(),
- MatchMode mode = Contains);
-
- /**
- * Create a query component. This defaults to searching all visible coulumns.
- */
- Component(const QRegExp &query, const ColumnList &columns = ColumnList());
-
- QString query() const { return m_query; }
- QRegExp pattern() const { return m_queryRe; }
- ColumnList columns() const { return m_columns; }
-
- bool matches(PlaylistItem *item) const;
- bool isPatternSearch() const { return m_re; }
- bool isCaseSensitive() const { return m_caseSensitive; }
- MatchMode matchMode() const { return m_mode; }
-
- bool operator==(const Component &v) const;
-
-private:
- QString m_query;
- QRegExp m_queryRe;
- mutable ColumnList m_columns;
- MatchMode m_mode;
- bool m_searchAllVisible;
- bool m_caseSensitive;
- bool m_re;
-};
-
-/**
- * Streams \a search to the stream \a s.
- * \note This does not save the playlist list, but instead will assume that the
- * search is just relevant to the collection list. This is all that is presently
- * needed by JuK.
- */
-QDataStream &operator<<(QDataStream &s, const PlaylistSearch &search);
-
-/**
- * Streams \a search from the stream \a s.
- * \note This does not save the playlist list, but instead will assume that the
- * search is just relevant to the collection list. This is all that is presently
- * needed by JuK.
- */
-QDataStream &operator>>(QDataStream &s, PlaylistSearch &search);
-
-QDataStream &operator<<(QDataStream &s, const PlaylistSearch::Component &c);
-QDataStream &operator>>(QDataStream &s, PlaylistSearch::Component &c);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "playlistsplitter.h"
-
-#include <kicon.h>
-#include <kaction.h>
-#include <kglobal.h>
-#include <kactioncollection.h>
-#include <kdebug.h>
-#include <ktoggleaction.h>
-#include <kconfiggroup.h>
-
-#include <QEvent>
-#include <QVBoxLayout>
-#include <QLatin1String>
-#include <QList>
-#include <QTime>
-#include <QStackedWidget>
-#include <QSizePolicy>
-
-#include "searchwidget.h"
-#include "playlistsearch.h"
-#include "actioncollection.h"
-#include "tageditor.h"
-#include "collectionlist.h"
-#include "playermanager.h"
-#include "nowplaying.h"
-#include "playlistbox.h"
-#include "lyricswidget.h"
-#include "mpris2/mpris2.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-PlaylistSplitter::PlaylistSplitter(PlayerManager *player, QWidget *parent) :
- QSplitter(Qt::Horizontal, parent),
- m_newVisible(0),
- m_playlistBox(0),
- m_searchWidget(0),
- m_playlistStack(0),
- m_editor(0),
- m_nowPlaying(0),
- m_player(player),
- m_lyricsWidget(0),
- m_editorSplitter(0)
-
-{
- setObjectName(QLatin1String("playlistSplitter"));
-
- setupActions();
- setupLayout();
- readConfig();
-
- m_editor->slotUpdateCollection();
- m_editor->setupObservers();
-}
-
-PlaylistSplitter::~PlaylistSplitter()
-{
- saveConfig();
-
- // TagEditor needs to write its configuration out while it's still valid,
- // destroy it now.
-
- delete m_editor;
-
- delete m_lyricsWidget;
-
- // NowPlaying depends on the PlaylistCollection, so kill it now.
- delete m_nowPlaying;
- m_nowPlaying = 0;
-
- delete m_searchWidget; // Take no chances here either.
-
- // Since we want to ensure that the shutdown process for the PlaylistCollection
- // (a base class for PlaylistBox) has a chance to write the playlists to disk
- // before they are deleted we're explicitly deleting the PlaylistBox here.
-
- delete m_playlistBox;
-}
-
-PlaylistInterface *PlaylistSplitter::playlist() const
-{
- return m_playlistBox;
-}
-
-bool PlaylistSplitter::eventFilter(QObject *, QEvent *event)
-{
- if(event->type() == FocusUpEvent::id) {
- m_searchWidget->setFocus();
- return true;
- }
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void PlaylistSplitter::setFocus()
-{
- m_searchWidget->setFocus();
-}
-
-void PlaylistSplitter::slotFocusCurrentPlaylist()
-{
- Playlist *playlist = m_playlistBox->visiblePlaylist();
-
- if(playlist) {
- playlist->setFocus();
- playlist->K3ListView::selectAll(false);
-
- // Select the top visible (and matching) item.
-
- PlaylistItem *item = static_cast<PlaylistItem *>(playlist->itemAt(QPoint(0, 0)));
-
- if(!item)
- return;
-
- // A little bit of a hack to make QListView repaint things properly. Switch
- // to single selection mode, set the selection and then switch back.
-
- playlist->setSelectionMode(Q3ListView::Single);
-
- playlist->markItemSelected(item, true);
- playlist->setCurrentItem(item);
-
- playlist->setSelectionMode(Q3ListView::Extended);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-Playlist *PlaylistSplitter::visiblePlaylist() const
-{
- return m_newVisible ? m_newVisible : m_playlistBox->visiblePlaylist();
-}
-
-void PlaylistSplitter::setupActions()
-{
- KActionCollection* coll = ActionCollection::actions();
- KToggleAction *showSearch =
- new KToggleAction(KIcon("edit-find"), i18n("Show &Search Bar"), this);
- coll->addAction("showSearch", showSearch);
-
- KAction *act = new KAction(KIcon("edit-clear"), i18n("Edit Track Search"), this);
- coll->addAction("editTrackSearch", act);
- act->setShortcut(Qt::Key_F6);
- connect(act, SIGNAL(triggered(bool)), SLOT(setFocus()));
-}
-
-void PlaylistSplitter::setupLayout()
-{
- setOpaqueResize(false);
-
- // Disable the GUI until startup is complete (as indicated by PlaylistBox)
-
- setEnabled(false);
-
- // Create a splitter to go between the playlists and the editor.
-
- m_editorSplitter = new QSplitter(Qt::Vertical, this);
- m_editorSplitter->setObjectName( QLatin1String("editorSplitter" ));
-
- // Make sure none of the optional widgets are collapsible, this causes the
- // widget to be essentially invisible but logically shown.
-
- this->setChildrenCollapsible(false);
- m_editorSplitter->setChildrenCollapsible(false);
-
- // Create the playlist and the editor.
-
- QWidget *top = new QWidget(m_editorSplitter);
- QVBoxLayout *topLayout = new QVBoxLayout(top);
- topLayout->setMargin(0);
- topLayout->setSpacing(0);
-
- m_playlistStack = new QStackedWidget(top);
- m_playlistStack->setObjectName( QLatin1String("playlistStack" ));
- m_playlistStack->installEventFilter(this);
- m_playlistStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- m_playlistStack->hide(); // Will be shown after CollectionList filled.
-
- m_editor = new TagEditor(m_editorSplitter);
- m_editor->setObjectName( QLatin1String("TagEditor" ));
-
- // Create the lyrics widget
- m_lyricsWidget = new LyricsWidget(this);
- insertWidget(2, m_lyricsWidget);
-
- // Create the PlaylistBox
- m_playlistBox = new PlaylistBox(m_player, this, m_playlistStack);
- m_playlistBox->setObjectName( QLatin1String( "playlistBox" ) );
-
- connect(m_playlistBox->object(), SIGNAL(signalSelectedItemsChanged()),
- this, SLOT(slotPlaylistSelectionChanged()));
- connect(m_playlistBox, SIGNAL(signalPlaylistDestroyed(Playlist*)),
- m_editor, SLOT(slotPlaylistDestroyed(Playlist*)));
- connect(m_playlistBox, SIGNAL(startupComplete()), SLOT(slotEnable()));
- connect(m_playlistBox, SIGNAL(startFilePlayback(FileHandle)),
- m_player, SLOT(play(FileHandle)));
-
- m_player->setPlaylistInterface(m_playlistBox);
-
- // Let interested parties know we're ready
- connect(m_playlistBox, SIGNAL(startupComplete()), SIGNAL(guiReady()));
-
- insertWidget(0, m_playlistBox);
-
- m_nowPlaying = new NowPlaying(top, m_playlistBox);
- connect(m_player, SIGNAL(signalItemChanged(FileHandle)),
- m_nowPlaying, SLOT(slotUpdate(FileHandle)));
- connect(m_player, SIGNAL(signalItemChanged(FileHandle)),
- m_lyricsWidget, SLOT(playing(FileHandle)));
-
- // Create the search widget -- this must be done after the CollectionList is created.
-
- m_searchWidget = new SearchWidget(top);
- connect(m_searchWidget, SIGNAL(signalQueryChanged()),
- this, SLOT(slotShowSearchResults()));
- connect(m_searchWidget, SIGNAL(signalDownPressed()),
- this, SLOT(slotFocusCurrentPlaylist()));
- connect(m_searchWidget, SIGNAL(signalAdvancedSearchClicked()),
- m_playlistBox->object(), SLOT(slotCreateSearchPlaylist()));
- connect(m_searchWidget, SIGNAL(signalShown(bool)),
- m_playlistBox->object(), SLOT(slotSetSearchEnabled(bool)));
- connect(m_searchWidget, SIGNAL(returnPressed()),
- m_playlistBox->object(), SLOT(slotPlayFirst()));
- connect(ActionCollection::action<KToggleAction>("showSearch"), SIGNAL(toggled(bool)),
- m_searchWidget, SLOT(setEnabled(bool)));
-
- topLayout->addWidget(m_nowPlaying);
- topLayout->addWidget(m_searchWidget);
- topLayout->insertStretch(-1); // Force search bar to top while playlistStack hides
- topLayout->addWidget(m_playlistStack, 1);
-
- // Now that GUI setup is complete, add some auto-update signals.
- connect(CollectionList::instance(), SIGNAL(signalCollectionChanged()),
- m_editor, SLOT(slotUpdateCollection()));
- connect(m_playlistStack, SIGNAL(currentChanged(int)), this, SLOT(slotPlaylistChanged(int)));
-
- // Show the collection on startup.
- m_playlistBox->setSelected(0, true);
-}
-
-void PlaylistSplitter::readConfig()
-{
- KConfigGroup config(KGlobal::config(), "Splitter");
-
- QList<int> splitterSizes = config.readEntry("PlaylistSplitterSizes",QList<int>());
- if(splitterSizes.isEmpty()) {
- splitterSizes.append(100);
- splitterSizes.append(640);
- }
- setSizes(splitterSizes);
-
- bool showSearch = config.readEntry("ShowSearch", true);
- ActionCollection::action<KToggleAction>("showSearch")->setChecked(showSearch);
- m_searchWidget->setHidden(!showSearch);
-
- splitterSizes = config.readEntry("EditorSplitterSizes",QList<int>());
- if(splitterSizes.isEmpty()) {
- // If no sizes were saved, use default sizes for the playlist and the
- // editor, respectively. The values are just hints for the actual size,
- // m_editorSplitter will distribute the space according to their
- // relative weight.
- splitterSizes.append(300);
- splitterSizes.append(200);
- }
- m_editorSplitter->setSizes(splitterSizes);
-}
-
-void PlaylistSplitter::saveConfig()
-{
- KConfigGroup config(KGlobal::config(), "Splitter");
- config.writeEntry("PlaylistSplitterSizes", sizes());
- config.writeEntry("ShowSearch", ActionCollection::action<KToggleAction>("showSearch")->isChecked());
- config.writeEntry("EditorSplitterSizes", m_editorSplitter->sizes());
-}
-
-void PlaylistSplitter::slotShowSearchResults()
-{
- PlaylistList playlists;
- playlists.append(visiblePlaylist());
- PlaylistSearch search = m_searchWidget->search(playlists);
- visiblePlaylist()->setSearch(search);
-}
-
-void PlaylistSplitter::slotPlaylistSelectionChanged()
-{
- m_editor->slotSetItems(visiblePlaylist()->selectedItems());
-}
-
-void PlaylistSplitter::slotPlaylistChanged(int i)
-{
- Playlist *p = qobject_cast<Playlist *>(m_playlistStack->widget(i));
-
- if(!p)
- return;
-
- m_newVisible = p;
- m_searchWidget->setSearch(p->search());
- m_newVisible = 0;
-}
-
-void PlaylistSplitter::slotEnable()
-{
- kDebug() << "Enabling GUI";
- QTime stopwatch; stopwatch.start();
- setEnabled(true); // Ready to go.
- m_playlistStack->show();
- kDebug() << "Finished enabling GUI, took" << stopwatch.elapsed() << "ms";
-
- (void) new Mpris2(this);
-}
-
-#include "playlistsplitter.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PLAYLISTSPLITTER_H
-#define PLAYLISTSPLITTER_H
-
-#include <QSplitter>
-
-class QStackedWidget;
-
-class Playlist;
-class SearchWidget;
-class PlaylistInterface;
-class TagEditor;
-class PlaylistBox;
-class NowPlaying;
-class PlayerManager;
-class FileHandle;
-class LyricsWidget;
-
-/**
- * This is the main layout class of JuK. It should contain a PlaylistBox and
- * a QStackedWidget of the Playlists.
- *
- * This class serves as a "mediator" (see "Design Patterns") between the JuK
- * class and the playlist classes. Thus all access to the playlist classes from
- * non-Playlist related classes should be through the public API of this class.
- */
-
-class PlaylistSplitter : public QSplitter
-{
- Q_OBJECT
-
-public:
- PlaylistSplitter(PlayerManager *player, QWidget *parent);
- virtual ~PlaylistSplitter();
-
- PlaylistInterface *playlist() const;
-
- virtual bool eventFilter(QObject *watched, QEvent *event);
-
-signals:
- /**
- * Emitted when GUI is created and the cache is loaded. Is kind of a hack
- * until we move the time-intensive parts to a separate thread but then
- * again at least this works.
- */
- void guiReady();
-
-public slots:
- virtual void setFocus();
- virtual void slotFocusCurrentPlaylist();
- void slotEnable();
-
-private:
-
- /**
- * This returns a pointer to the first item in the playlist on the top
- * of the QStackedWidget of playlists.
- */
- Playlist *visiblePlaylist() const;
-
- void setupActions();
- void setupLayout();
- void readConfig();
- void saveConfig();
-
-private slots:
-
- /**
- * Updates the visible search results based on the result of the search
- * associated with the currently visible playlist.
- */
- void slotShowSearchResults();
- void slotPlaylistSelectionChanged();
- void slotPlaylistChanged(int i);
-
-private:
- Playlist *m_newVisible;
- PlaylistBox *m_playlistBox;
- SearchWidget *m_searchWidget;
- QStackedWidget *m_playlistStack;
- TagEditor *m_editor;
- NowPlaying *m_nowPlaying;
- PlayerManager *m_player;
- LyricsWidget *m_lyricsWidget;
- QSplitter *m_editorSplitter;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "scrobbleconfigdlg.h"
-#include "scrobbler.h"
-
-#include <KDebug>
-#include <KLineEdit>
-#include <KPushButton>
-#include <KLocalizedString>
-#include <KMessageBox>
-
-#include <QLayout>
-#include <QLabel>
-#include <QFormLayout>
-
-
-
-ScrobbleConfigDlg::ScrobbleConfigDlg(QWidget* parent, Qt::WindowFlags f)
- : KDialog(parent, f)
- , m_wallet(0)
-{
- setWindowTitle(i18n("Configure scrobbling..."));
-
- setButtons(Apply | Cancel);
-
- m_passwordEdit = new KLineEdit(this);
- m_passwordEdit->setPasswordMode(true);
- m_usernameEdit = new KLineEdit(this);
- m_testButton = new KPushButton(i18n("Test login..."), this);
- m_testFeedbackLabel = new QLabel("");
-
- QWidget *mainWidget = new QWidget();
- QFormLayout *layout = new QFormLayout();
- mainWidget->setLayout(layout);
- QLabel *infoLabel = new QLabel(i18n("Please enter your <a href=\"http://last.fm/\">last.fm</a> login credentials:"));
- infoLabel->setOpenExternalLinks(true);
- infoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- layout->addRow(infoLabel);
- layout->addRow(new QLabel(i18n("Username:")), m_usernameEdit);
- layout->addRow(new QLabel(i18n("Password:")), m_passwordEdit);
- layout->addRow(m_testButton);
- layout->addRow(m_testFeedbackLabel);
-
- connect(m_passwordEdit, SIGNAL(textEdited(QString)), this, SLOT(valuesChanged()));
- connect(m_usernameEdit, SIGNAL(textEdited(QString)), this, SLOT(valuesChanged()));
- connect(m_testButton, SIGNAL(clicked(bool)), this, SLOT(testLogin()));
- connect(this, SIGNAL(applyClicked()), this, SLOT(save()));
-
- setMainWidget(mainWidget);
-
- // Loading credentials using either KWallet or KConfigGroup.
- m_wallet = Scrobbler::openKWallet();
-
- if (m_wallet) {
-
- QMap<QString, QString> scrobblingCredentials;
- m_wallet->readMap("Scrobbling", scrobblingCredentials);
-
- if (scrobblingCredentials.contains("Username") && scrobblingCredentials.contains("Password")) {
- m_usernameEdit->setText(scrobblingCredentials.value("Username"));
- m_passwordEdit->setText(scrobblingCredentials.value("Password"));
- }
-
- } else {
-
- // Warning message, KWallet is safer than KConfig.
- KMessageBox::information(this, i18n("KWallet is unavailable, your Last.fm credentials will be stored without encryption."), i18n("KWallet is unavailable"));
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- m_usernameEdit->setText(config.readEntry("Username", ""));
- m_passwordEdit->setText(config.readEntry("Password", ""));
- }
-
- if (m_passwordEdit->text().isEmpty() || m_usernameEdit->text().isEmpty()) {
- button(Apply)->setEnabled(false);
- m_testButton->setEnabled(false);
- }
-}
-
-ScrobbleConfigDlg::~ScrobbleConfigDlg()
-{
- delete m_wallet;
-}
-
-void ScrobbleConfigDlg::valuesChanged()
-{
- if (m_usernameEdit->text().isEmpty() || m_passwordEdit->text().isEmpty())
- m_testButton->setEnabled(false);
-
- else
- m_testButton->setEnabled(true);
-
- button(Apply)->setEnabled(false);
-}
-
-void ScrobbleConfigDlg::save()
-{
- QDialog::accept();
-
- if (m_wallet) {
-
- QMap<QString, QString> scrobblingCredentials;
- scrobblingCredentials.insert("Username", m_usernameEdit->text());
- scrobblingCredentials.insert("Password", m_passwordEdit->text());
-
- if (!m_wallet->writeMap("Scrobbling", scrobblingCredentials)) {
-
- kError() << "Couldn't save Last.fm credentials using KWallet.";
- }
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- config.writeEntry("Username", m_usernameEdit->text());
- config.writeEntry("Password", m_passwordEdit->text());
- }
-}
-
-void ScrobbleConfigDlg::testLogin()
-{
- m_testFeedbackLabel->setText(i18n("Validating login..."));
- Scrobbler *scrobbler = new Scrobbler(this);
- connect(scrobbler, SIGNAL(validAuth()), this, SLOT(validLogin()));
- connect(scrobbler, SIGNAL(invalidAuth()), this, SLOT(invalidLogin()));
- setEnabled(false);
- scrobbler->getAuthToken(m_usernameEdit->text(), m_passwordEdit->text());
-}
-
-void ScrobbleConfigDlg::invalidLogin()
-{
- m_testFeedbackLabel->setText(i18n("Login invalid."));
- setEnabled(true);
- sender()->deleteLater();
- button(Apply)->setEnabled(false);
-}
-
-void ScrobbleConfigDlg::validLogin()
-{
- m_testFeedbackLabel->setText(i18n("Login valid."));
- setEnabled(true);
- sender()->deleteLater();
- button(Apply)->setEnabled(true);
-}
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SCROBBLESETTINGS_H
-#define SCROBBLESETTINGS_H
-
-#include <KDialog>
-#include <KWallet/Wallet>
-
-class KLineEdit;
-class KPushButton;
-class QLabel;
-
-class ScrobbleConfigDlg : public KDialog
-{
- Q_OBJECT
-public:
- explicit ScrobbleConfigDlg(QWidget* parent = 0, Qt::WindowFlags f = 0);
- ~ScrobbleConfigDlg();
-
-private slots:
- void testLogin();
- void validLogin();
- void invalidLogin();
- void save();
- void valuesChanged();
-
-private:
- KLineEdit *m_usernameEdit;
- KLineEdit *m_passwordEdit;
- KPushButton *m_testButton;
- QLabel *m_testFeedbackLabel;
-
- KWallet::Wallet *m_wallet;
-};
-
-#endif//SCROBBLESETTINGS_H
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "scrobbler.h"
-
-#include <QCryptographicHash>
-#include <QDir>
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QDomDocument>
-#include <QByteArray>
-
-#include <kglobal.h>
-#include <kconfiggroup.h>
-#include <KDebug>
-#include <KSharedConfig>
-#include <KSharedPtr>
-
-#include "tag.h"
-
-Scrobbler::Scrobbler(QObject* parent)
- : QObject(parent)
- , m_networkAccessManager(0)
- , m_wallet(0)
-{
- QByteArray sessionKey;
-
- m_wallet = Scrobbler::openKWallet();
-
- if (m_wallet) {
-
- m_wallet->readEntry("SessionKey", sessionKey);
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- sessionKey.append(config.readEntry("SessionKey", ""));
- }
-
- if(sessionKey.isEmpty())
- getAuthToken();
-}
-
-Scrobbler::~Scrobbler()
-{
- delete m_wallet;
-}
-
-bool Scrobbler::isScrobblingEnabled()
-{
- QString username, password;
-
- if (KWallet::Wallet::folderDoesNotExist(KWallet::Wallet::LocalWallet(), "JuK")) {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
-
- username = config.readEntry("Username", "");
- password = config.readEntry("Password", "");
-
- } else {
-
- KWallet::Wallet* wallet = Scrobbler::openKWallet();
-
- if (wallet) {
-
- QMap<QString, QString> scrobblingCredentials;
- wallet->readMap("Scrobbling", scrobblingCredentials);
-
- if (scrobblingCredentials.contains("Username") && scrobblingCredentials.contains("Password")) {
-
- username = scrobblingCredentials["Username"];
- password = scrobblingCredentials["Password"];
- }
-
- delete wallet;
- }
- }
-
- return (!username.isEmpty() && !password.isEmpty());
-}
-
-KWallet::Wallet* Scrobbler::openKWallet() // static
-{
- const QString walletFolderName = "JuK";
-
- KWallet::Wallet* wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), 0);
-
- if (wallet) {
-
- if (!wallet->hasFolder(walletFolderName)) {
-
- if (!wallet->createFolder(walletFolderName)) {
-
- delete wallet;
- return 0;
- }
- }
-
- if (!wallet->setFolder(walletFolderName)) {
-
- delete wallet;
- return 0;
- }
- }
-
- return wallet;
-}
-
-QByteArray Scrobbler::md5(QByteArray data)
-{
- return QCryptographicHash::hash(data, QCryptographicHash::Md5)
- .toHex().rightJustified(32, '0').toLower();
-}
-
-void Scrobbler::sign(QMap< QString, QString >& params)
-{
- params["api_key"] = "3e6ecbd7284883089e8f2b5b53b0aecd";
-
- QString s;
- QMapIterator<QString, QString> i(params);
-
- while(i.hasNext()) {
- i.next();
- s += i.key() + i.value();
- }
-
- s += "2cab3957b1f70d485e9815ac1ac94096"; //shared secret
-
- params["api_sig"] = md5(s.toUtf8());
-}
-
-void Scrobbler::getAuthToken(QString username, QString password)
-{
- kDebug() << "Getting new auth token for user:" << username;
-
- QByteArray authToken = md5((username + md5(password.toUtf8())).toUtf8());
-
- QMap<QString, QString> params;
- params["method"] = "auth.getMobileSession";
- params["authToken"] = authToken;
- params["username"] = username;
-
- QUrl url("http://ws.audioscrobbler.com/2.0/?");
-
- sign(params);
-
- foreach(QString key, params.keys()) {
- url.addQueryItem(key, params[key]);
- }
-
- if (!m_networkAccessManager)
- m_networkAccessManager = new QNetworkAccessManager(this);
-
- QNetworkReply *reply = m_networkAccessManager->get(QNetworkRequest(url));
- connect(reply, SIGNAL(finished()), this, SLOT(handleAuthenticationReply()));
-}
-
-void Scrobbler::getAuthToken()
-{
- QString username, password;
-
- if (m_wallet) {
-
- QMap<QString, QString> scrobblingCredentials;
- m_wallet->readMap("Scrobbling", scrobblingCredentials);
-
- if (scrobblingCredentials.contains("Username") && scrobblingCredentials.contains("Password")) {
-
- username = scrobblingCredentials["Username"];
- password = scrobblingCredentials["Password"];
- }
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- username = config.readEntry("Username", "");
- password = config.readEntry("Password", "");
- }
-
- if(username.isEmpty() || password.isEmpty())
- return;
-
- getAuthToken(username, password);
-}
-
-void Scrobbler::handleAuthenticationReply()
-{
- QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
-
- kDebug() << "got authentication reply";
- if(reply->error() != QNetworkReply::NoError) {
- emit invalidAuth();
- kWarning() << "Error while getting authentication reply" << reply->errorString();
- return;
- }
-
- QDomDocument doc;
- QByteArray data = reply->readAll();
- doc.setContent(data);
-
- QString sessionKey = doc.documentElement()
- .firstChildElement("session")
- .firstChildElement("key").text();
-
- if(sessionKey.isEmpty()) {
- emit invalidAuth();
- kWarning() << "Unable to get session key" << data;
- return;
- }
-
- if (m_wallet) {
-
- m_wallet->writeEntry("SessionKey", sessionKey.toUtf8());
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- config.writeEntry("SessionKey", sessionKey);
- }
-
- emit validAuth();
-}
-
-void Scrobbler::nowPlaying(const FileHandle& file)
-{
- QString sessionKey;
-
- if (m_wallet) {
-
- QByteArray sessionKeyByteArray;
- m_wallet->readEntry("SessionKey", sessionKeyByteArray);
- sessionKey = QString::fromLatin1(sessionKeyByteArray);
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- sessionKey = config.readEntry("SessionKey", "");
- }
-
- if (!m_file.isNull()) {
- scrobble(); // Update time-played info for last track
- }
-
- QMap<QString, QString> params;
- params["method"] = "track.updateNowPlaying";
- params["sk"] = sessionKey;
- params["track"] = file.tag()->title();
- params["artist"] = file.tag()->artist();
- params["album"] = file.tag()->album();
- params["trackNumber"] = QString::number(file.tag()->track());
- params["duration"] = QString::number(file.tag()->seconds());
-
- sign(params);
- post(params);
-
- m_file = file; // May be FileHandle::null()
- m_playbackTimer = QDateTime::currentDateTime();
-}
-
-void Scrobbler::scrobble()
-{
- QString sessionKey;
-
- if (m_wallet) {
-
- QByteArray sessionKeyByteArray;
- m_wallet->readEntry("SessionKey", sessionKeyByteArray);
- sessionKey = QString::fromLatin1(sessionKeyByteArray);
-
- } else {
-
- KConfigGroup config(KGlobal::config(), "Scrobbling");
- sessionKey = config.readEntry("SessionKey", "");
- }
-
- if(sessionKey.isEmpty()) {
- getAuthToken();
- return;
- }
-
- int halfDuration = m_file.tag()->seconds() / 2;
- int timeElapsed = m_playbackTimer.secsTo(QDateTime::currentDateTime());
-
- if (timeElapsed < 30 || timeElapsed < halfDuration) {
- return; // API says not to scrobble if the user didn't play long enough
- }
-
- kDebug() << "Scrobbling" << m_file.tag()->title();
-
- QMap<QString, QString> params;
- params["method"] = "track.scrobble";
- params["sk"] = sessionKey;
- params["track"] = m_file.tag()->title();
- params["artist"] = m_file.tag()->artist();
- params["album"] = m_file.tag()->album();
- params["timestamp"] = QString::number(m_playbackTimer.toTime_t());
- params["trackNumber"] = QString::number(m_file.tag()->track());
- params["duration"] = QString::number(m_file.tag()->seconds());
-
- sign(params);
- post(params);
-}
-
-void Scrobbler::post(QMap<QString, QString> ¶ms)
-{
- if(!m_networkAccessManager) {
- return;
- }
-
- QUrl url("http://ws.audioscrobbler.com/2.0/");
-
- QByteArray data;
- foreach(QString key, params.keys()) {
- data += QUrl::toPercentEncoding(key) + '=' + QUrl::toPercentEncoding(params[key]) + '&';
- }
-
- QNetworkRequest req(url);
- req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
- QNetworkReply *reply = m_networkAccessManager->post(req, data);
- connect(reply, SIGNAL(finished()), this, SLOT(handleResults()));
-}
-
-void Scrobbler::handleResults()
-{
- QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
- QByteArray data = reply->readAll();
- if(data.contains("code=\"9\"")) // We need a new token
- getAuthToken();
-}
+++ /dev/null
-/**
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_SCROBBLER_H
-#define JUK_SCROBBLER_H
-
-#include <QObject>
-#include <QMap>
-#include <QDateTime>
-
-#include <KWallet/Wallet>
-
-#include "filehandle.h"
-
-class QByteArray;
-class QNetworkAccessManager;
-
-/**
- * A class that handles scrobbling of tracks to last.fm
- */
-class Scrobbler : public QObject {
- Q_OBJECT
-public:
- explicit Scrobbler(QObject* parent = 0);
- virtual ~Scrobbler();
-
- static bool isScrobblingEnabled();
- static KWallet::Wallet* openKWallet();
-
-public slots:
- void nowPlaying(const FileHandle&);
- void scrobble();
- void getAuthToken(QString username, QString password);
-
-private slots:
- void handleAuthenticationReply();
- void handleResults();
- void getAuthToken();
-
-signals:
- void invalidAuth();
- void validAuth();
-
-private:
- void sign(QMap<QString, QString> &request);
- void post(QMap<QString, QString> &request);
- QByteArray md5(QByteArray data);
-
- QDateTime m_playbackTimer;
- FileHandle m_file;
- QNetworkAccessManager *m_networkAccessManager;
-
- KWallet::Wallet *m_wallet;
-};
-
-#endif /* JUK_SCROBBLER_H */
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "searchplaylist.h"
-#include "juk-exception.h"
-
-#include <kdebug.h>
-
-#include <QHash>
-
-#include "playlistitem.h"
-#include "collectionlist.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-SearchPlaylist::SearchPlaylist(PlaylistCollection *collection,
- const PlaylistSearch &search,
- const QString &name,
- bool setupPlaylist,
- bool synchronizePlaying) :
- DynamicPlaylist(search.playlists(), collection, name, "edit-find",
- setupPlaylist, synchronizePlaying),
- m_search(search)
-{
-
-}
-
-void SearchPlaylist::setPlaylistSearch(const PlaylistSearch &s, bool update)
-{
- m_search = s;
- if(update)
- setPlaylists(s.playlists());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected methods
-////////////////////////////////////////////////////////////////////////////////
-
-void SearchPlaylist::updateItems()
-{
- // Here we don't simply use "clear" since that would involve a call to
- // items() which would in turn call this method...
-
- PlaylistItemList l = Playlist::items();
-
- QHash<CollectionListItem *, PlaylistItem *> oldItems;
- oldItems.reserve(503);
-
- foreach(PlaylistItem *item, l)
- oldItems.insert(item->collectionItem(), item);
-
- m_search.search();
- PlaylistItemList matched = m_search.matchedItems();
- PlaylistItemList newItems;
-
- foreach(PlaylistItem *item, matched) {
- if(oldItems.remove(item->collectionItem()) == 0)
- newItems.append(item->collectionItem());
- }
-
- clearItems(PlaylistItemList(oldItems.values()));
- createItems(newItems);
-
- if(synchronizePlaying()) {
- kDebug() << "synchronizing playing";
- synchronizePlayingItems(m_search.playlists(), true);
- }
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// helper functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const SearchPlaylist &p)
-{
- s << p.name()
- << p.playlistSearch();
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, SearchPlaylist &p)
-{
- QString name;
- PlaylistSearch search;
-
- s >> name
- >> search;
-
- if(name.isEmpty())
- throw BICStreamException();
-
- p.setName(name);
- p.setPlaylistSearch(search, false);
-
- return s;
-}
-
-#include "searchplaylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SEARCHPLAYLIST_H
-#define SEARCHPLAYLIST_H
-
-#include "dynamicplaylist.h"
-
-class SearchPlaylist : public DynamicPlaylist
-{
- Q_OBJECT
-public:
- explicit SearchPlaylist(PlaylistCollection *collection,
- const PlaylistSearch &search = PlaylistSearch(),
- const QString &name = QString(),
- bool setupPlaylist = true,
- bool synchronizePlaying = false);
-
- PlaylistSearch playlistSearch() const { return m_search; }
- void setPlaylistSearch(const PlaylistSearch &s, bool update = true);
- virtual bool searchIsEditable() const { return true; }
-
-protected:
- /**
- * Runs the search to update the current items.
- */
- virtual void updateItems();
-
-private:
- PlaylistSearch m_search;
-};
-
-QDataStream &operator<<(QDataStream &s, const SearchPlaylist &p);
-QDataStream &operator>>(QDataStream &s, SearchPlaylist &p);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Richard Lärkäng <nouseforaname@home.se>
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "searchwidget.h"
-#include "collectionlist.h"
-#include "actioncollection.h"
-#include "searchadaptor.h"
-
-#include <klocale.h>
-#include <klineedit.h>
-#include <kiconloader.h>
-#include <kcombobox.h>
-#include <kdebug.h>
-#include <kaction.h>
-
-#include <QLabel>
-#include <QCheckBox>
-#include <QPushButton>
-#include <QToolButton>
-#include <QKeyEvent>
-#include <QHBoxLayout>
-
-using namespace ActionCollection;
-
-////////////////////////////////////////////////////////////////////////////////
-// SearchLine public methods
-////////////////////////////////////////////////////////////////////////////////
-
-SearchLine::SearchLine(QWidget *parent, bool simple)
- : QFrame(parent),
- m_simple(simple),
- m_searchFieldsBox(0)
-{
- QHBoxLayout *layout = new QHBoxLayout(this);
- layout->setMargin(0);
- layout->setSpacing(5);
-
- if(!m_simple) {
- m_searchFieldsBox = new KComboBox(this);
- layout->addWidget(m_searchFieldsBox);
- m_searchFieldsBox->setObjectName( QLatin1String( "searchFields" ) );
- connect(m_searchFieldsBox, SIGNAL(activated(int)),
- this, SIGNAL(signalQueryChanged()));
- }
-
- m_lineEdit = new KLineEdit(this);
- layout->addWidget(m_lineEdit);
- m_lineEdit->setClearButtonShown(true);
- m_lineEdit->installEventFilter(this);
- connect(m_lineEdit, SIGNAL(textChanged(QString)),
- this, SIGNAL(signalQueryChanged()));
- connect(m_lineEdit, SIGNAL(returnPressed()),
- this, SLOT(slotActivate()));
-
- if(!m_simple) {
- m_caseSensitive = new KComboBox(this);
- layout->addWidget(m_caseSensitive);
- m_caseSensitive->addItem(i18n("Normal Matching"));
- m_caseSensitive->addItem(i18n("Case Sensitive"));
- m_caseSensitive->addItem(i18n("Pattern Matching"));
- connect(m_caseSensitive, SIGNAL(activated(int)),
- this, SIGNAL(signalQueryChanged()));
- }
- else
- m_caseSensitive = 0;
-
- updateColumns();
-}
-
-PlaylistSearch::Component SearchLine::searchComponent() const
-{
- QString query = m_lineEdit->text();
- bool caseSensitive = m_caseSensitive && m_caseSensitive->currentIndex() == CaseSensitive;
-
- Playlist *playlist = CollectionList::instance();
-
- QList<int> searchedColumns;
-
- if(!m_searchFieldsBox || m_searchFieldsBox->currentIndex() == 0) {
- foreach(int column, m_columnList) {
- if(playlist->isColumnVisible(column))
- searchedColumns.append(column);
- }
- }
- else
- searchedColumns.append(m_columnList[m_searchFieldsBox->currentIndex() - 1]);
-
- if(m_caseSensitive && m_caseSensitive->currentIndex() == Pattern)
- return PlaylistSearch::Component(QRegExp(query), searchedColumns);
- else
- return PlaylistSearch::Component(query, caseSensitive, searchedColumns);
-}
-
-void SearchLine::setSearchComponent(const PlaylistSearch::Component &component)
-{
- if(component == searchComponent())
- return;
-
- if(m_simple || !component.isPatternSearch()) {
- m_lineEdit->setText(component.query());
- if(m_caseSensitive)
- m_caseSensitive->setCurrentIndex(component.isCaseSensitive() ? CaseSensitive : Default);
- }
- else {
- m_lineEdit->setText(component.pattern().pattern());
- if(m_caseSensitive)
- m_caseSensitive->setCurrentIndex(Pattern);
- }
-
- if(!m_simple) {
- if(component.columns().isEmpty() || component.columns().size() > 1)
- m_searchFieldsBox->setCurrentIndex(0);
- else
- m_searchFieldsBox->setCurrentIndex(component.columns().front() + 1);
- }
-}
-
-void SearchLine::clear()
-{
- // We don't want to emit the signal if it's already empty.
- if(!m_lineEdit->text().isEmpty())
- m_lineEdit->clear();
-}
-
-void SearchLine::setFocus()
-{
- m_lineEdit->setFocus();
-}
-
-bool SearchLine::eventFilter(QObject *watched, QEvent *e)
-{
- if(watched != m_lineEdit || e->type() != QEvent::KeyPress)
- return QFrame::eventFilter(watched, e);
-
- QKeyEvent *key = static_cast<QKeyEvent *>(e);
- if(key->key() == Qt::Key_Down)
- emit signalDownPressed();
-
- return QFrame::eventFilter(watched, e);
-}
-
-void SearchLine::slotActivate()
-{
- action("stop")->trigger();
- action("playFirst")->trigger();
-}
-
-void SearchLine::updateColumns()
-{
- QString currentText;
-
- if(m_searchFieldsBox) {
- currentText = m_searchFieldsBox->currentText();
- m_searchFieldsBox->clear();
- }
-
- QStringList columnHeaders;
-
- columnHeaders.append(QString("<%1>").arg(i18n("All Visible")));
-
- Playlist *playlist = CollectionList::instance();
-
- int selection = -1;
- m_columnList.clear();
-
- for(int i = 0; i < playlist->columns(); i++) {
- m_columnList.append(i);
- QString text = playlist->columnText(i);
- columnHeaders.append(text);
- if(currentText == text)
- selection = m_columnList.size() - 1;
- }
-
- if(m_searchFieldsBox) {
- m_searchFieldsBox->addItems(columnHeaders);
- m_searchFieldsBox->setCurrentIndex(selection + 1);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SearchWidget public methods
-////////////////////////////////////////////////////////////////////////////////
-
-SearchWidget::SearchWidget(QWidget *parent)
- : KToolBar(parent),
- m_searchLine(this, true)
-{
- new SearchAdaptor(this);
- QDBusConnection::sessionBus().registerObject("/Search", this);
-
- QLabel *label = new QLabel(i18n("Search:"), this );
- label->setBuddy(&m_searchLine);
- addWidget(label);
- addWidget(&m_searchLine);
-
- connect(&m_searchLine, SIGNAL(signalQueryChanged()), this, SIGNAL(signalQueryChanged()));
- connect(&m_searchLine, SIGNAL(signalDownPressed()), this, SIGNAL(signalDownPressed()));
- connect(m_searchLine.m_lineEdit, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()));
-
- // I've decided that I think this is ugly, for now.
- /*
- QToolButton *b = new QToolButton(this);
- b->setTextLabel(i18n("Advanced Search"), true);
- b->setIconSet(SmallIconSet("wizard"));
-
- connect(b, SIGNAL(clicked()), this, SIGNAL(signalAdvancedSearchClicked()));
- */
- updateColumns();
-}
-
-void SearchWidget::setSearch(const PlaylistSearch &search)
-{
- PlaylistSearch::ComponentList components = search.components();
-
- if(components.isEmpty()) {
- clear();
- return;
- }
-
- m_searchLine.setSearchComponent(*components.begin());
-}
-
-QString SearchWidget::searchText() const
-{
- return m_searchLine.searchComponent().query();
-}
-
-void SearchWidget::setSearchText(const QString &text)
-{
- m_searchLine.setSearchComponent(PlaylistSearch::Component(text));
-}
-
-PlaylistSearch SearchWidget::search(const PlaylistList &playlists) const
-{
- PlaylistSearch::ComponentList components;
- components.append(m_searchLine.searchComponent());
- return PlaylistSearch(playlists, components);
-}
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// SearchWidget public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void SearchWidget::clear()
-{
- m_searchLine.clear();
-}
-
-void SearchWidget::setEnabled(bool enable)
-{
- emit signalShown(enable);
- setVisible(enable);
-}
-
-void SearchWidget::setFocus()
-{
- m_searchLine.setFocus();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SearchWidget private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void SearchWidget::updateColumns()
-{
- m_searchLine.updateColumns();
-}
-
-#include "searchwidget.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Richard Lärkäng <nouseforaname@home.se>
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SEARCHWIDGET_H
-#define SEARCHWIDGET_H
-
-#include <ktoolbar.h>
-
-#include <QtGui/QFrame>
-#include <QList>
-
-#include "playlistsearch.h"
-
-class QEvent;
-
-class KComboBox;
-class KLineEdit;
-class SearchWidget;
-
-class SearchLine : public QFrame
-{
- Q_OBJECT
-
- friend class SearchWidget;
-
-public:
- enum Mode { Default = 0, CaseSensitive = 1, Pattern = 2 };
-
- explicit SearchLine(QWidget *parent, bool simple = false);
-
- PlaylistSearch::Component searchComponent() const;
- void setSearchComponent(const PlaylistSearch::Component &component);
-
- void updateColumns();
-
-public slots:
- void clear();
- virtual void setFocus();
-
-protected:
- virtual bool eventFilter(QObject *watched, QEvent *e);
-
-signals:
- void signalQueryChanged();
- void signalDownPressed();
-
-private slots:
- void slotActivate();
-
-private:
- bool m_simple;
- KLineEdit *m_lineEdit;
- KComboBox *m_searchFieldsBox;
- KComboBox *m_caseSensitive;
- QList<int> m_columnList;
-};
-
-class SearchWidget : public KToolBar
-{
- Q_OBJECT
-
-public:
- explicit SearchWidget(QWidget *parent);
-
- PlaylistSearch search(const PlaylistList &playlists) const;
- void setSearch(const PlaylistSearch &search);
-
- virtual QString searchText() const;
- virtual void setSearchText(const QString &text);
-
-public slots:
- void clear();
- void setEnabled(bool enable);
- virtual void setFocus();
-
-signals:
- void signalQueryChanged();
- void signalAdvancedSearchClicked();
- void returnPressed();
-
- // This signal is only emitted when the Show/Hide action is triggered.
- // Minimizing/closing the JuK window will not trigger this signal.
-
- void signalShown(bool shown);
-
- void signalDownPressed();
-
-private:
- void updateColumns();
-
-private:
- SearchLine m_searchLine;
- QStringList m_columnHeaders;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (c) 2003-2009 Mark Kretschmann <kretschmann@kde.org>
- * Copyright (c) 2005 Gabor Lehel <illissius@gmail.com>
- * Copyright (c) 2008 Dan Meltzer <parallelgrapefruit@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "slider.h"
-#include "svghandler.h"
-
-#include <KIcon>
-#include <KLocale>
-#include <KStandardDirs>
-#include <KGlobalSettings>
-
-#include <QAction>
-#include <QContextMenuEvent>
-#include <QFontMetrics>
-#include <QMenu>
-#include <QPainter>
-#include <QStyle>
-#include <QStyleOptionSlider>
-
-Slider::Slider( Qt::Orientation orientation, uint max, QWidget *parent )
- : QSlider( orientation, parent )
- , m_sliding( false )
- , m_outside( false )
- , m_prevValue( 0 )
- , m_needsResize( true )
-{
- setMouseTracking( true );
- setRange( 0, max );
- setAttribute( Qt::WA_NoMousePropagation, true );
- setAttribute( Qt::WA_Hover, true );
- if ( orientation == Qt::Vertical )
- {
- setInvertedAppearance( true );
- setInvertedControls( true );
- }
-}
-
-QRect
-Slider::sliderHandleRect( const QRect &slider, qreal percent ) const
-{
- QRect rect;
- const bool inverse = ( orientation() == Qt::Horizontal ) ?
- ( invertedAppearance() != (layoutDirection() == Qt::RightToLeft) ) :
- ( !invertedAppearance() );
-
- if(m_usingCustomStyle)
- rect = The::svgHandler()->sliderKnobRect( slider, percent, inverse );
- else
- {
- if ( inverse )
- percent = 1.0 - percent;
- const int handleSize = style()->pixelMetric( QStyle::PM_SliderControlThickness );
- rect = QRect( 0, 0, handleSize, handleSize );
- rect.moveTo( slider.x() + qRound( ( slider.width() - handleSize ) * percent ), slider.y() + 1 );
- }
-
- return rect;
-}
-
-void
-Slider::wheelEvent( QWheelEvent *e )
-{
- if( orientation() == Qt::Vertical )
- {
- // Will be handled by the parent widget
- e->ignore();
- return;
- }
-
- // Position Slider (horizontal)
- // only used for progress slider now!
- int step = e->delta() * 24;
- int nval = value() + step;
- nval = qMax(nval, minimum());
- nval = qMin(nval, maximum());
-
- QSlider::setValue( nval );
-
- emit sliderReleased( value() );
-}
-
-void
-Slider::mouseMoveEvent( QMouseEvent *e )
-{
- if ( m_sliding )
- {
- //feels better, but using set value of 20 is bad of course
- QRect rect( -20, -20, width()+40, height()+40 );
-
- if ( orientation() == Qt::Horizontal && !rect.contains( e->pos() ) )
- {
- if ( !m_outside )
- {
- QSlider::setValue( m_prevValue );
- //if mouse released outside of slider, emit sliderMoved to previous value
- emit sliderMoved( m_prevValue );
- }
- m_outside = true;
- }
- else
- {
- m_outside = false;
- slideEvent( e );
- emit sliderMoved( value() );
- }
- }
- else
- QSlider::mouseMoveEvent( e );
-}
-
-void
-Slider::slideEvent( QMouseEvent *e )
-{
- QRect knob;
- if ( maximum() > minimum() )
- knob = sliderHandleRect( rect(), ((qreal)value()) / ( maximum() - minimum() ) );
-
- int position;
- int span;
-
- if( orientation() == Qt::Horizontal )
- {
- position = e->pos().x() - knob.width() / 2;
- span = width() - knob.width();
- }
- else
- {
- position = e->pos().y() - knob.height() / 2;
- span = height() - knob.height();
- }
-
- const bool inverse = ( orientation() == Qt::Horizontal ) ?
- ( invertedAppearance() != (layoutDirection() == Qt::RightToLeft) ) :
- ( !invertedAppearance() );
- const int val = QStyle::sliderValueFromPosition( minimum(), maximum(), position, span, inverse );
- QSlider::setValue( val );
-}
-
-void
-Slider::mousePressEvent( QMouseEvent *e )
-{
- m_sliding = true;
- m_prevValue = value();
-
- QRect knob;
- if ( maximum() > minimum() )
- knob = sliderHandleRect( rect(), ((qreal)value()) / ( maximum() - minimum() ) );
- if ( !knob.contains( e->pos() ) )
- mouseMoveEvent( e );
-}
-
-void
-Slider::mouseReleaseEvent( QMouseEvent* )
-{
- if( !m_outside && value() != m_prevValue )
- emit sliderReleased( value() );
-
- m_sliding = false;
- m_outside = false;
-}
-
-void
-Slider::setValue( int newValue )
-{
- //don't adjust the slider while the user is dragging it!
- if ( !m_sliding || m_outside )
- QSlider::setValue( newValue );
- else
- m_prevValue = newValue;
-}
-
-void Slider::paintCustomSlider( QPainter *p )
-{
- qreal percent = 0.0;
- if ( maximum() > minimum() )
- percent = ((qreal)value()) / ( maximum() - minimum() );
- QStyleOptionSlider opt;
- initStyleOption( &opt );
- if ( m_sliding ||
- ( underMouse() && sliderHandleRect( rect(), percent ).contains( mapFromGlobal(QCursor::pos()) ) ) )
- {
- opt.activeSubControls |= QStyle::SC_SliderHandle;
- }
- The::svgHandler()->paintCustomSlider( p, &opt, percent );
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-/// CLASS VolumeSlider
-//////////////////////////////////////////////////////////////////////////////////////////
-
-VolumeSlider::VolumeSlider( uint max, QWidget *parent, bool customStyle )
- : Slider( customStyle ? Qt::Horizontal : Qt::Vertical, max, parent )
-{
- m_usingCustomStyle = customStyle;
- setFocusPolicy( Qt::NoFocus );
- setInvertedAppearance( false );
- setInvertedControls( false );
- connect( this, SIGNAL(sliderMoved(int)),
- this, SLOT(emitVolumeChanged(int)) );
-
- connect( this, SIGNAL(sliderReleased(int)),
- this, SLOT(emitVolumeChanged(int)) );
-}
-
-void
-VolumeSlider::mousePressEvent( QMouseEvent *e )
-{
- if( e->button() != Qt::RightButton )
- {
- Slider::mousePressEvent( e );
- slideEvent( e );
- }
-}
-
-void
-VolumeSlider::contextMenuEvent( QContextMenuEvent *e )
-{
- QMenu menu;
- menu.setTitle( i18n( "Volume" ) );
- menu.addAction( i18n( "100%" ) )->setData( 100 );
- menu.addAction( i18n( "80%" ) )->setData( 80 );
- menu.addAction( i18n( "60%" ) )->setData( 60 );
- menu.addAction( i18n( "40%" ) )->setData( 40 );
- menu.addAction( i18n( "20%" ) )->setData( 20 );
- menu.addAction( i18n( "0%" ) )->setData( 0 );
-
- QAction* a = menu.exec( mapToGlobal( e->pos() ) );
- if( a )
- {
- const int n = a->data().toInt();
- if( n >= 0 )
- {
- QSlider::setValue( n );
- emit volumeChanged( float( n ) / float( maximum() ) );
- }
- }
-}
-
-void
-VolumeSlider::wheelEvent( QWheelEvent *e )
-{
- static const int volumeSensitivity = 30;
- const uint step = e->delta() / volumeSensitivity;
- QSlider::setValue( QSlider::value() + step );
-
- emit volumeChanged( float( value() ) / float( maximum() ) );
-}
-
-void
-VolumeSlider::paintEvent( QPaintEvent *event )
-{
- if( m_usingCustomStyle )
- {
- QPainter p( this );
- paintCustomSlider( &p );
- p.end();
- return;
- }
-
- QSlider::paintEvent( event );
-}
-
-void
-VolumeSlider::emitVolumeChanged( int value )
-{
- emit volumeChanged( float( value ) / float( maximum() ) );
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////// TIMESLIDER ////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////
-
-TimeSlider::TimeSlider( QWidget *parent )
- : Slider( Qt::Horizontal, 0, parent )
- , m_knobX( 0.0 )
-{
- m_usingCustomStyle = true;
- setFocusPolicy( Qt::NoFocus );
-}
-
-void
-TimeSlider::setSliderValue( int value )
-{
- Slider::setValue( value );
-}
-
-void
-TimeSlider::paintEvent( QPaintEvent *pe )
-{
- QPainter p( this );
- p.setClipRegion( pe->region() );
- paintCustomSlider( &p );
- p.end();
-
-}
-
-void TimeSlider::sliderChange( SliderChange change )
-{
- if ( change == SliderValueChange || change == SliderRangeChange )
- {
- int oldKnobX = m_knobX;
- qreal percent = 0.0;
- if ( maximum() > minimum() )
- percent = ((qreal)value()) / ( maximum() - minimum() );
- QRect knob = sliderHandleRect( rect(), percent );
- m_knobX = knob.x();
-
- if (oldKnobX < m_knobX)
- update( oldKnobX, knob.y(), knob.right() + 1 - oldKnobX, knob.height() );
- else if (oldKnobX > m_knobX)
- update( m_knobX, knob.y(), oldKnobX + knob.width(), knob.height() );
- }
- else
- Slider::sliderChange( change ); // calls update()
-}
-
-void TimeSlider::mousePressEvent( QMouseEvent *event )
-{
- // We should probably eat this event if we're not able to seek
- Slider::mousePressEvent( event );
-}
-
-#include "slider.moc"
+++ /dev/null
-/**
- * Copyright (c) 2003-2009 Mark Kretschmann <kretschmann@kde.org>
- * Copyright (c) 2005 Gabor Lehel <illissius@gmail.com>
- * Copyright (c) 2008 Dan Meltzer <parallelgrapefruit@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SLIDERWIDGET_H
-#define SLIDERWIDGET_H
-
-#include <QList>
-#include <QPixmap>
-#include <QSlider>
-#include <QVector>
-
-class QPalette;
-class QTimer;
-
-class Slider : public QSlider
-{
- Q_OBJECT
-
- public:
- explicit Slider( Qt::Orientation, uint max = 0, QWidget* parent = 0 );
-
- virtual void setValue( int );
-
-signals:
- //we emit this when the user has specifically changed the slider
- //so connect to it if valueChanged() is too generic
- //Qt also emits valueChanged( int )
- void sliderReleased( int );
-
-protected:
- virtual void wheelEvent( QWheelEvent* );
- virtual void mouseMoveEvent( QMouseEvent* );
- virtual void mouseReleaseEvent( QMouseEvent* );
- virtual void mousePressEvent( QMouseEvent* );
- virtual void slideEvent( QMouseEvent* );
- QRect sliderHandleRect( const QRect &slider, qreal percent ) const;
-
- void paintCustomSlider( QPainter *p );
-
- bool m_sliding;
- bool m_usingCustomStyle;
-
- static const int s_borderWidth = 6;
- static const int s_borderHeight = 6;
-
- static const int s_sliderInsertX = 5;
- static const int s_sliderInsertY = 5;
-
-private:
- bool m_outside;
- int m_prevValue;
- bool m_needsResize;
- QPixmap m_topLeft;
- QPixmap m_topRight;
- QPixmap m_top;
- QPixmap m_bottomRight;
- QPixmap m_right;
- QPixmap m_bottomLeft;
- QPixmap m_bottom;
- QPixmap m_left;
-
- Q_DISABLE_COPY( Slider )
-};
-
-class VolumeSlider : public Slider
-{
- Q_OBJECT
-
- public:
- explicit VolumeSlider( uint max, QWidget *parent, bool customStyle = true );
-
- // VolumePopupButton needs to access this
- virtual void wheelEvent( QWheelEvent *e );
-
-protected:
- virtual void paintEvent( QPaintEvent* );
- virtual void mousePressEvent( QMouseEvent* );
- virtual void contextMenuEvent( QContextMenuEvent* );
-
-signals:
- void volumeChanged( float );
-private slots:
- void emitVolumeChanged( int );
-
-private:
- Q_DISABLE_COPY( VolumeSlider )
-};
-
-class TimeSlider : public Slider
-{
- Q_OBJECT
-
-public:
- TimeSlider( QWidget *parent );
-
- void setSliderValue( int value );
-protected:
- virtual void paintEvent( QPaintEvent* );
- virtual void mousePressEvent( QMouseEvent* );
- virtual void sliderChange( SliderChange change );
-
-private:
- Q_DISABLE_COPY( TimeSlider )
-
- int m_knobX; // The position of the current indicator.
-};
-
-#endif
-
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "slideraction.h"
-
-#include <ktoolbar.h>
-#include <klocale.h>
-#include <kiconloader.h>
-#include <kactioncollection.h>
-#include <kdebug.h>
-
-#include <QMouseEvent>
-#include <QWheelEvent>
-#include <QFocusEvent>
-#include <QBoxLayout>
-
-#include "volumepopupbutton.h"
-#include "slider.h"
-#include "playermanager.h"
-#include "juk.h"
-
-TrackPositionAction::TrackPositionAction(const QString &text, QObject *parent) :
- KAction(text, parent)
-{
-
-}
-
-Slider *TrackPositionAction::slider() const
-{
- return parent()->findChild<Slider *>("timeSlider");
-}
-
-QWidget *TrackPositionAction::createWidget(QWidget *parent)
-{
- Slider *slider = new TimeSlider(parent);
- slider->setObjectName(QLatin1String("timeSlider"));
-
- PlayerManager *player = JuK::JuKInstance()->playerManager();
-
- connect(player, SIGNAL(tick(int)), slider, SLOT(setValue(int)));
- connect(player, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
- connect(player, SIGNAL(totalTimeChanged(int)), this, SLOT(totalTimeChanged(int)));
- connect(slider, SIGNAL(sliderMoved(int)), player, SLOT(seek(int)));
-
- return slider;
-}
-
-void TrackPositionAction::seekableChanged(bool seekable)
-{
- slider()->setEnabled(seekable);
- slider()->setToolTip(seekable ?
- QString() :
- i18n("Seeking is not supported in this file with your audio settings."));
-}
-
-void TrackPositionAction::totalTimeChanged(int ms)
-{
- slider()->setRange(0, ms);
-}
-
-VolumeAction::VolumeAction(const QString &text, QObject *parent) :
- KAction(text, parent),
- m_button(0)
-{
-
-}
-
-QWidget *VolumeAction::createWidget(QWidget *parent)
-{
- m_button = new VolumePopupButton(parent);
- return m_button;
-}
-
-#include "slideraction.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SLIDERACTION_H
-#define SLIDERACTION_H
-
-#include <kaction.h>
-#include <QBoxLayout>
-
-#include "volumepopupbutton.h"
-
-class Slider;
-
-class TrackPositionAction : public KAction
-{
- Q_OBJECT
-public:
- TrackPositionAction(const QString &text, QObject *parent);
- Slider *slider() const;
-protected:
- virtual QWidget *createWidget(QWidget *parent);
-private slots:
- void seekableChanged(bool seekable);
- void totalTimeChanged(int ms);
-};
-
-class VolumeAction : public KAction
-{
- Q_OBJECT
-public:
- VolumeAction(const QString &text, QObject *parent);
- VolumePopupButton *button() const { return m_button; }
-protected:
- virtual QWidget *createWidget(QWidget *parent);
-private:
- VolumePopupButton *m_button;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "sortedstringlist.h"
-
-#include <kdebug.h>
-
-class SortedStringList::Node
-{
-public:
- Node(const QString &value) : key(value), parent(0), left(0), right(0) {}
- ~Node() {}
-
- QString key;
- Node *parent;
- Node *left;
- Node *right;
-};
-
-SortedStringList::SortedStringList() : m_root(0)
-{
-
-}
-
-SortedStringList::~SortedStringList()
-{
-
-}
-
-bool SortedStringList::insert(const QString &value)
-{
- return BSTInsert(value);
-}
-
-bool SortedStringList::contains(const QString &value) const
-{
- return find(value);
-}
-
-SortedStringList::Node *SortedStringList::treeMinimum(Node *n) const
-{
- while(n->left)
- n = n->left;
- return n;
-}
-
-SortedStringList::Node *SortedStringList::treeSuccessor(Node *n) const
-{
- if(n->right)
- return treeMinimum(n->right);
-
- Node *p = n->parent;
-
- while(p && n == p->right) {
- n = p;
- p = p->parent;
- }
-
- return p;
-}
-
-bool SortedStringList::remove(const QString &value)
-{
- Node *n = find(value);
-
- if(!n)
- return false;
-
- Node *y;
- Node *x;
-
- if(!n->left || !n->right)
- y = n;
- else
- y = treeSuccessor(n);
-
- if(y->left)
- x = y->left;
- else
- x = y->right;
-
- if(x)
- x->parent = y->parent;
-
- if(!y->parent)
- m_root = x;
- else {
- if(y == y->parent->left)
- y->parent->left = x;
- else
- y->parent->right = x;
- }
-
- if(y != x)
- n->key = y->key;
-
- delete y;
-
- return true;
-}
-
-QStringList SortedStringList::values() const
-{
- QStringList l;
- traverse(m_root, l);
- return l;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-SortedStringList::Node *SortedStringList::find(const QString &value) const
-{
- Node *n = m_root;
- while(n && value != n->key) {
- if(value < n->key)
- n = n->left;
- else
- n = n->right;
- }
-
- return n;
-}
-
-bool SortedStringList::BSTInsert(const QString &value)
-{
- Node *previousNode = 0;
- Node *node = m_root;
-
- while(node) {
- previousNode = node;
- if(value == node->key)
- return true;
- else if(value < node->key)
- node = node->left;
- else
- node = node->right;
- }
-
- Node *n = new Node(value);
-
- n->parent = previousNode;
-
- if(!m_root)
- m_root = n;
- else {
- if(value < previousNode->key)
- previousNode->left = n;
- else
- previousNode->right = n;
- }
-
- return false;
-}
-
-void SortedStringList::traverse(const Node *n, QStringList &list) const
-{
- if(!n)
- return;
-
- traverse(n->left, list);
- list.append(n->key);
- traverse(n->right, list);
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SORTEDSTRINGLIST_H
-#define SORTEDSTRINGLIST_H
-
-#include <qstringlist.h>
-
-class SortedStringList
-{
-public:
- SortedStringList();
- ~SortedStringList();
-
- /**
- * Insert the value. Returns true if the item was already in the list
- * or false otherwise.
- */
- bool insert(const QString &value);
- bool contains(const QString &value) const;
- bool remove(const QString &value);
-
- /**
- * Returns a sorted list of the values.
- * Warning, this method is expensive and shouldn't be used except when
- * necessary.
- */
- QStringList values() const;
-
-private:
- class Node;
-
- Node *find(const QString &value) const;
- /**
- * The insertion implementation. Returns true if the item was already
- * present in the list.
- */
- bool BSTInsert(const QString &value);
- void traverse(const Node *n, QStringList &list) const;
-
- Node *treeMinimum(Node *n) const;
- Node *treeSuccessor(Node *n) const;
-
- Node *m_root;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "splashscreen.h"
-
-#include <kapplication.h>
-#include <kiconloader.h>
-#include <klocale.h>
-#include <kstandarddirs.h>
-#include <kdebug.h>
-
-#include <QPixmap>
-#include <QLabel>
-#include <QPalette>
-
-SplashScreen *SplashScreen::splash = 0;
-bool SplashScreen::done = false;
-int SplashScreen::count = 0;
-
-static QString loadedText(int i)
-{
- return i18nc("%1 is a count of loaded music tracks", "Loading: %1", i);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// pubic members
-////////////////////////////////////////////////////////////////////////////////
-
-SplashScreen *SplashScreen::instance()
-{
- if(!splash && !done)
- splash = new SplashScreen();
- return splash;
-}
-
-void SplashScreen::finishedLoading()
-{
- done = true;
- delete splash;
- splash = 0;
-}
-
-void SplashScreen::increment()
-{
- if(splash) {
- count++;
- if(( count & 63 ) == 0)
- splash->processEvents();
- }
-}
-
-void SplashScreen::update()
-{
- if(splash)
- splash->processEvents();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
-SplashScreen::SplashScreen() : QLabel(0, Qt::WStyle_Splash)
-{
- setObjectName( QLatin1String("splashScreen" ));
-
- QPixmap background = UserIcon("splash");
- resize(background.size());
- QPalette palette;
- palette.setBrush(backgroundRole(), QBrush(background));
-
- setMargin(7);
- setAlignment(Qt::AlignLeft | Qt::AlignBottom);
-
- palette.setColor(foregroundRole(), QColor(107, 158, 194));
- setPalette(palette);
-
- QFont f = font();
- f.setPixelSize(10);
- setFont(f);
-
- setText(loadedText(0));
-}
-
-SplashScreen::~SplashScreen()
-{
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void SplashScreen::processEvents()
-{
- setText(loadedText(count));
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SPLASHSCREEN_H
-#define SPLASHSCREEN_H
-
-#include <QLabel>
-
-/**
- * Well, all of this session restoration sure is fun, but it's starting to take
- * a while, especially say, if you're building KDE and indexing your file system
- * in the background. ;-) So, despite my general hate of splashscreens I
- * thought on appropriate here.
- *
- * As in other places, this is a singleton. That makes it relatively easy to
- * handle the updates from whichever class seems appropriate through static
- * methods.
- */
-
-class SplashScreen : public QLabel
-{
-public:
- static SplashScreen *instance();
- static void finishedLoading();
- static void increment();
- static void update();
-
-protected:
- SplashScreen();
- virtual ~SplashScreen();
-
-private:
- void processEvents();
-
- static SplashScreen *splash;
- static bool done;
- static int count;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "statuslabel.h"
-
-#include <kaction.h>
-#include <kpushbutton.h>
-#include <kiconloader.h>
-#include <ksqueezedtextlabel.h>
-#include <klocale.h>
-#include <kdebug.h>
-
-#include <QMouseEvent>
-#include <QLabel>
-#include <QFrame>
-#include <QHBoxLayout>
-#include <QEvent>
-
-#include "filehandle.h"
-#include "playlistinterface.h"
-#include "actioncollection.h"
-#include "tag.h"
-
-using namespace ActionCollection;
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-StatusLabel::StatusLabel(PlaylistInterface *playlist, QWidget *parent) :
- KHBox(parent),
- PlaylistObserver(playlist),
- m_showTimeRemaining(false)
-{
- QFrame *trackAndPlaylist = new QFrame(this);
- trackAndPlaylist->setFrameStyle(Box | Sunken);
- trackAndPlaylist->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
- // Make sure that we have enough of a margin to suffice for the borders,
- // hence the "lineWidth() * 2"
- QHBoxLayout *trackAndPlaylistLayout = new QHBoxLayout( trackAndPlaylist );
- trackAndPlaylistLayout->setMargin( trackAndPlaylist->lineWidth() * 2 );
- trackAndPlaylistLayout->setSpacing( 5 );
- trackAndPlaylistLayout->setObjectName( QLatin1String( "trackAndPlaylistLayout" ));
- trackAndPlaylistLayout->addSpacing(5);
-
- m_playlistLabel = new KSqueezedTextLabel(trackAndPlaylist);
- trackAndPlaylistLayout->addWidget(m_playlistLabel);
- m_playlistLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- m_playlistLabel->setTextFormat(Qt::PlainText);
- m_playlistLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
-
- m_trackLabel = new KSqueezedTextLabel(trackAndPlaylist);
- trackAndPlaylistLayout->addWidget(m_trackLabel);
- m_trackLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
- m_trackLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- m_trackLabel->setTextFormat(Qt::PlainText);
-
- trackAndPlaylistLayout->addSpacing(5);
-
- m_itemTimeLabel = new QLabel(this);
- QFontMetrics fontMetrics(font());
- m_itemTimeLabel->setAlignment(Qt::AlignCenter);
- m_itemTimeLabel->setMinimumWidth(fontMetrics.boundingRect("000:00 / 000:00").width());
- m_itemTimeLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
- m_itemTimeLabel->setFrameStyle(Box | Sunken);
- m_itemTimeLabel->installEventFilter(this);
-
- setItemTotalTime(0);
- setItemCurrentTime(0);
-
- KHBox *jumpBox = new KHBox(this);
- jumpBox->setFrameStyle(Box | Sunken);
- jumpBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
-
- QPushButton *jumpButton = new QPushButton(jumpBox);
- jumpButton->setIcon(SmallIcon("go-up"));
- jumpButton->setFlat(true);
-
- jumpButton->setToolTip( i18n("Jump to the currently playing item"));
- connect(jumpButton, SIGNAL(clicked()), action("showPlaying"), SLOT(trigger()));
-
- installEventFilter(this);
-
- updateData();
-}
-
-StatusLabel::~StatusLabel()
-{
-
-}
-
-void StatusLabel::updateCurrent()
-{
- if(playlist()->playing()) {
- FileHandle file = playlist()->currentFile();
-
- QString mid = file.tag()->artist().isEmpty() || file.tag()->title().isEmpty()
- ? QString::null : QString(" - "); //krazy:exclude=nullstrassign for old broken gcc
-
- QString text = file.tag()->artist() + mid + file.tag()->title();
-
- m_trackLabel->setText(text);
- m_playlistLabel->setText(playlist()->name().simplified());
- }
-}
-
-void StatusLabel::updateData()
-{
- updateCurrent();
-
- if(!playlist()->playing()) {
- setItemTotalTime(0);
- setItemCurrentTime(0);
-
- int time = playlist()->time();
-
- int days = time / (60 * 60 * 24);
- int hours = time / (60 * 60) % 24;
- int minutes = time / 60 % 60;
- int seconds = time % 60;
-
- QString timeString;
-
- if(days > 0) {
- timeString = i18np("1 day", "%1 days", days);
- timeString.append(" ");
- }
-
- if(days > 0 || hours > 0)
- timeString.append(QString().sprintf("%1d:%02d:%02d", hours, minutes, seconds));
- else
- timeString.append(QString().sprintf("%1d:%02d", minutes, seconds));
-
- m_playlistLabel->setText(playlist()->name());
- m_trackLabel->setText(i18np("1 item", "%1 items", playlist()->count()) + " - " + timeString);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-void StatusLabel::updateTime()
-{
- int minutes;
- int seconds;
-
- if(m_showTimeRemaining) {
- minutes = int((m_itemTotalTime - m_itemCurrentTime) / 60);
- seconds = (m_itemTotalTime - m_itemCurrentTime) % 60;
- }
- else {
- minutes = int(m_itemCurrentTime / 60);
- seconds = m_itemCurrentTime % 60;
- }
-
- int totalMinutes = int(m_itemTotalTime / 60);
- int totalSeconds = m_itemTotalTime % 60;
-
- QString timeString = formatTime(minutes, seconds) + " / " +
- formatTime(totalMinutes, totalSeconds);
- m_itemTimeLabel->setText(timeString);
-}
-
-bool StatusLabel::eventFilter(QObject *o, QEvent *e)
-{
- if(!o || !e)
- return false;
-
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e);
- if(e->type() == QEvent::MouseButtonRelease &&
- mouseEvent->button() == Qt::LeftButton)
- {
- if(o == m_itemTimeLabel) {
- m_showTimeRemaining = !m_showTimeRemaining;
- updateTime();
- }
- else
- action("showPlaying")->trigger();
-
- return true;
- }
- return false;
-}
-
-QString StatusLabel::formatTime(int minutes, int seconds) // static
-{
- QString m = QString::number(minutes);
- if(m.length() == 1)
- m = '0' + m;
- QString s = QString::number(seconds);
- if(s.length() == 1)
- s = '0' + s;
- return m + ':' + s;
-}
-
-#include "statuslabel.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef STATUSLABEL_H
-#define STATUSLABEL_H
-
-#include "playlistinterface.h"
-
-#include <khbox.h>
-//Added by qt3to4:
-#include <QLabel>
-#include <QEvent>
-
-class QLabel;
-class KSqueezedTextLabel;
-
-
-class StatusLabel : public KHBox, public PlaylistObserver
-{
- Q_OBJECT
-
-public:
- explicit StatusLabel(PlaylistInterface *playlist, QWidget *parent = 0);
- virtual ~StatusLabel();
- virtual void updateCurrent();
-
-public slots:
- /**
- * This just sets internal variables that are used by setItemCurrentTime().
- * Please call that method to display the time.
- */
- void setItemTotalTime(int time) { m_itemTotalTime = time; }
- void setItemCurrentTime(int time) { m_itemCurrentTime = time; updateTime(); }
- virtual void updateData();
-
-signals:
- void jumpButtonClicked();
-
-private:
- void updateTime();
- virtual bool eventFilter(QObject *o, QEvent *e);
-
- static QString formatTime(int minutes, int seconds);
-
- int m_itemTotalTime;
- int m_itemCurrentTime;
- bool m_showTimeRemaining;
-
- KSqueezedTextLabel *m_playlistLabel;
- KSqueezedTextLabel *m_trackLabel;
- QLabel *m_itemTimeLabel;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef STRINGHASH_H
-#define STRINGHASH_H
-
-#include <QSet>
-
-/**
- * A simple hash representing an (un-mapped) set of data.
- */
-template <class T> class Hash : public QSet<T>
-{
-public:
- /**
- * To combine two operations into one (that takes the same amount as each
- * independantly) this inserts an item and returns true if the item was
- * already in the set or false if it did not.
- */
- inline bool insert(const T &value)
- {
- if(this->contains(value))
- return true;
- QSet<T>::insert(value);
- return false;
- }
-};
-
-typedef Hash<QString> StringHash;
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Maksim Orlovich <maksim.orlovich@kdemail.net>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include "stringshare.h"
-
-#include <QHash>
-
-const int SIZE = 5003;
-
-StringShare::Data* StringShare::s_data = 0;
-
-/**
- * We store the strings in a simple direct-mapped (i.e. no collision handling,
- * just replace) hash, which contain strings or null objects. This costs only
- * 4 bytes per slot on 32-bit archs, so with the default constant size we only
- * really use 40K or so.
- *
- * The end result is that many strings end up pointing to the same underlying data
- * object, instead of each one having its own little copy.
- *
- * More importantly, the way the tryShare function is coded ensures that
- * most-recently inserted text stays in the cache, which gives a better chance
- * of continuing to share data. (Even if something old ("foo") that was shared
- * gets kicked out, all the other "foo"s will still be sharing each other's
- * data.
- */
-
-struct StringShare::Data
-{
- QString qstringHash [SIZE];
-};
-
-StringShare::Data* StringShare::data()
-{
- if (!s_data)
- s_data = new Data;
- return s_data;
-}
-
-QString StringShare::tryShare(const QString& in)
-{
- uint index = qHash(in) % SIZE;
-
- Data* dat = data();
- if (dat->qstringHash[index] == in) //Match
- return dat->qstringHash[index];
- else
- {
- //Else replace whatever was there before
- dat->qstringHash[index] = in;
- return in;
- }
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Maksim Orlovich <maksim.orlovich@kdemail.net>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef STRING_SHARE_H
-#define STRING_SHARE_H
-
-class QString;
-
-/**
- * This class attempts to normalize repeated occurrences of strings to use
- *the same shared object, if possible, by using a small hash
- */
-class StringShare
-{
- struct Data;
-public:
- static QString tryShare(const QString& in);
-
-private:
- static Data* data();
- static Data* s_data;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>
- * Copyright (c) 2008 Jeff Mitchell <kde-dev@emailgoeshere.com>
- * Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "svghandler.h"
-
-#include <KColorScheme>
-#include <KColorUtils>
-#include <KStandardDirs>
-#include <KDebug>
-
-#include <QHash>
-#include <QPainter>
-#include <QPalette>
-#include <QReadLocker>
-#include <QStringBuilder>
-#include <QStyleOptionSlider>
-#include <QSvgRenderer>
-#include <QWriteLocker>
-
-
-namespace The {
- static SvgHandler* s_SvgHandler_instance = 0;
-
- SvgHandler* svgHandler()
- {
- if( !s_SvgHandler_instance )
- s_SvgHandler_instance = new SvgHandler();
-
- return s_SvgHandler_instance;
- }
-}
-
-
-SvgHandler::SvgHandler( QObject* parent )
- : QObject( parent )
- , m_renderer( 0 )
- , m_themeFile( "juk/pics/theme.svg" )
-{
-}
-
-SvgHandler::~SvgHandler()
-{
- delete m_renderer;
-
- The::s_SvgHandler_instance = 0;
-}
-
-
-bool SvgHandler::loadSvg( const QString& name )
-{
- const QString &svgFilename = KStandardDirs::locate( "data", name );
- QSvgRenderer *renderer = new QSvgRenderer( svgFilename, this );
-
- if ( !renderer->isValid() )
- {
- delete renderer;
- return false;
- }
- QWriteLocker writeLocker( &m_lock );
-
- if( m_renderer )
- delete m_renderer;
-
- m_renderer = renderer;
- return true;
-}
-
-QSvgRenderer * SvgHandler::getRenderer()
-{
- QReadLocker readLocker( &m_lock );
- if( ! m_renderer )
- {
- readLocker.unlock();
- if( !loadSvg( m_themeFile ) )
- {
- QWriteLocker writeLocker( &m_lock );
- m_renderer = new QSvgRenderer( this );
- }
- readLocker.relock();
- }
- return m_renderer;
-}
-
-QPixmap SvgHandler::renderSvg( const QString& keyname,
- int width,
- int height,
- const QString& element )
-{
- QString key = keyname % QChar( ':' ) % QString::number( width ) %
- QChar( 'x' ) % QString::number( height );
-
- QPixmap pixmap;
- QMap<QString, QPixmap>::const_iterator it = m_cache.constFind( key );
- if( it != m_cache.constEnd() )
- {
- pixmap = *it;
- }
- else
- {
- pixmap = QPixmap( width, height );
- pixmap.fill( Qt::transparent );
-
- QReadLocker readLocker( &m_lock );
- if( ! m_renderer )
- {
- readLocker.unlock();
- if( !loadSvg( m_themeFile ) )
- {
- return pixmap;
- }
- readLocker.relock();
- }
-
- QPainter pt( &pixmap );
- if ( element.isEmpty() )
- m_renderer->render( &pt, QRectF( 0, 0, width, height ) );
- else {
- m_renderer->render( &pt, element, QRectF( 0, 0, width, height ) );
- }
-
- m_cache.insert( key, pixmap );
- }
-
- return pixmap;
-}
-
-void SvgHandler::reTint()
-{
- // The::svgTinter()->init();
- if ( !loadSvg( m_themeFile ))
- kDebug() << "Unable to load theme file: " << m_themeFile;
- emit retinted();
-}
-
-QString SvgHandler::themeFile()
-{
- return m_themeFile;
-}
-
-QRect SvgHandler::sliderKnobRect( const QRect &slider, qreal percent, bool inverse ) const
-{
- if ( inverse )
- percent = 1.0 - percent;
- const int knobSize = slider.height() - 4;
- QRect ret( 0, 0, knobSize, knobSize );
- ret.moveTo( slider.x() + qRound( ( slider.width() - knobSize ) * percent ), slider.y() + 1 );
- return ret;
-}
-
-// Experimental, using a mockup from Nuno Pinheiro (new_slider_nuno)
-void SvgHandler::paintCustomSlider( QPainter *p, QStyleOptionSlider *slider, qreal percentage )
-{
- int sliderHeight = slider->rect.height() - 6;
- const bool inverse = ( slider->orientation == Qt::Vertical ) ? slider->upsideDown :
- ( (slider->direction == Qt::RightToLeft) != slider->upsideDown );
- QRect knob = sliderKnobRect( slider->rect, percentage, inverse );
- QPoint pt = slider->rect.topLeft() + QPoint( 0, 2 );
-
- //debug() << "rel: " << knobRelPos << ", width: " << width << ", height:" << height << ", %: " << percentage;
-
- // Draw the slider background in 3 parts
-
- p->drawPixmap( pt, renderSvg( "progress_slider_left", sliderHeight, sliderHeight, "progress_slider_left" ) );
-
- pt.rx() += sliderHeight;
- QRect midRect(pt, QSize(slider->rect.width() - sliderHeight * 2, sliderHeight) );
- p->drawTiledPixmap( midRect, renderSvg( "progress_slider_mid", 32, sliderHeight, "progress_slider_mid" ) );
-
- pt = midRect.topRight() + QPoint( 1, 0 );
- p->drawPixmap( pt, renderSvg( "progress_slider_right", sliderHeight, sliderHeight, "progress_slider_right" ) );
-
- //draw the played background.
-
- int playedBarHeight = sliderHeight - 6;
-
- int sizeOfLeftPlayed = qBound( 0, inverse ? slider->rect.right() - knob.right() + 2 :
- knob.x() - 2, playedBarHeight );
-
- if( sizeOfLeftPlayed > 0 )
- {
- QPoint tl, br;
- if ( inverse )
- {
- tl = knob.topRight() + QPoint( -5, 5 ); // 5px x padding to avoid a "gap" between it and the top and bottom of the round knob.
- br = slider->rect.topRight() + QPoint( -3, 5 + playedBarHeight - 1 );
- QPixmap rightEnd = renderSvg( "progress_slider_played_right", playedBarHeight, playedBarHeight, "progress_slider_played_right" );
- p->drawPixmap( br.x() - rightEnd.width() + 1, tl.y(), rightEnd, qMax(0, rightEnd.width() - (sizeOfLeftPlayed + 3)), 0, sizeOfLeftPlayed + 3, playedBarHeight );
- br.rx() -= playedBarHeight;
- }
- else
- {
- tl = slider->rect.topLeft() + QPoint( 3, 5 );
- br = QPoint( knob.x() + 5, tl.y() + playedBarHeight - 1 );
- QPixmap leftEnd = renderSvg( "progress_slider_played_left", playedBarHeight, playedBarHeight, "progress_slider_played_left" );
- p->drawPixmap( tl.x(), tl.y(), leftEnd, 0, 0, sizeOfLeftPlayed + 3, playedBarHeight );
- tl.rx() += playedBarHeight;
- }
- if ( sizeOfLeftPlayed == playedBarHeight )
- p->drawTiledPixmap( QRect(tl, br), renderSvg( "progress_slider_played_mid", 32, playedBarHeight, "progress_slider_played_mid" ) );
-
- }
-
- if ( slider->state & QStyle::State_Enabled )
- { // Draw the knob (handle)
- const char *string = ( slider->activeSubControls & QStyle::SC_SliderHandle ) ?
- "slider_knob_200911_active" : "slider_knob_200911";
- p->drawPixmap( knob.topLeft(), renderSvg( string, knob.width(), knob.height(), string ) );
- }
-}
-
-#include "svghandler.moc"
+++ /dev/null
-/**
- * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>
- * Copyright (c) 2008 Jeff Mitchell <kde-dev@emailgoeshere.com>
- * Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SVGHANDLER_H
-#define SVGHANDLER_H
-
-class QStyleOptionSlider;
-
-#include <QMap>
-#include <QReadWriteLock>
-
-#include <QPixmap>
-#include <QString>
-
-class SvgHandler;
-class QSvgRenderer;
-
-namespace The {
- SvgHandler* svgHandler();
-}
-
-/**
-A class to abstract out some common operations of users of tinted svgs
-*/
-class SvgHandler : public QObject
-{
- Q_OBJECT
-
- friend SvgHandler* The::svgHandler();
-
- public:
- ~SvgHandler();
-
- QSvgRenderer* getRenderer();
-
- /**
- * Overloaded function that uses the current theme
- * @param keyname the name of the key to save in the cache
- * @param width Width of the resulting pixmap
- * @param height Height of the resulting pixmap
- * @param element The theme element to render ( if none the entire svg is rendered )
- * @return The svg element/file rendered into a pixmap
- */
- QPixmap renderSvg( const QString& keyname, int width, int height, const QString& element = QString() );
-
- /**
- * Paint a custom slider using the specified painter. The slider consists
- * of a background part, a "knob" that moves along it to show the current
- * position, and 2 end markers to clearly mark the ends of the slider.
- * The background part before the knob, is painted in a different color than the
- * part after (and under) the knob.
- * @param p The painter to use.
- * @param x The x position to begin painting at.
- * @param y The y position to begin painting at.
- * @param width The width of the slider to paint.
- * @param height The height of the slider. The background part does not scale in height, it will always be a relatively thin line, but the knob and end markers do.
- * @param percentage The percentange of the slider that the knob is positioned at.
- * @param active Specifies whether the slider should be painted "active" using the current palettes active colors, to specify that it currently has mouse focus or hover.
- */
- void paintCustomSlider( QPainter *p, QStyleOptionSlider *slider, qreal percentage );
-
- /**
- * Calculate the visual slider knob rect from its value, use it instead the QStyle functions
- * QStyle::sliderPositionFromValue() and QStyle::subControlRect();
- */
- QRect sliderKnobRect( const QRect &slider, qreal percent, bool inverse ) const;
-
- /**
- * Get the path of the currently used svg theme file.
- *
- * @return the path of the currently used theme file.
- */
- QString themeFile();
-
- public slots:
- void reTint();
-
- signals:
- void retinted();
-
- private:
- SvgHandler( QObject* parent = 0 );
-
- bool loadSvg( const QString& name );
-
- QPixmap sliderHandle( const QColor &color, bool pressed, int size );
-
- QMap<QString, QPixmap> m_cache;
-
- QSvgRenderer *m_renderer;
- QReadWriteLock m_lock;
-
- QString m_themeFile;
-};
-
-#endif
+++ /dev/null
-/**
- * Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org>
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2004-2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "systemtray.h"
-
-#include <klocale.h>
-#include <kiconloader.h>
-#include <kaction.h>
-#include <kdebug.h>
-#include <kactioncollection.h>
-#include <kactionmenu.h>
-#include <kvbox.h>
-#include <kmenu.h>
-#include <kwindowsystem.h>
-
-#include <QTimer>
-#include <QWheelEvent>
-#include <QColor>
-#include <QPushButton>
-#include <QPalette>
-#include <QPixmap>
-#include <QLabel>
-#include <QVBoxLayout>
-#include <QIcon>
-#include <QApplication>
-#include <QTextDocument> // Qt::escape()
-
-#include "tag.h"
-#include "actioncollection.h"
-#include "playermanager.h"
-#include "coverinfo.h"
-
-using namespace ActionCollection;
-
-PassiveInfo::PassiveInfo() :
- QFrame(static_cast<QWidget *>(0),
- Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint
- ),
- m_timer(new QTimer(this)),
- m_layout(new QVBoxLayout(this)),
- m_justDie(false)
-{
- connect(m_timer, SIGNAL(timeout()), SLOT(timerExpired()));
- setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
-
- // Workaround transparent background in Oxygen when (ab-)using Qt::ToolTip
- setAutoFillBackground(true);
-
- setFrameStyle(StyledPanel | Plain);
- setLineWidth(2);
-}
-
-void PassiveInfo::startTimer(int delay)
-{
- m_timer->start(delay);
-}
-
-void PassiveInfo::show()
-{
- m_timer->start(3500);
- setWindowOpacity(1.0);
- QFrame::show();
-}
-
-void PassiveInfo::setView(QWidget *view)
-{
- m_layout->addWidget(view);
- view->show(); // We are still hidden though.
- adjustSize();
- positionSelf();
-}
-
-void PassiveInfo::timerExpired()
-{
- // If m_justDie is set, we should just go, otherwise we should emit the
- // signal and wait for the system tray to delete us.
- if(m_justDie)
- hide();
- else
- emit timeExpired();
-}
-
-void PassiveInfo::enterEvent(QEvent *)
-{
- m_timer->stop();
- emit mouseEntered();
-}
-
-void PassiveInfo::leaveEvent(QEvent *)
-{
- m_justDie = true;
- m_timer->start(50);
-}
-
-void PassiveInfo::hideEvent(QHideEvent *)
-{
-}
-
-void PassiveInfo::wheelEvent(QWheelEvent *e)
-{
- if(e->delta() >= 0) {
- emit nextSong();
- }
- else {
- emit previousSong();
- }
-
- e->accept();
-}
-
-void PassiveInfo::positionSelf()
-{
- // Start with a QRect of our size, move it to the right spot.
- QRect r(rect());
- QRect curScreen(KWindowSystem::workArea());
-
- // Try to position in lower right of the screen
- QPoint anchor(curScreen.right() * 7 / 8, curScreen.bottom());
-
- // Now make our rect hit that anchor.
- r.moveBottomRight(anchor);
-
- move(r.topLeft());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-SystemTray::SystemTray(PlayerManager *player, QWidget *parent) :
- KStatusNotifierItem(parent),
- m_popup(0),
- m_player(player),
- m_fadeTimer(0),
- m_fade(true),
- m_hasCompositionManager(false)
-{
- // This should be initialized to the number of labels that are used.
- m_labels.fill(0, 3);
-
- setIconByName("juk");
- setCategory(ApplicationStatus);
- setStatus(Active); // We were told to dock in systray by user, force us visible
-
- m_forwardPix = SmallIcon("media-skip-forward");
- m_backPix = SmallIcon("media-skip-backward");
-
- // Just create this here so that it show up in the DBus interface and the
- // key bindings dialog.
-
- KAction *rpaction = new KAction(i18n("Redisplay Popup"), this);
- ActionCollection::actions()->addAction("showPopup", rpaction);
- connect(rpaction, SIGNAL(triggered(bool)), SLOT(slotPlay()));
-
- KMenu *cm = contextMenu();
-
- connect(m_player, SIGNAL(signalPlay()), this, SLOT(slotPlay()));
- connect(m_player, SIGNAL(signalPause()), this, SLOT(slotPause()));
- connect(m_player, SIGNAL(signalStop()), this, SLOT(slotStop()));
-
- cm->addAction( action("play") );
- cm->addAction( action("pause") );
- cm->addAction( action("stop") );
- cm->addAction( action("forward") );
- cm->addAction( action("back") );
-
- cm->addSeparator();
-
- // Pity the actionCollection doesn't keep track of what sub-menus it has.
-
- KActionMenu *menu = new KActionMenu(i18n("&Random Play"), this);
- actionCollection()->addAction("randomplay", menu);
- menu->addAction(action("disableRandomPlay"));
- menu->addAction(action("randomPlay"));
- menu->addAction(action("albumRandomPlay"));
- cm->addAction( menu );
-
- cm->addAction( action("togglePopups") );
-
- m_fadeTimer = new QTimer(this);
- m_fadeTimer->setObjectName( QLatin1String("systrayFadeTimer" ));
- connect(m_fadeTimer, SIGNAL(timeout()), SLOT(slotNextStep()));
-
- // Handle wheel events
- connect(this, SIGNAL(scrollRequested(int,Qt::Orientation)), SLOT(scrollEvent(int,Qt::Orientation)));
-
- // Add a quick hook for play/pause toggle
- connect(this, SIGNAL(secondaryActivateRequested(QPoint)),
- action("playPause"), SLOT(trigger()));
-
- if(m_player->playing())
- slotPlay();
- else if(m_player->paused())
- slotPause();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void SystemTray::slotPlay()
-{
- if(!m_player->playing())
- return;
-
- QPixmap cover = m_player->playingFile().coverInfo()->pixmap(CoverInfo::FullSize);
-
- setOverlayIconByName("media-playback-start");
- setToolTip(m_player->playingString(), cover);
- createPopup();
-}
-
-void SystemTray::slotPause()
-{
- setOverlayIconByName("media-playback-pause");
-}
-
-void SystemTray::slotPopupLargeCover()
-{
- if(!m_player->playing())
- return;
-
- FileHandle playingFile = m_player->playingFile();
- playingFile.coverInfo()->popup();
-}
-
-void SystemTray::slotStop()
-{
- setToolTip();
- setOverlayIconByName(QString());
-
- delete m_popup;
- m_popup = 0;
- m_fadeTimer->stop();
-}
-
-void SystemTray::slotPopupDestroyed()
-{
- for(int i = 0; i < m_labels.size(); ++i)
- m_labels[i] = 0;
-}
-
-void SystemTray::slotNextStep()
-{
- // Could happen I guess if the timeout event were queued while we're deleting m_popup
- if(!m_popup)
- return;
-
- ++m_step;
-
- // If we're not fading, immediately stop the fadeout
- if(!m_fade || m_step == STEPS) {
- m_step = 0;
- m_fadeTimer->stop();
- emit fadeDone();
- return;
- }
-
- if(m_hasCompositionManager) {
- m_popup->setWindowOpacity((1.0 * STEPS - m_step) / STEPS);
- }
- else {
- QColor result = interpolateColor(m_step);
-
- for(int i = 0; i < m_labels.size() && m_labels[i]; ++i) {
- QPalette palette;
- palette.setColor(m_labels[i]->foregroundRole(), result);
- m_labels[i]->setPalette(palette);
- }
- }
-}
-
-void SystemTray::slotFadeOut()
-{
- m_startColor = m_labels[0]->palette().color( QPalette::Text ); //textColor();
- m_endColor = m_labels[0]->palette().color( QPalette::Window ); //backgroundColor();
-
- m_hasCompositionManager = KWindowSystem::compositingActive();
-
- connect(this, SIGNAL(fadeDone()), m_popup, SLOT(hide()));
- connect(m_popup, SIGNAL(mouseEntered()), this, SLOT(slotMouseInPopup()));
- m_fadeTimer->start(1500 / STEPS);
-}
-
-// If we receive this signal, it's because we were called during fade out.
-// That means there is a single shot timer about to call slotNextStep, so we
-// don't have to do it ourselves.
-void SystemTray::slotMouseInPopup()
-{
- m_endColor = m_labels[0]->palette().color( QPalette::Text ); //textColor();
- disconnect(SIGNAL(fadeDone()));
-
- if(m_hasCompositionManager)
- m_popup->setWindowOpacity(1.0);
-
- m_step = STEPS - 1; // Simulate end of fade to solid text
- slotNextStep();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-KVBox *SystemTray::createPopupLayout(QWidget *parent, const FileHandle &file)
-{
- KVBox *infoBox = 0;
-
- // We always show the popup on the right side of the current screen, so
- // this logic assumes that. Earlier revisions has logic for popup being
- // wherever the systray icon is, so if it's decided to go that route again,
- // dig into the source control history. --mpyne
-
- if(file.coverInfo()->hasCover()) {
- addCoverButton(parent, file.coverInfo()->pixmap(CoverInfo::Thumbnail));
- addSeparatorLine(parent);
- }
-
- infoBox = new KVBox(parent);
-
- addSeparatorLine(parent);
- createButtonBox(parent);
-
- infoBox->setSpacing(3);
- infoBox->setMargin(3);
- return infoBox;
-}
-
-void SystemTray::createPopup()
-{
- FileHandle playingFile = m_player->playingFile();
- Tag *playingInfo = playingFile.tag();
-
- // If the action exists and it's checked, do our stuff
-
- if(!ActionCollection::action("togglePopups")->isChecked())
- return;
-
- delete m_popup;
- m_popup = 0;
- m_fadeTimer->stop();
-
- // This will be reset after this function call by slot(Forward|Back)
- // so it's safe to set it true here.
- m_fade = true;
- m_step = 0;
-
- m_popup = new PassiveInfo;
- connect(m_popup, SIGNAL(destroyed()), SLOT(slotPopupDestroyed()));
- connect(m_popup, SIGNAL(timeExpired()), SLOT(slotFadeOut()));
- connect(m_popup, SIGNAL(nextSong()), SLOT(slotForward()));
- connect(m_popup, SIGNAL(previousSong()), SLOT(slotBack()));
-
- KHBox *box = new KHBox(m_popup);
- box->setSpacing(15); // Add space between text and buttons
-
- KVBox *infoBox = createPopupLayout(box, playingFile);
-
- for(int i = 0; i < m_labels.size(); ++i) {
- QLabel *l = new QLabel(" ", infoBox);
- l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
- m_labels[i] = l;
- }
-
- // We have to set the text of the labels after all of the
- // widgets have been added in order for the width to be calculated
- // correctly.
-
- int labelCount = 0;
-
- QString title = Qt::escape(playingInfo->title());
- m_labels[labelCount++]->setText(QString("<qt><nobr><h2>%1</h2></nobr></qt>").arg(title));
-
- if(!playingInfo->artist().isEmpty())
- m_labels[labelCount++]->setText(playingInfo->artist());
-
- if(!playingInfo->album().isEmpty()) {
- QString album = Qt::escape(playingInfo->album());
- QString s = playingInfo->year() > 0
- ? QString("<qt><nobr>%1 (%2)</nobr></qt>").arg(album).arg(playingInfo->year())
- : QString("<qt><nobr>%1</nobr></qt>").arg(album);
- m_labels[labelCount++]->setText(s);
- }
-
- m_popup->setView(box);
- m_popup->show();
-}
-
-void SystemTray::createButtonBox(QWidget *parent)
-{
- KVBox *buttonBox = new KVBox(parent);
-
- buttonBox->setSpacing(3);
-
- QPushButton *forwardButton = new QPushButton(m_forwardPix, 0, buttonBox);
- forwardButton->setObjectName( QLatin1String("popup_forward" ));
- connect(forwardButton, SIGNAL(clicked()), SLOT(slotForward()));
-
- QPushButton *backButton = new QPushButton(m_backPix, 0, buttonBox);
- backButton->setObjectName( QLatin1String("popup_back" ));
- connect(backButton, SIGNAL(clicked()), SLOT(slotBack()));
-}
-
-/**
- * What happens here is that the action->trigger() call will end up invoking
- * createPopup(), which sets m_fade to true. Before the text starts fading
- * control returns to this function, which resets m_fade to false.
- */
-void SystemTray::slotBack()
-{
- action("back")->trigger();
- m_fade = false;
-}
-
-void SystemTray::slotForward()
-{
- action("forward")->trigger();
- m_fade = false;
-}
-
-void SystemTray::addSeparatorLine(QWidget *parent)
-{
- QFrame *line = new QFrame(parent);
- line->setFrameShape(QFrame::VLine);
-
- // Cover art takes up 80 pixels, make sure we take up at least 80 pixels
- // even if we don't show the cover art for consistency.
-
- line->setMinimumHeight(80);
-}
-
-void SystemTray::addCoverButton(QWidget *parent, const QPixmap &cover)
-{
- QPushButton *coverButton = new QPushButton(parent);
-
- coverButton->setIconSize(cover.size());
- coverButton->setIcon(cover);
- coverButton->setFixedSize(cover.size());
- coverButton->setFlat(true);
-
- connect(coverButton, SIGNAL(clicked()), this, SLOT(slotPopupLargeCover()));
-}
-
-QColor SystemTray::interpolateColor(int step, int steps)
-{
- if(step < 0)
- return m_startColor;
- if(step >= steps)
- return m_endColor;
-
- // TODO: Perhaps the algorithm here could be better? For example, it might
- // make sense to go rather quickly from start to end and then slow down
- // the progression.
- return QColor(
- (step * m_endColor.red() + (steps - step) * m_startColor.red()) / steps,
- (step * m_endColor.green() + (steps - step) * m_startColor.green()) / steps,
- (step * m_endColor.blue() + (steps - step) * m_startColor.blue()) / steps
- );
-}
-
-void SystemTray::setToolTip(const QString &tip, const QPixmap &cover)
-{
- if(tip.isEmpty())
- KStatusNotifierItem::setToolTip("juk", i18n("JuK"), QString());
- else {
- QPixmap myCover;
- if(cover.isNull()) {
- myCover = DesktopIcon("juk");
- } else {
- //Scale to proper icon size, otherwise KStatusNotifierItem will show an unknown icon
- int iconSize = KIconLoader::global()->currentSize(KIconLoader::Desktop);
- myCover = cover.scaled(iconSize, iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- }
-
- KStatusNotifierItem::setToolTip(QIcon(myCover), i18n("JuK"), tip);
- }
-}
-
-void SystemTray::scrollEvent(int delta, Qt::Orientation orientation)
-{
- if(orientation == Qt::Horizontal)
- return;
-
- switch(QApplication::keyboardModifiers()) {
- case Qt::ShiftButton:
- if(delta > 0)
- action("volumeUp")->trigger();
- else
- action("volumeDown")->trigger();
- break;
- default:
- if(delta > 0)
- action("forward")->trigger();
- else
- action("back")->trigger();
- break;
- }
-}
-
-#include "systemtray.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org>
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007, 2008, 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JUK_SYSTEMTRAY_H
-#define JUK_SYSTEMTRAY_H
-
-#include <kstatusnotifieritem.h>
-
-#include <QVector>
-#include <QColor>
-#include <QPixmap>
-#include <QIcon>
-#include <QFrame>
-
-class SystemTray;
-class PlayerManager;
-class QLabel;
-class QTimer;
-class KVBox;
-class FileHandle;
-class QVBoxLayout;
-
-/**
- * Workalike of KPassivePopup intended to more easily support JuK's particular
- * usage pattern, including things like staying open while under the mouse.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class PassiveInfo : public QFrame
-{
- Q_OBJECT
-public:
- PassiveInfo();
-
- // Sets view as a child widget to show in the popup window.
- // This widget does not take ownership of the widget. If you want it auto-deleted,
- // either re-parent it or create it using this widget as its parent.
- void setView(QWidget *view);
-
- QWidget *view() const;
-
-public slots:
- // Starts a timer to show the popup. The popup will not automatically delete itself
- // once hidden.
- void startTimer(int delay);
- virtual void show();
-
-signals:
- void mouseEntered();
- void timeExpired();
- void previousSong();
- void nextSong();
-
-protected:
- virtual void enterEvent(QEvent *);
- virtual void leaveEvent(QEvent *);
- virtual void hideEvent(QHideEvent *);
- virtual void wheelEvent(QWheelEvent *);
-
-private:
- // Move us near the required position.
- void positionSelf();
-
-private slots:
- void timerExpired();
-
-private:
- QTimer *m_timer;
- QVBoxLayout *m_layout;
- bool m_justDie;
-};
-
-class SystemTray : public KStatusNotifierItem
-{
- Q_OBJECT
-
-public:
- explicit SystemTray(PlayerManager *player, QWidget *parent = 0);
-
-signals:
- // Emitted when the fade process is complete.
- void fadeDone();
-
-private:
- static const int STEPS = 20; ///< Number of intermediate steps for fading.
-
- void createPopup();
- void setToolTip(const QString &tip = QString(), const QPixmap &cover = QPixmap());
-
- void createButtonBox(QWidget *parent);
-
- // Creates the widget layout for the popup, returning the QVBox that
- // holds the text labels.
-
- KVBox *createPopupLayout(QWidget *parent, const FileHandle &file);
-
- void addSeparatorLine(QWidget *parent);
- void addCoverButton(QWidget *parent, const QPixmap &cover);
-
- // Interpolates from start color to end color. If @p step == 0, then
- // m_startColor is returned, while @p step == @steps returns
- // m_endColor.
-
- QColor interpolateColor(int step, int steps = STEPS);
-
-private slots:
- void slotPlay();
- void slotPause();
- void slotStop();
- void slotPopupDestroyed();
- void slotNextStep(); ///< This is the fading routine.
- void slotPopupLargeCover();
- void slotForward();
- void slotBack();
- void slotFadeOut(); ///< Fades out the text
- void slotMouseInPopup(); ///< Forces the text back to its normal color.
- void scrollEvent(int delta, Qt::Orientation orientation);
-
-private:
- QPixmap m_backPix;
- QPixmap m_forwardPix;
- QColor m_startColor, m_endColor;
-
- PassiveInfo *m_popup;
- PlayerManager *m_player;
- QVector<QLabel *> m_labels;
- QTimer *m_fadeTimer;
- int m_step;
- bool m_fade;
-
- /// Used to choose between manual fade and windowOpacity
- bool m_hasCompositionManager;
-};
-
-#endif // JUK_SYSTEMTRAY_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tag.h"
-
-#include <kdebug.h>
-#include <klocale.h>
-
-#include <QtCore/QFile>
-
-#include <taglib/tag.h>
-#include <tfile.h>
-#include <audioproperties.h>
-#include <id3v2framefactory.h>
-
-#include "cache.h"
-#include "mediafiles.h"
-#include "stringshare.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-
-Tag::Tag(const QString &fileName) :
- m_fileName(fileName),
- m_track(0),
- m_year(0),
- m_seconds(0),
- m_bitrate(0),
- m_isValid(false)
-{
- if(fileName.isEmpty()) {
- kError() << "Trying to add empty file, backtrace follows:" << endl;
- kError() << kBacktrace(10) << endl;
- return;
- }
-
- TagLib::File *file = MediaFiles::fileFactoryByType(fileName);
- if(file && file->isValid()) {
- setup(file);
- delete file;
- }
- else {
- kError() << "Couldn't resolve the mime type of \"" <<
- fileName << "\" -- this shouldn't happen." << endl;
- }
-}
-
-bool Tag::save()
-{
- bool result;
- TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8);
- TagLib::File *file = MediaFiles::fileFactoryByType(m_fileName);
-
- if(file && !file->readOnly() && file->isValid() && file->tag()) {
- file->tag()->setTitle(TagLib::String(m_title.toUtf8().constData(), TagLib::String::UTF8));
- file->tag()->setArtist(TagLib::String(m_artist.toUtf8().constData(), TagLib::String::UTF8));
- file->tag()->setAlbum(TagLib::String(m_album.toUtf8().constData(), TagLib::String::UTF8));
- file->tag()->setGenre(TagLib::String(m_genre.toUtf8().constData(), TagLib::String::UTF8));
- file->tag()->setComment(TagLib::String(m_comment.toUtf8().constData(), TagLib::String::UTF8));
- file->tag()->setTrack(m_track);
- file->tag()->setYear(m_year);
- result = file->save();
- }
- else {
- kError() << "Couldn't save file." << endl;
- result = false;
- }
-
- delete file;
- return result;
-}
-
-QString Tag::playingString() const
-{
- QString str;
- if(artist().isEmpty())
- str = title();
- else {
- str = i18nc("a playing track, %1 is artist, %2 is song title",
- "%1 - <i>%2</i>", artist(), title());
- }
-
- return str;
-}
-
-CacheDataStream &Tag::read(CacheDataStream &s)
-{
- switch(s.cacheVersion()) {
- case 1: {
- qint32 track;
- qint32 year;
- qint32 bitrate;
- qint32 seconds;
-
- s >> m_title
- >> m_artist
- >> m_album
- >> m_genre
- >> track
- >> year
- >> m_comment
- >> bitrate
- >> m_lengthString
- >> seconds;
-
- m_track = track;
- m_year = year;
- m_bitrate = bitrate;
- m_seconds = seconds;
- break;
- }
- default: {
- static QString dummyString;
- static int dummyInt;
- QString bitrateString;
-
- s >> dummyInt
- >> m_title
- >> m_artist
- >> m_album
- >> m_genre
- >> dummyInt
- >> m_track
- >> dummyString
- >> m_year
- >> dummyString
- >> m_comment
- >> bitrateString
- >> m_lengthString
- >> m_seconds
- >> dummyString;
-
- bool ok;
- m_bitrate = bitrateString.toInt(&ok);
- if(!ok)
- m_bitrate = 0;
- break;
- }
- }
-
- minimizeMemoryUsage();
- return s;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private methods
-////////////////////////////////////////////////////////////////////////////////
-
-Tag::Tag(const QString &fileName, bool) :
- m_fileName(fileName),
- m_track(0),
- m_year(0),
- m_seconds(0),
- m_bitrate(0),
- m_isValid(true)
-{
-
-}
-
-void Tag::setup(TagLib::File *file)
-{
- if(!file || !file->tag()) {
- kWarning() << "Can't setup invalid file" << m_fileName;
- return;
- }
-
- m_title = TStringToQString(file->tag()->title()).trimmed();
- m_artist = TStringToQString(file->tag()->artist()).trimmed();
- m_album = TStringToQString(file->tag()->album()).trimmed();
- m_genre = TStringToQString(file->tag()->genre()).trimmed();
- m_comment = TStringToQString(file->tag()->comment()).trimmed();
-
- m_track = file->tag()->track();
- m_year = file->tag()->year();
-
- m_seconds = file->audioProperties()->length();
- m_bitrate = file->audioProperties()->bitrate();
-
- const int seconds = m_seconds % 60;
- const int minutes = (m_seconds - seconds) / 60;
-
- m_lengthString = QString::number(minutes) + (seconds >= 10 ? ":" : ":0") + QString::number(seconds);
-
- if(m_title.isEmpty()) {
- int i = m_fileName.lastIndexOf('/');
- int j = m_fileName.lastIndexOf('.');
- m_title = i > 0 ? m_fileName.mid(i + 1, j - i - 1) : m_fileName;
- }
-
- minimizeMemoryUsage();
- m_isValid = true;
-}
-
-void Tag::minimizeMemoryUsage()
-{
- // Try to reduce memory usage: share tags that frequently repeat, squeeze others
-
- m_title.squeeze();
- m_lengthString.squeeze();
-
- m_comment = StringShare::tryShare(m_comment);
- m_artist = StringShare::tryShare(m_artist);
- m_album = StringShare::tryShare(m_album);
- m_genre = StringShare::tryShare(m_genre);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// related functions
-////////////////////////////////////////////////////////////////////////////////
-
-QDataStream &operator<<(QDataStream &s, const Tag &t)
-{
- s << t.title()
- << t.artist()
- << t.album()
- << t.genre()
- << qint32(t.track())
- << qint32(t.year())
- << t.comment()
- << qint32(t.bitrate())
- << t.lengthString()
- << qint32(t.seconds());
-
- return s;
-}
-
-CacheDataStream &operator>>(CacheDataStream &s, Tag &t)
-{
- return t.read(s);
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2009 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAG_H
-#define TAG_H
-
-#include <QDateTime>
-
-namespace TagLib { class File; }
-
-class CacheDataStream;
-
-/*!
- * This should really be called "metadata" and may at some point be titled as
- * such. Right now it's mostly a Qt wrapper around TagLib.
- */
-
-class Tag
-{
- friend class FileHandle;
-public:
- Tag(const QString &fileName);
- /**
- * Create an empty tag. Used in FileHandle for cache restoration.
- */
- Tag(const QString &fileName, bool);
-
- bool save();
-
- QString title() const { return m_title; }
- QString artist() const { return m_artist; }
- QString album() const { return m_album; }
- QString genre() const { return m_genre; }
- int track() const { return m_track; }
- int year() const { return m_year; }
- QString comment() const { return m_comment; }
-
- QString fileName() const { return m_fileName; }
-
- void setTitle(const QString &value) { m_title = value; }
- void setArtist(const QString &value) { m_artist = value; }
- void setAlbum(const QString &value) { m_album = value; }
- void setGenre(const QString &value) { m_genre = value; }
- void setTrack(int value) { m_track = value; }
- void setYear(int value) { m_year = value; }
- void setComment(const QString &value) { m_comment = value; }
-
- void setFileName(const QString &value) { m_fileName = value; }
-
- int seconds() const { return m_seconds; }
- int bitrate() const { return m_bitrate; }
-
- bool isValid() const { return m_isValid; }
-
- /**
- * As a convenience, since producing a length string from a number of second
- * isn't a one liner, provide the length in string form.
- */
- QString lengthString() const { return m_lengthString; }
-
- /**
- * Convenience function to return a concise string describing the track,
- * usually in the form Artist - Title.
- */
- QString playingString() const;
-
- CacheDataStream &read(CacheDataStream &s);
-
-private:
- void setup(TagLib::File *file);
- void minimizeMemoryUsage();
-
- QString m_fileName;
- QString m_title;
- QString m_artist;
- QString m_album;
- QString m_genre;
- QString m_comment;
- int m_track;
- int m_year;
- int m_seconds;
- int m_bitrate;
- QDateTime m_modificationTime;
- QString m_lengthString;
- bool m_isValid;
-};
-
-QDataStream &operator<<(QDataStream &s, const Tag &t);
-CacheDataStream &operator>>(CacheDataStream &s, Tag &t);
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tageditor.h"
-#include "collectionlist.h"
-#include "playlistitem.h"
-#include "tag.h"
-#include "actioncollection.h"
-#include "tagtransactionmanager.h"
-
-#include <kactioncollection.h>
-#include <kconfiggroup.h>
-#include <kcombobox.h>
-#include <klineedit.h>
-#include <knuminput.h>
-#include <ktextedit.h>
-#include <kapplication.h>
-#include <kmessagebox.h>
-#include <kconfig.h>
-#include <klocale.h>
-#include <kdebug.h>
-#include <kiconloader.h>
-#include <kicon.h>
-#include <ktoggleaction.h>
-#include <kshortcut.h>
-
-#include <QLabel>
-#include <QApplication>
-#include <QCheckBox>
-#include <QDir>
-#include <QValidator>
-#include <QEventLoop>
-#include <QKeyEvent>
-#include <QHBoxLayout>
-#include <QVBoxLayout>
-#include <QSizePolicy>
-
-#include <id3v1genres.h>
-
-#undef KeyRelease
-
-class FileNameValidator : public QValidator
-{
-public:
- FileNameValidator(QObject *parent, const char *name = 0) :
- QValidator(parent)
- {
- setObjectName( QLatin1String( name ) );
- }
-
- virtual void fixup(QString &s) const
- {
- s.remove('/');
- }
-
- virtual State validate(QString &s, int &) const
- {
- if(s.contains('/'))
- return Invalid;
- return Acceptable;
- }
-};
-
-class FixedHLayout : public QHBoxLayout
-{
-public:
- FixedHLayout(QWidget *parent, int margin = 0, int spacing = -1, const char *name = 0) :
- QHBoxLayout(parent),
- m_width(-1)
- {
- setMargin(margin);
- setSpacing(spacing);
- setObjectName(QLatin1String(name));
- }
- FixedHLayout(QLayout *parentLayout, int spacing = -1, const char *name = 0) :
- QHBoxLayout(),
- m_width(-1)
- {
- parentLayout->addItem(this);
- setSpacing(spacing);
- setObjectName(QLatin1String(name));
- }
- void setWidth(int w = -1)
- {
- m_width = w == -1 ? QHBoxLayout::minimumSize().width() : w;
- }
- virtual QSize minimumSize() const
- {
- QSize s = QHBoxLayout::minimumSize();
- s.setWidth(m_width);
- return s;
- }
-private:
- int m_width;
-};
-
-class CollectionObserver : public PlaylistObserver
-{
-public:
- CollectionObserver(TagEditor *parent) :
- PlaylistObserver(CollectionList::instance()),
- m_parent(parent)
- {
- }
-
- virtual void updateData()
- {
- if(m_parent && m_parent->m_currentPlaylist && m_parent->isVisible())
- m_parent->slotSetItems(m_parent->m_currentPlaylist->selectedItems());
- }
-
- virtual void updateCurrent() {}
-
-private:
- TagEditor *m_parent;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-TagEditor::TagEditor(QWidget *parent) :
- QWidget(parent),
- m_currentPlaylist(0),
- m_observer(0),
- m_performingSave(false)
-{
- setupActions();
- setupLayout();
- readConfig();
- m_dataChanged = false;
- m_collectionChanged = false;
-
- setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
-}
-
-TagEditor::~TagEditor()
-{
- delete m_observer;
- saveConfig();
-}
-
-void TagEditor::setupObservers()
-{
- m_observer = new CollectionObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-void TagEditor::slotSetItems(const PlaylistItemList &list)
-{
- if(m_performingSave)
- return;
-
- // Store the playlist that we're setting because saveChangesPrompt
- // can delete the PlaylistItems in list.
-
- Playlist *itemPlaylist = 0;
- if(!list.isEmpty())
- itemPlaylist = list.first()->playlist();
-
- bool hadPlaylist = m_currentPlaylist != 0;
-
- saveChangesPrompt();
-
- if(m_currentPlaylist) {
- disconnect(m_currentPlaylist, SIGNAL(signalAboutToRemove(PlaylistItem*)),
- this, SLOT(slotItemRemoved(PlaylistItem*)));
- }
-
- if((hadPlaylist && !m_currentPlaylist) || !itemPlaylist) {
- m_currentPlaylist = 0;
- m_items.clear();
- }
- else {
- m_currentPlaylist = itemPlaylist;
-
- // We can't use list here, it may not be valid
-
- m_items = itemPlaylist->selectedItems();
- }
-
- if(m_currentPlaylist) {
- connect(m_currentPlaylist, SIGNAL(signalAboutToRemove(PlaylistItem*)),
- this, SLOT(slotItemRemoved(PlaylistItem*)));
- connect(m_currentPlaylist, SIGNAL(destroyed()), this, SLOT(slotPlaylistRemoved()));
- }
-
- if(isVisible())
- slotRefresh();
- else
- m_collectionChanged = true;
-}
-
-void TagEditor::slotRefresh()
-{
- // This method takes the list of currently selected m_items and tries to
- // figure out how to show that in the tag editor. The current strategy --
- // the most common case -- is to just process the first item. Then we
- // check after that to see if there are other m_items and adjust accordingly.
-
- if(m_items.isEmpty() || !m_items.first()->file().tag()) {
- slotClear();
- setEnabled(false);
- return;
- }
-
- setEnabled(true);
-
- PlaylistItem *item = m_items.first();
-
- Q_ASSERT(item);
-
- Tag *tag = item->file().tag();
-
- QFileInfo fi(item->file().absFilePath());
- if(!fi.isWritable() && m_items.count() == 1)
- setEnabled(false);
-
- artistNameBox->setEditText(tag->artist());
- trackNameBox->setText(tag->title());
- albumNameBox->setEditText(tag->album());
-
- fileNameBox->setText(item->file().fileInfo().fileName());
- fileNameBox->setToolTip(item->file().absFilePath());
-
- bitrateBox->setText(QString::number(tag->bitrate()));
- lengthBox->setText(tag->lengthString());
-
- if(m_genreList.indexOf(tag->genre()) >= 0)
- genreBox->setCurrentIndex(m_genreList.indexOf(tag->genre()) + 1);
- else {
- genreBox->setCurrentIndex(0);
- genreBox->setEditText(tag->genre());
- }
-
- trackSpin->setValue(tag->track());
- yearSpin->setValue(tag->year());
-
- commentBox->setPlainText(tag->comment());
-
- // Start at the second item, since we've already processed the first.
-
- PlaylistItemList::Iterator it = m_items.begin();
- ++it;
-
- // If there is more than one item in the m_items that we're dealing with...
-
-
- QList<QWidget *> disabledForMulti;
-
- disabledForMulti << fileNameLabel << fileNameBox << lengthLabel << lengthBox
- << bitrateLabel << bitrateBox;
-
- foreach(QWidget *w, disabledForMulti) {
- w->setDisabled(m_items.size() > 1);
- if(m_items.size() > 1 && !w->inherits("QLabel"))
- QMetaObject::invokeMethod(w, "clear");
- }
-
- if(it != m_items.end()) {
-
- foreach(QCheckBox *box, m_enableBoxes) {
- box->setChecked(true);
- box->show();
- }
-
- // Yep, this is ugly. Loop through all of the files checking to see
- // if their fields are the same. If so, by default, enable their
- // checkbox.
-
- // Also, if there are more than 50 m_items, don't scan all of them.
-
- if(m_items.count() > 50) {
- m_enableBoxes[artistNameBox]->setChecked(false);
- m_enableBoxes[trackNameBox]->setChecked(false);
- m_enableBoxes[albumNameBox]->setChecked(false);
- m_enableBoxes[genreBox]->setChecked(false);
- m_enableBoxes[trackSpin]->setChecked(false);
- m_enableBoxes[yearSpin]->setChecked(false);
- m_enableBoxes[commentBox]->setChecked(false);
- }
- else {
- for(; it != m_items.end(); ++it) {
- tag = (*it)->file().tag();
-
- if(tag) {
-
- if(artistNameBox->currentText() != tag->artist() &&
- m_enableBoxes.contains(artistNameBox))
- {
- artistNameBox->lineEdit()->clear();
- m_enableBoxes[artistNameBox]->setChecked(false);
- }
- if(trackNameBox->text() != tag->title() &&
- m_enableBoxes.contains(trackNameBox))
- {
- trackNameBox->clear();
- m_enableBoxes[trackNameBox]->setChecked(false);
- }
- if(albumNameBox->currentText() != tag->album() &&
- m_enableBoxes.contains(albumNameBox))
- {
- albumNameBox->lineEdit()->clear();
- m_enableBoxes[albumNameBox]->setChecked(false);
- }
- if(genreBox->currentText() != tag->genre() &&
- m_enableBoxes.contains(genreBox))
- {
- genreBox->lineEdit()->clear();
- m_enableBoxes[genreBox]->setChecked(false);
- }
- if(trackSpin->value() != tag->track() &&
- m_enableBoxes.contains(trackSpin))
- {
- trackSpin->setValue(0);
- m_enableBoxes[trackSpin]->setChecked(false);
- }
- if(yearSpin->value() != tag->year() &&
- m_enableBoxes.contains(yearSpin))
- {
- yearSpin->setValue(0);
- m_enableBoxes[yearSpin]->setChecked(false);
- }
- if(commentBox->toPlainText() != tag->comment() &&
- m_enableBoxes.contains(commentBox))
- {
- commentBox->clear();
- m_enableBoxes[commentBox]->setChecked(false);
- }
- }
- }
- }
- }
- else {
- foreach(QCheckBox *box, m_enableBoxes) {
- box->setChecked(true);
- box->hide();
- }
- }
- m_dataChanged = false;
-}
-
-void TagEditor::slotClear()
-{
- artistNameBox->lineEdit()->clear();
- trackNameBox->clear();
- albumNameBox->lineEdit()->clear();
- genreBox->setCurrentIndex(0);
- fileNameBox->clear();
- fileNameBox->setToolTip(QString());
- trackSpin->setValue(0);
- yearSpin->setValue(0);
- lengthBox->clear();
- bitrateBox->clear();
- commentBox->clear();
-}
-
-void TagEditor::slotUpdateCollection()
-{
- if(isVisible())
- updateCollection();
- else
- m_collectionChanged = true;
-}
-
-void TagEditor::updateCollection()
-{
- m_collectionChanged = false;
-
- CollectionList *list = CollectionList::instance();
-
- if(!list)
- return;
-
- QStringList artistList = list->uniqueSet(CollectionList::Artists);
- artistList.sort();
- artistNameBox->clear();
- artistNameBox->addItems(artistList);
- artistNameBox->completionObject()->setItems(artistList);
-
- QStringList albumList = list->uniqueSet(CollectionList::Albums);
- albumList.sort();
- albumNameBox->clear();
- albumNameBox->addItems(albumList);
- albumNameBox->completionObject()->setItems(albumList);
-
- // Merge the list of genres found in tags with the standard ID3v1 set.
-
- StringHash genreHash;
-
- m_genreList = list->uniqueSet(CollectionList::Genres);
-
- foreach(const QString &genre, m_genreList)
- genreHash.insert(genre);
-
- TagLib::StringList genres = TagLib::ID3v1::genreList();
-
- for(TagLib::StringList::Iterator it = genres.begin(); it != genres.end(); ++it)
- genreHash.insert(TStringToQString((*it)));
-
- m_genreList = genreHash.values();
- m_genreList.sort();
-
- genreBox->clear();
- genreBox->addItem(QString());
- genreBox->addItems(m_genreList);
- genreBox->completionObject()->setItems(m_genreList);
-
- // We've cleared out the original entries of these list boxes, re-read
- // the current item if one is selected.
- slotRefresh();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-void TagEditor::readConfig()
-{
- // combo box completion modes
-
- KConfigGroup config(KGlobal::config(), "TagEditor");
- if(artistNameBox && albumNameBox) {
- readCompletionMode(config, artistNameBox, "ArtistNameBoxMode");
- readCompletionMode(config, albumNameBox, "AlbumNameBoxMode");
- readCompletionMode(config, genreBox, "GenreBoxMode");
- }
-
- bool show = config.readEntry("Show", false);
- ActionCollection::action<KToggleAction>("showEditor")->setChecked(show);
- setVisible(show);
-
- TagLib::StringList genres = TagLib::ID3v1::genreList();
-
- for(TagLib::StringList::ConstIterator it = genres.begin(); it != genres.end(); ++it)
- m_genreList.append(TStringToQString((*it)));
- m_genreList.sort();
-
- genreBox->clear();
- genreBox->addItem(QString());
- genreBox->addItems(m_genreList);
- genreBox->completionObject()->setItems(m_genreList);
-}
-
-void TagEditor::readCompletionMode(const KConfigGroup &config, KComboBox *box, const QString &key)
-{
- KGlobalSettings::Completion mode =
- KGlobalSettings::Completion(config.readEntry(key, (int)KGlobalSettings::CompletionAuto));
-
- box->setCompletionMode(mode);
-}
-
-void TagEditor::saveConfig()
-{
- // combo box completion modes
-
- KConfigGroup config(KGlobal::config(), "TagEditor");
-
- if(artistNameBox && albumNameBox) {
- config.writeEntry("ArtistNameBoxMode", (int)artistNameBox->completionMode());
- config.writeEntry("AlbumNameBoxMode", (int)albumNameBox->completionMode());
- config.writeEntry("GenreBoxMode", (int)genreBox->completionMode());
- }
- config.writeEntry("Show", ActionCollection::action<KToggleAction>("showEditor")->isChecked());
-}
-
-void TagEditor::setupActions()
-{
- KToggleAction *show = new KToggleAction(KIcon(QLatin1String("document-properties")),
- i18n("Show &Tag Editor"), this);
- ActionCollection::actions()->addAction("showEditor", show);
- connect(show, SIGNAL(toggled(bool)), this, SLOT(setShown(bool)));
-
- KAction *act = new KAction(KIcon(QLatin1String( "document-save")), i18n("&Save"), this);
- ActionCollection::actions()->addAction("saveItem", act);
- act->setShortcut(Qt::CTRL + Qt::Key_T);
- connect(act, SIGNAL(triggered(bool)), SLOT(slotSave()));
-}
-
-void TagEditor::setupLayout()
-{
- setupUi(this);
-
- foreach(QWidget *input, findChildren<QWidget *>()) {
- if(input->inherits("QLineEdit") || input->inherits("QComboBox"))
- connect(input, SIGNAL(textChanged(QString)), this, SLOT(slotDataChanged()));
- if(input->inherits("QComboxBox"))
- connect(input, SIGNAL(activated(int)), this, SLOT(slotDataChanged()));
- if(input->inherits("QSpinBox"))
- connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotDataChanged()));
- if(input->inherits("QTextEdit"))
- connect(input, SIGNAL(textChanged()), this, SLOT(slotDataChanged()));
- }
-
- // Do some meta-programming to find the matching enable boxes
-
- foreach(QCheckBox *enable, findChildren<QCheckBox *>(QRegExp("Enable"))) {
- enable->hide();
- QRegExp re('^' + enable->objectName().replace("Enable", "") + "(Box|Spin)$");
- QList<QWidget *> targets = findChildren<QWidget *>(re);
- Q_ASSERT(!targets.isEmpty());
- m_enableBoxes[targets.front()] = enable;
- }
-
- // Make sure that the labels are as tall as the enable buttons so that the
- // layout doesn't jump around.
-
- foreach(QLabel *label, findChildren<QLabel *>()) {
- if(m_enableBoxes.contains(label->buddy()))
- label->setMinimumHeight(m_enableBoxes[label->buddy()]->height());
- }
-
- tagEditorLayout->setColumnMinimumWidth(1, 200);
-}
-
-void TagEditor::save(const PlaylistItemList &list)
-{
- if(!list.isEmpty() && m_dataChanged) {
-
- KApplication::setOverrideCursor(Qt::WaitCursor);
- m_dataChanged = false;
- m_performingSave = true;
-
- // The list variable can become corrupted if the playlist holding its
- // items dies, which is possible as we edit tags. So we need to copy
- // the end marker.
-
- PlaylistItemList::ConstIterator end = list.end();
-
- for(PlaylistItemList::ConstIterator it = list.begin(); it != end; /* Deliberately missing */ ) {
-
- // Process items before we being modifying tags, as the dynamic
- // playlists will try to modify the file we edit if the tag changes
- // due to our alterations here.
-
- qApp->processEvents(QEventLoop::ExcludeUserInput);
-
- PlaylistItem *item = *it;
-
- // The playlist can be deleted from under us if this is the last
- // item and we edit it so that it doesn't match the search, which
- // means we can't increment the iterator, so let's do it now.
-
- ++it;
-
- QString fileName = item->file().fileInfo().path() + QDir::separator() +
- fileNameBox->text();
- if(list.count() > 1)
- fileName = item->file().fileInfo().absoluteFilePath();
-
- Tag *tag = TagTransactionManager::duplicateTag(item->file().tag(), fileName);
-
- // A bit more ugliness. If there are multiple files that are
- // being modified, they each have a "enabled" checkbox that
- // says if that field is to be respected for the multiple
- // files. We have to check to see if that is enabled before
- // each field that we write.
-
- if(m_enableBoxes[artistNameBox]->isChecked())
- tag->setArtist(artistNameBox->currentText());
- if(m_enableBoxes[trackNameBox]->isChecked())
- tag->setTitle(trackNameBox->text());
- if(m_enableBoxes[albumNameBox]->isChecked())
- tag->setAlbum(albumNameBox->currentText());
- if(m_enableBoxes[trackSpin]->isChecked()) {
- if(trackSpin->text().isEmpty())
- trackSpin->setValue(0);
- tag->setTrack(trackSpin->value());
- }
- if(m_enableBoxes[yearSpin]->isChecked()) {
- if(yearSpin->text().isEmpty())
- yearSpin->setValue(0);
- tag->setYear(yearSpin->value());
- }
- if(m_enableBoxes[commentBox]->isChecked())
- tag->setComment(commentBox->toPlainText());
-
- if(m_enableBoxes[genreBox]->isChecked())
- tag->setGenre(genreBox->currentText());
-
- TagTransactionManager::instance()->changeTagOnItem(item, tag);
- }
-
- TagTransactionManager::instance()->commit();
- CollectionList::instance()->dataChanged();
- m_performingSave = false;
- KApplication::restoreOverrideCursor();
- }
-}
-
-void TagEditor::saveChangesPrompt()
-{
- if(!isVisible() || !m_dataChanged || m_items.isEmpty())
- return;
-
- QStringList files;
-
- foreach(const PlaylistItem *item, m_items)
- files.append(item->file().absFilePath());
-
- if(KMessageBox::questionYesNoList(this,
- i18n("Do you want to save your changes to:\n"),
- files,
- i18n("Save Changes"),
- KStandardGuiItem::save(),
- KStandardGuiItem::discard(),
- "tagEditor_showSaveChangesBox") == KMessageBox::Yes)
- {
- save(m_items);
- }
-}
-
-void TagEditor::showEvent(QShowEvent *e)
-{
- if(m_collectionChanged) {
- updateCollection();
- }
-
- QWidget::showEvent(e);
-}
-
-bool TagEditor::eventFilter(QObject *watched, QEvent *e)
-{
- QKeyEvent *ke = static_cast<QKeyEvent*>(e);
- if(watched->inherits("QSpinBox") && e->type() == QEvent::KeyRelease && ke->modifiers() == 0)
- slotDataChanged();
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// private slots
-////////////////////////////////////////////////////////////////////////////////
-
-void TagEditor::slotDataChanged(bool c)
-{
- m_dataChanged = c;
-}
-
-void TagEditor::slotItemRemoved(PlaylistItem *item)
-{
- m_items.removeAll(item);
- if(m_items.isEmpty())
- slotRefresh();
-}
-
-void TagEditor::slotPlaylistDestroyed(Playlist *p)
-{
- if(m_currentPlaylist == p) {
- m_currentPlaylist = 0;
- slotSetItems(PlaylistItemList());
- }
-}
-
-#include "tageditor.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAGEDITOR_H
-#define TAGEDITOR_H
-
-#include <QWidget>
-#include <QList>
-#include <QMap>
-
-#include "ui_tageditor.h"
-
-class KComboBox;
-class KLineEdit;
-class KIntSpinBox;
-class KTextEdit;
-class KConfigGroup;
-
-class QCheckBox;
-class QBoxLayout;
-
-class CollectionObserver;
-class Playlist;
-class PlaylistItem;
-
-typedef QList<PlaylistItem *> PlaylistItemList;
-
-class TagEditor : public QWidget, public Ui::TagEditor
-{
- Q_OBJECT
-
-public:
- TagEditor(QWidget *parent = 0);
- virtual ~TagEditor();
- PlaylistItemList items() const { return m_items; }
- void setupObservers();
-
-public slots:
- void slotSave() { save(m_items); }
- void slotSetItems(const PlaylistItemList &list);
- void slotRefresh();
- void slotClear();
- void slotPlaylistDestroyed(Playlist *p);
- /**
- * Update collection if we're visible, or defer otherwise
- */
- void slotUpdateCollection();
-
-private:
- void updateCollection();
-
- void setupActions();
- void setupLayout();
- void readConfig();
- void readCompletionMode(const KConfigGroup &config, KComboBox *box, const QString &key);
- void saveConfig();
- void save(const PlaylistItemList &list);
- void saveChangesPrompt();
- virtual void showEvent(QShowEvent *e);
- virtual bool eventFilter(QObject *watched, QEvent *e);
-
-private slots:
- void slotDataChanged(bool c = true);
- void slotItemRemoved(PlaylistItem *item);
- void slotPlaylistRemoved() { m_currentPlaylist = 0; }
-
-private:
- typedef QMap<QWidget *, QCheckBox *> BoxMap;
- BoxMap m_enableBoxes;
-
- QStringList m_genreList;
-
- PlaylistItemList m_items;
- Playlist *m_currentPlaylist;
-
- CollectionObserver *m_observer;
-
- bool m_dataChanged;
- bool m_collectionChanged;
- bool m_performingSave;
-
- friend class CollectionObserver;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TagEditor</class>
- <widget class="QWidget" name="TagEditor">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>622</width>
- <height>221</height>
- </rect>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <layout class="QGridLayout" name="tagEditorLayout">
- <item row="0" column="3" colspan="7">
- <widget class="QLabel" name="fileNameLabel">
- <property name="text">
- <string>F&ile name:</string>
- </property>
- <property name="buddy">
- <cstring>fileNameBox</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QLabel" name="trackLabel">
- <property name="text">
- <string>T&rack:</string>
- </property>
- <property name="buddy">
- <cstring>trackSpin</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="artistNameLabel">
- <property name="text">
- <string>&Artist name:</string>
- </property>
- <property name="buddy">
- <cstring>artistNameBox</cstring>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="albumNameLabel">
- <property name="text">
- <string>Album &name:</string>
- </property>
- <property name="buddy">
- <cstring>albumNameBox</cstring>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="genreLabel">
- <property name="text">
- <string>&Genre:</string>
- </property>
- <property name="buddy">
- <cstring>genreBox</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="3" colspan="7">
- <widget class="KLineEdit" name="fileNameBox"/>
- </item>
- <item row="2" column="7">
- <widget class="QLabel" name="yearLabel">
- <property name="text">
- <string>&Year:</string>
- </property>
- <property name="buddy">
- <cstring>yearSpin</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="4">
- <widget class="KLineEdit" name="lengthBox">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="8">
- <widget class="KLineEdit" name="bitrateBox">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="3">
- <widget class="QLabel" name="lengthLabel">
- <property name="text">
- <string>&Length:</string>
- </property>
- <property name="buddy">
- <cstring>lengthBox</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="7">
- <widget class="QLabel" name="bitrateLabel">
- <property name="text">
- <string>&Bitrate:</string>
- </property>
- <property name="buddy">
- <cstring>bitrateBox</cstring>
- </property>
- </widget>
- </item>
- <item row="4" column="3" colspan="2">
- <widget class="QLabel" name="commentLabel">
- <property name="text">
- <string>&Comment:</string>
- </property>
- <property name="buddy">
- <cstring>commentBox</cstring>
- </property>
- </widget>
- </item>
- <item row="5" column="3" rowspan="4" colspan="7">
- <widget class="KTextEdit" name="commentBox"/>
- </item>
- <item row="8" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="5" column="0" colspan="2">
- <widget class="KComboBox" name="albumNameBox">
- <property name="editable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="7" column="0" colspan="2">
- <widget class="KComboBox" name="genreBox">
- <property name="editable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="KComboBox" name="artistNameBox">
- <property name="editable">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="4">
- <widget class="KIntSpinBox" name="trackSpin">
- <property name="maximum">
- <number>999</number>
- </property>
- </widget>
- </item>
- <item row="2" column="8">
- <widget class="KIntSpinBox" name="yearSpin">
- <property name="maximum">
- <number>9999</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2" rowspan="8">
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="trackNameLabel">
- <property name="text">
- <string>Trac&k name:</string>
- </property>
- <property name="buddy">
- <cstring>trackNameBox</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="artistNameEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="KLineEdit" name="trackNameBox"/>
- </item>
- <item row="2" column="1">
- <widget class="QCheckBox" name="trackNameEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QCheckBox" name="albumNameEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="6" column="1">
- <widget class="QCheckBox" name="genreEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="2" column="5">
- <widget class="QCheckBox" name="trackEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="2" column="9">
- <widget class="QCheckBox" name="yearEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="4" column="5" colspan="5">
- <widget class="QCheckBox" name="commentEnable">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item row="2" column="6" rowspan="2">
- <widget class="Line" name="line_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KIntSpinBox</class>
- <extends>QSpinBox</extends>
- <header>knuminput.h</header>
- </customwidget>
- <customwidget>
- <class>KLineEdit</class>
- <extends>KLineEdit</extends>
- <header>klineedit.h</header>
- </customwidget>
- <customwidget>
- <class>KComboBox</class>
- <extends>QComboBox</extends>
- <header>kcombobox.h</header>
- </customwidget>
- <customwidget>
- <class>KTextEdit</class>
- <extends>QTextEdit</extends>
- <header>ktextedit.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections>
- <connection>
- <sender>artistNameEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>artistNameBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>141</x>
- <y>21</y>
- </hint>
- <hint type="destinationlabel">
- <x>138</x>
- <y>43</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>trackNameEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>trackNameBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>102</x>
- <y>71</y>
- </hint>
- <hint type="destinationlabel">
- <x>104</x>
- <y>90</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>albumNameEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>albumNameBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>126</x>
- <y>122</y>
- </hint>
- <hint type="destinationlabel">
- <x>125</x>
- <y>151</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>genreEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>genreBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>147</x>
- <y>170</y>
- </hint>
- <hint type="destinationlabel">
- <x>147</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>trackEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>trackSpin</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>330</x>
- <y>66</y>
- </hint>
- <hint type="destinationlabel">
- <x>303</x>
- <y>68</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>commentEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>commentBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>337</x>
- <y>121</y>
- </hint>
- <hint type="destinationlabel">
- <x>344</x>
- <y>156</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>yearEnable</sender>
- <signal>toggled(bool)</signal>
- <receiver>yearSpin</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>558</x>
- <y>66</y>
- </hint>
- <hint type="destinationlabel">
- <x>510</x>
- <y>69</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tagguesser.h"
-
-#include <kapplication.h>
-#include <kconfig.h>
-#include <kdebug.h>
-#include <kglobal.h>
-#include <kmacroexpander.h>
-#include <qhash.h>
-#include <kconfiggroup.h>
-
-FileNameScheme::FileNameScheme(const QString &s)
- : m_regExp(),
- m_titleField(-1),
- m_artistField(-1),
- m_albumField(-1),
- m_trackField(-1),
- m_commentField(-1)
-{
- int fieldNumber = 1;
- int i = s.indexOf('%');
- while (i > -1) {
- switch (s[ i + 1 ].toLatin1()) {
- case 't': m_titleField = fieldNumber++;
- break;
- case 'a': m_artistField = fieldNumber++;
- break;
- case 'A': m_albumField = fieldNumber++;
- break;
- case 'T': m_trackField = fieldNumber++;
- break;
- case 'c': m_commentField = fieldNumber++;
- break;
- default:
- break;
- }
- i = s.indexOf('%', i + 1);
- }
- m_regExp.setPattern(composeRegExp(s));
-}
-
-bool FileNameScheme::matches(const QString &fileName) const
-{
- /* Strip extension ('.mp3') because '.' may be part of a title, and thus
- * does not work as a separator.
- */
- QString stripped = fileName;
- stripped.truncate(stripped.lastIndexOf('.'));
- return m_regExp.exactMatch(stripped);
-}
-
-QString FileNameScheme::title() const
-{
- if(m_titleField == -1)
- return QString();
- return m_regExp.capturedTexts()[ m_titleField ];
-}
-
-QString FileNameScheme::artist() const
-{
- if(m_artistField == -1)
- return QString();
- return m_regExp.capturedTexts()[ m_artistField ];
-}
-
-QString FileNameScheme::album() const
-{
- if(m_albumField == -1)
- return QString();
- return m_regExp.capturedTexts()[ m_albumField ];
-}
-
-QString FileNameScheme::track() const
-{
- if(m_trackField == -1)
- return QString();
- return m_regExp.capturedTexts()[ m_trackField ];
-}
-
-QString FileNameScheme::comment() const
-{
- if(m_commentField == -1)
- return QString();
- return m_regExp.capturedTexts()[ m_commentField ];
-}
-
-QString FileNameScheme::composeRegExp(const QString &s) const
-{
- QHash<QChar, QString> substitutions;
-
- KConfigGroup config(KGlobal::config(), "TagGuesser");
-
- substitutions[ 't' ] = config.readEntry("Title regexp", "([\\w\\s'&_,\\.]+)");
- substitutions[ 'a' ] = config.readEntry("Artist regexp", "([\\w\\s'&_,\\.]+)");
- substitutions[ 'A' ] = config.readEntry("Album regexp", "([\\w\\s'&_,\\.]+)");
- substitutions[ 'T' ] = config.readEntry("Track regexp", "(\\d+)");
- substitutions[ 'c' ] = config.readEntry("Comment regexp", "([\\w\\s_]+)");
-
- QString regExp = QRegExp::escape(s.simplified());
- regExp = ".*" + regExp;
- regExp.replace(' ', "\\s+");
- regExp = KMacroExpander::expandMacros(regExp, substitutions);
- regExp += "[^/]*$";
- return regExp;
-}
-
-QStringList TagGuesser::schemeStrings()
-{
- QStringList schemes;
-
- KConfigGroup config(KGlobal::config(), "TagGuesser");
- schemes = config.readEntry("Filename schemes", QStringList());
-
- if ( schemes.isEmpty() ) {
- schemes += "%a - (%T) - %t [%c]";
- schemes += "%a - (%T) - %t (%c)";
- schemes += "%a - (%T) - %t";
- schemes += "%a - [%T] - %t [%c]";
- schemes += "%a - [%T] - %t (%c)";
- schemes += "%a - [%T] - %t";
- schemes += "%a - %T - %t [%c]";
- schemes += "%a - %T - %t (%c)";
- schemes += "%a - %T - %t";
- schemes += "(%T) %a - %t [%c]";
- schemes += "(%T) %a - %t (%c)";
- schemes += "(%T) %a - %t";
- schemes += "[%T] %a - %t [%c]";
- schemes += "[%T] %a - %t (%c)";
- schemes += "[%T] %a - %t";
- schemes += "%T %a - %t [%c]";
- schemes += "%T %a - %t (%c)";
- schemes += "%T %a - %t";
- schemes += "(%a) %t [%c]";
- schemes += "(%a) %t (%c)";
- schemes += "(%a) %t";
- schemes += "%a - %t [%c]";
- schemes += "%a - %t (%c)";
- schemes += "%a - %t";
- schemes += "%a/%A/[%T] %t [%c]";
- schemes += "%a/%A/[%T] %t (%c)";
- schemes += "%a/%A/[%T] %t";
- }
- return schemes;
-}
-
-void TagGuesser::setSchemeStrings(const QStringList &schemes)
-{
- KSharedConfig::Ptr cfg = KGlobal::config();
- KConfigGroup group(cfg, "TagGuesser");
- group.writeEntry("Filename schemes", schemes);
- cfg->sync();
-}
-
-TagGuesser::TagGuesser()
-{
- loadSchemes();
-}
-
-TagGuesser::TagGuesser(const QString &absFileName)
-{
- loadSchemes();
- guess(absFileName);
-}
-
-void TagGuesser::loadSchemes()
-{
- const QStringList schemes = schemeStrings();
- QStringList::ConstIterator it = schemes.begin();
- QStringList::ConstIterator end = schemes.end();
- for ( ; it != end; ++it )
- m_schemes += FileNameScheme( *it );
-}
-
-void TagGuesser::guess(const QString &absFileName)
-{
- m_title.clear();
- m_artist.clear();
- m_album.clear();
- m_track.clear();
- m_comment.clear();
-
- FileNameScheme::List::ConstIterator it = m_schemes.constBegin();
- FileNameScheme::List::ConstIterator end = m_schemes.constEnd();
- for (; it != end; ++it) {
- const FileNameScheme schema(*it);
- if(schema.matches(absFileName)) {
- m_title = capitalizeWords(schema.title().replace('_', " ")).trimmed();
- m_artist = capitalizeWords(schema.artist().replace('_', " ")).trimmed();
- m_album = capitalizeWords(schema.album().replace('_', " ")).trimmed();
- m_track = schema.track().trimmed();
- m_comment = schema.comment().replace('_', " ").trimmed();
- break;
- }
- }
-}
-
-QString TagGuesser::capitalizeWords(const QString &s)
-{
- if(s.isEmpty())
- return s;
-
- QString result = s;
- result[ 0 ] = result[ 0 ].toUpper();
-
- const QRegExp wordRegExp("\\s\\w");
- int i = result.indexOf( wordRegExp );
- while ( i > -1 ) {
- result[ i + 1 ] = result[ i + 1 ].toUpper();
- i = result.indexOf( wordRegExp, ++i );
- }
-
- return result;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAGGUESSER_H
-#define TAGGUESSER_H
-
-#include <QString>
-#include <QRegExp>
-#include <QList>
-
-class FileNameScheme
-{
- public:
- typedef QList<FileNameScheme> List;
-
- FileNameScheme() { }
- FileNameScheme(const QString &s);
-
- bool matches(const QString &s) const;
-
- QString title() const;
- QString artist() const;
- QString album() const;
- QString track() const;
- QString comment() const;
-
- private:
- QString composeRegExp(const QString &s) const;
-
- mutable QRegExp m_regExp;
- int m_titleField;
- int m_artistField;
- int m_albumField;
- int m_trackField;
- int m_commentField;
-};
-
-class TagGuesser
-{
- public:
-
- enum Type { FileName = 0, MusicBrainz = 1 };
-
- static QStringList schemeStrings();
- static void setSchemeStrings(const QStringList &schemes);
-
- TagGuesser();
- TagGuesser(const QString &absFileName);
-
- void guess(const QString &absFileName);
-
- QString title() const { return m_title; }
- QString artist() const { return m_artist; }
- QString album() const { return m_album; }
- QString track() const { return m_track; }
- QString comment() const { return m_comment; }
-
- private:
- void loadSchemes();
- QString capitalizeWords(const QString &s);
-
- FileNameScheme::List m_schemes;
- QString m_title;
- QString m_artist;
- QString m_album;
- QString m_track;
- QString m_comment;
-};
-
-#endif // TAGGUESSER_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tagguesserconfigdlg.h"
-#include "tagguesser.h"
-
-#include <kicon.h>
-#include <klocale.h>
-#include <kpushbutton.h>
-#include <klineedit.h>
-#include <kapplication.h>
-
-#include <QKeyEvent>
-#include <QStringListModel>
-
-TagGuesserConfigDlg::TagGuesserConfigDlg(QWidget *parent, const char *name)
- : KDialog(parent)
-{
- setObjectName( QLatin1String( name ) );
- setModal(true);
- setCaption(i18n("Tag Guesser Configuration"));
- setButtons(Ok | Cancel);
- setDefaultButton(Ok);
- showButtonSeparator(true);
-
- m_child = new TagGuesserConfigDlgWidget(this);
- setMainWidget(m_child);
-
- m_child->bMoveUp->setIcon(KIcon( QLatin1String( "arrow-up" )));
- m_child->bMoveDown->setIcon(KIcon( QLatin1String( "arrow-down" )));
-
- m_tagSchemeModel = new QStringListModel(m_child->lvSchemes);
- m_child->lvSchemes->setModel(m_tagSchemeModel);
- m_child->lvSchemes->setHeaderHidden(true);
- m_tagSchemeModel->setStringList(TagGuesser::schemeStrings());
-
- connect(m_child->lvSchemes, SIGNAL(clicked(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)));
- connect(m_child->bMoveUp, SIGNAL(clicked()), this, SLOT(slotMoveUpClicked()));
- connect(m_child->bMoveDown, SIGNAL(clicked()), this, SLOT(slotMoveDownClicked()));
- connect(m_child->bAdd, SIGNAL(clicked()), this, SLOT(slotAddClicked()));
- connect(m_child->bModify, SIGNAL(clicked()), this, SLOT(slotModifyClicked()));
- connect(m_child->bRemove, SIGNAL(clicked()), this, SLOT(slotRemoveClicked()));
-
- resize( 400, 300 );
-}
-
-void TagGuesserConfigDlg::slotCurrentChanged(QModelIndex item)
-{
- m_child->bRemove->setEnabled(m_tagSchemeModel->rowCount() != 0);
-
- // Ensure up/down buttons are appropriately enabled.
-
- if (!m_tagSchemeModel->rowCount() || item == m_tagSchemeModel->index(0, 0, QModelIndex()))
- m_child->bMoveUp->setEnabled(false);
- else
- m_child->bMoveUp->setEnabled(true);
-
- if (!m_tagSchemeModel->rowCount() || item == m_tagSchemeModel->index(m_tagSchemeModel->rowCount(QModelIndex())-1, 0, QModelIndex()))
- m_child->bMoveDown->setEnabled(false);
- else
- m_child->bMoveDown->setEnabled(true);
-}
-
-void TagGuesserConfigDlg::slotMoveUpClicked()
-{
- QModelIndex currentItem = m_child->lvSchemes->currentIndex();
- int row = currentItem.row();
-
- m_tagSchemeModel->insertRow(row - 1); // Insert in front of item above
- row++; // Now we're one row down
-
- QModelIndex newItem = m_tagSchemeModel->index(row - 2, 0);
-
- // Copy over, then delete old item
- currentItem = m_tagSchemeModel->index(row, 0);
- m_tagSchemeModel->setData(newItem, m_tagSchemeModel->data(currentItem, Qt::DisplayRole), Qt::DisplayRole);
- m_tagSchemeModel->removeRow(row);
-
- m_child->lvSchemes->setCurrentIndex(newItem);
- slotCurrentChanged(newItem);
-}
-
-void TagGuesserConfigDlg::slotMoveDownClicked()
-{
- QModelIndex currentItem = m_child->lvSchemes->currentIndex();
- int row = currentItem.row();
-
- m_tagSchemeModel->insertRow(row + 2); // Insert in front of 2 items below
-
- QModelIndex newItem = m_tagSchemeModel->index(row + 2, 0);
-
- // Copy over, then delete old item
- currentItem = m_tagSchemeModel->index(row, 0);
- m_tagSchemeModel->setData(newItem, m_tagSchemeModel->data(currentItem, Qt::DisplayRole), Qt::DisplayRole);
- m_tagSchemeModel->removeRow(row);
-
- newItem = m_tagSchemeModel->index(row + 1, 0);
- m_child->lvSchemes->setCurrentIndex(newItem);
- slotCurrentChanged(newItem);
-}
-
-void TagGuesserConfigDlg::slotAddClicked()
-{
- m_tagSchemeModel->insertRow(0, QModelIndex());
- m_child->lvSchemes->setCurrentIndex(m_tagSchemeModel->index(0, 0, QModelIndex()));
- m_child->lvSchemes->edit(m_child->lvSchemes->currentIndex());
- slotCurrentChanged(m_child->lvSchemes->currentIndex());
-}
-
-void TagGuesserConfigDlg::slotModifyClicked()
-{
- m_child->lvSchemes->edit(m_child->lvSchemes->currentIndex());
-}
-
-void TagGuesserConfigDlg::slotRemoveClicked()
-{
- m_tagSchemeModel->removeRow(m_child->lvSchemes->currentIndex().row(), QModelIndex());
- slotCurrentChanged(m_child->lvSchemes->currentIndex());
-}
-
-void TagGuesserConfigDlg::accept()
-{
- TagGuesser::setSchemeStrings(m_tagSchemeModel->stringList());
- KDialog::accept();
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAGGUESSERCONFIGDLG_H
-#define TAGGUESSERCONFIGDLG_H
-
-#include <kdialog.h>
-#include "ui_tagguesserconfigdlgwidget.h"
-
-class QStringListModel;
-
-
-class TagGuesserConfigDlgWidget : public QWidget, public Ui::TagGuesserConfigDlgWidget
-{
-public:
- TagGuesserConfigDlgWidget( QWidget *parent ) : QWidget( parent ) {
- setupUi( this );
- }
-};
-
-class TagGuesserConfigDlg : public KDialog
-{
- Q_OBJECT
- public:
- explicit TagGuesserConfigDlg(QWidget *parent, const char *name = 0);
-
- protected slots:
- virtual void accept();
-
- private slots:
- void slotCurrentChanged(QModelIndex item);
- void slotMoveUpClicked();
- void slotMoveDownClicked();
- void slotAddClicked();
- void slotModifyClicked();
- void slotRemoveClicked();
-
- private:
- TagGuesserConfigDlgWidget *m_child;
- QStringListModel *m_tagSchemeModel;
-};
-
-#endif // TAGGUESSERCONFIGDLG_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <author>Frerich Raabe <raabe@kde.org></author>
- <class>TagGuesserConfigDlgWidget</class>
- <widget class="QWidget" name="TagGuesserConfigDlgWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>671</width>
- <height>530</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0" rowspan="6">
- <widget class="QTreeView" name="lvSchemes">
- <property name="toolTip">
- <string>Currently used file name schemes</string>
- </property>
- <property name="whatsThis">
- <string>Here you can see the currently configured file name schemes which the "Guess Tag Information From File Name" entry in the song's context menu uses to extract tag information from a file name. Each string may contain one of the following placeholders:<ul>
-<li>%t: Title</li>
-<li>%a: Artist</li>
-<li>%A: Album</li>
-<li>%T: Track</li>
-<li>%c: Comment</li>
-</ul>
-For example, the file name scheme "[%T] %a - %t" would match "[01] Deep Purple - Smoke on the water" but not "(Deep Purple) Smoke on the water". For that second name, you would use the scheme "(%a) %t".<p/>
-Note that the order in which the schemes appear in the list is relevant, since the tag guesser will go through the list from the top to the bottom, and use the first matching scheme.</string>
- </property>
- <property name="rootIsDecorated">
- <bool>false</bool>
- </property>
- <property name="expandsOnDoubleClick">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QToolButton" name="bMoveUp">
- <property name="toolTip">
- <string>Move scheme up</string>
- </property>
- <property name="whatsThis">
- <string>Press this button to move the currently selected scheme one step upwards.</string>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QToolButton" name="bMoveDown">
- <property name="toolTip">
- <string>Move scheme down</string>
- </property>
- <property name="whatsThis">
- <string>Press this button to move the currently selected scheme one step downwards.</string>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="1" column="1" colspan="3">
- <widget class="KPushButton" name="bAdd">
- <property name="toolTip">
- <string>Add a new scheme</string>
- </property>
- <property name="whatsThis">
- <string>Press this button to add a new file name scheme to the end of the list.</string>
- </property>
- <property name="text">
- <string>&Add</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="3">
- <widget class="KPushButton" name="bModify">
- <property name="toolTip">
- <string>Modify scheme</string>
- </property>
- <property name="whatsThis">
- <string>Press this button to modify the currently selected scheme.</string>
- </property>
- <property name="text">
- <string>&Modify</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1" colspan="3">
- <widget class="KPushButton" name="bRemove">
- <property name="toolTip">
- <string>Remove scheme</string>
- </property>
- <property name="whatsThis">
- <string>Press this button to remove the currently selected scheme from the list.</string>
- </property>
- <property name="text">
- <string>&Remove</string>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <spacer name="spacer1">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>130</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="5" column="2">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>You can use the following placeholders:
-%t: Title
-%A: Album
-%a: Artist
-%T: Track
-%c: Comment</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KPushButton</class>
- <extends>QPushButton</extends>
- <header>kpushbutton.h</header>
- </customwidget>
- </customwidgets>
- <includes>
- <include location="local">kpushbutton.h</include>
- </includes>
- <resources/>
- <connections/>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tagrenameroptions.h"
-
-#include <kdebug.h>
-#include <kglobal.h>
-#include <klocale.h>
-#include <kconfig.h>
-#include <kconfigbase.h>
-#include <kconfiggroup.h>
-
-TagRenamerOptions::TagRenamerOptions() :
- m_emptyAction(IgnoreEmptyTag),
- m_trackWidth(0),
- m_disabled(true),
- m_category(TagUnknown)
-{
-}
-
-TagRenamerOptions::TagRenamerOptions(const TagRenamerOptions &other) :
- m_prefix(other.m_prefix),
- m_suffix(other.m_suffix),
- m_emptyAction(other.m_emptyAction),
- m_emptyText(other.m_emptyText),
- m_trackWidth(other.m_trackWidth),
- m_disabled(other.m_disabled),
- m_category(other.m_category)
-{
-}
-
-TagRenamerOptions::TagRenamerOptions(const CategoryID &category)
- : m_category(category.category)
-{
- // Set some defaults
-
- bool disabled;
- unsigned categoryNum = category.categoryNumber;
-
- switch(category.category) {
- case Title:
- case Artist:
- case Genre:
- case Year:
- case Album:
- case Track:
- disabled = false;
- break;
- default:
- disabled = true;
- }
-
- // Make sure we don't use translated strings for the config file keys.
-
- QString typeKey = tagTypeText(category.category, false);
- KConfigGroup config(KGlobal::config(), "FileRenamer");
-
- if(categoryNum > 0)
- typeKey.append(QString::number(categoryNum));
-
- setSuffix(config.readEntry(QString("%1Suffix").arg(typeKey), QString()));
- setPrefix(config.readEntry(QString("%1Prefix").arg(typeKey), QString()));
-
- // Default the emptyAction to ignoring the empty tag.
-
- const QString emptyAction = config.readEntry(QString("%1EmptyAction").arg(typeKey), QString()).toLower();
- setEmptyAction(IgnoreEmptyTag);
-
- if(emptyAction == "forceemptyinclude")
- setEmptyAction(ForceEmptyInclude);
- else if(emptyAction == "usereplacementvalue")
- setEmptyAction(UseReplacementValue);
-
- setEmptyText(config.readEntry(QString("%1EmptyText").arg(typeKey), QString()));
- setTrackWidth(config.readEntry(QString("%1TrackWidth").arg(typeKey), 0));
- setDisabled(config.readEntry(QString("%1Disabled").arg(typeKey), disabled));
-}
-
-QString TagRenamerOptions::tagTypeText(TagType type, bool translate)
-{
- const char *msg = 0, *context = 0;
-
- switch(type) {
- case Title:
- msg = I18N_NOOP2("song title", "Title");
- context = "song title";
- break;
-
- case Artist:
- msg = I18N_NOOP("Artist");
- break;
-
- case Album:
- msg = I18N_NOOP("Album");
- break;
-
- case Track:
- msg = I18N_NOOP2("cd track number", "Track");
- context = "cd track number";
- break;
-
- case Genre:
- msg = I18N_NOOP("Genre");
- break;
-
- case Year:
- msg = I18N_NOOP("Year");
- break;
-
- default:
- kWarning() << "I don't know what category we're looking up, this is a problem.";
- kWarning() << "The category ID is " << (unsigned) type;
- msg = I18N_NOOP2("unknown renamer category", "Unknown");
- context = "unknown renamer category";
- }
-
- if(translate)
- return context ? i18nc(context, msg) : i18n(msg);
- else
- return msg;
-}
-
-void TagRenamerOptions::saveConfig(unsigned categoryNum) const
-{
- // Make sure we don't use translated strings for the config file keys.
-
- QString typeKey = tagTypeText(false);
- if(categoryNum > 0)
- typeKey.append(QString::number(categoryNum));
-
- KConfigGroup config(KGlobal::config(), "FileRenamer");
-
- config.writeEntry(QString("%1Suffix").arg(typeKey), suffix());
- config.writeEntry(QString("%1Prefix").arg(typeKey), prefix());
-
- QString emptyStr;
-
- switch(emptyAction()) {
- case ForceEmptyInclude:
- emptyStr = "ForceEmptyInclude";
- break;
-
- case IgnoreEmptyTag:
- emptyStr = "IgnoreEmptyTag";
- break;
-
- case UseReplacementValue:
- emptyStr = "UseReplacementValue";
- break;
- }
-
- config.writeEntry(QString("%1EmptyAction").arg(typeKey), emptyStr);
- config.writeEntry(QString("%1EmptyText").arg(typeKey), emptyText());
- config.writeEntry(QString("%1Disabled").arg(typeKey), disabled());
-
- if(category() == Track)
- config.writeEntry(QString("%1TrackWidth").arg(typeKey), trackWidth());
-
- config.sync();
-}
-
-TagType TagRenamerOptions::tagFromCategoryText(const QString &text)
-{
- for(unsigned i = StartTag; i < NumTypes; ++i)
- if(tagTypeText(static_cast<TagType>(i), false) == text)
- return static_cast<TagType>(i);
-
- return TagUnknown;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAGRENAMEROPTIONS_H
-#define TAGRENAMEROPTIONS_H
-
-#include <QtCore/QString>
-
-// Insert all new tag types before NumTypes, that way NumTypes will always be
-// the count of valid tag types.
-enum TagType {
- StartTag, Title = StartTag, Artist, Album,
- Track, Genre, Year, NumTypes, TagUnknown
-};
-
-/**
- * Class that uniquely identifies a user's category (since the user may have
- * the same category more than once in their file renaming structure).
- */
-struct CategoryID
-{
- CategoryID() : category(TagUnknown), categoryNumber(0)
- {
- }
-
- CategoryID(const CategoryID &other) : category(other.category),
- categoryNumber(other.categoryNumber)
- {
- }
-
- CategoryID(TagType cat, unsigned num) : category(cat), categoryNumber(num)
- {
- }
-
- CategoryID &operator=(const CategoryID &other)
- {
- if(this == &other)
- return *this;
-
- category = other.category;
- categoryNumber = other.categoryNumber;
-
- return *this;
- }
-
- bool operator==(const CategoryID &other) const
- {
- return category == other.category && categoryNumber == other.categoryNumber;
- }
-
- bool operator!=(const CategoryID &other) const
- {
- return !(*this == other);
- }
-
- bool operator<(const CategoryID &other) const
- {
- if(category == other.category)
- return categoryNumber < other.categoryNumber;
-
- return category < other.category;
- }
-
- TagType category;
- unsigned categoryNumber;
-};
-
-/**
- * Defines options for a tag type. Used by FileRenamerTagOptions as its
- * data type.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class TagRenamerOptions
-{
-public:
- enum EmptyActions { ForceEmptyInclude, IgnoreEmptyTag, UseReplacementValue };
-
- TagRenamerOptions();
-
- /**
- * Construct the options by loading from KConfig.
- *
- * @param category The category to load the options for.
- */
- TagRenamerOptions(const CategoryID &category);
- TagRenamerOptions(const TagRenamerOptions &other);
-
- QString prefix() const { return m_prefix; }
- QString suffix() const { return m_suffix; }
- QString emptyText() const { return m_emptyText; }
- EmptyActions emptyAction() const { return m_emptyAction; }
- unsigned trackWidth() const { return m_trackWidth; }
- bool disabled() const { return m_disabled; }
- TagType category() const { return m_category; }
-
- void setPrefix(const QString &prefix) { m_prefix = prefix; }
- void setSuffix(const QString &suffix) { m_suffix = suffix; }
- void setEmptyText(const QString &emptyText) { m_emptyText = emptyText; }
- void setEmptyAction(EmptyActions action) { m_emptyAction = action; }
- void setTrackWidth(unsigned width) { m_trackWidth = width; }
- void setDisabled(bool disabled) { m_disabled = disabled; }
- void setCategory(TagType category) { m_category = category; }
-
- /**
- * Maps \p type to a textual representation of its name. E.g. Track => "Track"
- *
- * @param type the category to retrieve a text representation of.
- * @param translate if true, the string is translated (if possible).
- * @return text representation of category.
- */
- static QString tagTypeText(TagType category, bool translate = true);
-
- QString tagTypeText(bool translate = true) const
- {
- return tagTypeText(category(), translate);
- }
-
- /**
- * Function that tries to match a string back to its category. Uses only
- * the untranslated and case-sensitive form of the string. If it fails it
- * will return TagUnknown.
- */
- static TagType tagFromCategoryText(const QString &text);
-
- /**
- * This saves the options to the global KConfig object.
- *
- * @param categoryNum The zero-based count of the number of this type of
- * category. For example, this would be 1 for the
- * second category of this type. The stored category
- * number is not used in order to allow you to save with
- * a different one (for compaction purposes perhaps).
- */
- void saveConfig(unsigned categoryNum) const;
-
-private:
-
- // Member variables
-
- QString m_prefix;
- QString m_suffix;
-
- /// Defines the action to take when the tag is empty.
- EmptyActions m_emptyAction;
-
- /// If m_emptyAction is UseReplacementValue, this holds the text of the value
- /// to use.
- QString m_emptyText;
-
- /// Used only for the Track type. Defines the minimum track width when
- /// expanding the track token.
- unsigned m_trackWidth;
-
- /// This is true if this tag is always disabled when expanding file names.
- bool m_disabled;
-
- TagType m_category;
-};
-
-#endif /* TAGRENAMEROPTIONS_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tagtransactionmanager.h"
-
-#include <kdebug.h>
-#include <klocale.h>
-#include <kmessagebox.h>
-#include <kaction.h>
-#include <kapplication.h>
-
-#include <QFileInfo>
-#include <QDir>
-
-#include "playlistitem.h"
-#include "collectionlist.h"
-#include "tag.h"
-#include "actioncollection.h"
-
-using ActionCollection::action;
-
-TagTransactionManager *TagTransactionManager::m_manager = 0;
-
-TagTransactionAtom::TagTransactionAtom() : m_item(0), m_tag(0)
-{
- action("edit_undo")->setEnabled(false);
-}
-
-TagTransactionAtom::TagTransactionAtom(const TagTransactionAtom &other) :
- m_item(other.m_item), m_tag(other.m_tag)
-{
- other.m_tag = 0; // Only allow one owner
-}
-
-TagTransactionAtom::TagTransactionAtom(PlaylistItem *item, Tag *tag) :
- m_item(item), m_tag(tag)
-{
-}
-
-TagTransactionAtom::~TagTransactionAtom()
-{
- delete m_tag;
-}
-
-TagTransactionAtom &TagTransactionAtom::operator=(const TagTransactionAtom &other)
-{
- m_item = other.m_item;
- m_tag = other.m_tag;
-
- other.m_tag = 0; // Only allow one owner
-
- return *this;
-}
-
-TagTransactionManager *TagTransactionManager::instance()
-{
- return m_manager;
-}
-
-void TagTransactionManager::changeTagOnItem(PlaylistItem *item, Tag *newTag)
-{
- if(!item) {
- kWarning() << "Trying to change tag on null PlaylistItem.\n";
- return;
- }
-
- // Save the CollectionListItem, as it is the most likely to survive long
- // enough for the commit(). I should probably intercept the item deleted
- // signals from CollectionList to ensure that the commit list and the
- // playlists stay in sync.
-
- m_list.append(TagTransactionAtom(item->collectionItem(), newTag));
-}
-
-Tag *TagTransactionManager::duplicateTag(const Tag *tag, const QString &fileName)
-{
- Q_ASSERT(tag);
-
- QString name = fileName.isEmpty() ? tag->fileName() : fileName;
- Tag *newTag = new Tag(*tag);
-
- newTag->setFileName(name);
- return newTag;
-}
-
-bool TagTransactionManager::commit()
-{
- m_undoList.clear();
- bool result = processChangeList();
-
- m_list.clear();
- return result;
-}
-
-void TagTransactionManager::forget()
-{
- m_list.clear();
-}
-
-bool TagTransactionManager::undo()
-{
- kDebug() << "Undoing " << m_undoList.count() << " changes.\n";
-
- forget(); // Scrap our old changes (although the list should be empty
- // anyways.
-
- bool result = processChangeList(true);
-
- m_undoList.clear();
- action("edit_undo")->setEnabled(false);
-
- return result;
-}
-
-TagTransactionManager::TagTransactionManager(QWidget *parent) : QObject(parent)
-{
- setObjectName( QLatin1String("tagmanager" ));
- m_manager = this;
-}
-
-bool TagTransactionManager::renameFile(const QFileInfo &from, const QFileInfo &to) const
-{
- if(!QFileInfo(to.path()).isWritable() || !from.exists())
- return false;
-
- if(!to.exists() ||
- KMessageBox::warningContinueCancel(
- static_cast<QWidget *>(parent()),
- i18n("This file already exists.\nDo you want to replace it?"),
- i18n("File Exists"),KGuiItem(i18n("Replace"))) == KMessageBox::Continue)
- {
- kDebug() << "Renaming " << from.absoluteFilePath() << " to " << to.absoluteFilePath();
- QDir currentDir;
- return currentDir.rename(from.absoluteFilePath(), to.absoluteFilePath());
- }
-
- return false;
-}
-
-bool TagTransactionManager::processChangeList(bool undo)
-{
- TagAlterationList::ConstIterator it, end;
- QStringList errorItems;
-
- it = undo ? m_undoList.constBegin() : m_list.constBegin();
- end = undo ? m_undoList.constEnd() : m_list.constEnd();
-
- emit signalAboutToModifyTags();
-
- for(; it != end; ++it) {
- PlaylistItem *item = (*it).item();
- Tag *tag = (*it).tag();
-
- QFileInfo newFile(tag->fileName());
-
- if(item->file().fileInfo().fileName() != newFile.fileName()) {
- if(!renameFile(item->file().fileInfo(), newFile)) {
- errorItems.append(item->text(1) + QString(" - ") + item->text(0));
- continue;
- }
- }
-
- if(tag->save()) {
- if(!undo)
- m_undoList.append(TagTransactionAtom(item, duplicateTag(item->file().tag())));
-
- item->file().setFile(tag->fileName());
- item->refreshFromDisk();
- item->repaint();
- item->playlist()->dataChanged();
- item->playlist()->update();
- }
- else {
- Tag *errorTag = item->file().tag();
- QString str = errorTag->artist() + " - " + errorTag->title();
-
- if(errorTag->artist().isEmpty())
- str = errorTag->title();
-
- errorItems.append(str);
- }
-
- kapp->processEvents();
- }
-
- undo ? m_undoList.clear() : m_list.clear();
- if(!undo && !m_undoList.isEmpty())
- action("edit_undo")->setEnabled(true);
- else
- action("edit_undo")->setEnabled(false);
-
- if(!errorItems.isEmpty())
- KMessageBox::errorList(static_cast<QWidget *>(parent()),
- i18n("The following files were unable to be changed."),
- errorItems,
- i18n("Error"));
-
- emit signalDoneModifyingTags();
- return errorItems.isEmpty();
-}
-
-#include "tagtransactionmanager.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TAGTRANSACTIONMANAGER_H
-#define TAGTRANSACTIONMANAGER_H
-
-#include <QObject>
-#include <QList>
-
-class PlaylistItem;
-class QWidget;
-class Tag;
-class QFileInfo;
-
-/**
- * Class to encapsulate a change to the tag, and optionally the file name, of
- * a PlaylistItem.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see TagTransactionManager
- */
-class TagTransactionAtom
-{
- public:
- /**
- * Default constructor, for use by QValueList.
- */
- TagTransactionAtom();
-
- /**
- * Copy constructor. This takes ownership of the m_tag pointer, so the
- * object being copied no longer has access to the tag. This function also
- * exists mainly for QValueList's benefit.
- *
- * @param other The TagTransactionAtom to copy.
- */
- TagTransactionAtom(const TagTransactionAtom &other);
-
- /**
- * Creates an atom detailing a change made by \p tag to \p item.
- *
- * @param tag Contains the new tag to apply to item.
- * @param item The PlaylistItem to change.
- */
- TagTransactionAtom(PlaylistItem *item, Tag *tag);
-
- /**
- * Destroys the atom. This function deletes the tag, so make sure you've
- * already copied out any data you need. The PlaylistItem is unaffected.
- */
- ~TagTransactionAtom();
-
- /**
- * Assignment operator. This operator takes ownership of the m_tag pointer,
- * so the object being assigned from no longer has access to the tag. This
- * function exists mainly for the benefit of QValueList.
- *
- * @param other The TagTransactionAtom to copy from.
- * @return The TagTransactionAtom being assigned to.
- */
- TagTransactionAtom &operator=(const TagTransactionAtom &other);
-
- /**
- * Accessor function to retrieve the PlaylistItem.
- *
- * @return The PlaylistItem being changed.
- */
- PlaylistItem *item() const { return m_item; }
-
- /**
- * Accessor function to retrieve the changed Tag.
- *
- * @return The Tag containing the changes to apply to item().
- */
- Tag *tag() const { return m_tag; }
-
- private:
- PlaylistItem *m_item;
- mutable Tag *m_tag;
-};
-
-typedef QList<TagTransactionAtom> TagAlterationList;
-
-/**
- * This class manages alterations of a group of PlaylistItem's FileHandles. What this
- * means in practice is that you will use this class to change the tags and/or
- * filename of a PlaylistItem.
- *
- * This class supports a limited transactional interface. Once you commit a
- * group of changes, you can call the undo() method to revert back to the way
- * things were (except possibly for file renames). You can call forget() to
- * forget a series of changes as well.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class TagTransactionManager : public QObject
-{
- Q_OBJECT
-
- public:
- /**
- * Constructs a TagTransactionManager, owned by @p parent.
- *
- * @param parent The parent QWidget.
- */
- TagTransactionManager(QWidget *parent = 0);
-
- /**
- * Returns the global TagTransactionManager instance.
- *
- * @return The global TagTransactionManager.
- */
- static TagTransactionManager *instance();
-
- /**
- * Adds a change to the list of changes to apply. Internally this
- * function extracts the CollectionListItem of @p item, and uses that
- * instead, so there is no need to do so yourself.
- *
- * @param item The PlaylistItem to change.
- * @param newTag The Tag containing the changed data.
- */
- void changeTagOnItem(PlaylistItem *item, Tag *newTag);
-
- /**
- * Convienience function to duplicate a Tag object, since the Tag
- * object doesn't have a decent copy constructor.
- *
- * @param tag The Tag to duplicate.
- * @param fileName The filename to assign to the tag. If an empty QString
- * (the default) is passed, the filename of the existing tag is
- * used.
- * @bug Tag should have a correct copy ctor and assignment operator.
- * @return The duplicate Tag.
- */
- static Tag *duplicateTag(const Tag *tag, const QString &fileName = QString());
-
- /**
- * Commits the changes to the PlaylistItems. It is important that the
- * PlaylistItems still exist when you call this function, although this
- * shouldn't be a problem in practice. After altering the tags, and
- * renaming the files if necessary, you can call undo() to back out the
- * changes.
- *
- * If any errors have occurred, the user will be notified with a dialog
- * box, and those files which were unabled to be altered will be excluded
- * from the undo set.
- *
- * @return true if no errors occurred, false otherwise.
- */
- bool commit();
-
- /**
- * Clears the current update list. The current undo list is unaffected.
- */
- void forget();
-
- /**
- * Undoes the changes caused by commit(). Like commit(), if any errors
- * occur changing the state back (for example, it may be impossible to
- * rename a file back to its original name), the user will be shown notified
- * via a dialog box.
- *
- * After performing the undo operation, it is impossible to call undo()
- * again on the same set of files. Namely, you can't repeatedly call
- * undo() to switch between two different file states.
- *
- * @return true if no errors occurred, false otherwise.
- */
- bool undo();
-
- signals:
- void signalAboutToModifyTags();
- void signalDoneModifyingTags();
-
- private:
- /**
- * Renames the file identified by @p from to have the name given by @p to,
- * prompting the user to confirm if necessary.
- *
- * @param from QFileInfo with the filename of the original file.
- * @param to QFileInfo with the new filename.
- * @return true if no errors occurred, false otherwise.
- */
- bool renameFile(const QFileInfo &from, const QFileInfo &to) const;
-
- /**
- * Used internally by commit() and undo(). Performs the work of updating
- * the PlaylistItems and then updating the various GUI elements that need
- * to be updated.
- *
- * @param undo true if operating in undo mode, false otherwise.
- */
- bool processChangeList(bool undo = false);
-
- TagAlterationList m_list; ///< holds a list of changes to commit
- TagAlterationList m_undoList; ///< holds a list of changes to undo
- static TagTransactionManager *m_manager; ///< used by instance()
-};
-
-#endif /* TAGTRANSACTIONMANAGER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
-
-include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. )
-
-########### next target ###############
-
-set(tagguessertest_SRCS tagguessertest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../tagguesser.cpp )
-
-kde4_add_unit_test(tagguessertest ${tagguessertest_SRCS})
-
-target_link_libraries(tagguessertest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY})
+++ /dev/null
-// Copyright Frerich Raabe <raabe@kde.org>.
-// This notice was added by Michael Pyne <michael.pyne@kdemail.net>
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "tagguesser.h"
-#include <qtest_kde.h>
-#include <QDir>
-
-class TagGuesserTest : public QObject
-{
- Q_OBJECT
-
-private slots:
- void testGuesser_data();
- void testGuesser();
-
-private:
- void add(const QString &filename, const QString &title,
- const QString &artist, const QString &track,
- const QString &comment, const QString &album = QString());
-};
-
-
-void TagGuesserTest::testGuesser_data()
-{
- QTest::addColumn<QString>("filename");
- QTest::addColumn<QString>("title");
- QTest::addColumn<QString>("artist");
- QTest::addColumn<QString>("track");
- QTest::addColumn<QString>("comment");
- QTest::addColumn<QString>("album");
-
- add("/home/frerich/Chemical Brothers - (01) - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - (01) - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - (01) - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/Chemical Brothers - [01] - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - [01] - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - [01] - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/Chemical Brothers - 01 - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - 01 - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/Chemical Brothers - 01 - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/(01) Chemical Brothers - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/(01) Chemical Brothers - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/(01) Chemical Brothers - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/[01] Chemical Brothers - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/[01] Chemical Brothers - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/[01] Chemical Brothers - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/01 Chemical Brothers - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/01 Chemical Brothers - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", "Live");
- add("/home/frerich/01 Chemical Brothers - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString());
- add("/home/frerich/(Chemical Brothers) Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), "Live");
- add("/home/frerich/(Chemical Brothers) Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), "Live");
- add("/home/frerich/(Chemical Brothers) Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), QString());
- add("/home/frerich/Chemical Brothers - Block rockin' beats [Live].mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), "Live");
- add("/home/frerich/Chemical Brothers - Block rockin' beats (Live).mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), "Live");
- add("/home/frerich/Chemical Brothers - Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", QString(), QString());
- add("/home/frerich/mp3/Chemical Brothers/Dig your own hole/[01] Block rockin' beats.mp3",
- "Block Rockin' Beats", "Chemical Brothers", "01", QString(), "Dig Your Own Hole");
- add(QDir::homePath() + "/[01] Randy - Religion, religion.mp3",
- "Religion, Religion", "Randy", "01", QString(), QString());
- add(QDir::homePath() + "/(3) Mr. Doe - Punk.mp3",
- "Punk", "Mr. Doe", "3", QString(), QString());
- add("c:\\music\\mp3s\\(3) Mr. Doe - Punk.mp3",
- "Punk", "Mr. Doe", "3", QString(), QString());
-}
-
-void TagGuesserTest::testGuesser()
-{
- QFETCH(QString, filename);
- QFETCH(QString, title);
- QFETCH(QString, artist);
- QFETCH(QString, track);
- QFETCH(QString, comment);
- QFETCH(QString, album);
-
- TagGuesser guesser(filename);
-
- QCOMPARE(guesser.title(), title);
- QCOMPARE(guesser.artist(), artist);
- QCOMPARE(guesser.track(), track);
- QCOMPARE(guesser.comment(), comment);
- QCOMPARE(guesser.album(), album);
-}
-
-void TagGuesserTest::add(const QString &filename, const QString &title,
- const QString &artist, const QString &track,
- const QString &comment, const QString &album)
-{
- QTest::newRow(filename.toUtf8())
- << filename
- << title
- << artist
- << track
- << comment
- << album
- ;
-}
-
-QTEST_KDEMAIN_CORE(TagGuesserTest)
-
-// vim: set et sw=4 tw=0 sta:
-
-#include "tagguessettest.moc"
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config-juk.h>
-
-#include "trackpickerdialog.h"
-
-#if HAVE_TUNEPIMP
-
-
-#include <k3listview.h>
-#include <klocale.h>
-
-#define NUMBER(x) (x == 0 ? QString::null : QString::number(x)) //krazy:exclude=nullstrassign for old broken gcc
-
-class TrackPickerItem : public K3ListViewItem
-{
-public:
- TrackPickerItem(K3ListView *parent, const KTRMResult &result) :
- K3ListViewItem(parent, parent->lastChild(),
- result.title(), result.artist(), result.album(),
- NUMBER(result.track()), NUMBER(result.year())),
- m_result(result) {}
- KTRMResult result() const { return m_result; }
-
-private:
- KTRMResult m_result;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public methods
-////////////////////////////////////////////////////////////////////////////////
-
-TrackPickerDialog::TrackPickerDialog(const QString &name,
- const KTRMResultList &results,
- QWidget *parent) :
- KDialog(parent)
-{
- setObjectName(name.toAscii());
- setModal(true);
- setCaption(i18n("Internet Tag Guesser"));
- setButtons(Ok | Cancel);
- showButtonSeparator(true);
-
- m_base = new TrackPickerDialogBase(this);
- setMainWidget(m_base);
-
- m_base->fileLabel->setText(name);
- m_base->trackList->setSorting(-1);
-
- for(KTRMResultList::ConstIterator it = results.begin(); it != results.end(); ++it)
- new TrackPickerItem(m_base->trackList, *it);
-
- m_base->trackList->setSelected(m_base->trackList->firstChild(), true);
-
- connect(m_base->trackList, SIGNAL(doubleClicked(Q3ListViewItem*,QPoint,int)),
- this, SLOT(accept()));
-
- setMinimumWidth(qMax(400, width()));
-}
-
-TrackPickerDialog::~TrackPickerDialog()
-{
-
-}
-
-KTRMResult TrackPickerDialog::result() const
-{
- if(m_base->trackList->selectedItem())
- return static_cast<TrackPickerItem *>(m_base->trackList->selectedItem())->result();
- else
- return KTRMResult();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// public slots
-////////////////////////////////////////////////////////////////////////////////
-
-int TrackPickerDialog::exec()
-{
- int dialogCode = KDialog::exec();
-
- // Only return true if an item was selected.
-
- if(m_base->trackList->selectedItem())
- return dialogCode;
- else
- return Rejected;
-}
-
-#include "trackpickerdialog.moc"
-
-#endif // HAVE_TUNEPIMP
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRACKPICKERDIALOG_H
-#define TRACKPICKERDIALOG_H
-
-#include <config-juk.h>
-
-#include <kdialog.h>
-
-#include "musicbrainzquery.h"
-#include "ui_trackpickerdialogbase.h"
-
-class TrackPickerDialogBase : public QWidget, public Ui::TrackPickerDialogBase
-{
-public:
- TrackPickerDialogBase( QWidget *parent ) : QWidget( parent ) {
- setupUi( this );
- }
-};
-
-class TrackPickerDialog : public KDialog
-{
- Q_OBJECT
-
-public:
- TrackPickerDialog(const QString &name,
- const KTRMResultList &results,
- QWidget *parent = 0);
-
- virtual ~TrackPickerDialog();
-
- KTRMResult result() const;
-
-public slots:
- int exec();
-
-private:
- TrackPickerDialogBase *m_base;
-};
-
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-<ui version="4.0" stdsetdef="1" >
- <class>TrackPickerDialogBase</class>
- <widget class="QWidget" name="TrackPickerDialogBase" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>556</width>
- <height>310</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" >
- <item>
- <layout class="QHBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <item>
- <widget class="QGroupBox" name="fileInfoGroup" >
- <property name="title" >
- <string>File Name</string>
- </property>
- <property name="alignment" >
- <set>Qt::AlignTop</set>
- </property>
- <layout class="QHBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="fileLabel" >
- <property name="font" >
- <font>
- <bold>true</bold>
- </font>
- </property>
- <property name="text" >
- <string/>
- </property>
- <property name="alignment" >
- <set>Qt::AlignVCenter|Qt::AlignLeft</set>
- </property>
- <property name="indent" >
- <number>9</number>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <item>
- <widget class="QGroupBox" name="trackInfoGroup" >
- <property name="title" >
- <string>Select Best Possible Match</string>
- </property>
- <property name="alignment" >
- <set>Qt::AlignTop</set>
- </property>
- <layout class="QVBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <item>
- <widget class="K3ListView" name="trackList" >
- <property name="sizePolicy" >
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="allColumnsShowFocus" >
- <bool>true</bool>
- </property>
- <property name="itemMargin" >
- <number>1</number>
- </property>
- <property name="resizeMode" >
- <enum>LastColumn</enum>
- </property>
- <property name="fullWidth" >
- <bool>true</bool>
- </property>
- <column>
- <property name="text" >
- <string>Track Name</string>
- </property>
- <property name="clickable" >
- <bool>true</bool>
- </property>
- <property name="resizable" >
- <bool>false</bool>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Artist</string>
- </property>
- <property name="clickable" >
- <bool>true</bool>
- </property>
- <property name="resizable" >
- <bool>false</bool>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Album</string>
- </property>
- <property name="clickable" >
- <bool>true</bool>
- </property>
- <property name="resizable" >
- <bool>false</bool>
- </property>
- </column>
- <column>
- <property name="text" >
- <string comment="cd track number" >Track</string>
- </property>
- <property name="clickable" >
- <bool>true</bool>
- </property>
- <property name="resizable" >
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text" >
- <string>Year</string>
- </property>
- <property name="clickable" >
- <bool>true</bool>
- </property>
- <property name="resizable" >
- <bool>true</bool>
- </property>
- </column>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>K3ListView</class>
- <extends>Q3ListView</extends>
- <header>k3listview.h</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>trackList</tabstop>
- </tabstops>
- <includes>
- <include location="local" >k3listview.h</include>
- </includes>
-</ui>
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "tracksequenceiterator.h"
-
-#include <kaction.h>
-#include <kapplication.h>
-#include <kdebug.h>
-#include <krandom.h>
-#include <ktoggleaction.h>
-
-#include "playlist.h"
-#include "actioncollection.h"
-#include "tag.h"
-#include "filehandle.h"
-
-using namespace ActionCollection;
-
-TrackSequenceIterator::TrackSequenceIterator() :
- m_current(0)
-{
-}
-
-TrackSequenceIterator::TrackSequenceIterator(const TrackSequenceIterator &other) :
- m_current(other.m_current)
-{
-}
-
-TrackSequenceIterator::~TrackSequenceIterator()
-{
-}
-
-void TrackSequenceIterator::setCurrent(PlaylistItem *current)
-{
- m_current = current;
-}
-
-void TrackSequenceIterator::playlistChanged()
-{
-}
-
-void TrackSequenceIterator::itemAboutToDie(const PlaylistItem *)
-{
-}
-
-DefaultSequenceIterator::DefaultSequenceIterator() :
- TrackSequenceIterator()
-{
-}
-
-DefaultSequenceIterator::DefaultSequenceIterator(const DefaultSequenceIterator &other)
- : TrackSequenceIterator(other)
-{
-}
-
-DefaultSequenceIterator::~DefaultSequenceIterator()
-{
-}
-
-void DefaultSequenceIterator::advance()
-{
- if(!current())
- return;
-
- bool isRandom = action("randomPlay") && action<KToggleAction>("randomPlay")->isChecked();
- bool loop = action<KAction>("loopPlaylist") && action<KAction>("loopPlaylist")->isChecked();
- bool albumRandom = action("albumRandomPlay") && action<KToggleAction>("albumRandomPlay")->isChecked();
-
- if(isRandom || albumRandom) {
- if(m_randomItems.isEmpty() && loop) {
-
- // Since refillRandomList will remove the currently playing item,
- // we should clear it out first since that's not good for e.g.
- // lists with 1-2 items. We need to remember the Playlist though.
-
- Playlist *playlist = current()->playlist();
- setCurrent(0);
-
- refillRandomList(playlist);
- }
-
- if(m_randomItems.isEmpty()) {
- setCurrent(0);
- return;
- }
-
- PlaylistItem *item;
-
- if(albumRandom) {
- if(m_albumSearch.isNull() || m_albumSearch.matchedItems().isEmpty()) {
- item = m_randomItems[KRandom::random() % m_randomItems.count()];
- initAlbumSearch(item);
- }
-
- // This can be null if initAlbumSearch() left the m_albumSearch
- // empty because the album text was empty. Since we initAlbumSearch()
- // with an item, the matchedItems() should never be empty.
-
- if(!m_albumSearch.isNull()) {
- PlaylistItemList albumMatches = m_albumSearch.matchedItems();
- if(albumMatches.isEmpty()) {
- kError() << "Unable to initialize album random play.\n";
- kError() << "List of potential results is empty.\n";
-
- return; // item is still set to random song from a few lines earlier.
- }
-
- item = albumMatches[0];
-
- // Pick first song remaining in list.
-
- for(int i = 0; i < albumMatches.count(); ++i)
- if(albumMatches[i]->file().tag()->track() < item->file().tag()->track())
- item = albumMatches[i];
- m_albumSearch.clearItem(item);
-
- if(m_albumSearch.matchedItems().isEmpty()) {
- m_albumSearch.clearComponents();
- m_albumSearch.search();
- }
- }
- else
- kError() << "Unable to perform album random play on " << *item << endl;
- }
- else
- item = m_randomItems[KRandom::random() % m_randomItems.count()];
-
- setCurrent(item);
- m_randomItems.removeAll(item);
- }
- else {
- PlaylistItem *next = current()->itemBelow();
- if(!next && loop) {
- Playlist *p = current()->playlist();
- next = p->firstChild();
- while(next && !next->isVisible())
- next = static_cast<PlaylistItem *>(next->nextSibling());
- }
-
- setCurrent(next);
- }
-}
-
-void DefaultSequenceIterator::backup()
-{
- if(!current())
- return;
-
- PlaylistItem *item = current()->itemAbove();
-
- if(item)
- setCurrent(item);
-}
-
-void DefaultSequenceIterator::prepareToPlay(Playlist *playlist)
-{
- bool random = action("randomPlay") && action<KToggleAction>("randomPlay")->isChecked();
- bool albumRandom = action("albumRandomPlay") && action<KToggleAction>("albumRandomPlay")->isChecked();
-
- if(random || albumRandom) {
- PlaylistItemList items = playlist->selectedItems();
- if(items.isEmpty())
- items = playlist->visibleItems();
-
- PlaylistItem *newItem = 0;
- if(!items.isEmpty())
- newItem = items[KRandom::random() % items.count()];
-
- setCurrent(newItem);
- refillRandomList();
- }
- else {
- Q3ListViewItemIterator it(playlist, Q3ListViewItemIterator::Visible | Q3ListViewItemIterator::Selected);
- if(!it.current())
- it = Q3ListViewItemIterator(playlist, Q3ListViewItemIterator::Visible);
-
- setCurrent(static_cast<PlaylistItem *>(it.current()));
- }
-}
-
-void DefaultSequenceIterator::reset()
-{
- m_randomItems.clear();
- m_albumSearch.clearComponents();
- m_albumSearch.search();
- setCurrent(0);
-}
-
-void DefaultSequenceIterator::playlistChanged()
-{
- refillRandomList();
-}
-
-void DefaultSequenceIterator::itemAboutToDie(const PlaylistItem *item)
-{
- PlaylistItem *stfu_gcc = const_cast<PlaylistItem *>(item);
- m_randomItems.removeAll(stfu_gcc);
-}
-
-void DefaultSequenceIterator::setCurrent(PlaylistItem *current)
-{
- PlaylistItem *oldCurrent = DefaultSequenceIterator::current();
-
- TrackSequenceIterator::setCurrent(current);
-
- bool random = action("randomPlay") && action<KToggleAction>("randomPlay")->isChecked();
- bool albumRandom = action("albumRandomPlay") && action<KToggleAction>("albumRandomPlay")->isChecked();
-
- if((albumRandom || random) && current && m_randomItems.isEmpty()) {
-
- // We're setting a current item, refill the random list now, and remove
- // the current item.
-
- refillRandomList();
- }
-
- m_randomItems.removeAll(current);
-
- if(albumRandom && current && !oldCurrent) {
-
- // Same idea as above
-
- initAlbumSearch(current);
- m_albumSearch.clearItem(current);
- }
-}
-
-DefaultSequenceIterator *DefaultSequenceIterator::clone() const
-{
- return new DefaultSequenceIterator(*this);
-}
-
-void DefaultSequenceIterator::refillRandomList(Playlist *p)
-{
- if(!p) {
- if (!current())
- return;
-
- p = current()->playlist();
-
- if(!p) {
- kError() << "Item has no playlist!\n";
- return;
- }
- }
-
- m_randomItems = p->visibleItems();
- m_randomItems.removeAll(current());
- m_albumSearch.clearComponents();
- m_albumSearch.search();
-}
-
-void DefaultSequenceIterator::initAlbumSearch(PlaylistItem *searchItem)
-{
- if(!searchItem)
- return;
-
- m_albumSearch.clearPlaylists();
- m_albumSearch.addPlaylist(searchItem->playlist());
-
- ColumnList columns;
-
- m_albumSearch.setSearchMode(PlaylistSearch::MatchAll);
- m_albumSearch.clearComponents();
-
- // If the album name is empty, it will mess up the search,
- // so ignore empty album names.
-
- if(searchItem->file().tag()->album().isEmpty())
- return;
-
- columns.append(PlaylistItem::AlbumColumn);
-
- m_albumSearch.addComponent(PlaylistSearch::Component(
- searchItem->file().tag()->album(),
- true,
- columns,
- PlaylistSearch::Component::Exact)
- );
-
- // If there is an Artist tag with the track, match against it as well
- // to avoid things like multiple "Greatest Hits" albums matching the
- // search.
-
- if(!searchItem->file().tag()->artist().isEmpty()) {
- kDebug() << "Searching both artist and album.";
- columns[0] = PlaylistItem::ArtistColumn;
-
- m_albumSearch.addComponent(PlaylistSearch::Component(
- searchItem->file().tag()->artist(),
- true,
- columns,
- PlaylistSearch::Component::Exact)
- );
- }
-
- m_albumSearch.search();
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRACKSEQUENCEITERATOR_H
-#define TRACKSEQUENCEITERATOR_H
-
-#include "playlistitem.h"
-#include "playlistsearch.h"
-
-class Playlist;
-
-/**
- * This abstract class defines an interface to be used by TrackSequenceManager,
- * to iterate over the items in a playlist. Implement this class in a subclass
- * in order to define your own ordering for playlist sequences. For an example,
- * see the UpcomingPlaylist class.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see UpcomingPlaylist
- * @see TrackSequenceManager
- */
-class TrackSequenceIterator
-{
-public:
- /**
- * Default constructor.
- */
- TrackSequenceIterator();
-
- /**
- * Default copy constructor.
- *
- * @param other the TrackSequenceIterator we are copying
- */
- TrackSequenceIterator(const TrackSequenceIterator & other);
-
- /**
- * Default destructor.
- */
- virtual ~TrackSequenceIterator();
-
- /**
- * This function moves the current item to the next track. You must
- * reimplement this function in your subclasses.
- */
- virtual void advance() = 0;
-
- /**
- * This function moves the current item to the previous track. This may
- * not always make sense, and the history functionality of the Playlist
- * class currently overrides this. You must reimplement this function in
- * your subclass.
- */
- virtual void backup() = 0;
-
- /**
- * This function returns the current PlaylistItem, or 0 if the iterator is
- * not pointing at any PlaylistItem.
- *
- * @return current track
- */
- virtual PlaylistItem *current() const { return m_current; }
-
- /**
- * This function creates a perfect copy of the object it is called on, to
- * avoid the C++ slicing problem. When you reimplement this function, you
- * should change the return type to the name of the subclass.
- *
- * @return pointer to a copy of the object
- */
- virtual TrackSequenceIterator *clone() const = 0;
-
- /**
- * This function is called by the TrackSequenceManager when current() returns
- * 0, if the TrackSequenceManager has a playlist defined. This function
- * should choose an appropriate starting track and set it as the current
- * item. This function must be reimplemented in subclasses.
- *
- * @param playlist the playlist to iterate over
- */
- virtual void prepareToPlay(Playlist *playlist) = 0;
-
- /**
- * This function is called whenever the current playlist changes, such as
- * having a new search applied, items added/removed, etc. If you need to
- * update internal state, you should do so without affecting the current
- * playing item. Default implementation does nothing.
- */
- virtual void playlistChanged();
-
- /**
- * This function is called by the manager when \p item is about to be
- * removed. Subclasses should ensure that they're not still holding a
- * pointer to the item. The default implementation does nothing.
- *
- * @param item the item about to be removed.
- */
- virtual void itemAboutToDie(const PlaylistItem *item);
-
- /**
- * This function is called by the TrackSequenceManager is some situations,
- * such as when playback is being stopped. If you subclass needs to reset
- * any internal data members, do so in this function. This function must
- * be reimplemented in subclasses.
- */
- virtual void reset() = 0;
-
- /**
- * This function is a public mutator to set the current item.
- *
- * @param current the new current item
- */
- virtual void setCurrent(PlaylistItem *current);
-
-private:
- PlaylistItem::Pointer m_current; ///< the current item
-};
-
-/**
- * This is the default iterator for JuK, supporting normal, random, and album
- * random playback with or without looping.
- *
- * @author Michael Pyne <mpyne@kde.org>
- */
-class DefaultSequenceIterator : public TrackSequenceIterator
-{
-public:
- /**
- * Default constructor.
- */
- DefaultSequenceIterator();
-
- /**
- * Default copy constructor.
- *
- * @param other the DefaultSequenceIterator to copy.
- */
- DefaultSequenceIterator(const DefaultSequenceIterator &other);
-
- /**
- * Default destructor.
- */
- virtual ~DefaultSequenceIterator();
-
- /**
- * This function advances to the next item in the current sequence. The
- * algorithm used depends on what playback mode is selected.
- */
- virtual void advance();
-
- /**
- * This function moves to the previous item in the playlist. This occurs
- * no matter what playback mode is selected.
- */
- virtual void backup();
-
- /**
- * This function prepares the class for iterator. If no random play mode
- * is selected, the first item in the given playlist is the starting item.
- * Otherwise, an item is randomly picked to be the starting item.
- *
- * @param playlist The playlist to initialize for.
- */
- virtual void prepareToPlay(Playlist *playlist);
-
- /**
- * This function clears all internal state, including any random play lists,
- * and what the current album is.
- */
- virtual void reset();
-
- /**
- * This function recalculates the random lists, and is should be called
- * whenever its current playlist changes (at least for searches).
- */
- virtual void playlistChanged();
-
- /**
- * Called when \p item is about to be removed. This function ensures that
- * it isn't remaining in the random play list.
- */
- virtual void itemAboutToDie(const PlaylistItem *item);
-
- /**
- * This function sets the current item, and initializes any internal lists
- * that may be needed for playback.
- *
- * @param current The new current item.
- */
- virtual void setCurrent(PlaylistItem *current);
-
- /**
- * This function returns a perfect copy of the object it is called on, to
- * get around the C++ slicing problem.
- *
- * @return A copy of the object the method is called on.
- */
- virtual DefaultSequenceIterator *clone() const;
-
-private:
-
- /**
- * Reinitializes the internal random play list based on the playlist given
- * by \p p. The currently playing item, if any, is automatically removed
- * from the list.
- *
- * @param p The Playlist to read items from. If p is 0, the playlist of
- * the currently playing item is used instead.
- */
- void refillRandomList(Playlist *p = 0);
- void initAlbumSearch(PlaylistItem *searchItem);
-
-private:
- PlaylistItemList m_randomItems;
- PlaylistSearch m_albumSearch;
-};
-
-#endif /* TRACKSEQUENCEITERATOR_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <kconfig.h>
-#include <klocale.h>
-#include <kaction.h>
-#include <kmenu.h>
-
-#include "actioncollection.h"
-#include "tracksequencemanager.h"
-#include "playlist.h"
-#include "playlistitem.h"
-#include "tracksequenceiterator.h"
-#include "tag.h"
-#include "filehandle.h"
-#include "collectionlist.h"
-
-/////////////////////////////////////////////////////////////////////////////
-// public functions
-/////////////////////////////////////////////////////////////////////////////
-
-TrackSequenceManager::~TrackSequenceManager()
-{
- // m_playlist and m_popupMenu don't belong to us, don't try to delete them
- if(m_iterator == m_defaultIterator)
- m_iterator = 0;
-
- delete m_iterator;
- delete m_defaultIterator;
-}
-
-bool TrackSequenceManager::installIterator(TrackSequenceIterator *iterator)
-{
- PlaylistItem *oldItem = m_iterator ? m_iterator->current() : 0;
-
- if(m_iterator != m_defaultIterator)
- delete m_iterator;
-
- m_iterator = m_defaultIterator;
- if(iterator)
- m_iterator = iterator;
-
- m_iterator->setCurrent(oldItem);
-
- return true;
-}
-
-PlaylistItem *TrackSequenceManager::currentItem() const
-{
- return m_iterator->current();
-}
-
-TrackSequenceIterator *TrackSequenceManager::takeIterator()
-{
- TrackSequenceIterator *temp = m_iterator;
-
- m_iterator = 0;
- return temp;
-}
-
-TrackSequenceManager *TrackSequenceManager::instance()
-{
- static TrackSequenceManager manager;
-
- if(!manager.m_initialized)
- manager.initialize();
-
- return &manager;
-}
-
-PlaylistItem *TrackSequenceManager::nextItem()
-{
- if(m_playNextItem) {
-
- // Force the iterator to reset state (such as random item lists)
-
- m_iterator->reset();
- m_iterator->prepareToPlay(m_playNextItem->playlist());
- m_iterator->setCurrent(m_playNextItem);
- m_playNextItem = 0;
- }
- else if(m_iterator->current())
- m_iterator->advance();
- else if(currentPlaylist())
- m_iterator->prepareToPlay(currentPlaylist());
- else
- m_iterator->prepareToPlay(CollectionList::instance());
-
- return m_iterator->current();
-}
-
-PlaylistItem *TrackSequenceManager::previousItem()
-{
- m_iterator->backup();
- return m_iterator->current();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// public slots
-/////////////////////////////////////////////////////////////////////////////
-
-void TrackSequenceManager::setNextItem(PlaylistItem *item)
-{
- m_playNextItem = item;
-}
-
-void TrackSequenceManager::setCurrentPlaylist(Playlist *list)
-{
- if(m_playlist)
- m_playlist->disconnect(this);
- m_playlist = list;
-
- connect(m_playlist, SIGNAL(signalAboutToRemove(PlaylistItem*)),
- this, SLOT(slotItemAboutToDie(PlaylistItem*)));
-}
-
-void TrackSequenceManager::setCurrent(PlaylistItem *item)
-{
- if(item != m_iterator->current()) {
- m_iterator->setCurrent(item);
- if(item)
- setCurrentPlaylist(item->playlist());
- else
- m_iterator->reset();
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// private functions
-/////////////////////////////////////////////////////////////////////////////
-
-void TrackSequenceManager::initialize()
-{
- CollectionList *collection = CollectionList::instance();
-
- if(!collection)
- return;
-
- // Make sure we don't use m_playNextItem if it's invalid.
- connect(collection, SIGNAL(signalAboutToRemove(PlaylistItem*)),
- this, SLOT(slotItemAboutToDie(PlaylistItem*)));
-
- m_initialized = true;
-}
-
-TrackSequenceManager::TrackSequenceManager() :
- QObject(),
- m_playlist(0),
- m_playNextItem(0),
- m_popupMenu(0),
- m_iterator(0),
- m_initialized(false)
-{
- m_defaultIterator = new DefaultSequenceIterator();
- m_iterator = m_defaultIterator;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// protected slots
-/////////////////////////////////////////////////////////////////////////////
-
-void TrackSequenceManager::slotItemAboutToDie(PlaylistItem *item)
-{
- if(item == m_playNextItem)
- m_playNextItem = 0;
-
- m_iterator->itemAboutToDie(item);
-}
-
-#include "tracksequencemanager.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TRACKSEQUENCEMANAGER_H
-#define TRACKSEQUENCEMANAGER_H
-
-#include <QObject>
-#include <QPointer>
-
-class KMenu;
-class TrackSequenceIterator;
-class PlaylistItem;
-class Playlist;
-
-/**
- * This class is responsible for managing the music play sequence for JuK.
- * Instead of playlists deciding which song goes next, this class is used to
- * do so. You can replace the iterator used as well, although the class
- * provides a default iterator that supports random play and playlist looping.
- *
- * @see Playlist
- * @see TrackSequenceIterator
- * @author Michael Pyne <mpyne@kde.org>
- */
-class TrackSequenceManager : public QObject
-{
- Q_OBJECT
-
-public:
- /**
- * Destroys the track sequence manager. The sequence iterators will also
- * be deleted, but the playlist, popup menu, and playlist items will not be
- * touched.
- */
- ~TrackSequenceManager();
-
- /**
- * This function installs a new iterator to be used instead of the old
- * one. TrackSequenceManager will control the iterator after that,
- * deleting the iterator when another is installed, or when the
- * TrackSequenceManager is destroyed.
- *
- * @param iterator the iterator to install, or 0 for the default
- * @return true if installation successfully happened
- */
- bool installIterator(TrackSequenceIterator *iterator);
-
- /**
- * @return currently selected iterator
- */
- TrackSequenceIterator *iterator() const { return m_iterator; }
-
- /**
- * This function returns a pointer to the currently set iterator, and
- * then removes the TrackSequenceManager's pointer to the iterator without
- * deleting the iterator. You should only do this if you are going to be
- * using @see installIterator to give control of the iterator back to the
- * TrackSequenceManager at some point. Also, you must install a
- * replacement iterator before the TrackSequenceManager is otherwise
- * used. If you use this function, you must manually set the current
- * item of the iterator you replace the old one with (if you want).
- *
- * @see installIterator
- * @return the currently set iterator.
- */
- TrackSequenceIterator *takeIterator();
-
- /**
- * Returns the global TrackSequenceManager object. This is the only way to
- * access the TrackSequenceManager.
- *
- * @return the global TrackSequenceManager
- */
- static TrackSequenceManager *instance();
-
- /**
- * Returns the next track, and advances in the current sequence..
- *
- * @return the next track in the current sequence, or 0 if the end has
- * been reached
- */
- PlaylistItem *nextItem();
-
- /**
- * Returns the previous track, and backs up in the current sequence. Note
- * that if you have an item x, nextItem(previousItem(x)) is not guaranteed
- * to equal x, even ignoring the effect of hitting the end of list.
- *
- * @return the previous track in the current sequence, or 0 if the
- * beginning has been reached
- */
- PlaylistItem *previousItem();
-
- /**
- * @return the current track in the current sequence, or 0 if there is no
- * current track (for example, an empty playlist)
- */
- PlaylistItem *currentItem() const;
-
- /**
- * @return the current KMenu used by the manager, or 0 if none is
- * set
- */
- KMenu *menu() const { return m_popupMenu; }
-
- /**
- * @return the TrackSequenceManager's idea of the current playlist
- */
- Playlist *currentPlaylist() const { return m_playlist; }
-
-public slots:
- /**
- * Set the next item to play to @p item
- *
- * @param item the next item to play
- */
- void setNextItem(PlaylistItem *item);
-
- /**
- * Sets the current playlist. This is necessary in order for some of the
- * actions in the popup menu used by this class to work. Note that the
- * current playlist is not necessarily the same as the playlist that is
- * playlist. The TrackSequenceManager does not own @p list after this
- * call.
- *
- * @param list the current playlist
- */
- void setCurrentPlaylist(Playlist *list);
-
- /**
- * Sets the current item to @p item. You should try to avoid calling this
- * function, instead allowing the manager to perform its work. However,
- * this function is useful for clearing the current item. Remember that
- * you must have a valid playlist to iterate if you clear the current item.
- *
- * @param item the PlaylistItem that is currently playing. Set to 0 if
- * there is no item playing.
- */
- void setCurrent(PlaylistItem *item);
-
-private:
- /**
- * Sets up various connections, to be run after the GUI is running.
- * Automatically run by instance().
- *
- * @see instance
- */
- void initialize();
-
- /**
- * Constructs the sequence manager. The constructor will work even before
- * the GUI has been created. Note that you can't actually construct an
- * object with this function, use instance().
- *
- * @see instance
- */
- TrackSequenceManager();
-
-protected slots:
-
- /**
- * This slot should be called when @a item is about to be deleted, so that
- * the TrackSequenceManager can make sure that any pointers held pointing
- * to @a item are corrected.
- *
- * @param item The PlaylistItem about to be deleted.
- */
- void slotItemAboutToDie(PlaylistItem *item);
-
-private:
- QPointer<Playlist> m_playlist;
- PlaylistItem *m_playNextItem;
- KMenu *m_popupMenu;
- TrackSequenceIterator *m_iterator;
- TrackSequenceIterator *m_defaultIterator;
- bool m_initialized;
-};
-
-#endif /* TRACKSEQUENCEMANAGER_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "treeviewitemplaylist.h"
-
-#include <kapplication.h>
-#include <kdebug.h>
-#include <kmessagebox.h>
-#include <klocale.h>
-
-#include <QStringList>
-
-#include "collectionlist.h"
-#include "tag.h"
-#include "playlistitem.h"
-#include "playlistsearch.h"
-#include "tagtransactionmanager.h"
-
-TreeViewItemPlaylist::TreeViewItemPlaylist(PlaylistCollection *collection,
- const PlaylistSearch &search,
- const QString &name) :
- SearchPlaylist(collection, search, name, false)
-{
- PlaylistSearch::Component component = *(search.components().begin());
- m_columnType = static_cast<PlaylistItem::ColumnType>(*(component.columns().begin()));
-}
-
-void TreeViewItemPlaylist::retag(const QStringList &files, Playlist *)
-{
- CollectionList *collection = CollectionList::instance();
-
- if(files.isEmpty())
- return;
-
- QString changedTag = i18n("artist");
- if(m_columnType == PlaylistItem::GenreColumn)
- changedTag = i18n("genre");
- else if(m_columnType == PlaylistItem::AlbumColumn)
- changedTag = i18n("album");
-
- if(KMessageBox::warningContinueCancelList(
- this,
- i18n("You are about to change the %1 on these files.", changedTag),
- files,
- i18n("Changing Track Tags"),
- KStandardGuiItem::cont(),
- KStandardGuiItem::cancel(),
- "dragDropRetagWarn"
- ) == KMessageBox::Cancel)
- {
- return;
- }
-
- QStringList::ConstIterator it;
- for(it = files.begin(); it != files.end(); ++it) {
- CollectionListItem *item = collection->lookup(*it);
- if(!item)
- continue;
-
- Tag *tag = TagTransactionManager::duplicateTag(item->file().tag());
- switch(m_columnType) {
- case PlaylistItem::ArtistColumn:
- tag->setArtist(name());
- break;
-
- case PlaylistItem::AlbumColumn:
- tag->setAlbum(name());
- break;
-
- case PlaylistItem::GenreColumn:
- tag->setGenre(name());
- break;
-
- default:
- kDebug() << "Unhandled column type editing " << *it;
- }
-
- TagTransactionManager::instance()->changeTagOnItem(item, tag);
- }
-}
-
-#include "treeviewitemplaylist.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TREEVIEWITEMPLAYLIST_H
-#define TREEVIEWITEMPLAYLIST_H
-
-#include "searchplaylist.h"
-#include "playlistitem.h"
-
-class QStringList;
-
-class TreeViewItemPlaylist : public SearchPlaylist
-{
- Q_OBJECT
-
-public:
- explicit TreeViewItemPlaylist(PlaylistCollection *collection,
- const PlaylistSearch &search = PlaylistSearch(),
- const QString &name = QString());
-
- virtual bool searchIsEditable() const { return false; }
- void retag(const QStringList &files, Playlist *donorPlaylist);
-
-signals:
- void signalTagsChanged();
-
-private:
- PlaylistItem::ColumnType m_columnType;
-};
-
-#endif // TREEVIEWITEMPLAYLIST_H
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004, 2008 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "upcomingplaylist.h"
-#include "juk-exception.h"
-
-#include <kdebug.h>
-#include <kapplication.h>
-#include <kaction.h>
-
-#include "playlistitem.h"
-#include "playlistcollection.h"
-#include "tracksequencemanager.h"
-#include "collectionlist.h"
-#include "actioncollection.h"
-
-using namespace ActionCollection;
-
-UpcomingPlaylist::UpcomingPlaylist(PlaylistCollection *collection) :
- Playlist(collection, true),
- m_active(false),
- m_oldIterator(0)
-{
- setName(i18n("Play Queue"));
- setAllowDuplicates(true);
- setSorting(-1);
-}
-
-UpcomingPlaylist::~UpcomingPlaylist()
-{
- removeIteratorOverride();
-}
-
-void UpcomingPlaylist::initialize()
-{
- // Prevent duplicate initialization.
-
- if(m_active)
- return;
-
- m_active = true;
-
- m_oldIterator = manager()->takeIterator();
- manager()->installIterator(new UpcomingSequenceIterator(this));
-
- if(!m_oldIterator->current())
- m_oldIterator->prepareToPlay(CollectionList::instance());
- else
- manager()->iterator()->setCurrent(m_oldIterator->current());
-}
-
-void UpcomingPlaylist::appendItems(const PlaylistItemList &itemList)
-{
- initialize();
-
- if(itemList.isEmpty())
- return;
-
- PlaylistItem *after = static_cast<PlaylistItem *>(lastItem());
-
- foreach(PlaylistItem *playlistItem, itemList) {
- after = createItem(playlistItem, after);
- m_playlistIndex.insert(after, playlistItem->playlist());
- }
-
- dataChanged();
- slotWeightDirty();
-}
-
-void UpcomingPlaylist::playNext()
-{
- initialize();
-
- PlaylistItem *next = TrackSequenceManager::instance()->nextItem();
-
- if(next) {
- setPlaying(next);
- Playlist *source = m_playlistIndex[next];
- if(source) {
- PlaylistList l;
- l.append(this);
- source->synchronizePlayingItems(l, false);
- }
- }
- else {
- removeIteratorOverride();
-
- // Normally we continue to play the currently playing item that way
- // a user can continue to hear their song when deselecting Play Queue.
- // However we're technically still "playing" when the queue empties and
- // we reinstall the old iterator so in this situation manually advance
- // to the next track. (Otherwise we hear the same song twice in a row
- // during the transition)
-
- setPlaying(manager()->nextItem());
- }
-}
-
-void UpcomingPlaylist::clearItem(PlaylistItem *item)
-{
- m_playlistIndex.remove(item);
- Playlist::clearItem(item);
-}
-
-void UpcomingPlaylist::addFiles(const QStringList &files, PlaylistItem *after)
-{
- CollectionList::instance()->addFiles(files, after);
-
- PlaylistItemList l;
- foreach(const QString &file, files) {
- FileHandle f(file);
- PlaylistItem *i = CollectionList::instance()->lookup(f.absFilePath());
- if(i)
- l.append(i);
- }
-
- appendItems(l);
-}
-
-QMap< PlaylistItem::Pointer, QPointer<Playlist> > &UpcomingPlaylist::playlistIndex()
-{
- return m_playlistIndex;
-}
-
-void UpcomingPlaylist::removeIteratorOverride()
-{
- if(!m_active)
- return;
-
- m_active = false; // Allow re-initialization.
-
- if(!m_oldIterator)
- return;
-
- // Install the old track iterator.
-
- manager()->installIterator(m_oldIterator);
-
- // If we have an item that is currently playing, allow it to keep playing.
- // Otherwise, just reset to the default iterator (probably not playing
- // anything.)
- // XXX: Reset to the last playing playlist?
-
- m_oldIterator->reset();
- if(playingItem())
- m_oldIterator->setCurrent(playingItem()->collectionItem());
-
- setPlaying(manager()->currentItem(), true);
-
- Watched::currentChanged();
-}
-
-TrackSequenceManager *UpcomingPlaylist::manager() const
-{
- return TrackSequenceManager::instance();
-}
-
-UpcomingPlaylist::UpcomingSequenceIterator::UpcomingSequenceIterator(UpcomingPlaylist *playlist) :
- TrackSequenceIterator(), m_playlist(playlist)
-{
-}
-
-UpcomingPlaylist::UpcomingSequenceIterator::UpcomingSequenceIterator(const UpcomingSequenceIterator &other) :
- TrackSequenceIterator(other), m_playlist(other.m_playlist)
-{
-}
-
-UpcomingPlaylist::UpcomingSequenceIterator::~UpcomingSequenceIterator()
-{
-}
-
-void UpcomingPlaylist::UpcomingSequenceIterator::advance()
-{
- PlaylistItem *item = m_playlist->firstChild();
-
- if(item) {
- PlaylistItem *next = static_cast<PlaylistItem *>(item->nextSibling());
- m_playlist->clearItem(item);
- setCurrent(next);
- }
-}
-
-void UpcomingPlaylist::UpcomingSequenceIterator::backup()
-{
-}
-
-UpcomingPlaylist::UpcomingSequenceIterator *UpcomingPlaylist::UpcomingSequenceIterator::clone() const
-{
- return new UpcomingSequenceIterator(*this);
-}
-
-void UpcomingPlaylist::UpcomingSequenceIterator::setCurrent(PlaylistItem *currentItem)
-{
- if(!currentItem) {
- TrackSequenceIterator::setCurrent(currentItem);
- return;
- }
-
- // If the upcoming playlist is playing something, clear it out since
- // apparently the user didn't want to hear it.
-
- PlaylistItem *playingItem = m_playlist->playingItem();
- if(playingItem && playingItem->playlist() == m_playlist && currentItem != playingItem)
- m_playlist->clearItem(playingItem);
-
- // If a different playlist owns this item, add it to the upcoming playlist
-
- Playlist *p = currentItem->playlist();
-
- if(p != m_playlist) {
- PlaylistItem *i = m_playlist->createItem(currentItem, (PlaylistItem *) 0);
- m_playlist->playlistIndex().insert(i, p);
- m_playlist->dataChanged();
- m_playlist->slotWeightDirty();
- }
- else {
- // if(p == m_playlist) {
-
- // Bump this item up to the top
- m_playlist->takeItem(currentItem);
- m_playlist->insertItem(currentItem);
- }
-
- TrackSequenceIterator::setCurrent(m_playlist->firstChild());
-}
-
-void UpcomingPlaylist::UpcomingSequenceIterator::reset()
-{
- setCurrent(0);
-}
-
-void UpcomingPlaylist::UpcomingSequenceIterator::prepareToPlay(Playlist *)
-{
- if(!m_playlist->items().isEmpty())
- setCurrent(m_playlist->firstChild());
-}
-
-QDataStream &operator<<(QDataStream &s, const UpcomingPlaylist &p)
-{
- PlaylistItemList l = const_cast<UpcomingPlaylist *>(&p)->items();
-
- s << qint32(l.count());
-
- foreach(const PlaylistItem *playlistItem, l)
- s << playlistItem->file().absFilePath();
-
- return s;
-}
-
-QDataStream &operator>>(QDataStream &s, UpcomingPlaylist &p)
-{
- QString fileName;
- PlaylistItem *newItem = 0;
- qint32 count;
-
- s >> count;
-
- for(qint32 i = 0; i < count; ++i) {
- s >> fileName;
- if(fileName.isEmpty())
- throw BICStreamException();
-
- newItem = p.createItem(FileHandle(fileName), newItem, false);
- }
-
- return s;
-}
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2002-2004 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef UPCOMINGPLAYLIST_H
-#define UPCOMINGPLAYLIST_H
-
-
-#include <qpointer.h>
-
-#include "playlist.h"
-#include "tracksequenceiterator.h"
-
-class TrackSequenceManager;
-
-/**
- * A class to implement upcoming playlist support in JuK. It is closely
- * associated with the UpcomingSequenceIterator class. It works by using
- * whatever iterator is currently being used by the TrackSequenceManager
- * instance when this playlist is constructed to form a list of upcoming tracks.
- * After the playlist is created, tracks are played from top to bottom until
- * the list is empty. If loop playlist is enabled, tracks are automatically
- * added as tracks are removed. Also, enabling this playlist causes the base
- * Playlist class to add an item to the context-menu to add the selected items
- * to this playlist. If the user double-clicks any track to force it to play,
- * it is added to the top of this playlist automatically, replacing any
- * currently playing song.
- *
- * @author Michael Pyne <mpyne@kde.org>
- * @see UpcomingSequenceIterator
- */
-class UpcomingPlaylist : public Playlist
-{
-public:
- /**
- * Constructor for the UpcomingPlaylist object. You should only ever have
- * one instance of this class. You should call the initialize() function
- * before using the created object.
- *
- * @see initialize
- * @param collection The PlaylistCollection that owns this playlist.
- * @param defaultSize The default number of tracks to place in the playlist.
- */
- explicit UpcomingPlaylist(PlaylistCollection *collection);
- /**
- * Destructor for the UpcomingPlaylist. This destructor will restore the
- * iterator for the TrackSequenceManager, and if a song is playing when
- * this playlist is removed, it will remain playing after the playlist is
- * destroyed.
- */
- virtual ~UpcomingPlaylist();
-
- /**
- * This function initializes the upcoming playlist, so that you can create
- * it before the GUI has been completely setup. If a song is playing when
- * this function is called, then the song will be added to this playlist,
- * automatically with no interruption in playback.
- */
- void initialize();
-
- /**
- * Appends the given items to the end of the playlist. Use this function
- * instead of createItems() since this function ensures that the items are
- * added to the end of the playlist.
- *
- * @see createItems(const PlaylistItemList &, PlaylistItem *)
- * @param itemList The list of PlaylistItems to append.
- */
- void appendItems(const PlaylistItemList &itemList);
-
- /**
- * Reimplemented to set the playing item in both the source playlist
- * and the upcoming playlist.
- */
- virtual void playNext();
-
- /**
- * Reimplemented to remove the item from the Playlist index.
- */
- virtual void clearItem(PlaylistItem *item);
-
- virtual void addFiles(const QStringList &files, PlaylistItem *after = 0);
-
- /**
- * Returns a reference to the index between items in the list and the
- * playlist that they came from. This is used to remap the currently
- * playing item to the source playlist.
- */
- QMap<PlaylistItem::Pointer, QPointer<Playlist> > &playlistIndex();
-
- bool active() const { return m_active; }
-
-private:
-
- /**
- * Internal function to restore the TrackSequenceManager to the state
- * it was in when the object was constructed, except for the playing
- * item.
- */
- void removeIteratorOverride();
-
- /**
- * This function returns the instance of the TrackSequenceManager.
- *
- * @return the TrackSequenceManager instance.
- * @see TrackSequenceManager::instance()
- */
- TrackSequenceManager *manager() const;
-
-private:
- class UpcomingSequenceIterator;
- friend class UpcomingSequenceIterator;
-
- bool m_active;
- TrackSequenceIterator *m_oldIterator;
- QMap<PlaylistItem::Pointer, QPointer<Playlist> > m_playlistIndex;
-};
-
-/**
- * An implementation of TrackSequenceIterator designed to work with
- * UpcomingPlaylist. It is installed by UpcomingPlaylist to ensure that the
- * UpcomingPlaylist is in charge of the playback sequence.
- *
- * @see UpcomingPlaylist
- * @see TrackSequenceManager
- * @author Michael Pyne <mpyne@kde.org>
- */
-class UpcomingPlaylist::UpcomingSequenceIterator : public TrackSequenceIterator
-{
-public:
- /**
- * Default constructor.
- *
- * @param playlist The UpcomingPlaylist this iterator belongs to.
- */
- UpcomingSequenceIterator(UpcomingPlaylist *playlist);
-
- /**
- * Copy constructor.
- *
- * @param other The UpcomingSequenceIterator to copy.
- */
- UpcomingSequenceIterator(const UpcomingSequenceIterator &other);
-
- /**
- * Destructor.
- */
- virtual ~UpcomingSequenceIterator();
-
- /**
- * Advances to the next song in the UpcomingPlaylist.
- */
- virtual void advance();
-
- /**
- * This function does nothing, as the currently playing song in the
- * UpcomingPlaylist is always the first song in the sequence.
- */
- virtual void backup();
-
- /**
- * This function returns a perfect duplicate of the object it is called
- * on, to avoid the C++ slicing problem.
- *
- * @return A pointer to a copy of the object it is called on.
- */
- virtual UpcomingSequenceIterator *clone() const;
-
- /**
- * This function sets the currently playing item to @a currentItem. If the
- * item doesn't belong to the parent UpcomingPlaylist, it will be added to
- * the UpcomingPlaylist, replacing any track that may be playing.
- * Otherwise, it is moved up and set to play, replacing any track that may
- * be playing.
- *
- * @param currentItem The PlaylistItem to play.
- */
- virtual void setCurrent(PlaylistItem *currentItem);
-
- /**
- * This function resets any internet state.
- */
- virtual void reset();
-
- /**
- * This function readies the UpcomingSequenceIterator for playback, by
- * making sure the parent UpcomingPlaylist has items to play if it is
- * empty.
- */
- virtual void prepareToPlay(Playlist *);
-
-private:
- UpcomingPlaylist *m_playlist;
-};
-
-QDataStream &operator<<(QDataStream &s, const UpcomingPlaylist &p);
-QDataStream &operator>>(QDataStream &s, UpcomingPlaylist &p);
-
-#endif /* UPCOMINGPLAYLIST_H */
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "viewmode.h"
-
-#include <kiconloader.h>
-#include <kstandarddirs.h>
-#include <kdebug.h>
-
-#include <QPixmap>
-#include <QPainter>
-#include <QResizeEvent>
-
-#include "playlistbox.h"
-#include "searchplaylist.h"
-#include "treeviewitemplaylist.h"
-#include "collectionlist.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// ViewMode
-////////////////////////////////////////////////////////////////////////////////
-
-ViewMode::ViewMode(PlaylistBox *b) :
- QObject(b),
- m_playlistBox(b),
- m_visible(false),
- m_needsRefresh(false)
-{
- m_playlistBox->viewport()->installEventFilter(this);
-}
-
-ViewMode::~ViewMode()
-{
-
-}
-
-void ViewMode::paintCell(PlaylistBox::Item *item,
- QPainter *painter,
- const QColorGroup &colorGroup,
- int column, int width, int)
-{
- if(width < item->pixmap(column)->width())
- return;
-
- if(m_needsRefresh)
- updateHeights();
-
- QFontMetrics fm = painter->fontMetrics();
-
- int y = item->listView()->itemMargin() + border;
- const QPixmap *pm = item->pixmap(column);
-
- if(item->isSelected()) {
- painter->eraseRect(0, 0, width, item->height());
- painter->setRenderHint(QPainter::Antialiasing);
-
- QPen oldPen = painter->pen();
- QPen newPen = oldPen;
-
- painter->setPen(newPen);
- newPen.setJoinStyle(Qt::RoundJoin);
-
- newPen.setWidth(1);
-
- QColor background = m_playlistBox->palette().color(QPalette::Highlight);
- newPen.setColor(m_playlistBox->palette().color(QPalette::Text));
- painter->setPen(newPen);
- painter->drawRoundedRect(border, border, width - border * 2,
- item->height() - border * 2, 2, 2);
-
- QRect inner(border + 1, border + 1, width - border * 2 - 2,
- item->height() - border * 2 - 2);
-
- painter->fillRect(inner, background);
-
- QPainterPath path(inner.bottomLeft());
-
- path.lineTo(QPoint(inner.topLeft().x(), inner.topLeft().y() - 3));
- const QPointF topLeft(inner.topLeft());
- QRectF arc(topLeft, QSizeF(4, 4));
- path.arcTo(arc, 180, -90);
- path.lineTo(inner.topRight());
- path.lineTo(inner.bottomRight());
- path.lineTo(inner.bottomLeft());
-
- QColor window(item->listView()->palette().window().color());
- const QColor base = background;
-
- window.setAlphaF(0.5);
-
- QLinearGradient decoGradient1;
- decoGradient1.setStart(inner.topLeft());
- decoGradient1.setFinalStop(inner.bottomLeft());
- decoGradient1.setColorAt(0, window);
- decoGradient1.setColorAt(1, Qt::transparent);
-
- QLinearGradient decoGradient2;
- decoGradient2.setStart(inner.topLeft());
- decoGradient2.setFinalStop(inner.topRight());
- decoGradient2.setColorAt(0, Qt::transparent);
- decoGradient2.setColorAt(1, base);
-
- painter->fillPath(path, decoGradient1);
- painter->fillPath(path, decoGradient2);
-
- painter->setPen(colorGroup.color(QPalette::HighlightedText));
- }
- else
- painter->eraseRect(0, 0, width, item->height());
-
- if(!pm->isNull()) {
- int x = (width - pm->width()) / 2;
- x = qMax(x, item->listView()->itemMargin());
- painter->drawPixmap(x, y, *pm);
- }
-
- y += pm->height() + fm.height() - fm.descent();
-
- foreach(const QString &line, m_lines[item]) {
- int x = (width - fm.width(line)) / 2;
- x = qMax(x, item->listView()->itemMargin());
- painter->drawText(x, y, line);
- y += fm.height() - fm.descent();
- }
-
- if(item == item->listView()->dropItem())
- paintDropIndicator(painter, width, item->height());
-}
-
-bool ViewMode::eventFilter(QObject *watched, QEvent *e)
-{
- if(m_visible && watched == m_playlistBox->viewport() && e->type() == QEvent::Resize) {
- QResizeEvent *re = static_cast<QResizeEvent *>(e);
- if(re->size().width() != re->oldSize().width())
- m_needsRefresh = true;
- }
-
- if(e->type() == QEvent::Hide)
- m_needsRefresh = true;
-
- return QObject::eventFilter(watched, e);
-}
-
-QString ViewMode::name() const
-{
- return i18nc("the normal viewing mode", "Default");
-}
-
-void ViewMode::setShown(bool shown)
-{
- m_visible = shown;
- if(shown) {
- updateIcons(32);
- m_needsRefresh = true;
- }
-}
-
-void ViewMode::updateIcons(int size)
-{
- for(Q3ListViewItemIterator it(m_playlistBox); it.current(); ++it) {
- PlaylistBox::Item *i = static_cast<PlaylistBox::Item *>(*it);
- i->setPixmap(0, SmallIcon(i->iconName(), size));
- }
-}
-
-void ViewMode::setupItem(PlaylistBox::Item *item) const
-{
- const PlaylistBox *box = item->listView();
- const int width = box->width() - box->verticalScrollBar()->width() - border * 2;
- const int baseHeight = 2 * box->itemMargin() + 32 + border * 2;
- const QFontMetrics fm = box->fontMetrics();
- item->setHeight(baseHeight + (fm.height() - fm.descent()) * lines(item, fm, width).count());
-}
-
-void ViewMode::updateHeights()
-{
- const int width = m_playlistBox->width() - m_playlistBox->verticalScrollBar()->width() - border * 2;
-
- const int baseHeight = 2 * m_playlistBox->itemMargin() + 32 +
- border * 2 + 4;
- const QFontMetrics fm = m_playlistBox->fontMetrics();
-
- for(Q3ListViewItemIterator it(m_playlistBox); it.current(); ++it) {
- PlaylistBox::Item *i = static_cast<PlaylistBox::Item *>(it.current());
- m_lines[i] = lines(i, fm, width);
- const int height = baseHeight + (fm.height() - fm.descent()) * m_lines[i].count();
- i->setHeight(height);
- }
-
- m_needsRefresh = false;
-}
-
-void ViewMode::paintDropIndicator(QPainter *painter, int width, int height) // static
-{
- static const int border = 1;
- static const int lineWidth = 2;
-
- QPen oldPen = painter->pen();
- QPen newPen = oldPen;
-
- newPen.setWidth(lineWidth);
- newPen.setStyle(Qt::DotLine);
-
- painter->setPen(newPen);
- painter->drawRect(border, border, width - border * 2, height - border * 2);
- painter->setPen(oldPen);
-}
-
-QStringList ViewMode::lines(const PlaylistBox::Item *item,
- const QFontMetrics &fm,
- int width)
-{
- // Here 32 is a bit arbitrary, but that's the width of the icons in this
- // mode and seems to a reasonable toLower bound.
-
- if(width < 32)
- return QStringList();
-
- QString line = item->text();
-
- QStringList l;
-
- while(!line.isEmpty()) {
- int textLength = line.length();
- while(textLength > 0 &&
- fm.width(line.mid(0, textLength).trimmed()) +
- item->listView()->itemMargin() * 2 > width)
- {
- int i = line.lastIndexOf(QRegExp( "\\W"), textLength - 1);
- if(i > 0)
- textLength = i;
- else
- textLength--;
- }
-
- l.append(line.mid(0, textLength).trimmed());
- line = line.mid(textLength);
- }
- return l;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CompactViewMode
-////////////////////////////////////////////////////////////////////////////////
-
-CompactViewMode::CompactViewMode(PlaylistBox *b) : ViewMode(b)
-{
-
-}
-
-CompactViewMode::~CompactViewMode()
-{
-
-}
-
-void CompactViewMode::paintCell(PlaylistBox::Item *item,
- QPainter *painter,
- const QColorGroup &colorGroup,
- int column, int width, int align)
-{
- item->K3ListViewItem::paintCell(painter, colorGroup, column, width, align);
- if(item == item->listView()->dropItem())
- paintDropIndicator(painter, width, item->height());
-}
-
-QString CompactViewMode::name() const
-{
- return i18nc("compact viewing mode", "Compact");
-}
-
-void CompactViewMode::setShown(bool shown)
-{
- setVisible(shown);
-
- if(shown) {
- updateIcons(16);
- updateHeights();
- }
-}
-
-void CompactViewMode::updateHeights()
-{
- for(Q3ListViewItemIterator it(playlistBox()); it.current(); ++it)
- it.current()->setup();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TreeViewMode
-////////////////////////////////////////////////////////////////////////////////
-
-TreeViewMode::TreeViewMode(PlaylistBox *b) : CompactViewMode(b),
- m_dynamicListsFrozen(false), m_setup(false)
-{
-
-}
-
-TreeViewMode::~TreeViewMode()
-{
-
-}
-
-QString TreeViewMode::name() const
-{
- return i18n("Tree");
-}
-
-void TreeViewMode::setShown(bool show)
-{
- CompactViewMode::setShown(show);
-
- playlistBox()->setRootIsDecorated(show);
-
- if(show) {
- PlaylistBox::Item *collectionItem = PlaylistBox::Item::collectionItem();
-
- if(!collectionItem)
- return;
-
- if(collectionItem && m_searchCategories.isEmpty())
- setupDynamicPlaylists();
- else {
- foreach(PlaylistBox::Item *item, m_searchCategories)
- item->setVisible(true);
- }
-
- if(!m_setup) {
- m_setup = true;
- playlistBox()->setSorting(-1);
- CollectionList::instance()->setupTreeViewEntries(this);
- playlistBox()->setSorting(0);
- playlistBox()->sort();
- }
- }
- else {
- foreach(PlaylistBox::Item *item, m_searchCategories)
- item->setVisible(false);
- }
-}
-
-void TreeViewMode::removeItem(const QString &item, unsigned column)
-{
- if(!m_setup)
- return;
-
- QString itemKey;
- if(column == PlaylistItem::ArtistColumn)
- itemKey = "artists" + item;
- else if(column == PlaylistItem::GenreColumn)
- itemKey = "genres" + item;
- else if(column == PlaylistItem::AlbumColumn)
- itemKey = "albums" + item;
- else {
- kWarning() << "Unhandled column type " << column;
- return;
- }
-
- if(!m_treeViewItems.contains(itemKey))
- return;
-
- TreeViewItemPlaylist *itemPlaylist = m_treeViewItems.value(itemKey, 0);
-
- if(m_dynamicListsFrozen) {
- m_pendingItemsToRemove << itemKey;
- return;
- }
-
- m_treeViewItems.remove(itemKey);
- itemPlaylist->deleteLater();
- emit signalPlaylistDestroyed(itemPlaylist);
-}
-
-void TreeViewMode::addItems(const QStringList &items, unsigned column)
-{
- if(!m_setup)
- return;
-
- QString searchCategory;
- if(column == PlaylistItem::ArtistColumn)
- searchCategory = "artists";
- else if(column == PlaylistItem::GenreColumn)
- searchCategory = "genres";
- else if(column == PlaylistItem::AlbumColumn)
- searchCategory = "albums";
- else {
- kWarning() << "Unhandled column type " << column;
- return;
- }
-
- ColumnList columns;
- columns.append(column);
-
- PlaylistSearch::Component::MatchMode mode = PlaylistSearch::Component::ContainsWord;
- if(column != PlaylistItem::ArtistColumn)
- mode = PlaylistSearch::Component::Exact;
-
- PlaylistSearch::ComponentList components;
- PlaylistList playlists;
- playlists.append(CollectionList::instance());
-
- QString itemKey;
- PlaylistBox::Item *itemParent = m_searchCategories.value(searchCategory, 0);
-
- foreach(const QString &item, items) {
- itemKey = searchCategory + item;
-
- if(m_treeViewItems.contains(itemKey))
- continue;
-
- components.clear();
- components.append(PlaylistSearch::Component(item, false, columns, mode));
-
- PlaylistSearch s(playlists, components, PlaylistSearch::MatchAny, false);
-
- TreeViewItemPlaylist *p = new TreeViewItemPlaylist(playlistBox(), s, item);
- playlistBox()->setupPlaylist(p, "audio-midi", itemParent);
- m_treeViewItems.insert(itemKey, p);
- }
-}
-
-void TreeViewMode::setDynamicListsFrozen(bool frozen)
-{
- m_dynamicListsFrozen = frozen;
-
- if(frozen)
- return;
-
- foreach(const QString &pendingItem, m_pendingItemsToRemove) {
- m_treeViewItems[pendingItem]->deleteLater();
- m_treeViewItems.remove(pendingItem);
- }
-
- m_pendingItemsToRemove.clear();
-}
-
-void TreeViewMode::setupDynamicPlaylists()
-{
- PlaylistBox::Item *i;
- PlaylistBox::Item *collectionItem = PlaylistBox::Item::collectionItem();
-
- i = new PlaylistBox::Item(collectionItem, "media-optical-audio", i18n("Artists"));
- m_searchCategories.insert("artists", i);
-
- i = new PlaylistBox::Item(collectionItem, "media-optical-audio", i18n("Albums"));
- m_searchCategories.insert("albums", i);
-
- i = new PlaylistBox::Item(collectionItem, "media-optical-audio", i18n("Genres"));
- m_searchCategories.insert("genres", i);
-}
-
-#include "viewmode.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
- * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef VIEWMODE_H
-#define VIEWMODE_H
-
-#include <QObject>
-#include <QStringList>
-#include <QMap>
-
-#include "playlistbox.h"
-
-class QPainter;
-class QColorGroup;
-
-
-class ViewMode : public QObject
-{
- Q_OBJECT
-
-public:
- ViewMode(PlaylistBox *b);
- virtual ~ViewMode();
-
- virtual QString name() const;
- virtual void setShown(bool shown);
-
- virtual void paintCell(PlaylistBox::Item *item,
- QPainter *painter,
- const QColorGroup &colorGroup,
- int column, int width, int align);
-
- virtual bool eventFilter(QObject *watched, QEvent *e);
- void queueRefresh() { m_needsRefresh = true; }
-
- virtual void setupItem(PlaylistBox::Item *item) const;
-
- virtual void setupDynamicPlaylists() {}
-
- /**
- * If the view mode has dynamic lists, this function is used to temporarily
- * freeze them to prevent them from deleting dynamic elements.
- */
- virtual void setDynamicListsFrozen(bool /* frozen */) {}
-
- /**
- * Used for dynamic view modes. This function will be called when \p items
- * are added to \p column (even if the view mode hasn't been shown yet).
- */
- virtual void addItems(const QStringList &items, unsigned column)
- {
- Q_UNUSED(items);
- Q_UNUSED(column);
- }
-
- /**
- * Used for dynamic view modes. This function will be called when \p item
- * is removed from \p column (even if the view mode hasn't been shown yet).
- */
- virtual void removeItem(const QString &item, unsigned column)
- {
- Q_UNUSED(item);
- Q_UNUSED(column);
- }
-
-protected:
- PlaylistBox *playlistBox() const { return m_playlistBox; }
- bool visible() const { return m_visible; }
- void setVisible(bool v) { m_visible = v; }
- void updateIcons(int size);
- virtual void updateHeights();
- static void paintDropIndicator(QPainter *painter, int width, int height);
-
-private:
- static QStringList lines(const PlaylistBox::Item *item, const QFontMetrics &fm, int width);
-
- PlaylistBox *m_playlistBox;
- bool m_visible;
- bool m_needsRefresh;
- QMap<PlaylistBox::Item *, QStringList> m_lines;
- static const int border = 4;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class CompactViewMode : public ViewMode
-{
-public:
- CompactViewMode(PlaylistBox *b);
- virtual ~CompactViewMode();
-
- virtual QString name() const;
- virtual void setShown(bool shown);
-
- virtual void paintCell(PlaylistBox::Item *item,
- QPainter *painter,
- const QColorGroup &colorGroup,
- int column, int width, int align);
-
- virtual void setupItem(PlaylistBox::Item *item) const { item->K3ListViewItem::setup(); }
-protected:
- virtual void updateHeights();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class TreeViewItemPlaylist;
-
-class TreeViewMode : public CompactViewMode
-{
- Q_OBJECT
-
-public:
- TreeViewMode(PlaylistBox *l);
- virtual ~TreeViewMode();
-
- virtual QString name() const;
- virtual void setShown(bool shown);
- virtual void setupDynamicPlaylists();
- virtual void setDynamicListsFrozen(bool frozen);
-
- virtual void removeItem(const QString &item, unsigned column);
- virtual void addItems(const QStringList &items, unsigned column);
-
-signals:
- void signalPlaylistDestroyed(Playlist*);
-
-private:
- QMap<QString, PlaylistBox::Item*> m_searchCategories;
- QMap<QString, TreeViewItemPlaylist*> m_treeViewItems;
- QStringList m_pendingItemsToRemove;
- bool m_dynamicListsFrozen;
- bool m_setup;
-};
-
-#endif
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (c) 2009 Nikolaj Hald Nielsen <nhn@kde.org>
- * Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "volumepopupbutton.h"
-#include "slider.h"
-
-#include <KLocale>
-#include <KVBox>
-#include <KIcon>
-
-#include <QAction>
-#include <QLabel>
-#include <QMenu>
-#include <QToolBar>
-#include <QWheelEvent>
-#include <QWidgetAction>
-
-#include "playermanager.h"
-#include "juk.h"
-
-VolumePopupButton::VolumePopupButton( QWidget * parent )
- : QToolButton( parent )
-{
- m_volumeBeforeMute = 0.0;
-
- //create the volume popup
- m_volumeMenu = new QMenu( this );
-
- KVBox *mainBox = new KVBox( this );
-
- m_volumeLabel= new QLabel( mainBox );
- m_volumeLabel->setAlignment( Qt::AlignHCenter );
-
- KHBox *sliderBox = new KHBox( mainBox );
- m_volumeSlider = new VolumeSlider( 100, sliderBox, false );
- m_volumeSlider->setFixedHeight( 170 );
- mainBox->setMargin( 0 );
- mainBox->setSpacing( 0 );
- sliderBox->setSpacing( 0 );
- sliderBox->setMargin( 0 );
- mainBox->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
- sliderBox->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
-
- PlayerManager *player = JuK::JuKInstance()->playerManager();
-
- QWidgetAction *sliderActionWidget = new QWidgetAction( this );
- sliderActionWidget->setDefaultWidget( mainBox );
-
- connect( m_volumeSlider, SIGNAL(volumeChanged(float)), player, SLOT(setVolume(float)) );
-
- QToolBar *muteBar = new QToolBar( QString(), mainBox );
- muteBar->setContentsMargins( 0, 0, 0, 0 );
- muteBar->setIconSize( QSize( 16, 16 ) );
-
- m_muteAction = new QAction( KIcon( "audio-volume-muted" ), QString(), muteBar );
- m_muteAction->setToolTip( i18n( "Mute/Unmute" ) );
- m_muteAction->setCheckable( true );
- m_muteAction->setChecked( player->muted() );
-
- connect( m_muteAction, SIGNAL(toggled(bool)), player, SLOT(setMuted(bool)) );
- connect( player, SIGNAL(mutedChanged(bool)), this, SLOT(muteStateChanged(bool)) );
-
- m_volumeMenu->addAction( sliderActionWidget );
- muteBar->addAction( m_muteAction );
-
- // set correct icon and label initially
- volumeChanged( player->volume() );
-
- connect( player, SIGNAL(volumeChanged(float)), this, SLOT(volumeChanged(float)) );
-}
-
-void
-VolumePopupButton::refresh()
-{
- volumeChanged( JuK::JuKInstance()->playerManager()->volume() );
-}
-
-void
-VolumePopupButton::volumeChanged( float newVolume )
-{
- if (!JuK::JuKInstance()->playerManager()->muted())
- {
- m_volumeBeforeMute = newVolume;
- }
-
- if ( newVolume <= 0.0001 )
- setIcon( KIcon( "audio-volume-muted" ) );
- else if ( newVolume < 0.34 )
- setIcon( KIcon( "audio-volume-low" ) );
- else if ( newVolume < 0.67 )
- setIcon( KIcon( "audio-volume-medium" ) );
- else
- setIcon( KIcon( "audio-volume-high" ) );
-
- m_volumeLabel->setText( i18n( "%1%" , int( newVolume * 100 ) ) );
-
- if( newVolume != m_volumeSlider->value() )
- m_volumeSlider->setValue( newVolume * 100 );
-
- //make sure to uncheck mute toolbar when moving slider
- if ( newVolume > 0 )
- m_muteAction->setChecked( false );
-
- const KLocalizedString tip = m_muteAction->isChecked() ? ki18n( "Volume: %1% (muted)" ) : ki18n( "Volume: %1%" );
- setToolTip( tip.subs( int( 100 * newVolume ) ).toString() );
-}
-
-void
-VolumePopupButton::muteStateChanged( bool muted )
-{
- if ( muted )
- {
- const float volume = JuK::JuKInstance()->playerManager()->volume();
- setIcon( KIcon( "audio-volume-muted" ) );
- setToolTip( i18n( "Volume: %1% (muted)", int( 100 * volume ) ) );
- }
- else
- {
- JuK::JuKInstance()->playerManager()->setVolume( m_volumeBeforeMute );
- }
-
- m_muteAction->setChecked( muted );
-}
-
-void
-VolumePopupButton::mouseReleaseEvent( QMouseEvent * event )
-{
- if( event->button() == Qt::LeftButton )
- {
- if ( m_volumeMenu->isVisible() )
- m_volumeMenu->hide();
- else
- {
- const QPoint pos( 0, height() );
- m_volumeMenu->exec( mapToGlobal( pos ) );
- }
- }
- else if( event->button() == Qt::MidButton )
- {
- muteStateChanged( JuK::JuKInstance()->playerManager()->mute() );
- }
-
- QToolButton::mouseReleaseEvent( event );
-}
-
-void
-VolumePopupButton::wheelEvent( QWheelEvent * event )
-{
- event->accept();
- PlayerManager *player = JuK::JuKInstance()->playerManager();
- float volume = qBound( 0.0f, player->volume() + float( event->delta() ) / 4000.0f, 1.0f );
- player->setVolume( volume );
- volumeChanged( volume );
-}
-
-#include "volumepopupbutton.moc"
+++ /dev/null
-/**
- * Copyright (c) 2009 Nikolaj Hald Nielsen <nhn@kde.org>
- * Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef VOLUMEPOPUPBUTTON_H
-#define VOLUMEPOPUPBUTTON_H
-
-#include <QToolButton>
-
-class QAction;
-class QEvent;
-class QLabel;
-class QMenu;
-class QMouseEvent;
-class QWheelEvent;
-
-class VolumeSlider;
-
-class VolumePopupButton : public QToolButton
-{
- Q_OBJECT
-
-public:
- VolumePopupButton( QWidget * parent );
- void refresh();
-
-protected:
- virtual void mouseReleaseEvent( QMouseEvent * event );
- virtual void wheelEvent( QWheelEvent * event );
-
-private slots:
- void volumeChanged( float newVolume );
- void muteStateChanged( bool muted );
-
-private:
- QLabel * m_volumeLabel;
- QMenu * m_volumeMenu;
- VolumeSlider * m_volumeSlider;
- QAction * m_muteAction;
- float m_volumeBeforeMute;
-};
-
-#endif // VOLUMEPOPUPBUTTON_H
+++ /dev/null
-/**
- * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
- * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "webimagefetcher.h"
-
-#include <KApplication>
-#include <KStatusBar>
-#include <KXmlGuiWindow>
-#include <KLocale>
-#include <KInputDialog>
-#include <KUrl>
-#include <KDebug>
-#include <KIO/Job>
-#include <KPushButton>
-#include <KDialog>
-
-#include "covermanager.h"
-#include "filehandle.h"
-#include "tag.h"
-#include "juk.h"
-
-#include <QPixmap>
-#include <QDomDocument>
-#include <QDomElement>
-#include <QPointer>
-#include <QLayout>
-#include <QLabel>
-#include <QPainter>
-
-
-class WebImageFetcher::Private
-{
- friend class WebImageFetcher;
-
- Private() : connection(0), dialog(0)
- {
- }
-
- FileHandle file;
- QString artist;
- QString albumName;
- QPointer<KIO::StoredTransferJob> connection;
- KDialog *dialog;
- KUrl url;
-};
-
-WebImageFetcher::WebImageFetcher(QObject *parent)
- : QObject(parent), d(new Private)
-{
-}
-
-WebImageFetcher::~WebImageFetcher()
-{
- delete d;
-}
-
-void WebImageFetcher::setFile(const FileHandle &file)
-{
- d->file = file;
- d->artist = file.tag()->artist();
- d->albumName = file.tag()->album();
-}
-
-void WebImageFetcher::abortSearch()
-{
- if (d->connection)
- d->connection->kill();
-}
-void WebImageFetcher::searchCover()
-{
- KStatusBar *statusBar = JuK::JuKInstance()->statusBar();
- statusBar->showMessage(i18n("Searching for cover. Please Wait..."));
-
-
- KUrl url("http://ws.audioscrobbler.com/2.0/");
- url.addQueryItem("method", "album.getInfo");
- url.addQueryItem("api_key", "3e6ecbd7284883089e8f2b5b53b0aecd");
- url.addQueryItem("artist", d->artist);
- url.addQueryItem("album", d->albumName);
-
- kDebug() << "Using request " << url.encodedPathAndQuery();
-
- d->connection = KIO::storedGet(url, KIO::Reload /* reload always */, KIO::HideProgressInfo);
- connect(d->connection, SIGNAL(result(KJob*)), SLOT(slotWebRequestFinished(KJob*)));
-
- // Wait for the results...
-}
-
-void WebImageFetcher::slotWebRequestFinished(KJob *job)
-{
- kDebug() << "Results received.\n";
-
- if (job != d->connection)
- return;
-
- if (!job || job->error()) {
- kError() << "Error reading image results from last.fm!\n";
- kError() << d->connection->errorString() << endl;
- return;
- }
-
- kDebug() << "Checking for data!!\n";
- if (d->connection->data().isEmpty()) {
- kError() << "last.fm returned an empty result!\n";
- return;
- }
-
- QDomDocument results("ResultSet");
-
- QString errorStr;
- int errorCol, errorLine;
- if (!results.setContent(d->connection->data(), &errorStr, &errorLine, &errorCol)) {
- kError() << "Unable to create XML document from results.\n";
- kError() << "Line " << errorLine << ", " << errorStr << endl;
-
- return;
- }
-
- QDomNode n = results.documentElement();
-
- if (n.isNull()) {
- kDebug() << "No document root in XML results??\n";
- return;
- }
- n = n.firstChildElement("album");
-
- d->url = n.lastChildElement("image").text(); //FIXME: We assume they have a sane sorting (smallest -> largest)
- //TODO: size attribute can have the values mega, extralarge, large, medium and small
-
- kDebug() << "Got cover:" << d->url;
-
- KStatusBar *statusBar = JuK::JuKInstance()->statusBar();
- statusBar->showMessage(i18n("Downloading cover. Please Wait..."));
-
- KIO::StoredTransferJob *newJob = KIO::storedGet(d->url, KIO::Reload /* reload always */, KIO::HideProgressInfo);
- connect(newJob, SIGNAL(result(KJob*)), SLOT(slotImageFetched(KJob*)));
-}
-
-void WebImageFetcher::slotImageFetched(KJob* j)
-{
- KStatusBar *statusBar = JuK::JuKInstance()->statusBar();
- statusBar->clearMessage();
-
- KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob*>(j);
-
- if (d->dialog) return;
- d->dialog = new KDialog();
- d->dialog->setCaption(i18n("Cover found"));
- d->dialog->setButtons(KDialog::Apply | KDialog::Cancel);
- d->dialog->button(KDialog::Apply)->setText(i18n("Store"));
- QWidget *mainWidget = new QWidget();
- d->dialog->setMainWidget(mainWidget);
- mainWidget->setLayout(new QVBoxLayout);
-
- if(job->error()) {
- kError() << "Unable to grab image\n";
- d->dialog->setWindowIcon(DesktopIcon("dialog-error"));
- return;
- }
-
- QPixmap iconImage, realImage(150, 150);
- iconImage.loadFromData(job->data());
- realImage.fill(Qt::transparent);
-
- if(iconImage.isNull()) {
- kError() << "Thumbnail image is not of a supported format\n";
- return;
- }
-
- // Scale down if necesssary
- if(iconImage.width() > 150 || iconImage.height() > 150)
- iconImage = iconImage.scaled(150, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation);
-
- QLabel *cover = new QLabel();
- cover->setPixmap(iconImage);
- mainWidget->layout()->addWidget(cover);
- QLabel *infoLabel = new QLabel(i18n("Cover fetched from <a href='http://last.fm/'>last.fm</a>."));
- infoLabel->setOpenExternalLinks(true);
- infoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- mainWidget->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
- mainWidget->layout()->addWidget(infoLabel);
-
- d->dialog->setWindowIcon(realImage);
- d->dialog->show();
- connect(d->dialog, SIGNAL(applyClicked()), SLOT(slotCoverChosen()));
-}
-
-
-void WebImageFetcher::slotCoverChosen()
-{
- kDebug() << "Adding new cover for " << d->file.tag()->fileName()
- << "from URL" << d->url;
-
- coverKey newId = CoverManager::addCover(d->url, d->file.tag()->artist(), d->file.tag()->album());
-
- if (newId != CoverManager::NoMatch) {
- emit signalCoverChanged(newId);
- d->dialog->close();
- d->dialog->deleteLater();
- d->dialog = 0;
- }
-}
-
-#include "webimagefetcher.moc"
-
-// vim: set et sw=4 tw=0 sta:
+++ /dev/null
-/**
- * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
- * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
- * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef WEBIMAGEFETCHER_H
-#define WEBIMAGEFETCHER_H
-
-#include <QObject>
-
-// Predeclare some classes.
-
-
-template<class T>
-class QList;
-
-class KJob;
-class KUrl;
-
-class FileHandle;
-
-
-class WebImageFetcher : public QObject
-{
- Q_OBJECT
-
-public:
- WebImageFetcher(QObject *parent);
- ~WebImageFetcher();
-
- void setFile(const FileHandle &file);
-
-public slots:
- void abortSearch();
- void searchCover();
-
-
-signals:
- void signalCoverChanged(int coverId);
-
-private slots:
- void slotWebRequestFinished(KJob *job);
- void slotImageFetched(KJob *job);
- void slotCoverChosen();
-
-private:
- class Private;
- Private *d;
-};
-#endif
-
-// vim: set et sw=4 tw=0 sta: