Comparar commits

...

1501 Commits

Autor SHA1 Mensagem Data
David Mohammed f8562992d9 Merge pull request #400 from mlvtito/master
rename variable to avoid use of key word
2019-07-31 12:00:44 +01:00
Arnaud Fonce ee1ac265bd rename variable to avoid use of key word 2019-07-01 12:05:36 +02:00
fossfreedom 6efdf8b750 one more try to get the headerbar to correctly display the search toolbar 2015-06-03 17:49:30 +01:00
fossfreedom 0d2fcc27bb better working with alternative-toolbar and headerbar - view button is shown correctly depending upon what mode the alternative toolbar is using 2015-05-30 09:22:04 +01:00
fossfreedom 43f2dec84f make autostart work with alternative toolbar 2015-05-24 08:54:31 +01:00
fossfreedom d5768b8184 Merge remote-tracking branch 'origin/master' 2015-05-14 21:09:14 +01:00
fossfreedom ab4888efca faster startup of plugin by loading artist data only if necessary 2015-05-14 21:08:45 +01:00
David Mohammed 5847ab0081 Update README.md 2015-05-12 16:32:33 +01:00
fossfreedom 7a4b510a2a do some proper cleanup of the headerbar objects when the plugin exits 2015-05-06 23:51:15 +01:00
fossfreedom 9b188f4d4e fix lockup due to llyrics plugin not releasing gdk threads but flow view was dependent also on similar thread usage - issue #342 2015-04-27 00:12:10 +01:00
fossfreedom ae918845ff correct symbolic icons for coverart_browser and entryview - issue #360 2015-04-25 23:55:37 +01:00
fossfreedom ed275b8736 default to sidebar for the overlay picture - issue #351 2015-04-25 22:40:20 +01:00
fossfreedom e377735696 update readme - issue #356 2015-04-25 16:06:53 +01:00
fossfreedom 0979b84e85 cleanup of coverart_playsource - issue #356 2015-04-25 16:04:07 +01:00
fossfreedom b4cd3aa305 rework playlist_source so that it behaves like the other views which means we dont need the separate whatsplaying icon and other access methods - issue #356 2015-04-25 16:02:54 +01:00
fossfreedom d266d851ac ensure alttoolbarsidebar is a recognised treeview for the playsource toggle 2015-04-19 22:53:53 +01:00
fossfreedom cb76fc11ff interact with the alternative-toolbar correctly to setup the headerbar stuff 2015-04-18 11:38:08 +01:00
fossfreedom 8e4ff492f2 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2015-04-13 19:58:58 +01:00
fossfreedom 20440530e2 hide the source unless needed 2015-04-13 19:58:49 +01:00
fossfreedom 5fde6b4db4 correctly load the new switcher symbolic icon 2015-04-10 13:16:04 +01:00
fossfreedom e5b3ac585f rejig so that views are correctly defined depending upon the combinations of song-category and stackswitcher - issue #359 2015-04-08 22:37:57 +01:00
fossfreedom 13007fa6af hook up headerbar with coverart and switcher - issue #359 2015-04-07 23:53:23 +01:00
fossfreedom 3baac6bf26 add some tracing statements 2015-04-06 23:05:17 +01:00
fossfreedom 6d995200f9 initial implementation of header switch - not as yet hooked up - issue #359 2015-04-06 22:13:26 +01:00
fossfreedom d9e952bcba update readme for icons fix 2015-03-14 00:29:17 +00:00
fossfreedom 4c0f10b950 fix dark-theme icon visibility issues for key display icons - issue #352 2015-03-14 00:27:45 +00:00
fossfreedom b77391b13d switch to playlist via properties menu - issue #353 2015-03-10 18:19:55 +00:00
fossfreedom 5d30d526fc tidy up and make playing from toolbar possible - issue #347 2015-03-10 00:54:58 +00:00
fossfreedom a199f1019e save and load methods for persistent playlist - issue #347 2015-03-09 22:25:14 +00:00
fossfreedom b6e0295968 add gtk_version helper function 2015-03-01 21:42:48 +00:00
fossfreedom d9c310bdf9 remember export dialog settings between openings - issue #350 2015-02-28 23:08:01 +00:00
fossfreedom fd69e2fbaa take latest po's from release 2.1 branch 2015-02-28 22:04:59 +00:00
fossfreedom 45e59f82d5 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2015-02-25 20:40:42 +00:00
fossfreedom 08c0ad0991 fix spurious dbchange error when playing radio streams instead of musi 2015-02-25 20:40:16 +00:00
fossfreedom 58339c78f7 fix for api changein rb3.2 for rb.append_plugin_source_path 2015-02-25 20:39:42 +00:00
David Mohammed 3000ce1dd2 Update README.md 2015-02-17 20:38:46 +00:00
fossfreedom fa5833a969 add ability to select and play using RB's own toolbar play button - issue #349 2015-02-11 21:34:55 +00:00
fossfreedom 1a83844fe0 on startup make sure we set the playing/selected source correctly so that clicking the toolbar playbutton doesnt start with a random track from the music library 2015-02-09 22:20:39 +00:00
fossfreedom 5a946e87e5 a bit of cleanup and explanation - issue #348 2015-02-09 19:35:29 +00:00
fossfreedom 9a892d0a67 fix retrieval of coverat info for rb 3.2 - issue #348 2015-02-09 00:08:50 +00:00
fossfreedom 01534acefa respond to toolbar visibility signal for the alternative toolbar 2015-02-08 20:29:47 +00:00
fossfreedom a51c43fc0d update readme for beta 1 2015-02-06 22:32:12 +00:00
fossfreedom 0a3d4be746 latest tr translation 2015-02-05 16:23:38 +00:00
fossfreedom f6a7119247 smaller resizing - issue #79 2015-02-03 23:25:02 +00:00
fossfreedom 850f9bcb9b add smooth-scrolling support to icon-view resize - issue #79 2015-01-29 23:59:10 +00:00
fossfreedom 92995493d0 add ctrl+mousewheel icon resizing - issue #79 2015-01-29 23:35:49 +00:00
fossfreedom 4bc283a420 remove lots of deprecated Gtk syntax 2015-01-28 20:40:04 +00:00
David Mohammed 124f6f647d revert previous change and some cleanup 2015-01-28 13:47:50 +00:00
fossfreedom a49ec03b67 run update_all on translations 2015-01-26 21:23:11 +00:00
fossfreedom bdf8a7638a update README for issue #318 2015-01-26 20:08:31 +00:00
fossfreedom b268362880 add picture icons to track-view and play-source to allow switching between views - issue #318 2015-01-26 20:05:00 +00:00
David Mohammed 35ce340691 use $HOME rather than $USER for those users who's home is not home 2015-01-24 23:28:25 +00:00
fossfreedom 444cc7cd58 latest ru translation 2015-01-24 21:27:24 +00:00
fossfreedom 5ce1e3edd5 respond to alternative-toolbar toolbar-visibility message to hide/show the source toolbar - issue #321 2015-01-11 15:16:44 +00:00
fossfreedom 53a5b0bc3d latest translations 2015-01-07 22:50:22 +00:00
fossfreedom b01a20d806 rerun translation stuff 2014-12-21 23:14:14 +00:00
fossfreedom ceea5d06dc more logical right-click menu structures 2014-12-08 20:00:59 +00:00
fossfreedom 9425b1e1b5 pycharm autorefactor 2014-12-03 19:32:49 +00:00
David Mohammed 72fc8cb4b2 Update README.md 2014-11-29 10:31:30 +00:00
fossfreedom 8880d9a08e add text alignment options - issue #340 2014-11-23 00:11:41 +00:00
fossfreedom a51329e0dd add text alignment options - issue #340 2014-11-23 00:09:59 +00:00
fossfreedom 4ffb187890 better overlay icon 2014-11-20 10:21:29 +00:00
fossfreedom 0256a65b18 fix toggle coverart to work with new overlay 2014-11-19 23:26:24 +00:00
fossfreedom cbbb254886 update readme 2014-11-19 21:49:14 +00:00
fossfreedom d24459f6a4 Merge remote-tracking branch 'origin/master'
Conflicts:
	README.md
2014-11-19 21:44:42 +00:00
fossfreedom 2dfb1a1566 add a coverwindow - issue #339 2014-11-19 21:42:26 +00:00
David Mohammed 8e53da5ca1 Update README.md 2014-11-12 11:26:56 +00:00
fossfreedom 746e6b9ede make the hover play icon consistently positioned - issue #343 2014-11-10 21:22:56 +00:00
fossfreedom d3bbfa798a some minor code cleanup 2014-11-05 20:29:40 +00:00
fossfreedom 908b564cb8 update release me with issue #313 2014-10-30 22:03:44 +00:00
fossfreedom ffa85938a2 add double click to track and cover pane handle to open to full height, close if already open - issue #313 2014-10-30 22:01:25 +00:00
fossfreedom c634c8f514 add play-next option for tracks - issue #329 2014-10-24 20:06:15 +01:00
fossfreedom d7eea33c9d add play-next option for albums - issue #329 2014-10-23 23:35:45 +01:00
fossfreedom 6a02d3b74a fix obscure GtkBuilder bug with parameter inheritance issues for iconview - issue #338 2014-10-18 10:01:24 +01:00
fossfreedom 92020328ea update readme 2014-10-12 10:01:16 +01:00
fossfreedom 5ad55ccab3 auto-close bottom pane if too small - issue #337 2014-10-12 09:54:36 +01:00
fossfreedom 16d2593b09 intelligent pane handles - issue #335 2014-10-04 09:37:18 +01:00
fossfreedom 47e5220357 resize entry grid cover correctly - issue #336 2014-10-03 22:25:32 +01:00
fossfreedom aca7ff9d02 replace expander with hidden version - issue #320 2014-10-02 20:46:10 +01:00
fossfreedom 3abf4537db add double click support for artist-info pane - issue #314 2014-07-21 23:40:02 +01:00
fossfreedom 666395e547 add double click support for track-artist pane - issue #314 2014-07-20 00:12:34 +01:00
fossfreedom 533c830838 fix links icons in global installation 2014-07-16 21:57:04 +01:00
fossfreedom 1900e51ff1 fix global darker theme install and missing css file 2014-07-15 22:48:05 +01:00
fossfreedom 513f9301dc corrected call from makefile to ensure translation build does not fail 2014-07-15 22:47:38 +01:00
fossfreedom 3aa9e24f81 fixed makefile install for translations 2014-07-15 22:47:09 +01:00
David Mohammed 58eed3a889 Update README.md 2014-07-12 21:55:55 +01:00
fossfreedom 4058056b70 adjust readme for release info 2014-07-12 00:24:48 +01:00
fossfreedom a9fe7ddd27 release info in plugin files 2014-07-12 00:21:38 +01:00
fossfreedom ac52161047 latest readme 2014-07-12 00:19:35 +01:00
fossfreedom e2803df857 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2014-07-12 00:00:30 +01:00
fossfreedom 8aa2e7105e updated coverart_artistinfo icons as per jrbastiens recommendations - issue #317 2014-07-12 00:00:08 +01:00
fossfreedom f968221bff new majority translation - ru 2014-07-11 13:48:31 +01:00
fossfreedom 90b4bf31f3 latest translation - ms 2014-07-11 07:10:15 +01:00
fossfreedom 49b355b8cf latest ko translation and run and update_all 2014-07-08 08:12:11 +01:00
fossfreedom edfd24bbd3 some fixups when adding and deleting tracks 2014-07-06 22:59:49 +01:00
fossfreedom c5042bdc57 amend readme 2014-07-06 13:00:00 +01:00
fossfreedom e6c650d7b8 replace views label with an ellipsis - issue #328 2014-07-06 12:58:20 +01:00
fossfreedom 52e3e7e2ef latest translations 2014-07-05 22:01:41 +01:00
fossfreedom 82558792b5 latest translations and remove translations where no longer majority translated 2014-07-04 19:49:40 +01:00
fossfreedom e0e5e5b812 reduce install to a users locale or if it doesnt exist then default to en_US - issue #327 2014-07-03 21:16:33 +01:00
fossfreedom 31041fa39a rework coverart display to overcome perceived GTK scrollwindow resizing bug when policy is usually set to NEVER to hide the scrollwindow scrollbars - issue #325 2014-07-03 20:41:05 +01:00
fossfreedom 1dcbc4ce07 latest translations 2014-07-01 23:03:22 +01:00
fossfreedom 003b10afa6 change entryview compact image from AspectFrame to Frame - this gives the image better balance vertically 2014-06-30 23:06:43 +01:00
fossfreedom c1fbb27b0c latest fr_CA translation 2014-06-30 12:28:31 +01:00
fossfreedom 657abe17fb update readme to reflect localisation - issue #319 2014-06-29 19:50:34 +01:00
fossfreedom ba5d9e139a add internationalization on lastfm results - issue #319 2014-06-29 19:41:42 +01:00
fossfreedom d345e75952 latest de translation 2014-06-28 23:29:18 +01:00
fossfreedom 0f20559e2f latest pt_BR translation 2014-06-28 22:11:23 +01:00
fossfreedom 5977335253 latest translations from launchpad 2014-06-28 21:44:37 +01:00
fossfreedom 6d5be5812a delay cover_size update slightly to improve usability 2014-06-28 15:18:45 +01:00
fossfreedom 5c20b3bdcc readme update 2014-06-28 10:54:57 +01:00
fossfreedom 17c871897e cleanup unneeded icons in source base 2014-06-28 10:27:28 +01:00
fossfreedom 8947aebe48 reversed shadow cover hover icons - prefer the standard white icons 2014-06-28 10:25:44 +01:00
fossfreedom 802cd5a36a various cleanups and fix display of entry-pane coverart if artist info is displayed and the entry-view is opened for the first time 2014-06-28 10:18:58 +01:00
fossfreedom 115a652a71 use more solid hover icons when covers have shadow effect 2014-06-26 21:36:12 +01:00
fossfreedom 2148fd428a corrected hover icon calculation to take into account icon spacing and padding correctly - issue #316 2014-06-26 21:11:18 +01:00
fossfreedom 9c90b0b8bb add missing files and add the alternative hover icon set 2014-06-25 23:27:14 +01:00
fossfreedom e10a75945a revamped single click icons - issue #300 2014-06-25 23:09:33 +01:00
fossfreedom b1837365a2 add ability to see and adjust what is playing - issue #296 2014-06-25 22:53:49 +01:00
fossfreedom d9dc24447c latest es and fr_CA translations - issue #288 2014-06-22 14:45:10 +01:00
fossfreedom b35f4b5615 add missing imports - issue #288 2014-06-22 10:33:02 +01:00
fossfreedom ad04ae14dd remove bool error and regen locales to capture extra message - issue #288 2014-06-22 10:30:40 +01:00
fossfreedom 8392648ffe fix propagation issues for areas that respond to button_release events - the idea being that button_release events must have a corresponding button_press event otherwise the call is invalid and comes from somewhere else - issue #298 2014-06-20 21:08:49 +01:00
fossfreedom fd07433c87 Merge remote-tracking branch 'origin/master' 2014-06-20 17:26:45 +01:00
fossfreedom a78ad58de5 fix issue with track artist filter opening when clicking on artist info panes - issue #309 2014-06-20 17:26:12 +01:00
fossfreedom 052df42b29 add missing queued to playing notification message - issue #288 2014-06-20 13:09:04 +01:00
fossfreedom cd3847ba67 latest fr_CA from transifex 2014-06-20 09:16:42 +01:00
David Mohammed cabc112d1c Merge pull request #310 from jrbastien/master
Updated monochrome coverart browser icon and original design files
2014-06-20 08:46:57 +01:00
jrbastien cfde5a42b4 Changing the monochrome coverart browser icon for the left tool bar and adding the original design files as per discussion in issue #300. 2014-06-19 21:25:37 -04:00
fossfreedom 72710425e5 latest fr_CA and it translations - issue #299 2014-06-19 20:24:32 +01:00
fossfreedom 606bb0d065 fix blink display of single click icon if moving the mouse fast between cells 2014-06-18 23:50:36 +01:00
fossfreedom 7ec7ff72e3 stop inadvertent refresh of tile display due to setting of the display text radio button on first load - issue #308 2014-06-18 19:58:39 +01:00
fossfreedom b6dd370470 new entryview icon - issue #300 2014-06-18 19:16:35 +01:00
fossfreedom 5b23026ae8 better spacing in flow appearance dialog - issue #266 2014-06-18 19:13:28 +01:00
fossfreedom e71656aeb3 fix locale display issues with the coverart info panes - issue #299 2014-06-17 20:06:00 +01:00
fossfreedom 67b5575fb4 latest it.po translation 2014-06-16 21:14:27 +01:00
fossfreedom 0a71517161 add and remove some debug trying to track down issue #307 2014-06-15 10:34:10 +01:00
fossfreedom 5735d6d6f3 added some more translator hints and ensure that these comments are correctly extracted - issue #299 2014-06-14 23:21:33 +01:00
fossfreedom c98881b676 latest translations from release 1.1 and update config files to pull the latest translation items from the source files - issue #299 2014-06-14 12:14:33 +01:00
fossfreedom 7806c91c86 incorporated recommendations from mgratton to resolve focus crashes - issue #305 2014-06-12 23:40:28 +01:00
fossfreedom a34ebbd3db better vertical pane handles - simple gradient with a smaller size. Works with dark themes and standard themes such as adwaita and ambiance 2014-06-10 21:41:03 +01:00
fossfreedom 635afa73e5 completely rewrite single click capability - issue #288 2014-06-09 22:34:40 +01:00
fossfreedom ee5b1a19ea ignore ALT-Left key to summons the quick search - issue #305 2014-06-08 09:43:28 +01:00
fossfreedom cb3b67991b replicated auto-open capability for track artist pane for artist info pane 2014-06-07 22:40:59 +01:00
fossfreedom 1504c90b4d stop using child allocated width and just use the paned position #298 2014-06-07 17:56:37 +01:00
fossfreedom 9a8efff960 more debug info to track down issue #298 2014-06-07 09:59:58 +01:00
fossfreedom 9068149d07 Merge remote-tracking branch 'origin/master' 2014-06-07 07:17:42 +01:00
fossfreedom 4decb6c260 add notification feedback that an album has been queue when single click append has been chosen - issue #288 2014-06-07 07:17:21 +01:00
David Mohammed 8303145003 Update README.md 2014-06-06 08:44:59 +01:00
fossfreedom 039a772795 fix local genre error on playing - issue #303 2014-06-06 00:08:40 +01:00
fossfreedom 84f34bcf18 hide whatplayingicon correctly 2014-06-05 21:43:53 +01:00
fossfreedom c766a4dedc fix locale tooltip for All Genres - issue #303 2014-06-05 21:37:42 +01:00
fossfreedom 4fe43a950f make the highlight a little more stylish - issue #298 2014-06-05 20:58:28 +01:00
fossfreedom 437dc66cf7 add highlight for the vertical panes to indicate that something can be selected - issue #298 2014-06-05 20:18:17 +01:00
fossfreedom d4e172aafb add highlight for the vertical panes to indicate that something can be selected - issue #298 2014-06-05 20:17:40 +01:00
fossfreedom 28a8c346c7 remove bottom display hiding option - issue #302 2014-06-04 19:45:00 +01:00
fossfreedom a4c8d23fbb fix for preferences button from plugins - issue #301 2014-06-04 19:38:44 +01:00
fossfreedom d35f173453 prelim stuff for displaying queue tracks - issue #296 2014-06-04 19:35:27 +01:00
fossfreedom 3a9589074f run pycharms optimize imports over the python modules in the project 2014-06-03 20:04:38 +01:00
David Mohammed 8cf80c99bd Update README.md 2014-06-03 17:39:25 +01:00
David Mohammed 0bbde2077c Update README.md 2014-06-03 16:30:56 +01:00
fossfreedom 519fb78c84 general cleanup - remove old rb2 code that is no longer applicable 2014-06-02 20:31:26 +01:00
fossfreedom 2d828b4587 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2014-06-02 00:18:31 +01:00
fossfreedom 0dd34ca8f3 missing file for entryview smallwindow support 2014-06-02 00:17:56 +01:00
fossfreedom 2d6bcd02b6 add missing file for compact view 2014-06-01 23:26:18 +01:00
fossfreedom 5fa4fd391e latest readme 2014-05-26 14:08:38 +01:00
fossfreedom 535059df62 add uninstall for coverart-browser - issue #232 2014-05-26 14:04:12 +01:00
fossfreedom 6f10706ac1 support smallwindow plugin - issue #295 2014-05-25 00:13:14 +01:00
fossfreedom a5a3d6b85c reformat code according to pycharm 2014-05-24 14:52:09 +01:00
fossfreedom cae74bf6e7 entryview add-to-playing menu item. Also have only one query model for the entire source rather than as before seperate query models for entry views and main source - issue #288 2014-05-24 00:10:19 +01:00
fossfreedom 08b979fa0a entryview add-to-playing menu item. Also have only one query model for the entire source rather than as before seperate query models for entry views and main source - issue #288 2014-05-23 23:52:40 +01:00
fossfreedom 7a20522c2f view add-to-playing menu item - issue #288 2014-05-23 19:54:11 +01:00
fossfreedom 8243b2ed34 single click queue adds to playing source - issue #288 2014-05-22 23:47:28 +01:00
fossfreedom 1ea5d3dd67 Add Views button to Play Queue and and Play Queue within the views button - issue #294 2014-05-21 21:37:05 +01:00
fossfreedom 4c2ef51454 latest README updates 2014-05-21 19:50:15 +01:00
fossfreedom c7696d412c slightly delay filter whilst typing - issue #293 2014-05-21 19:26:42 +01:00
fossfreedom 82adb4653d better spacing of the coverart - issue #291 2014-05-19 22:11:25 +01:00
fossfreedom 41e80ee47b various fixups part 2 - issue #291 2014-05-19 21:28:09 +01:00
fossfreedom 87ea90d054 various fixups - issue #291 2014-05-19 21:05:54 +01:00
fossfreedom ec24905ed0 update README with the latest information 2014-05-18 23:48:35 +01:00
fossfreedom 1758a56ef2 refactored track pane code issue #291 2014-05-18 23:32:33 +01:00
fossfreedom 934606eb2f fix for autosizing problem in compact view issue #289 2014-05-18 10:39:53 +01:00
fossfreedom 043790eda2 add follow song option to properties menu together with its implementation issue #278 2014-05-18 08:41:21 +01:00
fossfreedom eed81c45a1 complete stack conversion for artist view issue #287 2014-05-17 23:49:45 +01:00
fossfreedom edf995395a change display of cover to be a stack to give it an animation effect when changing the selection - issue #289 2014-05-10 23:49:23 +01:00
fossfreedom e12d09e52e cleanup and use scrolledwindow to display image rather than custom draw - issue #289 2014-05-10 21:23:31 +01:00
fossfreedom 0ec0cd8f75 replace notebook with GtkStack - issue #289 2014-05-09 22:36:54 +01:00
fossfreedom 473b656412 ignore pycharms idea files 2014-05-05 20:33:31 +01:00
fossfreedom 22c0b68add its not unusual to not be returned similar tracks for a given search - lets reduce the display of the info box to real errors being returned from the provider 2014-05-04 11:08:56 +01:00
fossfreedom 8edf61af6a add similar genre playlist 2014-05-04 10:54:59 +01:00
fossfreedom e8aad1c034 remember the setting of the entry view mode as well as making the menu signals unique for each entry view. We need to do this otherwise clicking on a menu option will invoke the method in the wrong entry view class - e.g. SongInfo dialog fails to display in compact view mode because the signal being invoked is the full entry view class. 2014-05-03 23:16:09 +01:00
fossfreedom 4091c9be50 fix closure of artist info where the icons confused the width calculation 2014-05-03 18:38:07 +01:00
fossfreedom d2be6895f0 some cleanup 2014-05-02 23:49:42 +01:00
fossfreedom 52b8588f3f add initial capability for compact vs full entry view mode - issue #289 2014-05-02 22:43:07 +01:00
fossfreedom e7669d3117 attempt to redraw correctly to improve appearance of icon - issue #285 2014-04-17 00:23:48 +01:00
fossfreedom 1804a55426 single click queue - issue #288 2014-04-17 00:09:00 +01:00
fossfreedom b514740e19 add similar playlist capability - issue #258 2014-04-14 22:24:44 +01:00
David Mohammed d39e964bc5 Update README.md 2014-04-04 21:57:09 +01:00
fossfreedom c7f6281e11 fix locale display of window title - issue #284 2014-04-04 21:34:37 +01:00
fossfreedom 4afc22c686 add filter by composer 2014-03-29 00:28:14 +00:00
fossfreedom fb64f74663 copy coverart_rb3compat module from release1.1 2014-03-28 21:50:44 +00:00
fossfreedom 3896c62844 fix search placement so that it correctly moves when rhythmbox window is resized 2014-03-28 21:42:38 +00:00
David Mohammed 52033cb0a9 Update README.md 2014-03-22 10:05:02 +00:00
fossfreedom 48c21be900 lets remember the last genre folder chosen - issue #215 2014-03-22 10:00:58 +00:00
fossfreedom 72a903992d Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2014-03-22 09:35:31 +00:00
fossfreedom f8351aadb4 lets save custom user icon info in the cache folder not the plugin folder so that it survives a reinstall - issue #215 2014-03-22 09:35:07 +00:00
David Mohammed 29da8eda3e Update README.md 2014-03-22 00:17:33 +00:00
fossfreedom b202684e0a boost artistinfo with echonest biography - issue #272 2014-03-21 23:50:55 +00:00
fossfreedom 873571f1ab add filter buttons to artist info to allow filtering by similar artist - issue #279 2014-03-17 21:31:41 +00:00
fossfreedom 48342cdd18 prettify export dialog - issue #266 2014-03-10 23:43:49 +00:00
fossfreedom 90e02345fb prettify the browser plugin preferences - issue #266 2014-03-10 21:57:41 +00:00
fossfreedom b48731ed6a cleanup 2014-03-09 23:10:31 +00:00
fossfreedom 870b4cdd7b rework jump to playing so that all views are correctly scrolled to - issue #278 2014-03-09 23:09:46 +00:00
fossfreedom ecfdc66706 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2014-03-09 18:53:19 +00:00
fossfreedom aa8d23e65b fix focus issues so that we don't jump back to the plugin unless we started playing from the plugin - issue #278 2014-03-09 18:52:54 +00:00
David Mohammed 5013de9127 Update README.md 2014-03-09 11:54:10 +00:00
fossfreedom 0c0d4d6c57 add support for JumpToPlaying song shortcut - issue #278 2014-03-09 11:43:36 +00:00
fossfreedom 9da85017b9 manually apply #277 patch 2014-03-06 18:31:31 +00:00
fossfreedom 4174f71436 fix track artist filter display on startup if closed 2014-02-15 22:54:53 +00:00
fossfreedom 3088768fe6 some tidyups 2014-02-15 21:24:11 +00:00
fossfreedom acb6caaba0 wrong override caused failure to check lastfm plugin presence in artist view - issue #264 2014-02-15 00:29:54 +00:00
fossfreedom 8619d73007 fix 14.04 playlists + openfolder plugin support - issue #263 2014-02-14 22:54:33 +00:00
fossfreedom 18666de36f change some of the defaults for new users 2014-02-05 23:53:23 +00:00
fossfreedom e9af41d634 rework track artist filter to mirror the artist info pane - issue #271 2014-02-05 00:02:21 +00:00
fossfreedom 9763743a95 snap shut the artist paned if too small to visually see anything useful - issue #268 2014-02-04 19:46:58 +00:00
fossfreedom b6ffa2de70 update README 2014-02-04 00:07:51 +00:00
fossfreedom 74adbe6c3f transfer darker stuff from popups.xml to popups.xml.in so that it is not overwritten when we run the translation stuff 2014-02-04 00:06:02 +00:00
fossfreedom fd42d4e601 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2014-02-04 00:03:11 +00:00
fossfreedom 0b97a39edc add artist-info-pane implementation - issue #268 2014-02-04 00:03:01 +00:00
David Mohammed 23e2ed5297 Merge pull request #270 from jrbastien/master
Fine tuning of the lighter theme and added new darker theme.
2014-02-03 15:17:06 -08:00
jrbastien 273841ec65 Fine tuning of the lighter theme and added new darker theme. 2014-02-02 19:29:25 -05:00
fossfreedom d128149d8d this is now a python3 only install - remove the old python2 installation stuff 2014-01-26 22:01:39 +00:00
fossfreedom 9cdf49e975 fix rb2 encoding issue with last commit - issue #262 2014-01-22 21:40:49 +00:00
fossfreedom 74319826d2 correct action_name to be valid in RB3 - issue #262 2014-01-22 21:33:16 +00:00
fossfreedom afea82eee5 use rb3compat functions - issue #257 2014-01-22 20:30:24 +00:00
fossfreedom dda323ac04 fix crash for album titles that have unicode characters - issue #257 2014-01-22 20:20:23 +00:00
fossfreedom a09a25690c fix crash for non-english locales where artist is not translated by the plugin 2014-01-22 18:10:09 +00:00
fossfreedom f27ee2464c replace tabs with spaces 2014-01-20 23:59:04 +00:00
fossfreedom 18aaf08f4b fix sorting of artist view after album information such its rating has been changed - issue #257 2014-01-20 23:14:28 +00:00
fossfreedom c03166007f fix boundary issues which caused crash when moving albums to the end of the view - issue #259 2014-01-20 23:06:56 +00:00
fossfreedom 0c66334569 latest sprite image - issue #240 2014-01-20 09:11:34 +00:00
fossfreedom 1e88bab104 latest bg translation 2014-01-19 20:23:46 +00:00
fossfreedom b2eabeb8eb fix sorting issue after restart together with scroll sync issue between artist and tile view - issue #257 2014-01-19 19:46:33 +00:00
fossfreedom d93ea16d1a fix for float issues in earlier versions of rhythmbox - issue #256 2014-01-18 21:22:22 +00:00
fossfreedom ac321f7815 update README for beta 3 release 2014-01-18 14:43:05 +00:00
fossfreedom c53e6c33f8 scale tooltip to original image dimensions - issue #256 2014-01-18 14:35:15 +00:00
fossfreedom 368dda444b latest translations 2014-01-18 14:02:54 +00:00
fossfreedom d2640cf11a latest translations 2014-01-16 22:50:23 +00:00
fossfreedom b56ec0e5d9 reorder the album when the sort keys change - issue #254 2014-01-16 21:34:45 +00:00
fossfreedom 5d0d513f93 fix trusty icon offset issue 2014-01-15 23:57:53 +00:00
fossfreedom 914098f4f4 fix trusty spacing issues 2014-01-15 22:54:43 +00:00
fossfreedom 16beb62e9c fix display of icons in trusty - issue #253 2014-01-15 22:00:29 +00:00
fossfreedom c1eb1d279e redisplay pictures in iconview 2014-01-15 21:44:13 +00:00
fossfreedom f9ab0104cd remove depreciation of dialog creation 2014-01-15 20:46:44 +00:00
fossfreedom 1a7e154f64 more depreciation this time with GObject.idle_add 2014-01-15 20:16:02 +00:00
fossfreedom 4cfe692b9e fix various depreciations in trusty 2014-01-15 19:58:19 +00:00
fossfreedom d165f5fc0c updated README for beta 2 2014-01-14 21:50:24 +00:00
fossfreedom 06a7478c70 latest translations 2014-01-14 21:23:10 +00:00
fossfreedom 7d629e5bcb add a space after labels in export dialog - issue #248 2014-01-14 21:11:19 +00:00
fossfreedom 5ddf0b306c resolve misaligned sorting issues - issue #250 2014-01-14 20:46:30 +00:00
fossfreedom ade9939053 rerun translation extraction 2014-01-13 21:50:19 +00:00
fossfreedom e6f8c887c9 Merge branch 'sort'
Conflicts:
	po/fr_CA.po
2014-01-13 21:35:58 +00:00
fossfreedom db09860d08 add new sprites, fix sorting of artists column so that we cannot become unsorted and finally, fix a bug on startup showing sort key error 2014-01-13 21:33:41 +00:00
fossfreedom 1718296e46 swap sort keys for album artist and album name so that we can use those sort keys correctly - issue #249 2014-01-12 21:56:14 +00:00
fossfreedom f5a6b56c3a latest cs translation 2014-01-12 12:37:25 +00:00
fossfreedom 53ff1990d2 add new cs translation 2014-01-11 23:18:52 +00:00
fossfreedom 4e5929237f tidied up sort actions 2014-01-11 22:52:13 +00:00
fossfreedom f1f4f451b8 Merge branch 'master' into sort
Conflicts:
	po/fr_CA.po
2014-01-11 12:03:32 +00:00
fossfreedom 581c1b6c0c work in progress - connect artist sort buttons and sort viewable albums 2014-01-11 12:01:33 +00:00
fossfreedom 2cafad60b6 use the correct translator comments for px - issue #248 2014-01-10 00:14:43 +00:00
fossfreedom 1cd75c4664 give new artist icons its own config called sort_artist 2014-01-09 23:51:38 +00:00
fossfreedom 161997c0d0 use separate sort and sort order buttons for album and artist views and connect signals for these buttons to sort independently 2014-01-08 23:26:34 +00:00
fossfreedom cc32904e80 latest fr_CA translation 2014-01-08 14:54:11 +00:00
fossfreedom c0edd4895e resolve out of synch picture popup - issue #244 2014-01-07 21:53:03 +00:00
fossfreedom f9dfa0c39d add latest fr_CA translation 2014-01-05 23:42:49 +00:00
fossfreedom 7eaeebf168 set the default sort indicator on the artist sort column to be ascending - issue #245 2014-01-05 23:08:09 +00:00
fossfreedom 290f06981e rerun translation stuff to capture new lastfm translation 2014-01-05 16:05:37 +00:00
fossfreedom 87de8b9a8b check if valid lastfm connection before searching - issue #243 2014-01-05 12:25:43 +00:00
fossfreedom 7a233c2dbb display artist albums ordered by year + their name rather than the current random order - issue #241 2014-01-05 11:18:28 +00:00
fossfreedom 931135ba70 remove secondary image update for disabled toolbar icons - issue #240 2014-01-05 10:23:31 +00:00
fossfreedom adba91d077 fix shake in treeview caused by expander lines - need to add space in next column to allow the expander lines to float into - issue #239 2014-01-05 00:13:17 +00:00
fossfreedom 466112068a encode unicode string to fix crash when clicking on artist - issue #238 2014-01-04 22:57:50 +00:00
fossfreedom 767e2791cf tidied up clicking on row actions to correct display of track & cover pane together with ensure that we show the artist cover search when clicking on artists - issue #236 2014-01-04 09:00:27 +00:00
fossfreedom f60bf048b2 latest es.po 2014-01-03 23:21:42 +00:00
fossfreedom 006d621327 add english language locales 2014-01-03 21:34:09 +00:00
fossfreedom 03b01b58f2 ensure translation of Views button works correctly 2014-01-03 21:17:54 +00:00
fossfreedom e915b353cc translation clarifications 2014-01-03 04:39:00 +00:00
fossfreedom cf8e2b383e version and help info moved to v1.0 2014-01-02 11:02:31 +00:00
fossfreedom 272127f5a3 make sure we copy the plugin3 file to allow the POSTINST script to run in the rb3 debian package 2014-01-01 21:12:55 +00:00
fossfreedom d4f0e9212a corrected version and source icon display for rb3 2014-01-01 20:40:42 +00:00
fossfreedom 78546f3643 re-run translation stuff to upload to launchpad 2014-01-01 15:31:00 +00:00
David Mohammed e1cd035095 Update README.md 2014-01-01 00:56:59 +00:00
fossfreedom 07aca0cdf6 redo deletion of artists when there is no albums - this time lets do stuff simply - just look at the iters we remembered when adding the albums to artists - issue #209 2013-12-28 22:05:30 +00:00
fossfreedom 7b96b47a6c correctly rename album artist and update the artist model - issue #209 2013-12-28 19:20:14 +00:00
fossfreedom d3654e1457 bug fix crash when modifying album in artist view 2013-12-28 17:31:04 +00:00
fossfreedom 98045cae32 blank expander column allows clicking on artist cover - issue #209 2013-12-28 15:15:26 +00:00
fossfreedom 50ae5a2a99 remove export and reduce search to just the artist - issue #209 2013-12-28 12:11:01 +00:00
fossfreedom 0ca674fb7b add right click menu for artists - issue #209 2013-12-28 11:50:47 +00:00
fossfreedom 0ed6f0e3ec tidied up permissions and reduce spacing in carousel to improve look 2013-12-27 17:09:11 +00:00
fossfreedom ed1d8899be add lighter icons to the Makefile 2013-12-27 16:27:15 +00:00
fossfreedom 0c8d408688 disable flowview if webkit support is disabled 2013-12-27 09:02:16 +00:00
fossfreedom d67a802b3d updated readme 2013-12-27 08:57:50 +00:00
fossfreedom 51c05b6202 add xingmux for accurate bitrate resampling 2013-12-27 00:40:41 +00:00
fossfreedom 2a098b1047 copy po's from release 0.9 2013-12-23 00:24:24 +00:00
fossfreedom 5effd50acd latest translation updates 2013-12-23 00:19:14 +00:00
fossfreedom 729d7f1ff0 sync artist view with the other views so that the artist last selected in the other views is scrolled to correctly 2013-12-22 23:50:40 +00:00
fossfreedom 47faf9a509 reflect album name changes back into the artist view. Also took the opportunity to fix a bug specific to RB3 to ensure all track changes are correctly updated in the album-model - issue #209 2013-12-20 18:20:24 +00:00
fossfreedom 6afe9bbed5 remove naff try except by using arrays rather than generators 2013-12-18 23:35:16 +00:00
fossfreedom 6bb5f885bb bug fix when calculating album year - ignore tracks where the year is zero ... this can cause the year to be the current date because the min value returns zero rather than the min of real track years 2013-12-18 23:10:11 +00:00
fossfreedom f763b00f3a cope with locales in markup - issue #209 2013-12-18 16:45:04 +00:00
fossfreedom 7d903e84cf format album names for artist view - issue #209 2013-12-18 16:38:59 +00:00
fossfreedom 7cbf51d168 update README for toolbar changes 2013-12-18 00:06:05 +00:00
fossfreedom 4a1443cf66 link our plugin menu in the music library up with our plugin - issue #230 2013-12-16 23:55:21 +00:00
fossfreedom 7a45d9531e switch to music library source when requested from the plugin view button - issue #230 2013-12-15 16:16:22 +00:00
fossfreedom b1544a8983 temporary fix to prevent crash for RB2.96 2013-12-15 00:12:02 +00:00
fossfreedom 1ff243df66 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-12-14 23:59:09 +00:00
fossfreedom 9076627ca9 rework toolbars to be RB3 visually compatible with popups placed below the buttons and themed accordingly. Also taken the opportunity to redo the right toolbar to fit on one less line since this sidebar is often used with lyrics which is wider and thus offers more space. Preliminary views button created for library source although not connected as yet. issue #230 2013-12-14 23:58:21 +00:00
fossfreedom 49d9540f8c 26 languages not 22 in the README 2013-12-07 21:24:46 +00:00
fossfreedom 5d1e68c268 more readme changes 2013-12-07 21:09:20 +00:00
fossfreedom 4692c6b8ee add rb2 support for repeat one song - issue #231 2013-12-07 20:52:53 +00:00
fossfreedom f34fd79952 revert plugin loader 2013-12-07 20:16:04 +00:00
fossfreedom 295ee80351 add rb3 menu item for repeat one song - issue#231 2013-12-07 20:15:05 +00:00
fossfreedom a508e52f0d latest README for changes 2013-12-07 17:20:43 +00:00
fossfreedom 2bda0f1cb0 reduce list of target to just uris - issue #233 2013-12-07 17:12:21 +00:00
fossfreedom 74f37075e5 cleanup 2013-12-07 15:08:18 +00:00
fossfreedom 88821ef68a drag-drop support for albums in artist view 2013-12-07 14:57:13 +00:00
fossfreedom 677855e5c7 fix cancel mechanism for artist search 2013-12-07 00:24:07 +00:00
fossfreedom d593463a25 cleanup 2013-12-06 19:39:16 +00:00
fossfreedom 66070a6b0e cleanup 2013-12-03 23:06:35 +00:00
fossfreedom 66b4895458 rework to use new coverartextdb 2013-12-02 21:49:02 +00:00
fossfreedom 2f6af4fa7a use coverview for artists as well as for albums 2013-11-24 21:19:00 +00:00
fossfreedom 80eefa8737 expand or collapse artist on single click 2013-11-23 13:27:41 +00:00
fossfreedom 5fa51b6ed3 allow drag-drop from coverview and also autoexpand when clicking on artist 2013-11-22 22:54:31 +00:00
fossfreedom 4bdd1b4809 show artist cover in a enlarged tooltip 2013-11-22 18:55:48 +00:00
fossfreedom 0c65a494d6 use download covers menu option to download artist covers 2013-11-21 22:48:50 +00:00
fossfreedom f0acad9dca also support album cover update for drag and drop events 2013-11-20 23:21:40 +00:00
fossfreedom 10b4c152c4 support drag and drop of pictures onto artists 2013-11-20 20:29:33 +00:00
fossfreedom 1eab887896 fire the load of the artists after the album model has loaded so that the artists view is correctly initialised 2013-11-17 13:00:58 +00:00
fossfreedom 616ccb2d53 add standard right-click menu for albums 2013-11-17 09:42:40 +00:00
fossfreedom 8b5e234cd2 link filters to artists so that they show or hide artists in the treeview 2013-11-16 10:28:31 +00:00
fossfreedom dfc0002a2c some cleanups 2013-11-13 21:54:30 +00:00
fossfreedom 111147ca2a remove unneeded file 2013-11-13 20:52:22 +00:00
fossfreedom 297378349c change view to be an album-artists view 2013-11-13 20:51:51 +00:00
fossfreedom 0678179585 convert adding of artists as iterators to improve visual appearance when loading 2013-11-12 22:55:51 +00:00
fossfreedom a03119ef29 disable rather than hide toolbar objects 2013-11-11 23:11:51 +00:00
fossfreedom 66ddba7d78 remove unnecessary file 2013-11-11 00:10:22 +00:00
fossfreedom 4a23b78816 update toolbar signal whenever view is initialised or moved to 2013-11-11 00:09:53 +00:00
fossfreedom 07273d8351 remove obsolete file 2013-11-08 23:50:35 +00:00
fossfreedom 1dc678f31f refactor toolbar stuff into its own module 2013-11-08 23:50:09 +00:00
fossfreedom 64f7f3a978 various cleanups and use RB.search_fold for ordering of track artists 2013-11-08 21:20:04 +00:00
fossfreedom 846e995d82 add dummy column so that main column doesnt excessively expand to fill the space 2013-11-08 13:38:35 +00:00
fossfreedom 840ef0fd68 add clickable header for sorting 2013-11-08 13:00:03 +00:00
fossfreedom c562d3c4b3 ensure startup of view has a collapsed paned and is also initialised correctly when switching to it from another view 2013-11-06 23:44:27 +00:00
fossfreedom b2aec88ccf rework to use selection changed event which is similar to how the iconview is done 2013-11-06 22:53:59 +00:00
fossfreedom 7302165293 connect click and double click events 2013-11-05 00:09:36 +00:00
fossfreedom 9502bcf528 display artist and album images in tree-view 2013-11-04 23:00:24 +00:00
fossfreedom afbc8bd3b9 display albums for artists when the artist is expanded 2013-11-04 19:37:23 +00:00
fossfreedom 958e6ad6de refactor to separate data model from the view to be analagous to how album data model is done 2013-11-03 18:07:48 +00:00
fossfreedom 7027112b58 reactivate artist button ready for new artist treeview 2013-10-31 21:57:05 +00:00
fossfreedom 2c8554d79f display message if albums do not meet threshold - issue #213 2013-10-29 17:22:57 +00:00
fossfreedom 16f6055488 make sure double click and hover play use favourites - issue #213 2013-10-29 00:28:10 +00:00
fossfreedom d09ac59971 use 'New Playlist' as the default label when adding a new playlist - issue #213 2013-10-29 00:19:27 +00:00
fossfreedom 9e83e420bc its back! trick was realising calculation needs to be in widget coords - issue #84 2013-10-28 11:13:48 +00:00
fossfreedom 7e2eb1b8f9 temporarily abandon hotspot functionality - when view is scrolled it doesnt work anyway due to the way the hotspot position is calculated. Need to investigate further - issue #84 2013-10-28 09:42:38 +00:00
fossfreedom d7b7de854a rejig to delay immediate hotspot display slightly and also to force a view redraw so that hover is displayed even if the mouse is not moving - issue #84 2013-10-28 09:24:59 +00:00
fossfreedom 025cd52e3c refine hover display - displays immediately if move cursor over the hotspot region - issue #84 2013-10-27 23:42:24 +00:00
fossfreedom ab7643d7fa turn-off tooltips if cover display-text is active - issue #228 2013-10-26 23:14:54 +01:00
fossfreedom 211f4019bb slightly reduce time interval and remove print statements 2013-10-26 23:00:43 +01:00
fossfreedom 5ccd07e4b2 rework with new button images and half-second delay before display of hover - issue #84 2013-10-26 21:36:55 +01:00
fossfreedom 7b2c529228 rework to support play-pause on hover icon 2013-10-23 21:58:19 +01:00
fossfreedom 2a28592360 rejig so that iconview controls play icon 2013-10-23 20:08:33 +01:00
fossfreedom 00e0c80594 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-10-22 21:37:27 +01:00
fossfreedom a79591f9c0 ensure play icon responds to mouse hovering over it by dimming to show it is clickable - issue #84 2013-10-22 21:37:04 +01:00
David Mohammed f32713855f Update README.md 2013-10-20 17:49:03 +01:00
fossfreedom 27fdc07f28 fix multiple progress bars appearing on loading - issue #226 2013-10-20 17:36:28 +01:00
fossfreedom 8ba870184d add rb3 monochrome icon for the browser source icon - issue #225 2013-10-20 17:08:35 +01:00
fossfreedom bd9f7c52c0 update readme and available GTK version for single click play - issue #84 2013-10-19 22:37:53 +01:00
fossfreedom 3fd7fa281e single click play on hovered play-symbol shown in cover - issue #84 2013-10-19 22:06:59 +01:00
fossfreedom cafda03761 lighten the mood 2013-10-16 22:07:00 +01:00
fossfreedom 752357ad68 removed obsolete file 2013-10-13 19:49:58 +01:00
fossfreedom 1394cedbd2 latest az translation 2013-10-13 19:47:26 +01:00
fossfreedom 5bc4d5ef31 updated missing artwork images - issue #183 2013-10-12 14:05:16 +01:00
fossfreedom 97ec1dab0a ensure that text_within option does not conflict with add-shadow option 2013-10-11 21:10:16 +01:00
fossfreedom d0e3f218e0 link up coverart-text-pos with cellrenderer 2013-10-11 20:14:36 +01:00
fossfreedom e37655d7e0 add text position option to preferences and schema 2013-10-11 00:02:50 +01:00
fossfreedom d8967fb4e1 add cellrenderer for the text embed capability 2013-10-10 22:59:46 +01:00
fossfreedom b7a5a8e023 readded jrbastiens changes in popup.xml into the translation equivalent so that we dont lose the changes when we regenerate the translation files later 2013-10-07 13:30:58 +01:00
David Mohammed 57808278d3 Update README.md 2013-10-07 13:19:27 +01:00
David Mohammed 9412ddfb29 Merge pull request #222 from jrbastien/master
Introducing a new icons theme for the coverart browser
2013-10-07 05:09:55 -07:00
jrbastien d99cab53d1 Merge branch 'master' of https://github.com/jrbastien/coverart-browser 2013-10-06 20:00:46 -04:00
jrbastien 9312c37305 Adding the documentary genre as an alternate genre for the spoken genre. 2013-10-06 19:58:23 -04:00
Jean-Rene Bastien f8eb618d84 Delete Tour_Effel.png
Custom icon. Should not have been included in the theme.
2013-10-06 19:33:55 -04:00
jrbastien 3f610a74a1 Introducing a new icons theme with the goal of having something less distracting on the eyes. All icons have been redesigned but the genre sprite. 2013-10-06 19:29:13 -04:00
fossfreedom 12826cdde6 minor mods for finnish translation 2013-10-05 23:05:01 +01:00
fossfreedom c6eb082aca ensure that columns are correctly ordered - issue #219 2013-09-30 20:39:22 +01:00
fossfreedom 58815e03a9 add progress bar if required for RB3.0 - issue #189 2013-09-29 20:14:58 +01:00
fossfreedom 1380515c63 made properties option favourites and quick artist filter persistent - issue #213 2013-09-26 21:06:59 +01:00
fossfreedom 3c18ca9052 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-09-23 19:45:45 +01:00
fossfreedom f9422d8a19 remove all the pointless menu label changing stuff - #213 2013-09-23 19:45:23 +01:00
fossfreedom d64f1bcaf7 change labels for favourites - issue #213 2013-09-22 10:21:13 +01:00
fossfreedom 27c386e172 fix for external plugin case sensitive issue and fix wrong group name for opencontainingfolder plugin 2013-09-17 00:01:24 +01:00
fossfreedom 5e2cec619e add new translation - pt 2013-09-16 22:49:51 +01:00
fossfreedom 8ab66a192f tidied master readme 2013-09-11 21:10:42 +01:00
fossfreedom 4e480c40fe Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-09-11 20:58:12 +01:00
fossfreedom 9b58df3784 add use favourites menu option to properties menu - issue #213 2013-09-11 20:57:54 +01:00
fossfreedom 34583e0086 latest translations from launchpad 2013-09-11 16:09:58 +01:00
fossfreedom 368e582fe2 fix initial display of album info on startup - issue #214 2013-09-11 08:35:00 +01:00
fossfreedom 186977f6ef ensure the version of the coverart_search_providers plugin is correct to prevent unnecessary crashes and other confusion - issue #212 2013-09-08 21:53:22 +01:00
fossfreedom ce119120b7 connect resize art option - issue #212 2013-09-08 20:43:08 +01:00
fossfreedom 6759472a2e add optional mp3 conversion with bitrate calculation - issue #212 2013-09-08 11:47:55 +01:00
fossfreedom 58ef685380 latest spanish translation 2013-08-27 20:51:31 +01:00
fossfreedom 594feaca93 latest ro translation 2013-08-27 12:45:10 +01:00
fossfreedom edcf74f005 latest az, fr & pl translations 2013-08-26 16:38:51 +01:00
fossfreedom a6993e3d2e latest tr.po 2013-08-26 10:54:07 +01:00
fossfreedom 5ccc4c1c7d Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-08-25 23:54:33 +01:00
fossfreedom 35335da6b8 latest translations and removed those translations that are less than 50 percent translated 2013-08-25 23:54:22 +01:00
David Mohammed ba9ae93d87 Update README.md 2013-08-25 23:45:18 +01:00
David Mohammed 6b999b0099 Update README.md 2013-08-25 23:33:53 +01:00
David Mohammed 388e8faec6 Updated - ready for release 2013-08-25 23:22:52 +01:00
fossfreedom da92ed7d9a bug fix - prevent help button being continually duplicated when preferences dialog repeatedly opened 2013-08-25 10:09:01 +01:00
fossfreedom a17a32e33b latest translations 25/08/13 2013-08-25 09:43:29 +01:00
fossfreedom 17db0b98df remove obsolete icons 2013-08-22 14:09:04 +01:00
fossfreedom d500fdb0bf latest translations 22/08/13 2013-08-22 11:52:14 +01:00
fossfreedom 69fccf10f4 latest fr_CA translations - issue #202 2013-08-18 20:06:11 +01:00
David Mohammed fa2050486e remove "sh" from the running of the bash shell script install.sh - issue #211 2013-08-18 15:57:08 +01:00
fossfreedom 3f85bc1da6 updated padding description - issue #202 2013-08-18 15:42:56 +01:00
fossfreedom 9d59cb0748 remember the position of the quick artist filter handle position - issue #210 2013-08-18 15:26:46 +01:00
fossfreedom e1aa1ba082 readd previous translations that jrbastien made - issue #202 2013-08-18 10:57:58 +01:00
fossfreedom 8ac60117ac center view buttons and allow search button to expand to its full extent - issue #202 2013-08-18 10:33:18 +01:00
fossfreedom 7179b2e601 latest fr_CA translation 2013-08-17 21:58:21 +01:00
fossfreedom e93a7dd36b Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-08-17 20:38:53 +01:00
fossfreedom 85df2fa79d regenerated po's using less restrictive intltool-extract 2013-08-17 20:30:27 +01:00
fossfreedom 3e55c8daa9 changed tile to tiles, tooltip swap and added translator info for 'All' 2013-08-17 20:07:16 +01:00
David Mohammed 59f1a840ec Update README.md 2013-08-15 23:02:10 +01:00
fossfreedom 74d6a62238 add help button to preferences dialog called from coverart-browser 2013-08-13 19:36:46 +01:00
fossfreedom ef657da311 remove obsolete code when right click on source in rb2.96 2013-08-11 21:31:12 +01:00
David Mohammed 250eea8053 Update README.md 2013-08-10 21:24:59 +01:00
fossfreedom f243e2aba2 add llyrics and fileorganizer as supported plugins for rb2.99 users 2013-08-10 21:17:23 +01:00
fossfreedom e47c3dedac latest translations update 2013-08-07 14:50:31 +01:00
fossfreedom 2a2a51c1ed hook up quick artist filter to properties menu item 2013-08-06 21:54:04 +01:00
fossfreedom c27ae05e3c connect up quick artist filter to album model 2013-08-06 20:43:34 +01:00
fossfreedom 00ccb84fc3 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser into quickfilter 2013-08-05 21:07:30 +01:00
fossfreedom 83e73f95d5 fix missing import of RB 2013-08-05 21:06:05 +01:00
fossfreedom 154e5df152 force the state of a stateful action - this fixes the issue where an accelerator is used to activate rather than a menu option - issue #208 2013-08-05 21:04:23 +01:00
David Mohammed 5781a67a70 Update coverart_rb3compat.py 2013-08-05 13:26:01 +01:00
David Mohammed 0322dfd248 Merge pull request #207 from dmo60/patch-1
enable passing a custom stock_id for actions
2013-08-05 05:22:29 -07:00
Timo Loewe ecd1a07026 Update coverart_rb3compat.py
enable passing a custom stock_id for actions
2013-08-04 12:48:48 +02:00
fossfreedom 3273c920ec create paned layout and connect model to library source 2013-08-04 00:20:14 +01:00
fossfreedom 7b33009e67 fixed name reference for our panedcollapsible widget 2013-08-03 21:30:29 +01:00
fossfreedom 73e218e99f update readme for iconview toggle 2013-08-03 18:10:35 +01:00
fossfreedom 30a6ebeb45 add optional track-view toggle to keep consistent with flow-view 2013-08-03 18:08:15 +01:00
fossfreedom 2e27bbd794 add rb3 install instructions - issue #194 2013-08-03 13:48:52 +01:00
fossfreedom a029c43144 add option to install RB version 3 - issue #194 2013-08-03 13:46:21 +01:00
fossfreedom 474fba83c0 fix python3 depreciation warnings in ubuntu saucy - issue #187 2013-08-02 22:23:27 +01:00
fossfreedom 491d35b581 update makefile for global installation and deb creation 2013-08-02 16:14:48 +01:00
fossfreedom e7b68f91b7 uplift source files for translation activities 2013-08-02 15:01:45 +01:00
fossfreedom c348988325 each view now remembers if the track-view should be open or closed when switching between those views - issue #206 2013-08-01 23:06:06 +01:00
fossfreedom 6c76820891 relaxed check for mouse to be over the coverflow when controlling the coverflow via keyboard - issue #206 2013-07-31 10:18:17 +01:00
fossfreedom fadb361a0c remove scrollbar 2013-07-30 23:07:05 +01:00
fossfreedom 52d6828480 remove unwanted file 2013-07-30 23:02:47 +01:00
fossfreedom 9d0666144b fix resizing issue on coverflow 2013-07-30 23:02:17 +01:00
fossfreedom c9d27129b1 some python3 fixups 2013-07-30 21:20:21 +01:00
fossfreedom 5fc8e853ad move signal update out of loop so that it always fires not just when the caption is visible 2013-07-29 22:00:52 +01:00
fossfreedom 0c072028c0 add optional argument 2013-07-29 20:46:32 +01:00
fossfreedom bc3d194920 centre view buttons correctly on top-bar - issue #206 2013-07-29 14:59:07 +01:00
fossfreedom da37365b38 display active album in trackview whilst scrolling in coverflow - issue #206 2013-07-29 14:08:34 +01:00
fossfreedom ebfc12ef15 reset on_first_use counter after it actually has been through this section of code 2013-07-29 11:38:59 +01:00
fossfreedom 017312e7c5 expand pane on very first use on coverflow - issue #206 2013-07-29 11:27:08 +01:00
fossfreedom 5302cca0a1 changed label to reflect true meaning 2013-07-29 09:50:53 +01:00
fossfreedom b9f82a794f changed filter message to be more meaningful - issue #206 2013-07-29 09:48:29 +01:00
fossfreedom b9ac6a5c8a Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-07-28 23:52:34 +01:00
fossfreedom 1e1e6481a9 move items creation to filter_changed to be consistent with the rest of the html manipulation 2013-07-28 23:52:03 +01:00
David Mohammed 6840a52d67 Update README.md 2013-07-28 19:21:02 +01:00
fossfreedom 42fb3f650b add support to disable call to webkit library via a gsettings value - issue #199 2013-07-28 19:19:02 +01:00
fossfreedom 9130f32038 focus issues on coverflow after quick search and expand descriptions of the abstract view 2013-07-28 09:15:14 +01:00
fossfreedom 6a7b7f7146 remove obsolete code and renamed methods that are really just private to the coverflow 2013-07-28 08:59:50 +01:00
fossfreedom f4f1086883 fix for reason why rating was not being recalculating - issue #204 2013-07-27 22:37:33 +01:00
fossfreedom 14b84f1a9c lets add generic support for RB2.98 and 2.99 i.e. assume something has modified on the album 2013-07-27 17:26:56 +01:00
fossfreedom 44cf1a94c6 remove some strange code causing spurious album updates whenever anything changes - now the track modified signal is only thrown when a track artist details are changed 2013-07-27 17:19:02 +01:00
fossfreedom e348ec9b45 fix locking issue due to incorrect use of threads 2013-07-27 05:51:01 +01:00
fossfreedom 0ea4d413c3 some cleanups including reducing flickering when changing album properties or changing cover as well as fixing the quick search on the flow 2013-07-26 20:15:39 +01:00
fossfreedom 69800ebb6d move separators to more logical locations 2013-07-26 12:57:20 +01:00
fossfreedom e9c869e5ad fix typos primarily in album-updated emit signal 2013-07-26 12:53:50 +01:00
fossfreedom 34367b8e85 add jrbastiens new icons and hide the artist button 2013-07-26 09:25:42 +01:00
fossfreedom 77436aca08 fix quick search on iconview if flowview was the default on startup 2013-07-25 23:51:55 +01:00
fossfreedom d72cac5424 a bit of a hack - refilter the coverflow whenever something on an album changes such as changing the picture 2013-07-25 21:50:01 +01:00
fossfreedom 10d26bb4d3 disable default drag-drop on webview and enable the active element to receive the dropped picture from the cover pane 2013-07-24 20:36:21 +01:00
fossfreedom f9cff865bf substitute properties.png with jrbastien's version 2013-07-24 13:28:46 +01:00
fossfreedom 0e43b68a73 simplify processing, link display to flow-max number, re-add slider and circular-flow 2013-07-23 21:09:25 +01:00
David Mohammed 0541665488 Update README.md 2013-07-23 13:00:57 +01:00
fossfreedom 76a9610422 add random album functionality - issue #196 2013-07-21 10:34:27 +01:00
fossfreedom 6c09a042f9 connect automatic click setting to coverflow 2013-07-20 22:09:28 +01:00
fossfreedom 844a514ccc revert toggle buttons to text only and differentiate the label colour depending upon which is active 2013-07-20 11:07:53 +01:00
fossfreedom b991fd6993 add separator in properties menu to differentiate between preferences and other view functionality 2013-07-20 09:48:36 +01:00
fossfreedom ab47c5f97d add search providers dialog to properties button 2013-07-19 20:40:05 +01:00
fossfreedom 6a5eace53d link up plugin preferences dialog to properties button menu 2013-07-19 14:57:07 +01:00
fossfreedom 639429fed1 changed my mind - lets display albums anyway - just need to add the limit when refactoring the batch processing part 2013-07-18 22:31:13 +01:00
fossfreedom 28ee9474f8 connect max albums to preferences 2013-07-18 21:55:57 +01:00
fossfreedom b98ea85bdb add max number of albums to display in coverflow 2013-07-18 21:38:47 +01:00
fossfreedom bb02cbc035 correct names for notify properties so that they sync when preferences change 2013-07-18 14:29:34 +01:00
fossfreedom 3ef9bb6afc refactor coverflow code for properties and their signals 2013-07-18 13:14:34 +01:00
fossfreedom b3ed080e09 wrong default width for coverflow 2013-07-18 12:24:30 +01:00
fossfreedom eb5014483a slight modifications to README 2013-07-17 23:54:07 +01:00
fossfreedom 8bd4799bf4 connect startup gsettings values to various values in the coverflow index.html 2013-07-17 23:35:49 +01:00
fossfreedom a3c3631ecb link prefs dialog flow items to gsettings 2013-07-17 19:27:24 +01:00
David Mohammed e4ecbb3c11 Add LICENSE file via addalicense.com 2013-07-17 01:21:38 -07:00
fossfreedom 94f7e1045e Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-07-16 21:20:08 +01:00
fossfreedom a5a9096732 add check on paned release event - temporary resolution for flow click issue 2013-07-16 21:20:00 +01:00
fossfreedom 1f3f5b7df1 add GUI options to preferences - note, these have not been linked as yet to the flow 2013-07-16 13:01:36 +01:00
fossfreedom da09955aeb add check and use path instead of pixbuf when creating Cover on drag-drop - issue #195 2013-07-14 20:03:26 +01:00
fossfreedom 1fce749c3e reinstate download all covers via properties button 2013-07-13 00:02:28 +01:00
fossfreedom 1bb5e94b1e add various flow addons 2013-07-12 11:32:09 +01:00
fossfreedom f19a5d3e75 relinked the toggle with the view on startup 2013-07-11 23:47:24 +01:00
fossfreedom e479bb2983 fix picture display on top toolbar 2013-07-11 23:05:19 +01:00
fossfreedom 2d61b6ebab fix sidebar display of new buttons 2013-07-11 21:58:32 +01:00
fossfreedom 339b25633a rework toggle buttons to be image buttons and add a dummy properties button as well as a dummy artist view button 2013-07-11 20:45:16 +01:00
fossfreedom a651ac93d4 fix right click on coverflow as well as selection issues when switching views 2013-07-10 23:13:54 +01:00
fossfreedom 44a281ff99 minor mod to use scalefactor rather than maxheight for the sizing of images 2013-07-10 22:45:39 +01:00
fossfreedom 64b900f21a minor mod to use scalefactor rather than maxheight for the sizing of images 2013-07-10 22:44:04 +01:00
fossfreedom dd84f9183c various fixes to ensure that the coverflow is loaded after all covers have been loaded as well as resolving various scroll to album issues 2013-07-09 23:24:22 +01:00
fossfreedom acb86fea37 Update coverart_browser.plugin 2013-07-08 08:19:59 +01:00
fossfreedom dcc89ed8a2 now works for RB3.00 - adjusted comment - issue #186 2013-07-08 00:05:42 +01:00
fossfreedom 100a552d56 fix some python3 issues 2013-07-07 23:59:22 +01:00
fossfreedom f96bc30716 tidyup playlist monitoring code 2013-07-07 22:51:32 +01:00
fossfreedom 727165a9d5 assume the shell display-page-model changes can be used to monitor playlist events as well - issue #192 2013-07-07 22:24:15 +01:00
fossfreedom b6bb7eaeb6 fix playlist crash in RB2.99 - issue #191 2013-07-07 21:56:56 +01:00
fossfreedom 6002454340 tie two views to clickable toolbar radio-buttons 2013-07-07 15:14:07 +01:00
fossfreedom 023ebcf1d3 must remember to at least run RB to check for crashes... 2013-07-07 08:58:11 +01:00
fossfreedom 4a3add381b fix for fedora19 crash #191 2013-07-07 08:51:23 +01:00
fossfreedom 206f574cdf delegate switching of views to themselves and better sync between views 2013-07-06 07:41:43 +01:00
fossfreedom 9789b697f0 sync selected albums when flipping between views 2013-07-05 21:48:10 +01:00
fossfreedom 0116413aa2 connect views to viewmanager via a schema key 2013-07-04 21:59:31 +01:00
fossfreedom 2b03440adc ensure new batch is passed the album identifier 2013-07-04 13:24:18 +01:00
fossfreedom d22355d29d refactor iconview specific methods from abstractview 2013-07-04 12:38:59 +01:00
fossfreedom 1ccde3b5d4 fix constant dragging issue after right-click menu is removed from the display 2013-07-03 23:09:21 +01:00
fossfreedom a10dc87ef0 add rudimentary right-click support 2013-07-03 22:26:46 +01:00
fossfreedom 828787dc8d added rudimentary response to click and double click events 2013-07-02 23:49:57 +01:00
fossfreedom bc7052f671 link coverflow with albummodel 2013-07-02 21:36:46 +01:00
fossfreedom afc4a2939c bug fix - playlists were never updated on the playlist menu 2013-07-02 21:35:59 +01:00
fossfreedom 5bad5fa5e2 various RB3 & python3 issues 2013-07-01 21:07:51 +01:00
fossfreedom 452de7f834 integrate coverflow folder structure using initial prototype code 2013-06-30 20:32:18 +01:00
fossfreedom 205fa02435 update supported external plugins 2013-06-30 12:08:48 +01:00
fossfreedom 791787559b restructure so that we have a definitive list of methods a view should have and create a ViewManager class which will eventually manage our different views 2013-06-29 23:35:24 +01:00
fossfreedom 70575fb308 add space between : to cope with french locale requirements - issue #185 2013-06-25 21:38:18 +01:00
fossfreedom 7360482c9d add space between : to cope with french locale requirements - issue #185 2013-06-25 10:41:00 +01:00
fossfreedom d05231de82 latest az translation 2013-06-22 16:04:18 +01:00
fossfreedom 8b38ae236e move cover view specific stuff from covert_album to the cover icon view module 2013-06-22 00:09:09 +01:00
fossfreedom 0ed9d54e22 regeneration of plugin and popups 2013-06-21 20:36:46 +01:00
fossfreedom e7d7efaf61 readd copyright statement 2013-06-21 20:36:14 +01:00
fossfreedom 4cac3ed47d latest translations in release-0.8 2013-06-21 20:32:50 +01:00
fossfreedom 777e78fbc4 more translations for zh_CN 2013-06-21 19:35:02 +01:00
fossfreedom e5e66a1f24 fix change selection 2013-06-21 19:33:30 +01:00
fossfreedom 6aaee47cb6 latest zh_CN translation 2013-06-21 15:57:06 +01:00
fossfreedom db028fa7c8 latest zh_CN translation 2013-06-21 09:23:13 +01:00
fossfreedom 2f50a382ea move icon notify gsetting signals to new module 2013-06-20 23:58:52 +01:00
fossfreedom 60c6cba7cf move signals for iconview to new module 2013-06-20 23:41:22 +01:00
fossfreedom 424f18799d drag drop refactoring 2013-06-20 23:25:04 +01:00
fossfreedom b12423ca63 new translations - bs, el and fi 2013-06-20 22:38:36 +01:00
fossfreedom f6c23576a0 refactored covericonview specifics into its own source module 2013-06-20 22:02:55 +01:00
fossfreedom 5c1736cb04 Update README.md 2013-06-19 21:04:52 +02:00
fossfreedom ebe6678e43 latest pl translation 2013-06-19 09:29:47 +01:00
fossfreedom 6ab0bcecd3 cherry pick 97e1f79ad5 2013-06-18 23:53:48 +01:00
fossfreedom b0b6a09100 Merge branch 'release-0.8' of https://github.com/fossfreedom/coverart-browser into release-0.8 2013-06-18 23:42:53 +01:00
fossfreedom 97e1f79ad5 fix for crash if using BPM column - issue #188 2013-06-18 23:42:19 +01:00
fossfreedom 302048e93b Update README.md 2013-06-18 22:16:05 +02:00
fossfreedom 157cc0359b added new romanian translation 2013-06-18 10:00:37 +01:00
fossfreedom 85b76af44a Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-06-17 22:43:45 +01:00
fossfreedom 6f29b47576 python3 fixes for git compiled version of RB running on saucy 2013-06-17 22:43:25 +01:00
fossfreedom 45aa5281e2 remove obsolete param in constructor call 2013-06-17 11:52:28 +01:00
fossfreedom 6f4ff35547 revert python3 requirement 2013-06-17 11:51:45 +01:00
fossfreedom b578d8f386 fixed some errors that prevented plugin initialisation under python3 2013-06-15 16:55:27 +01:00
fossfreedom 8d40dad422 Update README.md 2013-06-13 12:37:03 +02:00
fossfreedom c7d6dc3481 resync from release-0.8 branch 2013-06-13 11:26:37 +01:00
fossfreedom 953a159018 latest pl translation 2013-06-13 11:19:17 +01:00
fossfreedom 68aacc4f72 latest az translation 2013-06-10 15:35:24 +01:00
fossfreedom 1dad8ae6d3 sync with lastfmqueue changes 2013-06-08 11:32:32 +01:00
fossfreedom 6860b4d4a3 latest polish translation 2013-06-06 20:05:08 +01:00
fossfreedom 28e6ad9a04 pull in changes whilst working on lastfm_queue 2013-06-05 18:00:25 +01:00
fossfreedom c2260d6806 fix display of accelerators in rb299 2013-05-31 16:30:25 +01:00
fossfreedom 6ffdc361b3 add support for RB2.99 view app menu as well as the default tools app menu 2013-05-31 00:01:06 +01:00
fossfreedom 4e8a081cad added API to associate accelerators with actions 2013-05-30 17:32:55 +01:00
fossfreedom 193bd37572 Update README.md 2013-05-28 21:05:23 +02:00
fossfreedom e666803e2d Update README.md 2013-05-28 21:04:36 +02:00
fossfreedom d6128831c4 remove spurious .orig files 2013-05-28 19:50:03 +01:00
fossfreedom 3277635a97 merge 2013-05-28 19:47:20 +01:00
fossfreedom cd1a6d1f91 add header to compat module 2013-05-28 19:20:34 +01:00
fossfreedom ce452dbba5 add app action toggle 2013-05-26 08:51:15 +01:00
fossfreedom cf0b264062 fix rb299 action_name vs label override issue 2013-05-25 21:32:15 +01:00
fossfreedom e95e4a0af7 fix tabs vs spaces and oops with send-first action name 2013-05-25 20:17:31 +01:00
fossfreedom c851f3d913 fix some cleanup issues 2013-05-25 16:48:36 +01:00
fossfreedom 83168a14bd bug fix to display browser menu items enabled in rb299 2013-05-25 16:07:40 +01:00
fossfreedom b792a42371 finalised RB299 functionality and completed code definitions - issue #171 2013-05-25 11:15:44 +01:00
fossfreedom dc0b9a113b fix menu crash in rb299 2013-05-25 00:04:40 +01:00
fossfreedom 77a3867152 bug fixes for rb296 after rework of Action object 2013-05-24 22:38:04 +01:00
fossfreedom 6fb90792af add new ast translation 2013-05-22 10:10:20 +01:00
Agustin Carrasco dabb80dc65 Merge branch 'order-keys'
Added support for multiple ordering on some order types (to allow a
better subordering inside each type).

closes #138
Conflicts:
	coverart_album.py
	coverart_browser_source.py
	coverart_utils.py
2013-05-22 00:46:25 -03:00
Agustin Carrasco 8855b85653 Merge branch 'refactor-statusbar' into order-keys 2013-05-22 00:20:26 -03:00
fossfreedom ccff276ab0 fixed app menu support for rb299 2013-05-21 23:50:06 +01:00
fossfreedom 8f42a9ea71 add label support for rb296 actions 2013-05-21 20:57:17 +01:00
fossfreedom c094a8f445 made menu more generic by removing the dependency on the source for the Menu creation 2013-05-20 23:56:30 +01:00
fossfreedom ae44b76a41 bug fixes for rb299 support 2013-05-20 23:02:16 +01:00
fossfreedom 263df5c62c finish restructuring for rb296 2013-05-19 23:39:56 +01:00
fossfreedom c7f8fe0ded fixed activation events for rb296 2013-05-19 21:03:19 +01:00
fossfreedom 3bd947bf16 preliminary rework to external plugins to support rb299 2013-05-18 23:51:34 +01:00
Agustin Carrasco 65de81ebc0 statusbar: removed extra space on status text 2013-05-16 22:52:35 -03:00
Agustin Carrasco a4c8cc4258 statusbar: finished refactoring statusbar (issue #123) 2013-05-16 22:39:48 -03:00
fossfreedom bc59cd85a2 rework external plugin support to use XML datafile instead of python classes 2013-05-15 19:34:38 +01:00
fossfreedom 08dc4ee2e1 config file used to describe external plugins 2013-05-14 20:08:11 +01:00
fossfreedom c098d0a5ac latest changes made by coverart-search-providers 2013-05-14 20:07:28 +01:00
fossfreedom 419b95d49c Update README.md 2013-05-13 00:52:46 +02:00
fossfreedom 8f3c66b726 Update README.md 2013-05-13 00:51:40 +02:00
Agustin Carrasco 35b2bda943 statusbar: start isolating statusbar behavior in a couple of classes 2013-05-11 23:46:57 -03:00
fossfreedom 7c584aa1e3 working playlists - issue #171 2013-05-10 23:15:43 +01:00
fossfreedom d1583f78f5 latest translations from launchpad 2013-05-10 13:57:01 +01:00
fossfreedom fd4f1a86fd add structure around playlist support - need to debug playlist creation and test against older versions of rhythmbox to ensure restructuring hasnt broken extant capabilities - issue #171 2013-05-08 23:26:38 +01:00
fossfreedom 8d58c448e8 converted entry-view menu - issue #171 2013-05-06 09:07:59 +01:00
fossfreedom 83f0194f2f first cut of rb2.99 support - lots of stuff still not working such as playlists, external plugins and track-view still to be converted - issue #171 2013-05-05 17:12:32 +01:00
fossfreedom 6347abcd2f fixed typos 2013-04-28 22:58:40 +01:00
fossfreedom 09c73972a5 fix missing merge 2013-04-28 11:52:41 +01:00
fossfreedom e9f16ab6b3 merge from master 2013-04-28 11:43:47 +01:00
fossfreedom 0a012d97bc convert pure list-map items to loops to prevent wasteful list generation - issue #179 2013-04-27 23:29:54 +01:00
Agustin Carrasco d674618904 albums: fix dumb name collision on sort_keys 2013-04-27 17:00:37 -03:00
Agustin Carrasco 9349e965c3 albums: added internal support for multiple propery sorting (issue #138)
Had to do some little changes to make this work on the AlbumModel:
- The album_sort and album_sort_artist were returning a redundant list
  that made ordering kinda quirky. Used the uniqyfy function to make
  them return a more sane result.
- Added a sort_keys dictionary to translate the different sort keys into
  a group of properties to sort by. This may have to change in the
  future to make it more mantianable.
- Changed the sort method to use the sort_keys when creating the sort
  fuction for the sorted collection.
2013-04-27 16:47:22 -03:00
Agustin Carrasco 0a6dc5620b utils: added a uniqyfy_and_sort function that removes duplicates and sorts an iterable 2013-04-27 16:40:01 -03:00
fossfreedom f78c77c98d Update README.md 2013-04-25 15:36:52 +02:00
fossfreedom 2c025d32f8 Update README.md 2013-04-25 15:36:27 +02:00
fossfreedom aa6144d575 Update README.md 2013-04-25 15:34:39 +02:00
fossfreedom 37f1cfd632 adjust help hyperlink to release-0.8 2013-04-24 23:45:12 +01:00
fossfreedom c38bdf0608 necessary changes to allow plugin to work in global install location 2013-04-24 23:07:27 +01:00
fossfreedom 2550d46f15 necessary changes to allow plugin to work in global install location 2013-04-24 23:06:05 +01:00
fossfreedom c868c1a44e rework specific python2 to 3 function issues - issue #179 2013-04-24 20:55:46 +01:00
fossfreedom 9aa78d4c6a latest polish translation 2013-04-24 12:51:20 +01:00
fossfreedom 059f8a937b Update README.md 2013-04-23 14:00:51 +02:00
fossfreedom 204ff93a59 Merge branch 'release-0.8' of https://github.com/fossfreedom/coverart-browser into release-0.8 2013-04-22 20:17:02 +01:00
fossfreedom f6d83086c4 remove less than 50 percent translated translations 2013-04-22 20:16:21 +01:00
fossfreedom a100ed29da latest polish translation 2013-04-22 20:06:24 +01:00
fossfreedom 555d6490b5 Update README.md 2013-04-22 20:48:30 +02:00
Agustin Carrasco ae6042e228 albums: Added a check to save_to_disk property before adding entry
Doing this prevents that a "trancient" entry gets added to an Album.
This kind of entries usually come from external devices, which generally
generates duplicates on the album track list. (issue #169)
2013-04-22 19:40:23 +01:00
Agustin Carrasco aa44101ed5 albums: Added a check to save_to_disk property before adding entry
Doing this prevents that a "trancient" entry gets added to an Album.
This kind of entries usually come from external devices, which generally
generates duplicates on the album track list. (issue #169)
2013-04-21 23:29:22 -03:00
fossfreedom c6099bb89d a quick 2to3 run to see what breaks when running under python2.7 - this will give a better idea of how to keep both python 2.7 and python3 compatibility - issue #179 2013-04-21 20:43:03 +01:00
fossfreedom 86b25086ac updated spanish translations 2013-04-21 18:25:59 +01:00
fossfreedom 70e8139b48 update readme for release v0.8 2013-04-21 18:17:08 +01:00
fossfreedom c0a5d2566f updated readme for v0.9 2013-04-21 18:14:04 +01:00
fossfreedom 9f4b104322 Merge branch 'viewadvanceoptions' 2013-04-21 17:45:56 +01:00
fossfreedom ab60fb0eb3 latest translations 2013-04-20 23:09:02 +01:00
fossfreedom 292201f926 change the position and icon of the preferences wiki link button 2013-04-20 23:02:02 +01:00
fossfreedom 522cdb25f8 add advance options for iconview spacing and padding 2013-04-20 21:44:55 +01:00
fossfreedom 362abfbedc regenerate translation pot file 2013-04-20 11:53:38 +01:00
fossfreedom 2be1cf05b1 remove unneeded markup tooltips 2013-04-20 11:50:33 +01:00
fossfreedom 82777c340c add link to wiki 2013-04-19 12:51:56 +01:00
fossfreedom 207c3ee97d latest pt_BR translation 2013-04-19 12:51:32 +01:00
fossfreedom 6a5ef715e5 Update README.md 2013-04-19 00:54:30 +02:00
fossfreedom 8be7155fd0 changed launchpad credit to be visible only on request via info button - issue #168 2013-04-18 23:37:30 +01:00
fossfreedom a395c00df8 display translators on preferences dialog - issue #168 2013-04-18 21:50:47 +01:00
fossfreedom e0ef6f040d add translator-credits 2013-04-18 20:16:44 +01:00
fossfreedom 3d41829949 Merge branch 'master' of http://github.com/fossfreedom/coverart-browser 2013-04-18 08:14:02 +01:00
fossfreedom 9c142c6036 latest es.po translation 2013-04-18 08:13:42 +01:00
fossfreedom 6cb11029b1 Update README.md 2013-04-17 23:56:08 +02:00
fossfreedom 449d0375de Update README.md 2013-04-17 23:55:58 +02:00
fossfreedom e880bba103 corrected help link - this will be version defined 2013-04-17 22:21:05 +01:00
Agustin Carrasco c4504c274d Damn, I keep getting it wrong 2013-04-17 08:21:02 -03:00
Agustin Carrasco 0c70ecdb6b Oops, wrong link 2013-04-17 08:18:45 -03:00
Agustin Carrasco edef1f564e Updated url for asermax fattr button 2013-04-17 08:12:20 -03:00
fossfreedom 33820cfeb9 make sure preferences use translation locale before building - issue #176 2013-04-17 10:45:23 +01:00
fossfreedom 50b7c1f936 Update README.md 2013-04-16 20:45:49 +02:00
fossfreedom 8c756fa01a add support for WikipediaSearch plugin 2013-04-16 16:56:43 +01:00
fossfreedom acb5ff7061 prevent crash if search providers plugin is not installed - issue #159 2013-04-16 15:30:13 +01:00
fossfreedom 6af7e36af8 latest launchpad translations 2013-04-16 09:40:39 +01:00
fossfreedom bf56c47c3e latest translations 2013-04-15 12:33:13 +01:00
fossfreedom f3f389006a latest translations from launchpad 2013-04-14 13:43:15 +01:00
fossfreedom 8f18571626 regenerate after asermax ui translate change 2013-04-14 11:13:45 +01:00
Agustin Carrasco ae8f3a5da3 bugfix ui: added translatable marter to the collapsible pane label
Issue #123
2013-04-13 20:17:55 -03:00
fossfreedom 8fcf0f6712 update README for new coverart export and embed functionality 2013-04-13 23:49:02 +01:00
fossfreedom 9ce6e8c7d9 regenerate po for new coverart export and embed strings 2013-04-13 23:46:55 +01:00
fossfreedom aa4904ded7 minor typo 2013-04-13 23:45:51 +01:00
fossfreedom da31e95cab Merge branch 'master' of http://github.com/fossfreedom/coverart-browser 2013-04-13 23:45:02 +01:00
fossfreedom 198426e55e implementation of coverart export and embed functionality - issue #159 2013-04-13 23:44:40 +01:00
fossfreedom ef2ff02b28 add help button on preferences 2013-04-09 09:41:01 +01:00
Agustin Carrasco 3744855057 albums: fixed bug introduced when changed to using _sort properties for
sorting: whenever an album would need to get deleted (because it was
empty), it would fail since the key using for sorting and finding an
element inside the sorted structure was given by the _sort key. The
_sort key was naively decided to be obtained from the first track of the
album, and since the album is empty, it would raise a IndexError.
2013-04-07 16:51:29 -03:00
fossfreedom f296c644a6 drag and drop coverart onto playlists and sources 2013-04-06 12:18:36 +02:00
fossfreedom cd665e2bb9 change the drag icon 2013-04-06 00:06:44 +01:00
fossfreedom 35c02421a5 seems playlists are working now 2013-04-05 23:18:55 +01:00
fossfreedom dcc3dc3187 basic support for drag and drop from coverview - issue #169 2013-04-05 23:02:25 +01:00
fossfreedom 75b9a540fe minor mods 2013-04-03 21:00:34 +01:00
fossfreedom 1d639d6730 remove automatic enablement of plugin 2013-04-03 21:00:17 +01:00
fossfreedom ca1fbcd899 add lLyrics to supported external plugins 2013-04-03 20:59:32 +01:00
fossfreedom 25940e3485 minor mods 2013-04-03 20:12:29 +01:00
Agustin Carrasco 2438cbdd08 widgets: fix bug on EnhancedIconview where the selected objects were returned in reversed order 2013-03-31 23:31:33 -03:00
Agustin Carrasco bab9311225 On play album: use the queue_selected_album instead of copying the entryview query (issue #130) 2013-03-31 23:31:09 -03:00
Agustin Carrasco 76215de1b2 Changed the method to play entries/albums to replace the source's query model
instead of queuing the entries into the play queue (issue #130)
2013-03-31 23:16:12 -03:00
fossfreedom 3c6a3e8c4d queue remaining tracks in entry view on playing - issue #130 2013-03-31 23:53:54 +01:00
fossfreedom eddfe978a3 Merge branch 'master' of http://github.com/fossfreedom/coverart-browser 2013-03-31 11:53:49 +01:00
fossfreedom a38fc28763 latest french translations 2013-03-31 11:53:32 +01:00
fossfreedom 9bf3f333ea Update README.md 2013-03-30 17:06:25 +00:00
fossfreedom 6d2d45b518 add file-organizer support - this is pending a pull request being accepted. It it isnt, this will need to be backed out before release 0.8 2013-03-29 20:20:37 +00:00
fossfreedom 408f78d634 latest fr_CA translation 2013-03-29 16:57:01 +00:00
fossfreedom ced468ac65 fix external module name for opencontainingfolder - issue #147 2013-03-29 11:25:47 +00:00
fossfreedom de9bdf67e3 Merge branch 'master' of http://github.com/fossfreedom/coverart-browser 2013-03-28 23:40:46 +00:00
fossfreedom 8859688606 initial support for external plugins - issue #147 2013-03-28 23:40:37 +00:00
Agustin Carrasco ccd8f10786 widgets: added some documentation for the EnhancedIconView widget. 2013-03-28 19:53:43 -03:00
Agustin Carrasco fe159d07b7 Merge branch 'collapsible-paned'
Refactored code that managed the paned behavior of the source main view on it's
own widget, which also takes care of the expandable on one of it's children.
This new widget abstracts the storing of the paned handle position, handles the
expandable child and handles the workaround to keep the handle in a fixed place
(when the expandable child is collapsed).
2013-03-28 19:10:21 -03:00
Agustin Carrasco 4057318255 widgets: added some more comments to the CollapsiblePaned widget 2013-03-28 19:10:08 -03:00
fossfreedom 3f47a48f71 fix tooltip - issue #168 2013-03-28 10:16:55 +00:00
fossfreedom 2d24ca1d38 latest translations 2013-03-27 12:37:36 +00:00
fossfreedom 039330dbae embed GtkArrows - issue #167 2013-03-26 09:54:40 +00:00
fossfreedom 0590acc605 embed GtkArrows - issue #167 2013-03-26 09:53:27 +00:00
fossfreedom 2a881319e3 Update README.md 2013-03-25 23:52:34 +00:00
fossfreedom fabe82c919 add comments to methods 2013-03-25 23:45:28 +00:00
fossfreedom 0a32a19aec separated providers plugin from coverartbrowser 2013-03-25 19:51:41 +00:00
fossfreedom 62ac5f5a15 latest translation bits 2013-03-25 16:44:24 +00:00
fossfreedom 9889e2ecb8 slight modifications to label positions - issue #151 2013-03-25 15:56:40 +00:00
fossfreedom d3e9961a56 revert excessive cleanup - issue #151 2013-03-25 11:03:57 +00:00
fossfreedom c8624ea86f move load icons and fix system genre lookup match - issue #151 2013-03-24 23:47:55 +00:00
fossfreedom 6e2bd1f650 tidy up genre gui - issue #151 2013-03-24 17:33:01 +00:00
fossfreedom dbdadac043 makes sense for delete button to use the remove icon to complement the add icon 2013-03-22 13:33:21 +00:00
fossfreedom cd9d36f688 add labels, change save icon and move load icons button - issue #151 2013-03-22 13:24:29 +00:00
fossfreedom 7993695a11 cleanup files 2013-03-21 23:30:58 +00:00
fossfreedom ac861a82b5 Merge branch 'master' into customgenre 2013-03-21 23:27:02 +00:00
fossfreedom 69c5979fb6 new genre gui and connect GUI changes with plugin controller 2013-03-21 23:24:39 +00:00
Agustin Carrasco b1d598b762 Added some comments and rewrote a function to reuse a portion of code instead of repeating it 2013-03-20 13:07:59 -03:00
fossfreedom 0db85fe051 background code and gui for alternative genre icons 2013-03-09 07:33:57 +00:00
Agustin Carrasco 6dbce1846e Finished porting some stuff to the CollapsiblePaned widget and removed now obsolete code from coverart_browser_source 2013-03-08 12:29:00 -03:00
Agustin Carrasco f336b2f64e widget: updated the PanedCollapsible and replaced the GtkPaned on the interface. Now it supports the basic expand/collapse functionality and blocking the handle when collapsed 2013-03-05 22:20:07 -03:00
fossfreedom d6028ca00c Update README.md 2013-03-04 12:17:05 +00:00
fossfreedom db8123d960 Merge branch 'master' into artistorder 2013-03-04 12:11:48 +00:00
Agustin Carrasco 6845ebc3b9 CoverartRequester: remove debugging prints 2013-03-02 21:51:39 -03:00
Agustin Carrasco 71cc9976de CoverRequester: modified the locking mechanism, to avoid the call to next from the same album search or timeout to be processed twice 2013-03-02 21:51:39 -03:00
Agustin Carrasco 97634dddd5 This kind of problems make my heard hurt~
This reverts commit 403d1f51bb.
2013-03-02 21:49:48 -03:00
fossfreedom 7ead18fc5d use sort fields in preference to actual fields - issue #161 2013-03-02 15:08:47 +00:00
fossfreedom 3fbc91fb57 Update README.md 2013-02-25 19:26:21 +00:00
fossfreedom 8c8cfcdc6d bug fix - ensure queuing is sorted first by disc number and then by track number - issue #160 2013-02-25 16:29:41 +00:00
fossfreedom dc9d0332c3 lets ensure both plugins are installed 2013-02-24 16:44:01 +00:00
fossfreedom a63c513423 remove duplication of code with helper functions - issue #149 2013-02-23 23:30:51 +00:00
fossfreedom 334976832b move theme logic to toolbar from toolbar manager - issue #149 2013-02-23 17:49:36 +00:00
fossfreedom ff5ccf49f7 add new signal key for buttons to update image - issue #149 2013-02-23 17:39:47 +00:00
fossfreedom 5827b32e54 move theme control to the Toolbar manager rather than on the controller - issue #149 2013-02-23 17:02:38 +00:00
fossfreedom 677fb805a9 update button theme when user changes - issue #149 2013-02-23 07:48:21 +00:00
fossfreedom 7de5cb2940 few tidyups from icon merge 2013-02-22 09:40:17 +00:00
fossfreedom 94e639ef6c Merge pull request #162 from jrbastien/master
Enhancements to standar icons (issue #149)
2013-02-22 00:00:18 -08:00
jrbastien b7a6347a5f Issue #149. New light and dark team + minor tweak to the sprites genre on standard theme. 2013-02-21 21:23:30 -05:00
fossfreedom 403d1f51bb reset 2013-02-19 16:25:33 +00:00
fossfreedom 28aae8aad1 Merge branch 'cover_search_queue' 2013-02-19 16:18:58 +00:00
fossfreedom f6dc74e7d2 reworked from dialog to window and narrowed buttons with image arrows - issue #126 2013-02-18 21:16:56 +00:00
Agustin Carrasco 4c6b3b12ab PanedCollapsible: set options to the current expander 2013-02-18 13:17:54 -03:00
Agustin Carrasco a1eeaaa037 PanedCollapsible: fixed typo and save expander as object variable 2013-02-18 13:11:22 -03:00
Agustin Carrasco 3ce9a8dc85 OptionsListViewWidget: cleaned code formatting 2013-02-18 13:05:11 -03:00
Agustin Carrasco c9fd8cf418 CoverRequester: the queue was working like a stack actually... 2013-02-18 12:59:25 -03:00
fossfreedom e498d3dd92 add button click pageup/down and focus stuff -- issue #126 2013-02-18 15:58:45 +00:00
fossfreedom 3e19f0555a autoscroll - issue #126 2013-02-17 23:39:35 +00:00
fossfreedom 8d56ad73a8 change from selection to button_release to allow hover selection - issue #126 2013-02-17 22:43:52 +00:00
Agustin Carrasco 01e3762c86 ProxyPopupButton: increase the min fixed limit of options to 25 2013-02-17 16:06:57 -03:00
Agustin Carrasco c99eff7af7 CoverManager: reimplemented the requesting mechanism into a different class that makes use of a queue instead of independent process. This gives the requesting process more flexibility 2013-02-17 03:27:08 -03:00
Agustín Carrasco e5e3d935ae Merge pull request #158 from jrbastien/master
Enhancements to standard icons
2013-02-16 19:36:51 -08:00
Jean-Rene Bastien 2853dc507d Update img/popups.xml
Enhancements to standard icons.  Issue #149
2013-02-16 21:26:17 -05:00
jrbastien 02231061d6 Improvements to calendar icons and default genre icon look. 2013-02-16 21:18:18 -05:00
fossfreedom 594a399b0c add theme support - issue #149 2013-02-13 22:13:01 +00:00
Agustin Carrasco 6ca4a5d3a2 PanedCollapsible: initial implementation of the Paned container with a collapsible child. 2013-02-11 20:07:47 -03:00
Agustin Carrasco 41d3cd8cfc CoverManager: fix bug on the timeout routine for the cover search 2013-02-10 04:51:55 -03:00
Agustin Carrasco 650c2320dc CoverManager: fix bug on the timeout routine for the cover search 2013-02-10 04:23:03 -03:00
Agustin Carrasco f2f4e75670 CoverManager: removed the timer module and replaced the timeout managment from the Source with an internal timemout on the search cover routine 2013-02-10 03:22:55 -03:00
Agustin Carrasco 42ddff79e1 Merge branch 'enhanced-iconview'
Introduced the EnhancedIconview widget, which enhances the iconview capability in some senses:
* Adds a signal for a single click on a icon.
* Fixes column reallocation on width change.
* Adds a popup to the widget, that gets fired when right clicking on an icon.
* Adds a new property to indicate the column of the model that contains the actual object to which the icon and other info belongs to. Through this property, a new method get_selected_objects allows to retrieve those objects corresponding to the current selection on the iconview.
* Adds a method to select and scroll to a given path on the iconview.
2013-02-09 22:18:26 -03:00
Agustin Carrasco 30a8c8322e EnhancedIconview: refactored the code to select and scroll to a path on the iconview.
* Moved the code to select and scroll to the a path from the source to the iconview.
* Refactored the AlbumQuickSearchController to use this new capability directly insted of through the source.
2013-02-09 22:16:41 -03:00
Agustin Carrasco 01c2f57f3b CoverartSource: replaced the get_selected_albums method for the new get_selected_objects method of the EnhancedIconview class 2013-02-07 23:55:32 -03:00
Agustin Carrasco 8942dac647 EnhancedIconview: fixed the get_selected_objects methods, it wasn't managing the model correctly 2013-02-07 23:54:50 -03:00
Agustin Carrasco 7888186e0c CoverartSource: fixed a issue with the second click bottom pane expand. It wasn't working correctly after a shift or ctrl multi selection 2013-02-07 23:52:34 -03:00
Agustin Carrasco 161eb5714b Removed a signal that isn't used anymore 2013-02-07 23:40:53 -03:00
Agustin Carrasco 20388f54a7 Gonna start moving up those methods that got refactored to make it easier to identify those that still need to be looked at 2013-02-07 23:29:28 -03:00
Agustin Carrasco b5d9a53d44 Removed old, unused method 2013-02-07 22:27:00 -03:00
Agustin Carrasco b00e3e6949 CoverartSource: refactored the click callback using the new capabilities of the EnhancedIconview.
Selecting the path on right click and showing the popup is taken care on the new iconview, the only left to do in the source is the second click detection to show/hide the bottom pane.
2013-02-07 22:20:43 -03:00
Agustin Carrasco 61b7c6386e EnhancedIconview: made some fixes on the do_button_press_event method.
* The item-clicked event now send the event two
* The call to the parent class do_button_press_event is made after our custom behavior
* Fixed typo (variable brought from the old code).
2013-02-07 22:18:55 -03:00
fossfreedom e1a68c4acb Merge branch 'master' of https://github.com/fossfreedom/coverart-browser
Conflicts:
	coverart_widgets.py
2013-02-06 22:55:53 +00:00
fossfreedom 4f0251902a open popup at cursor position - issue #144 2013-02-06 22:47:30 +00:00
Agustin Carrasco f31dc04af1 Added a timeout to the columns reallocation to avoid innecesary reallocations while the user is adjusting the pane size 2013-02-06 00:04:40 -03:00
Agustin Carrasco dd58b8a5e3 Removed the update_iconview_callback method from the source since it's not needed anymore 2013-02-05 23:57:58 -03:00
Agustin Carrasco d172061280 Use the available variables instead of saving redundant information 2013-02-05 23:57:03 -03:00
Agustin Carrasco 01696eaa2d Had to call to the superclass' do_button_press_event too, otherwise the selection wouldn't work 2013-02-05 23:47:12 -03:00
Agustin Carrasco 82859ceb2f Added the object_column property to the EnhancedIconView on the source ui 2013-02-05 23:36:28 -03:00
Agustin Carrasco 79bf0a5f79 Replaced the IconView for the EnhancedIconView as the cover_view on the source ui 2013-02-05 23:21:53 -03:00
Agustin Carrasco d382e30c2f Did some fixes on the EnhancedIconView
* The do_size_allocate wasn't calling the superclass behavior, and the allocation wasn't being correctly made.
* Added a signal to inform when a single click is made on a icon.
2013-02-05 23:20:14 -03:00
Agustin Carrasco c24fd22f45 Moved the EnhancedIconView class to the end of file to keep it organized 2013-02-05 22:22:40 -03:00
Agustin Carrasco 6f5783f8ba Organized the Toolbar tab; added some margins and stuff to make it look pretty (blame Glade for the other code that got moved around) 2013-02-05 21:32:51 -03:00
fossfreedom 86e7c4a99f Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-02-05 20:02:57 +00:00
fossfreedom 2a3d455838 add button style for toolbar - issue #149 2013-02-05 20:02:11 +00:00
fossfreedom 96e425aee9 Update README.md 2013-02-04 23:03:49 +00:00
fossfreedom 47ff73ba09 Update README.md 2013-02-04 23:02:38 +00:00
fossfreedom 1097077104 add dimensions to sprites - issue #149 2013-02-04 14:45:13 +00:00
fossfreedom 18ba48f572 Merge branch 'source-refactoring' 2013-02-04 14:23:14 +00:00
Agustin Carrasco 448663cfef Removed some unused code too. That call wasn't really doing anything. 2013-02-03 20:58:30 -03:00
fossfreedom b52b7ec8dd remove more unneeded code 2013-02-03 23:45:45 +00:00
fossfreedom 83e587405f merge listviewwindow with optionslistviewwidget 2013-02-03 23:41:03 +00:00
fossfreedom 401ae1bd60 Update README.md 2013-02-03 22:57:26 +00:00
fossfreedom cdd681a8e5 Merge branch 'source-refactoring' 2013-02-03 22:51:14 +00:00
Agustin Carrasco 3079af48bc Fixed the issue when the genre ListWindow would get destroyed after pressing [ESC] (issue #123). 2013-02-03 18:45:48 -03:00
Agustin Carrasco 67f22db97a Modified the ListWindow and the OptionsListViewWidget to recreate the liststore only when necesary (issue #123).
* Removed the activate method from the ListWindow and moved the relevant code to other places to help with the flow of the OptionsWidget.
* Correctly implemented the update_options and update_current_key callbacks to do what they should (recreate the list and select the currently selected item respectively)
* TODO: maybe the ListWindow should be merged with OptionListViewWidget? Right now they seem like two layers of the same thing, maybe it could be simplified by merging.
* TODO: the "mouse" flag for the window position seems to put the center of the windo on the mouse, instead of the corner (like the poups). Should look into that.
2013-02-03 17:15:46 -03:00
Agustin Carrasco b0a87d9d53 Adapted some syntax to PEP8 2013-02-03 17:15:46 -03:00
fossfreedom 16be637fd0 latest translations - also translates separate search providers plugin 2013-02-03 18:15:40 +00:00
Agustin Carrasco 784de34081 Fixed some stuff on the "Cover" tab of the bottom pane:
* Fixed the hiding of the show more results links. Now it hides when it haves to.
* Floated the Google branding div to the right. This way the show more link is more visible and easily accesible, while the branding is still there but doesn't obstruct the rest of the interface.
2013-02-03 11:39:42 -03:00
Agustin Carrasco 82545062b2 Optimized search for album with a given ext_db_key to only try to match against an album with the corresponding name. 2013-02-03 11:19:30 -03:00
fossfreedom 9c6d37a285 refact search providers into separate plugin - issue #152 2013-02-03 11:32:20 +00:00
fossfreedom 37da774bd6 rework to use selection changed event - issue #144 2013-02-01 16:47:12 +00:00
fossfreedom a6e3a42fab oops change 12 to 25 for when to display listwindow - issue #144 2013-02-01 15:37:27 +00:00
fossfreedom 028a38570a remove cancel button and close when lose focus - issue #144 2013-02-01 15:35:34 +00:00
fossfreedom 718d9b6b61 Merge branch 'source-refactoring' of https://github.com/fossfreedom/coverart-browser into source-refactoring 2013-02-01 15:18:13 +00:00
fossfreedom 4229614129 refactor listview to be separate widget/button - issue #144 2013-01-31 22:42:21 +00:00
fossfreedom 348f4350f5 add latest finnish po from launchpad 2013-01-26 16:47:55 +00:00
fossfreedom 99484c016c fix global makefile and remove unneeded file 2013-01-26 16:45:00 +00:00
fossfreedom c08be9f2fc add coverart archive to preferences - issue #69 2013-01-25 23:00:55 +00:00
fossfreedom 623894d5a6 add translations for search providers plugin - issue #145 2013-01-25 22:42:37 +00:00
fossfreedom b2485b739a Merge branch 'master' into source-refactoring 2013-01-25 22:32:46 +00:00
fossfreedom da36e0c0dd rename plugin to be more obvious - issue #145 2013-01-25 20:51:38 +00:00
fossfreedom ba40924cb7 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-01-25 18:55:27 +00:00
fossfreedom fbb8e137d6 bug fix - mp3 files now correctly recognised in coverart embedded search - issue #145 2013-01-25 18:55:04 +00:00
fossfreedom 04bc511509 Update README.md 2013-01-25 15:04:19 +00:00
fossfreedom 323ce36b89 Update README.md 2013-01-25 15:00:43 +00:00
fossfreedom ebb93e6098 Merge branch 'master' into source-refactoring 2013-01-24 23:34:57 +00:00
fossfreedom 5dc5e6f83f latest launchpad translations 2013-01-24 23:30:45 +00:00
fossfreedom d28fc234e2 Update README.md 2013-01-24 14:59:11 +00:00
fossfreedom df1119b2a7 Update README.md 2013-01-24 14:20:58 +00:00
fossfreedom f0e3f9e658 Update README.md 2013-01-24 14:20:43 +00:00
fossfreedom ef1722ea4b Update README.md 2013-01-24 14:02:55 +00:00
fossfreedom c2c4d0f9e0 Update README.md 2013-01-24 13:51:29 +00:00
fossfreedom 440ff178b6 Merge branch 'master' into source-refactoring 2013-01-24 12:51:39 +00:00
fossfreedom 4b11d1a6c8 rework to be a dialog - issue #126 2013-01-23 15:41:03 +00:00
fossfreedom b13d370f19 remove plugin function and now depend on plugin property - issue #126 2013-01-23 13:13:35 +00:00
fossfreedom 6d2397bcf7 initial implementation of list window - issue #126 2013-01-22 23:52:22 +00:00
fossfreedom dd175bc366 fixed various issues - issue #142 2013-01-20 23:18:47 +00:00
Agustin Carrasco a3cda5d976 Readded the property decorator for the calc_artist property (issue #142) 2013-01-20 19:01:18 -03:00
Agustin Carrasco 0e4d722f2d Initial implementation of an enhanced icon view that manages it's own popup and haves a method to retrieve the selected objects, given that the column number of the object that represent each models row is setted 2013-01-20 18:29:09 -03:00
fossfreedom 4008db5d5b more sensible searching algorithm for discogs - issue #94 2013-01-18 17:03:40 +00:00
Agustin Carrasco 75bf6d4d27 Use of search_fold on all search parameters. Fix for issue #140 2013-01-18 01:52:49 -03:00
fossfreedom 08d3b775b9 latest launchpad translations 2013-01-17 21:51:01 +00:00
fossfreedom 567533dcf1 ensure genre 'all' is translated - issue #121 2013-01-17 21:22:13 +00:00
fossfreedom b2ea2c1c0e fix for sort - issue #139 2013-01-17 10:54:30 +00:00
fossfreedom e5a3f36cf2 provisionally add coverartarchive.org as a potential cover provider - not 'user' enabled as yet except through dconf - issue #69 2013-01-16 23:09:33 +00:00
fossfreedom 5f9797a433 latest launchpad translations 2013-01-16 21:27:07 +00:00
fossfreedom 66fdb07a43 use alternative URI format and also ensure data is correctly flushed before reading - issue #135 2013-01-16 14:25:59 +00:00
fossfreedom d86d64d146 remove use of deprecated webview API call and split titles that may have a % in them - issue #135 2013-01-15 23:30:05 +00:00
fossfreedom ce770b59db add google branding - issue #136 2013-01-15 22:39:29 +00:00
fossfreedom d76fe8ad67 few tidyups - double click issue still to be understood - issue #135 2013-01-15 21:39:45 +00:00
fossfreedom 29af04bf14 remove second call to activate_markup - issue #123 2013-01-14 19:48:54 +00:00
fossfreedom 9fcc9a9f3f remove conflicting file 2013-01-13 23:23:21 +00:00
fossfreedom be50d77ea2 Update README.md 2013-01-13 15:21:10 +00:00
fossfreedom 333f6ab314 remove genre default from list to be translated 2013-01-09 15:17:00 +00:00
fossfreedom 3a47f5899e fix error in popups.xml.in that stop translation and added Launchpad translation instructions 2013-01-08 21:33:56 +00:00
fossfreedom 791483db09 add in jrbastien french alternatives and split alternatives to be english and french 2013-01-08 21:13:10 +00:00
fossfreedom 982ee1d9ab temporarily prevent generation of popups.xml - waiting for refactor code to be merged in before uncommenting 2013-01-08 20:43:01 +00:00
fossfreedom 335cc699f4 generate popups.xml containing translations 2013-01-08 20:22:58 +00:00
fossfreedom 1b30a2abd6 latest fr.po from launchpad 2013-01-08 10:00:43 +00:00
fossfreedom 166164f7b8 rework translation to use xgettext instead of deprecated pygettext and also add support for translation of popups.xml 2013-01-08 00:06:11 +00:00
fossfreedom 61d0c4046f rename package.pot to coverartbrowser.pot 2013-01-07 13:55:25 +00:00
fossfreedom fb0cd7172a use artists instead of retrieving track artists separately again - issue #125 2013-01-06 22:44:15 +00:00
fossfreedom c4e460d3bd add natural search for track artists - issue #125 2013-01-06 22:29:34 +00:00
fossfreedom c88413b7bb Merge branch 'naturalsort' of https://github.com/fossfreedom/coverart-browser into naturalsort 2013-01-06 15:13:24 +00:00
fossfreedom cd716a2824 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser into naturalsort 2013-01-06 15:13:03 +00:00
Agustin Carrasco d5e95f08e7 Removed superfluous variable _string and tidied up the NaturalString class a little 2013-01-06 11:44:07 -03:00
fossfreedom 9078f6c778 Natural String should inherit from str - issue #124 2013-01-06 13:32:25 +00:00
fossfreedom 8845226251 minor refresh - issue #121 2013-01-06 11:10:20 +00:00
fossfreedom aec56ccbcc removed unneeded print statement 2013-01-06 00:21:01 +00:00
fossfreedom 116fbc9a16 add natural sort - issue #124 2013-01-06 00:13:49 +00:00
fossfreedom fde36f8af7 tidyup - do not clear calculated album & artist when album is modified 2013-01-05 22:10:08 +00:00
fossfreedom c3b0e34a6b remove unneeded files 2013-01-05 15:26:46 +00:00
fossfreedom c2a70c112b use rhythmbox search for album artist and album name filter & sort 2013-01-05 15:24:10 +00:00
fossfreedom aa700342d1 Merge pull request #127 from jrbastien/patch-1
Updated French Canadian translation for issue #121
2013-01-04 23:11:33 -08:00
Jean-Rene Bastien 5be3fb6c95 Update po/fr_CA.po
Fixed missing msgid on coverart_browser_prefs.ui.h:13
2013-01-04 19:15:50 -05:00
Jean-Rene Bastien 9e9b8cb8b1 Update po/fr_CA.po
More updates done.
2013-01-04 09:14:49 -05:00
Jean-Rene Bastien 75f8e8cf0f Update po/fr_CA.po
First commit
2013-01-04 08:48:36 -05:00
Agustin Carrasco 29eab89366 Only create one renderer and reuse it later if needed 2013-01-04 04:40:56 -03:00
Agustin Carrasco e0a8b573cf Replaced the IconView's internal text cell renderer for a custom that behaves exactly the same way, as a workaround for an bug introduced on Gtk 3.6. This should resolve issue #118 2013-01-03 22:35:43 -03:00
Agustin Carrasco 7d439b20de Bugfix: correctly manage the AlbumModel when:
* A second sort request is made when a first one is already being processed. The implemented behavior in this commit is to cancel the previous process and initiate a new one, with the new sorting order.
* A filter is requested when the model is being sorted. Previously, this led to the model trying to set the 'show' column to albums that weren't currently in the tree model, given that they were removed to reorder them, and thus causing a lot of "invalid tree iter" assert fails. The current behavior is to check if a tree iter is valid before trying to asign the 'show' value.
2013-01-03 01:28:08 -03:00
fossfreedom d4c992e59e Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2013-01-02 23:38:20 +00:00
fossfreedom f69e5b3050 more translation stuff 2013-01-02 23:37:43 +00:00
Agustin Carrasco f0d1d3474a Bugfix: now, even if the album is in the last row, it's made visible in the case the entry view shadows it (issue #104) 2013-01-02 19:52:55 -03:00
Agustin Carrasco 22c7f46d3b Cleaned and added some comments to mouseclick_callback 2013-01-02 19:52:55 -03:00
Agustin Carrasco fc587622e7 Removed unneeded lines on item_activated_callback 2013-01-02 19:52:55 -03:00
fossfreedom d6180601c1 slightly resized decade icon to make better use of available space 2013-01-02 20:47:19 +00:00
fossfreedom af3e7c9e1c removed unneeded files 2013-01-02 20:23:53 +00:00
fossfreedom c0b777b807 removed unneeded files 2013-01-02 20:23:41 +00:00
fossfreedom 20fb628f67 regenerated all po's and fixed en_US.po 2013-01-02 20:22:38 +00:00
Agustin Carrasco 433c03e4eb Bugfix: only update the iconview item distribution (to use the allocated space) **only when the width is updated**. There's no need to update the iconview on height changes, since it's vertically scrollable; also, updating on height changes slows down the UI when working with the bottom expander. 2013-01-02 16:03:04 -03:00
Agustin Carrasco ecb20e7efc Updated spansish translation 2013-01-02 15:14:43 -03:00
Agustin Carrasco 1005531f65 Removed translatable property from settings keys that should not be translated (issue #121) 2013-01-02 15:01:12 -03:00
Agustin Carrasco e58964e65d Bugfixes:
* Move the iconview cursor when right clicking to the clicked album.
* Ignore context menu triggers (right clicks) on the coverview to hide/show entry view.
2013-01-02 14:51:17 -03:00
fossfreedom e6b091df34 fix some minor fr.po translation issues 2013-01-02 13:47:54 +00:00
fossfreedom 293557342a updated translation files with current 2013-01-02 11:32:36 +00:00
fossfreedom f0de06c10c use expand -t 4 to change tabs to spaces 2013-01-02 11:28:38 +00:00
Agustin Carrasco b69168b157 Some bugfixes:
* Correctly update the last selected album when using keyboard cursor movement, which allows the entry view to expand when clicking the currently focused album, doesn't matter how it got focused in the first place.
* Fixed some bugs arround rapidly clicking different albums, which caused a incorrectly interpreted double click.
2013-01-01 21:03:45 -03:00
Agustin Carrasco 3ef2ff2eb1 Introduced the viewport scrolling when the album is not visible to the manual expansion too 2013-01-01 20:01:39 -03:00
Agustin Carrasco 0072871853 Simplified the second-click-expand and third-click-collapse behaviors, using a couple of local variables and removing the Expansion related code. Also, removed the manual expanded/collapsed indicators, since it doesn't make sense in the second-click expand schema 2013-01-01 19:45:15 -03:00
Agustin Carrasco 99ea410269 Style fixes acording to PEPs 2013-01-01 17:53:07 -03:00
fossfreedom 0203d4a8e4 replaced custom async with gdk timeout equiv - issue #104 2013-01-01 15:39:57 +00:00
fossfreedom 986d20d1fc minor timing changes - issue #104 2013-01-01 14:45:44 +00:00
fossfreedom 15a1e37e39 remove unneeded files 2013-01-01 10:43:09 +00:00
fossfreedom ff6c2249ef manual merge from master 2013-01-01 10:41:20 +00:00
fossfreedom 0fb8926717 minor calculation changes on spritesheet 2013-01-01 10:21:47 +00:00
fossfreedom a38da1dfe3 revised decade spritesheet - issue #120 2013-01-01 10:17:02 +00:00
fossfreedom e3b5c798fa add decade spritesheet and code - issue #120 2012-12-31 18:44:00 +00:00
fossfreedom 610dccd35a remove orig file - issue #120 2012-12-31 13:40:23 +00:00
fossfreedom 77c7b9b5b7 add new icon - issue #120 2012-12-31 13:37:29 +00:00
fossfreedom 38a0a4784e add new button plus code for decade filter - issue #120 2012-12-31 12:04:03 +00:00
Agustin Carrasco 1f9779cb1d Merge branch 'quick-search'
This introduces the quick search feature to the master branch. This feature allows the user to do a quick search by album name through the visible albums, quickly selecting the first match and allowing the user to navigate through the matches using the up and down arrow keys (close #99)
2012-12-30 20:12:31 -03:00
fossfreedom 8c509334d7 bug fix - remove use of deprecated VBOX 2012-12-30 22:38:34 +00:00
fossfreedom 009b4bc03b Merge branch 'master' into click 2012-12-30 18:19:42 +00:00
Agustin Carrasco 5cdf587e96 Change timeout from 3 to 4 seconds and fix an issue with the match selection (issue #99) 2012-12-30 14:19:13 -03:00
Agustin Carrasco b0b4aafe74 Added the posibility to navigate through the quick search matches using the up and down arrows. (issue #99) 2012-12-30 12:44:17 -03:00
Agustin Carrasco 764df82454 Fixed bug on ReversedSortedCollection class' index method 2012-12-30 12:38:56 -03:00
Agustin Carrasco 057ef59d24 Hide the quick search entry when it loses focus 2012-12-30 11:42:10 -03:00
Agustin Carrasco 59dcf4ac19 Added a timeout of 3 seconds after the last input on the quick search entry before automatically hiding it (issue #99). 2012-12-30 00:14:28 -03:00
Agustin Carrasco d4f13ee7de Added a visible border around the text quick search entry to make it blend better with it's surroundings (issue #99) 2012-12-29 23:47:53 -03:00
Agustin Carrasco 76e0cc2661 Clean the widgets module:
* Some minor style adjustments following python PEPs
* Removed the superflous ```initial_label``` PopupButton's property and its accesors, since it was confusing and didn't add any real value. The value saved on it was something only used on the subclasses (the superclass only used it on initialization) and is really easy to access it using other mediums instead (other object properties). Plus, using accesors on python isn't really necesary. For plain variables there aren't needed at all, and if you need to do some proccessing before setting/getting a variable, you can replace accesors with a property.
* Fixed bug on the SortPopupButton that caused that the radio button would, on initialization, select the 'Sort by album name' item, even if that wasn't the current sorting key.
2012-12-29 19:49:49 -03:00
Agustin Carrasco 008bda1f8c Bugfix: the toolbar positions radiobuttons were firing an extra signal when the pref window was opened, forcing the toolbar to dissapear if it was positioned in one of the sidebars. Changed the radiobuttons for a more suitable (in my opinion) combobox, fixing this bug at the same time (issue #117). 2012-12-29 19:17:57 -03:00
Agustin Carrasco d75e4ff8b6 Bugfix: instead of removing and readding an item into the sorted collection, defined a reorder method which internally checks if the items needs to be reordered and return the new index in case it does (issue #119). Removed the pre-modified signal since it's no longer needed. 2012-12-29 18:26:47 -03:00
fossfreedom 36c2e15e0b rework to introduce second/third click show hide options - issue #104 2012-12-29 17:03:34 +00:00
fossfreedom 922300a0a6 add shift or ctrl click override - issue #104 2012-12-27 11:29:26 +00:00
fossfreedom bab3e9c0dc scroll if selected album would be hidden by entry view - issue #104 2012-12-26 22:12:04 +00:00
fossfreedom d13a1919c7 initial implementation - issue #104 2012-12-23 22:33:06 +00:00
Agustin Carrasco 45d23660ce Minor bugfixes:
- Prevent the quick search to gain focus if a modifier key is being pressed, since they have an special meaning on the cover view.
- Move the cover view cursor to the album selected by the quick search mechanism.
2012-12-23 03:57:41 -03:00
Agustin Carrasco 64c9003d15 Added functionality to the quick search (issue #99). TODO: timeout to hide the quick searcn entry 2012-12-23 02:48:27 -03:00
Agustin Carrasco 6bbaa0a4e4 Initial implementation of the quick entry on a overlay for the iconview 2012-12-23 00:49:32 -03:00
fossfreedom c05977d224 Merge branch 'master' into split 2012-12-22 22:57:19 +00:00
Agustin Carrasco d2211d6af2 Changed radio buttons for combobox issue #116 2012-12-22 18:37:30 -03:00
Agustin Carrasco 58fef049d5 Fixed memory usage issue #116 2012-12-22 13:27:28 -03:00
fossfreedom 4f0b0739f8 add shadow options - issue #116 2012-12-22 07:54:50 +00:00
fossfreedom f6d4a11c1a add gothic as alt and removed alt world beat - issue #115 2012-12-20 23:50:11 +00:00
fossfreedom df9e24bd31 typo for ragtime - issue #115 2012-12-20 16:14:25 +00:00
fossfreedom 900f2daf77 karaoke typo - issue #115 2012-12-20 16:11:54 +00:00
fossfreedom 72d1c0ca84 get library and queue names from source - issue #112 2012-12-20 15:07:31 +00:00
fossfreedom 4f619dd869 Merge branch 'spritesheet' 2012-12-19 20:03:39 +00:00
fossfreedom 8b6a7e623b set start-position for genres to zero - issue #109 2012-12-19 20:02:23 +00:00
fossfreedom 788c7c450d Merge branch 'master' into split 2012-12-19 16:36:43 +00:00
fossfreedom 93ec578647 merge from spritesheet 2012-12-19 16:21:37 +00:00
fossfreedom bc7239f1aa oops now latest files issue #109 2012-12-19 16:12:31 +00:00
fossfreedom 7917d05fb1 remember sort order - issue #114 2012-12-19 15:41:32 +00:00
fossfreedom 7322ad5060 removed unneeded file 2012-12-19 14:59:33 +00:00
fossfreedom 90603e7e02 revised positioning of genre icons - issue #109 2012-12-19 14:59:08 +00:00
fossfreedom 4aa6c29d63 revert default genre icon - issue #109 2012-12-19 12:33:18 +00:00
fossfreedom b250ce98e2 latest icons and add x_start and y_start on spritesheets - issue #109 2012-12-19 10:00:28 +00:00
fossfreedom 1e8da857f8 merge from master 2012-12-19 09:45:43 +00:00
Agustin Carrasco 8662fec1da Removed unnecesary query reasigment of query model 2012-12-19 01:04:02 -03:00
Agustin Carrasco ae0420b130 Bugfix: had to create a new prop model instead of using the library source one. The reason: the library source genre prop model is linked to the library source filtered query instead of the base query, which means that each time you filter the library source, all genres are being filtered too. This caused two problems: 1º the genre popup would get filtered (when it shuldn't); 2º in the case of big libraries (like mine) the UI would hang since the row-deleted/row-inserted would get fired once for each genre. 2012-12-19 00:45:55 -03:00
Agustin Carrasco 3ba609b760 Bugfix: fixed internalization error on genre filter (issue #110) 2012-12-18 22:00:42 -03:00
fossfreedom 09a3e7022d workaround for playlist popup issue #111 2012-12-18 23:50:00 +00:00
fossfreedom 00d6ef8ae5 copes with r&b which is mapped to blues - issue #109 2012-12-18 13:53:37 +00:00
fossfreedom a00de52d77 ensure partial matching is done on longest genre strings first - issue #109 2012-12-18 13:37:46 +00:00
fossfreedom 244a12e205 fix sizing and positioning of genre icons - issue #109 2012-12-18 10:53:36 +00:00
fossfreedom 9d2ff14c3a add partial and alternate genre checks - issue #109 2012-12-18 00:07:48 +00:00
fossfreedom 80dce0529b latest genre icons issue #109 2012-12-17 23:00:08 +00:00
fossfreedom a5835c660c backout proxy stuff 2012-12-17 20:25:23 +00:00
fossfreedom 9f02f8befc Merge branch 'master' into split 2012-12-17 15:57:50 +00:00
fossfreedom 665d9dc8d8 add proxy for discogs 2012-12-17 15:55:53 +00:00
Agustin Carrasco 7a2d4fbb6d Changed album_artists for artists on the popup.xml file 2012-12-17 11:52:29 -03:00
Agustin Carrasco 55af65c571 Bugfix: changed some places that still referenced the Album's album_artist property instead of the artist attribute (issue #83) 2012-12-17 11:46:26 -03:00
fossfreedom 8dc26baa19 Update README.md 2012-12-17 14:17:20 +00:00
fossfreedom b0470c04fe creative license for genre icons 2012-12-17 10:11:36 +00:00
fossfreedom 27dc0d0c74 make shadow the default and discogs an optional 2012-12-17 10:01:31 +00:00
fossfreedom 59c6d68210 Merge branch 'master' into spritesheet 2012-12-17 09:53:15 +00:00
fossfreedom bb76e3a720 latest icons issue #109 2012-12-17 09:52:29 +00:00
Agustin Carrasco f96729e2e8 Merge branch 'album-artists'
This introduces a the album artists as a identity parameter for albums. This means that an album is unique given it's name AND artist, effectivelly dividing albums with the same name but different artists. It's responsability of the user to correctly tag their collection for this to work correctly, since a missing or wrong album artist tag may produce an incorrect view of the collections albums.
2012-12-17 02:06:15 -03:00
Agustin Carrasco a31fdecfea Bugfix: added a check and a resize on the cover creation if the pixbuf loaded from a file isn't a square. This should avoid albums with ugly shadows since it doesn't cover the whole area 2012-12-17 01:55:03 -03:00
Agustin Carrasco 226291602b Bugfix: changed the strategy to indicate to the cover_view that it should update to something more blunt. The old method was generating some ugly bugs on my view 2012-12-17 01:32:10 -03:00
fossfreedom 50d0a7b682 new iconset #109 2012-12-16 23:39:48 +00:00
Agustin Carrasco 15464534b6 Bugfix: fix cover search to work with all the providers (artsearch plugin, our providers and the cover search pane) (issue #83) 2012-12-16 18:24:07 -03:00
Agustin Carrasco 2fa11460c2 Modified the album managment to include the album artist as an identity parameter for the album itself. This way, each album is unique given it's name AND artist, effectivelly dividing albums with the same name but diferent album artist. (issue #83) 2012-12-16 15:36:24 -03:00
fossfreedom 9d7a2ad49c tidied sort and playlist images - issue #109 2012-12-16 18:35:57 +00:00
fossfreedom d556c21f5a update popups.xml with new sort and playlist sprites 2012-12-16 14:39:49 +00:00
fossfreedom f95d24fac6 merge from upstream spritesheet 2012-12-16 12:33:31 +00:00
fossfreedom 4edd210f2f convert spr to xml 2012-12-16 12:29:39 +00:00
Agustin Carrasco e7c14a93d7 Added the posibillity to indicate the icon 'size' when creating a spritesheet, this is, scalling the original icons to a new size (squared) 2012-12-15 23:29:45 -03:00
Agustin Carrasco 313e80571d Merge branch 'idle-call'
Abstracted idle calls iterations into an utility class (plus a decorator) to avoid code duplication and make the code more redeable.
2012-12-15 23:19:32 -03:00
Agustin Carrasco 539f52a51d Reimplemented the idle iter methods creating with a decorator 2012-12-15 23:15:21 -03:00
Agustin Carrasco b9627a7499 Modified the rest of the idle calls to use the IdleCallIterator 2012-12-15 22:41:24 -03:00
fossfreedom fb8348874d Merge branch 'spritesheet' of https://github.com/fossfreedom/coverart-browser into spritesheet 2012-12-15 12:19:28 +00:00
fossfreedom a27c31d7f6 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser into split 2012-12-15 12:18:36 +00:00
Agustin Carrasco d7fe753ba3 Oops, forgot about the image and the spr file. Also added __contains__ to the ConfiguredSpriteSheet 2012-12-15 03:12:41 -03:00
Agustin Carrasco 76dd4b5687 Created an utility class to manage spritesheets. Added a genres spritesheet togheter with a spr spritesheet config file for it. (issue #109) 2012-12-15 03:06:42 -03:00
Agustin Carrasco 0642edd593 Implemented idle calls on the AlbumsModel using the IdleCallIterator 2012-12-15 01:53:28 -03:00
Agustin Carrasco 5619c19182 Created an utility class to abstract the idle calls. 2012-12-15 01:51:40 -03:00
Agustin Carrasco 2272cb9880 Bugfix: Unknown cover not updating correctly when enabling/disabling the add-shadow setting (issue #68) 2012-12-14 18:29:25 -03:00
fossfreedom 39a62baade Merge branch 'master' into split 2012-12-14 20:41:42 +00:00
fossfreedom f1324fa2b7 threading seems to work now 2012-12-14 20:39:05 +00:00
Agustin Carrasco 06f50ad843 Merge branch 'shadow'
Added the posibility to add a shadow to the album's cover, adding some depth to the coverview. (closes #68)
2012-12-14 17:26:20 -03:00
Agustin Carrasco 1341ec239e Added option to enable/disable the shadow (issue #68) 2012-12-14 17:14:15 -03:00
fossfreedom 763058e1b5 trying lastfm async method - not working as yet 2012-12-14 16:41:26 +00:00
fossfreedom b2131b285a Merge branch 'master' into split 2012-12-14 14:15:55 +00:00
Agustin Carrasco f66d662c8b Bugfix: blank cover view on autostart with big library (issue #108) 2012-12-13 23:09:55 -03:00
Agustin Carrasco 2a0d431976 Just changed the place of some lines since it looked better xD 2012-12-13 18:20:06 -03:00
Agustin Carrasco 0d69463945 Fixed exception on CoverManager initialisation (issue #68) 2012-12-13 18:17:49 -03:00
Agustin Carrasco 5ae748638c Change the page increment for the cover size to 5 pixels 2012-12-13 17:39:38 -03:00
Agustin Carrasco bf7faefcf2 Bugfix: change item_width on cover resize 2012-12-13 17:39:25 -03:00
Agustin Carrasco 118a36ffc1 Bugfix: since the album manager isn't longer a singleton, it should be passed as a parameter to the coversearch pane 2012-12-13 16:50:46 -03:00
Agustin Carrasco a8f5a1bcf6 Some bugfixes and little changes:
- Bugfix: resizing the ShadowedCover failed because the Shadow dimensions weren't being updated.
- Change: reduce padding between items.
- Change: reduced shadow width by 1 pixel.
2012-12-13 16:41:01 -03:00
Agustin Carrasco 07c35ecf99 Initial modifications to add shadow to the coverview (issue #68) 2012-12-13 09:19:39 -03:00
Agustin Carrasco 2d01e0fd12 Bugfix: iconview wouldn't expand to max available width 2012-12-13 09:19:30 -03:00
fossfreedom e388afcbef merge from master 2012-12-13 11:31:56 +00:00
fossfreedom eea7dac481 remove extraneous file 2012-12-13 10:10:14 +00:00
fossfreedom c4a594bb5f Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-12-13 10:00:29 +00:00
fossfreedom e399b257f8 move pictures to img folder - issue #106 2012-12-13 10:00:15 +00:00
Agustin Carrasco 41a80bedca Changed chunk sizes for different data processing. The cover_load_chunk is smaller than the album_load_chunk to make the UI more responsive when loading covers (I/O to disk) 2012-12-13 06:55:06 -03:00
Agustin Carrasco dd68e6b096 Bugfix: avoid the firing of the update_iconview callback when we are moving the bottom pane handle. There's no need for the signal to be fired and it only makes the UI choppy 2012-12-13 00:15:28 -03:00
Agustin Carrasco 912c84d44e Some style clean up. If anyone's wondering, I clean up acording to python PEPs on code style. Yeah, kinda OCD but w/e 2012-12-12 23:56:01 -03:00
Agustin Carrasco 94b181a21c Bugfix: entryview popup shouldn't fire when no entries are selected 2012-12-12 23:51:16 -03:00
Agustin Carrasco 787599858e Sync our entryview sort order with the library source's entryview sort order 2012-12-12 23:48:43 -03:00
Agustin Carrasco df46d6d0f1 Added the posibility to sort by column on the entryview. Closes #38 2012-12-12 22:27:38 -03:00
Agustin Carrasco e1831d5e2e Removed rating update, doesn't make much sense since it's supposed to be the album's rating, not it's entries. 2012-12-12 22:21:44 -03:00
fossfreedom 94d71c14c6 imagetogglebutton widget #106 2012-12-12 23:29:28 +00:00
fossfreedom f019a1c4c1 fix sort order button to have custom images rather than stock icons - issue #106 2012-12-12 23:25:44 +00:00
Agustin Carrasco 3f3829393e Actually these should be object properties, not class properties 2012-12-12 12:21:45 -03:00
fossfreedom 174fe76371 resolve merge issues
Merge branch 'genre'

Conflicts:
	ui/coverart_browser_prefs.ui
2012-12-12 13:22:37 +00:00
Agustin Carrasco d32b1b6ea7 Still had some imperfections, now I think it's done 2012-12-11 20:30:40 -03:00
Agustin Carrasco 347a837dca Cleaned up the sort image a little more since there were still some traces of white where it should've been trasnparent 2012-12-11 20:27:55 -03:00
fossfreedom 5843ff594d remove legacy playlist menu from other sources - issue #101 2012-12-11 23:09:03 +00:00
fossfreedom 0106b422f7 add music queue + arrows for sort order - issue #101 2012-12-11 22:55:46 +00:00
fossfreedom c21f864a7a make sort button grey/black and background transparent - issue #101 2012-12-11 21:34:12 +00:00
fossfreedom a973526de7 ensure initialise is only runnable once - issue #101 2012-12-11 21:04:56 +00:00
fossfreedom 304e7906b8 merge and fix sidebar toolbar - issue #101 2012-12-11 15:20:33 +00:00
Agustin Carrasco 01fc7552d9 Readded signals to the bottom pane. They were deleted somewhere along the way. issue #101 2012-12-10 23:31:52 -03:00
Agustin Carrasco 1c7462e246 Removes actions from the PopupButton, use the radio_items directly. This fixes the issue with the genres (I don't know yet why it was happening) issue #101 2012-12-10 23:18:34 -03:00
Agustin Carrasco 0717352161 Fixed genre filter removal when no more albums on the genre 2012-12-10 21:17:08 -03:00
fossfreedom f9bab2eeff make menus radiomenuitems - issue #101 2012-12-10 23:51:57 +00:00
Agustin Carrasco 8a85ee0843 Moved the creation of the popup for the genres to the button initialization. Added signal handlers for model changes to update the genres. (issue #101) 2012-12-10 15:08:24 -03:00
fossfreedom 5c6a92db62 cleanup obsolete commented out code 2012-12-10 16:24:51 +00:00
fossfreedom 4fec0615b8 convert menuitems to radiomenuitems 2012-12-10 00:09:00 +00:00
Agustin Carrasco 9973f8fd90 Fixed problem on line 270 and some style fixes (sorry, I got carried away xD) issue #101 2012-12-09 19:58:09 -03:00
fossfreedom 8e3c7452cc sort by button - issue #101 2012-12-09 22:35:04 +00:00
Agustin Carrasco dcd531fb3e Readded missing 'pixbuf_column' property for the incoview (issue #101) 2012-12-09 16:53:53 -03:00
Agustin Carrasco 89ce607a9f Merge branch 'clean-settings'
This changes the ui for the preferences window, that now uses a notebook with separated tabs for different options. closes #105
2012-12-09 16:48:33 -03:00
Agustin Carrasco 8a8ef6dc80 Replaced some strings on the settings ui 2012-12-09 16:48:21 -03:00
fossfreedom fbaa034d40 add playlist and genre buttons - issue #101 and #102 2012-12-09 18:37:25 +00:00
Agustin Carrasco 6dd414a2d5 Since the new AlbumManager keeps a reference of the cover_view (an various managers keep signals connected to it) it's easier to make the source to be a singleton instead of the AlbumManager. It probably is wrong, but it works for now; I plan to decouple the coverart_browser_source module a lot more later on, so this is a workaround for now 2012-12-09 00:24:32 -03:00
Agustin Carrasco fd3711a7e3 Added new commetns to the coverart_album module 2012-12-08 23:49:05 -03:00
Agustin Carrasco 91955c3c83 Fix some problems on entry deletion/allocation: check for duration before allocation; delete the track from the tracks list on deletion 2012-12-08 22:29:43 -03:00
Agustin Carrasco 879a4b4147 Redistributed the settings on the preferences window using a GtkNotebook #105 2012-12-08 20:16:47 -03:00
Agustin Carrasco 3ba07eb628 Merge branch 'loading'
This merge implies a change on the coverart_album module. A somewhat fullfilling explanation of the changes can be found on #44
2012-12-08 19:17:13 -03:00
Agustin Carrasco 08b37dda42 Cleaned up the settings 2012-12-08 19:13:00 -03:00
Agustin Carrasco 1afccba41c Changed the 'cover-updated' model's signal for 'visual-updated' since it may be also the markup text. Fixed the text settings (ellipsizing, font, etc) #44 2012-12-08 13:19:13 -03:00
Agustin Carrasco 93a3e42747 Changed the way the filter text is checked when empty. There may be filters than don't use text, like the model filter, then it's easier to pass a None 2012-12-08 12:24:36 -03:00
Agustin Carrasco bebcd0e51a Lower the searchtext too to make the search case insensitive 2012-12-08 12:16:09 -03:00
Agustin Carrasco c4f51ed10e Use map to disconnect signals, is more concise 2012-12-08 12:13:21 -03:00
Agustin Carrasco 72120f010b Avoid signaling twice on track modification 2012-12-08 12:11:34 -03:00
Agustin Carrasco f30aafb4fe Modified rating calculation. There's no need to cast since it's already a float. All tracks should be taken into account when calculating the mean value, even those whit rating 0. 2012-12-08 12:08:13 -03:00
Agustin Carrasco d7b4b05c73 Fixed one last index on _iters, forgot to change it for it's name 2012-12-08 05:22:03 -03:00
Agustin Carrasco 067f5681a7 Separated the signal 'cover-updated' from the 'album-updated' on the AlbumsModel. The source doesn't need to get informed when the cover is updated, only the ShowingPolicy 2012-12-08 05:19:15 -03:00
Agustin Carrasco b695ca5dea Changed the way the _iters internal structure is used to work with a dict instead of a list, that way the code is more redeable e.g. you know what you are referencing using words instead of numbers 2012-12-08 05:12:48 -03:00
Agustin Carrasco 27b161d5f2 Fixed error when trying to show a source on the coverview when it hasn't been initialized yet 2012-12-08 05:04:55 -03:00
Agustin Carrasco 98739e44e0 Changed for loop to use map instead. Idk if it's faster, but at least is more pretty 2012-12-08 05:04:26 -03:00
Agustin Carrasco ee5af5cd3b Changed the loading procedure to use a python iterator instead of manually iterating with the model's iters 2012-12-08 00:57:06 -03:00
Agustin Carrasco 2c4d28f7ac Made the model filtering a little more safe and fast. Still think that the posible sources to filter by should be another filter-like list on the main coverview source 2012-12-08 00:50:36 -03:00
Agustin Carrasco 678eeee2f3 Transformed the playlist album limiting into a filter. It doesn't filter it's *tracks* and I don't think it should, since our plugin manages albums mostly. #44 2012-12-08 00:43:11 -03:00
fossfreedom c49c26feea fix coverart view from playlists - #44 2012-12-07 15:48:34 +00:00
fossfreedom 70d66121e2 remove the old prefs code from provider plugin 2012-12-07 10:10:23 +00:00
fossfreedom 3e7ecf70e8 add version info to plugins 2012-12-07 10:03:29 +00:00
fossfreedom b572aa64a1 re-add search providers key code stuff to main preferences 2012-12-07 09:52:56 +00:00
fossfreedom 00ec100037 remove separate prefs for providers plugin 2012-12-07 09:42:55 +00:00
Agustin Carrasco 6c7acdbcfc Fixed persistence of toolbar position. Don't know exactl why it works now #44 2012-12-07 02:06:14 -03:00
Agustin Carrasco 3673f80fd5 Fixed favourites. I think this was the problem. #44 2012-12-07 01:42:22 -03:00
Agustin Carrasco 1f94adc564 Fixed double-click play. My bad, though the query_model could be treated as a liststore. #44 2012-12-07 01:34:19 -03:00
Agustin Carrasco f053591127 Fixed track title filter #44 2012-12-06 22:41:18 -03:00
Agustin Carrasco dd03e229a8 Fixed album reordering when changed. Had to add a new signal to inform before the album is updated so the model can take care of reordering it. #44 2012-12-06 22:37:48 -03:00
Agustin Carrasco b617e86632 Fixed sorting issues making the sort_order changes to fail, together with some glitches in some types of sorting #44 2012-12-06 21:37:35 -03:00
Agustin Carrasco 1894e96d56 Fixed handler warning on startup 2012-12-06 20:52:14 -03:00
fossfreedom a830617f1b split to two plugins 2012-12-06 10:06:11 +00:00
Agustin Carrasco d27ed24a65 Changed the strategy to obtain the album_artist to a one more comprehensive 2012-12-06 04:03:01 -03:00
Agustin Carrasco 3f7a9e474e Fixed the genres combobox behavior 2012-12-06 03:14:42 -03:00
Agustin Carrasco 78396a5c41 Fixed some little issues on the Album class, fixed the path retrieval on the AblumsModel previous the throw of the album-update signal, and removed the genres manager since it's not needed. 2012-12-06 03:14:06 -03:00
Agustin Carrasco 1ab8bb5f6e Fixed behavior on album update 2012-12-06 02:09:23 -03:00
Agustin Carrasco 1167245871 Fixed album rating 2012-12-06 01:55:35 -03:00
Agustin Carrasco 16016a73b7 Fixed cover resize 2012-12-05 22:38:02 -03:00
Agustin Carrasco 00367c465b Fixed sort_order, now it does get saved on the settings 2012-12-05 22:37:37 -03:00
Agustin Carrasco 951332a3ac Changed the style of the idle_loads 2012-12-05 21:57:13 -03:00
Agustin Carrasco 1a9526108e Fixed sorting 2012-12-05 21:30:18 -03:00
Agustin Carrasco fd978fe8a6 Fixed some typos 2012-12-05 18:57:46 -03:00
Agustin Carrasco 343595b04d Fixed autoupdate of albums 2012-12-05 18:45:24 -03:00
Agustin Carrasco 2ea67bf72c Fixed some style and minor issues 2012-12-05 18:18:22 -03:00
Agustin Carrasco b0ebc7a67f Fixed all cover search aspects 2012-12-05 18:18:22 -03:00
Agustin Carrasco a5986e9998 Fixed entryview to use the new Album interface 2012-12-05 18:18:22 -03:00
Agustin Carrasco 61c6ffb112 Fixed play/queue album 2012-12-05 18:18:22 -03:00
Agustin Carrasco 48d798c838 Removed the covers_model from the source. It now should be accesed from the manager 2012-12-05 18:18:22 -03:00
Agustin Carrasco 11dc1edfe0 Fixed filters. It allows multiples filters e.g: genre + another filter 2012-12-05 18:18:22 -03:00
Agustin Carrasco c3134519dd Fixed some typos on Album's properties. Added a param to the remove_filter method of the AlbumsModel class to determine if this should fire a refilter or not; this is because in some cases, you want to remove a filter to add another one, which causes two refilters. 2012-12-05 18:18:22 -03:00
Agustin Carrasco c3010e4f84 Back to old default_load_chunk. Change the direction of the progress for the second bar to make it more pretty 2012-12-05 18:18:22 -03:00
Agustin Carrasco 3ba1e71461 Fixed issue of loading images when the model is filtered, now the images updated even in that case 2012-12-05 18:18:22 -03:00
Agustin Carrasco 8ac49fa006 Added check before changing visible paths. Changed the filtering procedure using signals now 2012-12-05 18:18:22 -03:00
Agustin Carrasco 299b4578be Some more modifications/refinements:
- Removed all the prop changed functions and just inform that the track is modified, so the album cleans itself and is readded to the model.
- Made the album_loading asynchronous and added progress information. In total there are three phases to the loading: album loading, model loading and cover loading.
- Made the duration property of the albums precalculated, to avoid recalculation each time it's selected. This implies that we should listen to changes on track duration too to update the album, but is not that hard with the new events model.
2012-12-05 18:18:22 -03:00
Agustin Carrasco d3a3a7b6a7 Refined the module:
- The Album listen to changes on it's Tracks and informs when gets modified. This way there's no need to follow each specific change; instead, we update the model when the album gets updated. Neverthless, the managers are responsible of emiting the tracks signals (given that is more cost effective to listen to db changes in a centralized way).
- Fixed some issues with the album filters.
- Refined the AlbumsModel. Now it takes care of a couple more things, principally, updating corresponding treestore row when an album or it's cover gets changed. Added the posibility to add filters and sorting (although not fully tested yet).
- Changed the purpouse of the ShowingPolicy. For now it just takes care of some workarounds concerning the cover_view: it takes care of updating it when necesary. After some changes, there seems that there's no need to use a progressive strategy since it's working faster now.
- The TextManager now takes care of prividing the tooltip and markups for the model.
- Made some changes on the CoverManager and AlbumLoader, but idk if they will be permanent yet, just testing stuff.
- There's still tons of stuff to test and fix, but so far it's working better than before and is waay more organized.
2012-12-05 18:18:22 -03:00
Agustin Carrasco 5299bda35b Added an utility module to put there whatever we could need that isn't related with the plugin perse, but that are aditions that we use on different parts of it 2012-12-05 18:18:22 -03:00
Agustin Carrasco c2519efdfc Removed model definition from ui file 2012-12-05 18:18:22 -03:00
Agustin Carrasco 783959f230 Rewrote the Album class to be more small and don't work with things that aren't related to it (for instance, working with the model). Added a Track class to wrap the rhythmbox entry and make it more accesible. Initial draft of the AlbumsCoversModel that will intend to abstract the tree store 2012-12-05 18:18:22 -03:00
Agustin Carrasco 8d4f639c64 Fixed filtering 2012-12-05 18:18:22 -03:00
Agustin Carrasco b33f2d8e34 Removed the sort_by parameter since it's not used anywhere. Gotta keep working on fixing all the other functionalitty with the new managers model. 2012-12-05 18:18:21 -03:00
Agustin Carrasco 12a790a7b0 Added some changes to allow the album to insert itself in a determined position 2012-12-05 18:18:21 -03:00
Agustin Carrasco fd3761b886 Initial behavior working now, it shows the albums on the screen. It takes a while to fully load the albums but it works 2012-12-05 18:18:21 -03:00
Agustin Carrasco 74f507677d Massive cleanup + reimplementing some stuff to get along with the new application model 2012-12-05 18:18:21 -03:00
Agustin Carrasco a0e7ca9746 Some fixes on the overall structure, almost ready to test the changes to watch for bugs and then implement the showing policies 2012-12-05 18:18:21 -03:00
Agustin Carrasco ca9219b76d Working on refactoring the album module 2012-12-05 18:18:21 -03:00
Agustin Carrasco d55b43e6c3 Style fixes 2012-12-05 18:18:21 -03:00
fossfreedom 6bb47bb05e remove thread causing hang - issue #94 2012-12-03 21:42:14 +00:00
fossfreedom 10f49f336b re-enable discogs 2012-12-03 19:46:21 +00:00
fossfreedom 16824baa95 wrap up discogs and embedded searching in main plugin 2012-12-03 16:31:24 +00:00
fossfreedom d61b612c4a Update coverart_album.py 2012-11-28 08:09:14 +00:00
fossfreedom 17d74b323a when adding to entry view - sort by track number, fix for issue #97 2012-11-27 23:48:01 +00:00
fossfreedom 7adcf7d21e translation stuff 2012-11-27 14:15:46 +00:00
fossfreedom 5ca9d70613 latest translations 2012-11-27 13:02:01 +00:00
fossfreedom 0afd8ee44c update for installation instructions and use - issue #94 2012-11-26 23:32:18 +00:00
fossfreedom 7bea7a8cea add locally embedded cover search - issue #94 2012-11-26 23:24:00 +00:00
fossfreedom 586b46ed24 Update README.md 2012-11-24 22:33:17 +00:00
fossfreedom e9d50a65a4 Merge pull request #95 from mateuswetah/patch-5
Update po/pt_BR.po
2012-11-24 04:35:42 -08:00
Mateus Machado Luna 9edacc98ae Update po/pt_BR.po
Updated with the latest translation for Brazilian Portuguese. Bring some features like displaying options for the toolbar icons.
2012-11-24 10:23:24 -02:00
fossfreedom a6b6f90673 Update README.md 2012-11-22 23:47:40 +00:00
fossfreedom a9d060a438 add timeout for when no coversearch providers issue #89 2012-11-21 21:05:51 +00:00
fossfreedom b4c1cb4d88 timer class 2012-11-21 16:48:07 +00:00
Agustin Carrasco 5ac822359c Updated spanish translation file 2012-11-20 18:25:25 -03:00
fossfreedom 24a48946b0 Merge pull request #91 from jrbastien/master
Updated French Canadian Translation for issue #87
2012-11-20 12:07:44 -08:00
fossfreedom 3e1971dc9b manual merge 2012-11-20 20:07:08 +00:00
fossfreedom e34a77d2be leave year as a date (day) value for sorting purposes - issue #86 2012-11-20 16:00:52 +00:00
Jean-Rene Bastien f5c09e091c Update po/fr_CA.po
Updated translations after fix done on issue #87
2012-11-19 20:25:24 -05:00
Agustin Carrasco cc85c4480a Added a condition to check if there's providers for a ExtDB request. It works the first time but it brokes the second. This was intended to fix issue #89 but doesn't do the trick just yet 2012-11-19 20:54:21 -03:00
fossfreedom 710c7ae836 en_US updates 2012-11-19 15:43:26 +00:00
fossfreedom 8fbdc46efc rename rating threshold to favourite threshold to be consistent with right click menu options 2012-11-19 15:33:34 +00:00
fossfreedom 2377943430 disable playlist menu option if no threshold is set 2012-11-19 15:28:36 +00:00
fossfreedom b1149d54fe Merge pull request #88 from jrbastien/patch-1
Update po/fr_CA.po
2012-11-18 14:08:06 -08:00
fossfreedom a6bac8a659 manual merge of jrbastien latest pull request 2012-11-18 22:06:04 +00:00
Jean-Rene Bastien 55523bfd8c Update po/fr_CA.po
Second try at updating the French Canadian language file.  These updates contain the strings for the new settings and the "add to Playlist" function.
2012-11-18 14:08:37 -05:00
fossfreedom 34333100c2 Update README.md 2012-11-13 11:21:43 +00:00
fossfreedom 7a5b9de454 Update README.md 2012-11-13 11:17:32 +00:00
fossfreedom 6aeff5a71f Update README.md 2012-11-13 11:15:19 +00:00
fossfreedom 810c7adb2f more translation updates from preferences changes 2012-11-12 21:24:15 +00:00
fossfreedom 84e24132ed add entry view rating selection and stars to preferences - issue #71 2012-11-12 21:17:17 +00:00
fossfreedom cbaee796c8 various translations issues 2012-11-11 22:36:09 +00:00
fossfreedom b3e1c5ec5e add album rating support and remove entry view menu rating stuff - issue #71 2012-11-11 00:23:31 +00:00
fossfreedom 4fc1ff34c7 add playlist support to entry view - issue #82 2012-11-08 20:33:00 +00:00
fossfreedom ab5b3f8c97 add playlist support to album right click menu 2012-11-08 16:44:16 +00:00
fossfreedom 6bfc4cdcee cleanup popup menus when plugin is deactivated 2012-11-03 23:30:59 +00:00
fossfreedom 02ff9862b9 playlist support - issue #82 2012-11-03 23:13:25 +00:00
fossfreedom 3b6b3553dc fixed configurable font size - issue #72 2012-10-30 22:16:56 +00:00
fossfreedom d96fbda1cd changed togglebutton to standard button - tooltips not working however 2012-10-30 20:50:52 +00:00
fossfreedom 87663e7fbf fix repositioning of album when year or rating has changed 2012-10-30 16:59:31 +00:00
fossfreedom 06d01d647f changed YEAR to db.DATE 2012-10-28 21:08:08 +00:00
fossfreedom b7f479bc47 tidy sidebar positioning 2012-10-27 20:01:13 +01:00
fossfreedom 58dfc339f2 link toolbar with gsettings to turn off-on optional components 2012-10-27 16:28:28 +01:00
fossfreedom 1c4455e712 connect toolbar options to gsettings 2012-10-27 13:35:51 +01:00
fossfreedom ac078d72ab rating and year sort options 2012-10-27 12:36:39 +01:00
fossfreedom 8dcbac22e3 various tidyups 2012-10-27 12:34:34 +01:00
Agustin Carrasco 3f47f3ed4e Bugfix: preferences' dialog not showing correctly because the referenced object doesn't existe on the ui file 2012-10-26 15:34:24 -03:00
fossfreedom 1f55bd7092 reworked preferences window 2012-10-26 19:15:19 +01:00
fossfreedom 80c2c1a9dd fix multiple signal callbacks on filling genres 2012-10-26 15:52:25 +01:00
fossfreedom 595e81fd82 tidy up function debugs 2012-10-26 15:07:54 +01:00
fossfreedom 4a4fba433c various cleanups 2012-10-25 20:57:42 +01:00
fossfreedom c2faea3586 fill genres on focus of combobox 2012-10-25 23:51:03 +01:00
fossfreedom e0fab258b8 merge sidebar branch 2012-10-25 20:33:11 +01:00
fossfreedom 95b2859067 fix toolbar placement on start 2012-10-25 18:54:55 +01:00
fossfreedom 007a01ce43 few tidy ups - still not working correctly though 2012-10-24 23:16:42 +01:00
fossfreedom 3c7f3e0ba8 sidebar stuff not working yet 2012-10-25 17:49:24 +01:00
fossfreedom dabedddfb4 add genre filter and made sort-order toggle - issue #77 2012-10-23 22:02:16 +01:00
fossfreedom 43907eaf33 Merge branch 'issue81' 2012-10-21 09:59:49 +01:00
fossfreedom 33d6e4a3fc fix with recommended style context call - issue #81 2012-10-21 09:53:00 +01:00
Agustin Carrasco 21eb8afe53 Bugfix: 'show more results' link on the cover search pane shouldn't appear if the searcher returns less than the max imageset (8 images) 2012-10-20 14:06:31 -03:00
fossfreedom 1c815c1a9d temporary fix from crash issue #81 2012-10-20 16:39:37 +01:00
fossfreedom 5ce2fd298f Update README.md 2012-10-20 15:48:21 +02:00
Agustin Carrasco 9e62dff957 Fixed a latent bug on the albums reload.
If a reload would be called to reload something that doesn't include the cover reloading, and after that another reload that DO include the cover reloading, the resizing wouldn't happen (since the reload_covers flag would be false).
2012-10-19 17:50:38 -03:00
fossfreedom 2b580d41dc backed out gc change 2012-10-19 19:15:55 +01:00
fossfreedom aa40e2d365 force garbage collection on pixbuf deletion - issue #28 2012-10-19 15:12:19 +01:00
fossfreedom 31be0e7610 Update README.md 2012-10-19 14:40:01 +01:00
fossfreedom 7134ca2b07 Update README.md 2012-10-19 15:36:48 +02:00
fossfreedom ee0573a265 tidied display space - issue #70 2012-10-17 21:11:23 +01:00
fossfreedom f705b76349 truncate album artist in a similar manner as album name - issue #72 2012-10-17 20:50:51 +01:00
fossfreedom 5ca2090a0f removed unneeded files 2012-10-17 15:20:54 +01:00
Agustín Carrasco eef2136ec7 Merge pull request #75 from jrbastien/master
Update to French Canadian Translation
2012-10-16 18:10:53 -07:00
Jean-Rene Bastien ecd16b9e17 Update po/fr_CA.po
Fine tuning made after reviewing French po (fr.po).  This is more in line with it except for the "jaquettes" being "pochettes" in Canada.
2012-10-16 20:10:45 -03:00
fossfreedom a638624894 Merge pull request #74 from lannic/patch-1
Update po/fr.po
2012-10-16 12:59:28 -07:00
lannic fb34421531 Update po/fr.po
Correction ligne 80 sélectionés -> sélectionnés

Correct line 80 sélectionés -> sélectionnés
2012-10-16 22:53:22 +03:00
fossfreedom a5d417bba1 prepare for dutch and portuguese translations 2012-10-16 12:43:47 +01:00
Agustin Carrasco 0cfdcd41e9 Fixed untranslated Covers string (issue #67) 2012-10-15 22:57:05 -03:00
fossfreedom 4cfa58c1de Update README.md 2012-10-16 00:44:04 +02:00
fossfreedom 06b5e66df6 Modification de jacquette en jaquette 2012-10-15 23:09:42 +01:00
lannic 318ab56067 Update po/fr.po
Traduction française
2012-10-15 14:09:45 -03:00
Agustín Carrasco 22414af3a2 Merge pull request #64 from jrbastien/master
Latest French Canadian translation for issue #62 and first French (France) po file.
2012-10-14 18:09:43 -07:00
Jean-Rene Bastien 9e5a5835f6 Update po/fr.po
First French file created from French Canadian version.  To French translators, if you prefer the word "jaquette" instead of "pochette" don't hesitate to change it.
2012-10-14 22:06:29 -03:00
Jean-Rene Bastien 365f5e85c8 Update po/fr_CA.po
Added string for issue #62
2012-10-14 22:03:15 -03:00
Agustin Carrasco 280df05a34 Added adaptative selection color to the cover search pane, acording to the current Gtk theme (issue #62) 2012-10-14 20:55:28 -03:00
Agustin Carrasco 1532dabce4 Updated spanish translation 2012-10-14 20:34:49 -03:00
fossfreedom 38db330870 added standard french po 2012-10-14 23:17:00 +01:00
fossfreedom 5c623b76ec translation for new cover tip - issue #62 2012-10-14 23:12:02 +01:00
fossfreedom 73cf1fe6a0 disable right click #62 2012-10-14 22:56:19 +01:00
Agustin Carrasco 4912f7d860 Added a line to explain how to use the cover search pane covers (issue #62) 2012-10-14 18:27:24 -03:00
Agustin Carrasco 340f5fe1fe Added border on clicked image to indicate it can be double clicked or drag it (issue #62) 2012-10-14 18:19:12 -03:00
fossfreedom 6d47f60f33 fixed entry translation - issue #54 2012-10-14 20:14:39 +01:00
fossfreedom 2b0488a27c Merge pull request #61 from jrbastien/master
Update French Canadian Translation
2012-10-14 11:23:42 -07:00
fossfreedom 5fd0cfb139 manually updated fr_CA from pull request 2012-10-14 19:20:31 +01:00
Jean-Rene Bastien 74f03fadc9 Update po/fr_CA.po
Updated to include strings for issue #54 item 6.
2012-10-14 12:35:40 -03:00
Agustin Carrasco fb8950b0be Updated spanish translations 2012-10-13 18:34:58 -03:00
fossfreedom b50af2bf73 fix for plugin name and description translations - issue #54 2012-10-13 21:29:06 +01:00
fossfreedom c873f6d880 fix translation on entry-view - issue #54 2012-10-13 20:56:03 +01:00
Agustin Carrasco b8f64bc16b Fixed bug introduced on 92ba955: albums with non-ascii names would cause a decoding error while loading 2012-10-13 01:57:58 -03:00
fossfreedom 83bcee3edf revert play crash fix RB2.8 - issue #57 2012-10-12 08:23:48 +01:00
fossfreedom 4506d284c7 fix play crash in RB2.8 - issue #57 2012-10-12 08:18:58 +01:00
Jean-Rene Bastien 1c94c56577 Applied fr_CA translation update (closes #60) 2012-10-11 22:58:04 -03:00
Jean-Rene Bastien d972dcdd88 Update po/fr_CA.po
New update with strings from issue #54.
2012-10-11 21:59:19 -03:00
fossfreedom 55ce5272a4 Merge pull request #59 from mateuswetah/patch-4
Update po/pt_BR.po
2012-10-11 14:38:52 -07:00
Agustin Carrasco 6154cb252b Updated spanish translation 2012-10-11 18:38:10 -03:00
Mateus Machado Luna a746d2dff0 Update po/pt_BR.po
Fixed latest translation with some details that I messed up. Sorry for that :P
2012-10-11 18:20:47 -03:00
fossfreedom e4c68e2138 regen po again - issue #54 2012-10-11 21:58:28 +01:00
Agustin Carrasco bc45892429 Changed str name to 'translated', since str overlaps with the built-in str class (not much of a problem right now, but just in case, since it could cause a bug if we modify the method without noticing the overlap) 2012-10-11 17:35:05 -03:00
Agustin Carrasco f75f3c68c8 Bugfix: initially, the coversearch pane should show the empty template 2012-10-11 17:23:57 -03:00
Agustin Carrasco 4c33d199e7 Moved Tracks & Covers tabs to the botton (issue #58) 2012-10-11 17:23:50 -03:00
fossfreedom 92ba9555cc fix cover markup translation string - issue #54 2012-10-11 21:08:07 +01:00
fossfreedom 05caff704d revised translation strings - issue #54 2012-10-11 21:07:16 +01:00
fossfreedom 5ec1b026c4 move translation setup to browser plugin - issue #54 2012-10-11 20:19:14 +01:00
fossfreedom b781c2c3f3 manually add fr_CA issue #55 2012-10-11 20:04:02 +01:00
fossfreedom b591d6c89d Merge pull request #56 from mateuswetah/patch-3
Update po/pt_BR.po
2012-10-11 11:58:59 -07:00
Mateus Machado Luna 1fa6802ae1 Update po/pt_BR.po
Updated po/pt_BR.po with the Brazilian Portuguese translation for a lot of new features, as sorting and cover resizing.
2012-10-11 10:39:21 -03:00
Jean-Rene Bastien 3da40740b5 Update po/fr_CA.po
Updated the translations as per FossFreedom master branch of 2012-10-10.
2012-10-11 08:19:43 -03:00
fossfreedom 80ac50041f Update README.md 2012-10-11 00:31:50 +02:00
fossfreedom 2ed0c97575 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-10-10 23:28:30 +01:00
fossfreedom 2e851565b5 add autostart preferences option - issue #48 2012-10-10 23:28:04 +01:00
fossfreedom 546522f0ce Update README.md 2012-10-10 21:23:39 +02:00
fossfreedom bf015f9bfb pending italian translation 2012-10-10 19:48:19 +01:00
fossfreedom 46c2489452 en_US translation 2012-10-10 19:17:12 +01:00
fossfreedom 0f1f9f61de pending hindi translation 2012-10-10 16:51:51 +01:00
fossfreedom 4313ee42e3 pending tamil translation 2012-10-10 16:41:53 +01:00
fossfreedom cd486f1797 pending bengali translation 2012-10-10 16:36:48 +01:00
fossfreedom 20f73999ad Update README.md 2012-10-10 15:54:17 +02:00
fossfreedom 940da38569 Update README.md 2012-10-10 15:47:20 +02:00
fossfreedom 0c80cc6457 Update README.md 2012-10-10 15:44:52 +02:00
fossfreedom 66bb816043 tracks and covers 2012-10-09 23:49:35 +01:00
Agustin Carrasco 8f238ff815 Updated spanish translations for mako templates 2012-10-09 19:28:10 -03:00
fossfreedom 9a86691f81 latest translations 2012-10-09 23:16:34 +01:00
fossfreedom b0cab87e05 fixed more unicode issues 2012-10-09 23:13:53 +01:00
fossfreedom a1cfff6e78 fix concat error 2012-10-09 21:51:44 +01:00
fossfreedom fdac389a05 fix unicode errors 2012-10-09 21:20:49 +01:00
fossfreedom 0f6929a397 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser into mako 2012-10-09 20:47:25 +01:00
fossfreedom 63672aea9e initial translation conversion 2012-10-09 20:40:54 +01:00
Agustin Carrasco b55f847b3f Updated spanish translation 2012-10-08 21:59:44 -03:00
fossfreedom 1cbcf53368 updated instructions to how to deal with Fuzzy translations 2012-10-08 21:23:57 +01:00
fossfreedom 7f5bf9d795 notebook titles needed translation strings 2012-10-08 21:19:58 +01:00
fossfreedom 54d86c0025 notebook translation strings 2012-10-08 20:19:17 +01:00
Agustin Carrasco 70b18e3857 Updated spanish translations 2012-10-08 15:52:57 -03:00
Agustin Carrasco 3ab6f8e4dc Moved the visible-columns' changes listening to the entry view, to avoid delegating through the source 2012-10-08 15:40:19 -03:00
Agustin Carrasco 63cc32ab59 Rearranged the do_impl_activate method and distributed it's code into different methods, where each ones tackles one particular part of the source activation 2012-10-08 15:40:04 -03:00
fossfreedom fbfc063884 translation updates 2012-10-08 18:38:51 +01:00
fossfreedom 4d53921e96 slight textual changes 2012-10-08 18:37:18 +01:00
fossfreedom 9910f1dbfb removed unneeded translation 2012-10-08 18:29:45 +01:00
Agustin Carrasco 7324d4a60b Minor controls rearragment on the prefs dialog 2012-10-08 13:10:50 -03:00
fossfreedom 67270611b7 Update README.md 2012-10-08 09:28:45 +02:00
Agustin Carrasco 039419e2fb Added support for URI drag and dropping, which allows the cover view to accept images dropped from nautilus (for example) or URLs from the web. 2012-10-07 21:20:17 -03:00
Agustin Carrasco f40b9dca60 Moved the image-from-uri loading logic to the AlbumLoader class 2012-10-07 20:19:05 -03:00
fossfreedom 351913a337 Update README.md 2012-10-07 21:56:49 +02:00
Agustin Carrasco 3804c70463 Fixed bug on AlbumLoader's _allocate_entry method that wasn't updated to use the updated Album's load_cover method's signature. Also separated the method to retrieve album name and artist into two differente methods. 2012-10-07 14:43:41 -03:00
Agustin Carrasco eca33905e1 Removed title from empty template to avoid unneeded title-changed signal 2012-10-07 14:43:29 -03:00
Agustin Carrasco a9729f3120 Updated the album modified callback on source to respond to new features: Multiselect wasn't taken into account when first implemented; The cover search pane should be updated if the album is updated 2012-10-07 14:43:06 -03:00
fossfreedom d12ae54c8b Update README.md 2012-10-07 18:46:17 +02:00
fossfreedom 30aeae1fc2 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-10-07 13:41:22 +01:00
fossfreedom 35fee3a030 fix for issue #52 2012-10-07 13:41:00 +01:00
fossfreedom 14d41178f5 whats new section 2012-10-07 14:35:08 +02:00
fossfreedom 7527ebdbc6 minor text changes 2012-10-07 13:19:02 +01:00
fossfreedom 89cba0e852 updates for latest folder changes 2012-10-07 13:07:04 +01:00
Agustin Carrasco 2df8c0fede Merged master branch on favourites 2012-10-06 20:29:04 -03:00
Agustin Carrasco b10d2c9e24 Fixed error on startup on the notebook_switch_page callback 2012-10-06 20:22:52 -03:00
Agustin Carrasco fac3213957 Some cleanup, moving a signal to the ui file and changing some widgets id's to match the new disposition 2012-10-06 20:20:05 -03:00
Agustin Carrasco 4ce111c673 Added a notebook on the bottom pane where the entry_view and a new cover search pane ar allocated. Fully implemented cover search pane (closes #49) 2012-10-06 19:34:09 -03:00
Agustin Carrasco a3519269a8 Removed title to avoid and initial, meaningless title-changed signal thrown 2012-10-06 19:32:15 -03:00
Agustin Carrasco ac02a30966 Rewrote the set_cover routine to use a workaround to load the pixbuf, since setting the uri did NOT work if the album already had an album 2012-10-06 19:31:49 -03:00
fossfreedom 5fa9216913 compromise for love/ban menus issue #47 2012-10-06 23:24:33 +01:00
Agustin Carrasco a3c2d6ece7 Modified the display-tracks settings to be display-bottom, since now it haves the tracks and covers 2012-10-06 19:04:37 -03:00
Agustin Carrasco 6ea08f1bc2 Changed the dnd behavior to NOT select the album where the image was droppend (no need for that really) 2012-10-06 18:47:24 -03:00
Agustin Carrasco cf5e9865a8 Added come comments and cleaned up style 2012-10-06 18:47:02 -03:00
Agustin Carrasco 80cb2acadb Removed unused import and code 2012-10-06 18:33:22 -03:00
Agustin Carrasco 4b24fa3f42 Added support to double click to set cover on selected album 2012-10-06 18:17:38 -03:00
Agustin Carrasco 420944fdc7 Show more albums links initially hiden 2012-10-06 17:54:58 -03:00
Agustin Carrasco 574f7660c5 Update the cover tab on album selection change (when it's visible) 2012-10-06 17:54:39 -03:00
Agustin Carrasco 8ce96db3a6 Merged to apply some changes that would conflict otherwise 2012-10-06 17:48:58 -03:00
fossfreedom ff0eaf2ca0 minor fixes 2012-10-06 21:13:47 +01:00
Agustin Carrasco bc054189cf Show the results under the old results, instead of replacing them 2012-10-06 17:01:00 -03:00
Agustin Carrasco 435e362d7c woops, forgot a div 2012-10-06 16:21:57 -03:00
Agustin Carrasco 96168c66c0 Added support to get more results on the cover search 2012-10-06 16:19:04 -03:00
Agustin Carrasco 3d6716a974 Cleaned up the cover search template 2012-10-06 15:58:27 -03:00
fossfreedom d47081e164 refactor code and enable menus depending upon threshold - issue #47 2012-10-06 18:47:52 +01:00
fossfreedom 4d009ea91e prelim support - issue #47 2012-10-06 13:55:27 +01:00
Agustin Carrasco d9c8ff40ce Revert "Added some sort of exception managment for albums that given it's nature, even if two tracks have the same album, shouldn't be grouped together (e.g Singles and Unknown albums)"
This reverts commit e4c078761b.

Reverting the exceptions managment since it brings a lot of problems.
2012-10-06 02:01:26 -03:00
Agustin Carrasco fea0f31aed Revert "Added '[non-album trakcs]' to the exceptions list"
This reverts commit 36d20df06d.

Reverting the changes made to add exceptions since it brings a lot of problems.
2012-10-06 02:00:43 -03:00
Agustin Carrasco 36d20df06d Added '[non-album trakcs]' to the exceptions list 2012-10-06 01:06:17 -03:00
Agustin Carrasco 8edf853bdc Modified the global filter to have a similar behavior to the library source filter. 2012-10-06 01:03:48 -03:00
Agustin Carrasco e4c078761b Added some sort of exception managment for albums that given it's nature, even if two tracks have the same album, shouldn't be grouped together (e.g Singles and Unknown albums) 2012-10-06 00:54:19 -03:00
Agustin Carrasco 9f17b78bec Fixed bug on AlbumLoader progress property not correctly being set at 1 on load finish, making the activate_markup method on the source misbehave. 2012-10-06 00:48:50 -03:00
Agustin Carrasco f7c3723ee5 Moved ellipsizes and cover-size properties to the AlbumLoader for easier managment. Fixed the behavior of the ellipsize enable/disable 2012-10-05 21:42:50 -03:00
Agustin Carrasco 53a1bb285c Changed source creation mechanism from GObject.new to python constructor 2012-10-05 20:17:36 -03:00
Agustin Carrasco 3dff345235 A little more cleanup and a minor fix of a problem introduced on the last cleanup commit (added a none radio button on the sort direction group to force the initial ordering) 2012-10-05 18:02:08 -03:00
Agustin Carrasco 096c52c339 Cleaned up the prefs module 2012-10-05 17:40:42 -03:00
Agustin Carrasco 1f349b1ef9 Removed unused imports 2012-10-05 17:27:43 -03:00
Agustin Carrasco 2ca4f03323 Cleanup + moved source's properies connection to a method inside the source class 2012-10-05 17:20:28 -03:00
fossfreedom 6c38284f43 merge gsettings 2012-10-05 20:19:15 +01:00
fossfreedom fcb30e3bbb remove files that have been moved to subfolders 2012-10-05 19:22:08 +01:00
fossfreedom 48ffe08f7f move ui and schema to sub-folders 2012-10-05 19:21:23 +01:00
fossfreedom 78a8ab5129 Merge branch 'master' of http://github.com/fossfreedom/coverart-browser into gsettings 2012-10-05 19:12:39 +01:00
fossfreedom bf5e5d10b3 fix saving of sort and direction - issue #43 2012-10-05 19:09:57 +01:00
Agustin Carrasco 31d4286f25 Fixed aspersand on ui file 2012-10-05 01:17:50 -03:00
Agustin Carrasco 8cee4c1dcf Initial implementation of cover search on bottom notebook. It's still incomplete but usable (issue #49). 2012-10-05 01:11:10 -03:00
Agustin Carrasco c1984ef8a2 Moved images to a separated folder. Deleted unused files 2012-10-04 23:05:49 -03:00
fossfreedom b97a42ef78 fixed saving paned-position - issue #43 2012-10-04 23:37:36 +01:00
fossfreedom 51029d105d merge 2012-10-04 20:31:42 +01:00
fossfreedom c90f40192b Merge branch 'master' of http://github.com/fossfreedom/coverart-browser into gsettings 2012-10-04 20:11:58 +01:00
fossfreedom eea94a7efc minor mods 2012-10-04 20:11:52 +01:00
Agustin Carrasco 2873686e37 Merge branch 'dnd'
Added support for drag 'n drop on the cover view, allowing the user to update the cover from the AlbumArtSearch plugin (closes #42)
2012-10-04 00:38:31 -03:00
Agustin Carrasco d16f65d2bc Added call to context.finish to inform the source the drag was succesfull 2012-10-04 00:38:12 -03:00
Agustin Carrasco b2542c1a37 Added comments 2012-10-04 00:14:11 -03:00
Agustin Carrasco ee2e004935 Modified the update cover method to add the cover to all the artists on the album (since an album could have more than one artist) 2012-10-04 00:13:10 -03:00
Agustin Carrasco a9747a3a15 Added support to save the cover into the cover db 2012-10-03 23:41:32 -03:00
Agustin Carrasco a649de2427 Fixed the dnd mecanism, now it works alright. Just one little problem tho, for some reason if you dnd the same image multiple times, it starts loosing color... 2012-10-03 23:28:59 -03:00
fossfreedom ee45ce9837 attempt to add paned-position into gsettings - doesnt work as yet 2012-10-03 22:59:29 +01:00
Agustin Carrasco d034cb3a14 Initial implementation of drag and drop. It doesn't save the droped cover yet (issue #42) 2012-10-03 18:37:25 -03:00
Agustin Carrasco bc28959f27 Fixed bug related to the last change on the reloading strategy that wouldn't work as expected since the reloading list wasn't correctly updated 2012-10-03 18:36:41 -03:00
fossfreedom 65bf291a6f merge with master 2012-10-02 23:16:32 +01:00
fossfreedom c4af2933ca Merge branch 'master' of http://github.com/fossfreedom/coverart-browser into gsettings
Conflicts:
	coverart_browser_prefs.py
	coverart_entryview.py
2012-10-02 23:16:05 +01:00
fossfreedom f579c4f518 tidying singleton implementation 2012-10-02 22:33:48 +01:00
Agustin Carrasco a33c8c3b2b Modified reloading strategy to only spawn one idle call at a time (instead of spawning a new one each time the reload_model method is called) 2012-10-02 13:09:48 -03:00
Agustin Carrasco 272cf52683 Added support for custom cover size (closes #13) 2012-10-02 12:56:42 -03:00
Agustin Carrasco 6311b9c8fb Bugfix: update iconview after initiating the cover reload after a cover size change, since the new size may left some free space, or use more space than the available 2012-10-01 22:01:43 -03:00
fossfreedom 12f21daee5 initial - singleton stuff needs to be defined 2012-10-02 00:00:22 +01:00
fossfreedom 75c6c00261 add rework of columns 2012-10-01 22:35:28 +01:00
Agustin Carrasco 55a656ff31 Changed the entryview initialization to be able to hide it's columns (issue #45) 2012-10-01 18:23:14 -03:00
Agustin Carrasco 1720976565 Bugfix: the text shouldn't be enabled after finishing loading the albums if the model is being reloaded 2012-10-01 17:19:43 -03:00
Agustin Carrasco a408dbb264 Minor change: if the reloading includes cover reloading, it should use smaller chunks 2012-10-01 17:17:50 -03:00
Agustin Carrasco 13954fd276 Finished adding support for coverart adjustable size (issue #13) 2012-10-01 17:06:19 -03:00
Agustin Carrasco 316cd68024 Initial structure modification to allow cover resizing 2012-10-01 16:07:16 -03:00
Agustin Carrasco aea1b482cd Removed unused separator 2012-09-30 21:10:07 -03:00
Agustin Carrasco 1291c15a71 Removed unused code on selectionchanged callback 2012-09-30 21:03:46 -03:00
Agustin Carrasco f511f868e4 Bugfix: if no album is selected, the statusbar should be cleared 2012-09-30 20:58:24 -03:00
Agustin Carrasco e30e117979 Merge branch 'markup'
Added support for showing album name and artist under the album's cover (closes #15)
2012-09-30 20:48:47 -03:00
Agustin Carrasco 2128ce1649 Added some lifeguards on Album methods that use it's model, since it might not be asigned. Also, update the model when an entry is added or removed\! 2012-09-30 20:48:15 -03:00
Agustin Carrasco 9c6c7f0248 Bugfix: updating an album's entry's artist wouldn't update the markup 2012-09-30 20:36:37 -03:00
Agustin Carrasco 82698da17f Normalized the iconview mouseclick callback to use Gdk definition of which action should popup a menu 2012-09-30 19:46:04 -03:00
Agustin Carrasco c560b0edd0 Changed behavior of right-click over iconview: if there's currently a selection and the clicked album is NOT in the selection, the old selection should be cleared. Note: I consider this the correct behavior, it might not be it tho d: 2012-09-30 18:01:58 -03:00
Agustin Carrasco 0a5b1808e8 Minor fixes 2012-09-30 17:41:13 -03:00
Agustin Carrasco 18514d42b8 Added support for ellipsizing albums' names 2012-09-30 16:54:50 -03:00
fossfreedom 29a0b09035 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-09-30 15:16:10 +01:00
fossfreedom 94afcb9857 add depends=rb - issue #46 2012-09-30 15:15:50 +01:00
Agustin Carrasco ebeb865b24 Changed the tooltip and status formats to be be consistent 2012-09-30 05:36:48 -03:00
Agustin Carrasco 7800f0f708 Little modification on the markup text format 2012-09-30 05:26:47 -03:00
Agustin Carrasco 895cc7cade Bugfix: if the view is reloading and the option to show the text while loading is activated/deavtivated, it should affect the view too 2012-09-30 04:35:26 -03:00
Agustin Carrasco ad4ca181e7 Changed the chunks to test for better performance 2012-09-30 04:34:20 -03:00
Agustin Carrasco 28e279d733 Respect the 'show text during loading' option when reordering too, since it boost performance on that situation also 2012-09-30 04:02:25 -03:00
Agustin Carrasco 3b154138d3 Added preference to indicate if the text should be shown during load or not, since in some cases it can help to performance 2012-09-30 03:41:45 -03:00
Agustin Carrasco f77ea8bff0 Set the font size on the markup given the size of the Cover 2012-09-30 02:49:14 -03:00
Agustin Carrasco f421dd4697 Added some style to the markup text 2012-09-30 02:49:14 -03:00
Agustin Carrasco 17de8979d0 Enable markup text after loading to avoid the performance hit 2012-09-30 02:49:14 -03:00
Agustin Carrasco c4e5dd780e Initial implementation for an option to show album's basic info as text under it's cover (issue #15) 2012-09-30 02:49:07 -03:00
Agustin Carrasco 0fcd45f255 Bugfix: get_selected_albums would misbehave when the model got filtered by the search entry. 2012-09-29 23:16:52 -03:00
Agustin Carrasco 6cd83ac4fd Updated spanish translations 2012-09-29 18:38:16 -03:00
fossfreedom 5ffae4fafa latest translations 2012-09-29 21:49:18 +01:00
fossfreedom 888333b4f9 add track properties - issue #40 2012-09-29 21:28:20 +01:00
fossfreedom 00e65e8a6f Merge branch 'songinfo' of https://github.com/fossfreedom/coverart-browser into songinfo 2012-09-29 20:29:41 +01:00
Agustin Carrasco 667d67ccaf Cleaned up the entryview module a little bit 2012-09-29 14:53:23 -03:00
Agustin Carrasco 4494178032 Added support for albums properties (issue #40) 2012-09-29 13:13:23 -03:00
Agustin Carrasco 187ea052e6 Created a general get_selected_entries method to reuse it in multiple places 2012-09-29 11:48:17 -03:00
Agustin Carrasco ff165cb1c1 Cleanup some uneeded stuff after the latest changes 2012-09-29 11:42:12 -03:00
Agustin Carrasco 1b960b2ebe Merge branch 'sorting'
Added sorting support to master branch (closes #23)
2012-09-29 11:13:44 -03:00
Agustin Carrasco 09f5c63685 Changed the behavior of the resorting to 'reload' the model when the sorting field/direction is changed. This way, the ui responds a lot better, althought the 'moving' produced by the reloading, may be a problem (issue #23) 2012-09-29 00:59:42 -03:00
Agustin Carrasco 321c4a5220 Readd album to the model on album_artist change to force a reordering if necesary 2012-09-28 23:32:00 -03:00
Agustin Carrasco a3d8fd15df Added sorting direction to the equation (issue #23) 2012-09-28 22:57:54 -03:00
Agustin Carrasco 028865e5c0 Bugfix: model wouldn't sort. NOTE: the current sorting metodology is REALLY SLOW for big libraries (issue #23) 2012-09-28 22:23:42 -03:00
Agustin Carrasco abfcf9f222 Modified the search_all_covers method to make it more generic (to use it either from the full search or individual/multiselect search) and avoid code duplication (issue #33) + Some minor changes 2012-09-28 21:57:00 -03:00
fossfreedom 6eead0baca async call for selected albums - issue #33 2012-09-28 21:32:18 +01:00
fossfreedom 91d5635356 Merge branch 'master' into multiselect
Conflicts:
	coverart_browser_source.py
2012-09-28 19:45:14 +01:00
fossfreedom 85d665621f multiselect play,queue and search 2012-09-28 12:34:51 +01:00
fossfreedom 250dea94ea multi selection support issue #33 2012-09-28 09:37:59 +01:00
Agustin Carrasco 63ae0d0fd5 Implemented sorting functionality (issue #23). Some minor changes too. 2012-09-28 01:17:04 -03:00
Agustin Carrasco efe8ae24a1 Created ui and enhanced previous ui. Initial coding to implement sorting(issue #23) 2012-09-28 00:20:40 -03:00
Agustin Carrasco d6624d31d9 Reimplemented the unique loader as singleton + minor fixes 2012-09-27 21:00:04 -03:00
Agustin Carrasco dc8d623191 Initial workaround for the memory leaking when reactivating the plugin: the album loader is saved and reused when the plugin is reactivated
Implemented delete_thyself to clean the source (issue #28).
2012-09-27 20:15:56 -03:00
Agustin Carrasco 68431affb4 Changed implementation of paned handle's blocking when the entry view expander is collapsed (issue #35). 2012-09-27 19:14:19 -03:00
fossfreedom b6ea815b42 add double click support for iconview and entryview 2012-09-27 21:41:24 +01:00
fossfreedom 6ebb4547b5 Merge branch 'entryview' 2012-09-27 19:45:11 +01:00
fossfreedom 9a28525678 disable movable pane when not expanded 2012-09-27 19:42:11 +01:00
Agustin Carrasco 2a4077d75d Moved the liststore creation to the ui file 2012-09-26 23:18:06 -03:00
fossfreedom 80a12fcc7a add playing state 2012-09-26 21:38:15 +01:00
fossfreedom 90312e2518 disable pane position bar if display tracks is not enabled 2012-09-26 20:00:50 +01:00
fossfreedom db874e21d0 remember paned position 2012-09-26 19:35:13 +01:00
Agustin Carrasco 92fb7053bd Little modification to reallocate the showing/hiding of the entryview and it's expander 2012-09-26 13:22:13 -03:00
Agustin Carrasco 0b1236b636 Added a clear method and trimed blank spaces (lol, my python ide does that automatically) 2012-09-26 13:21:23 -03:00
Agustin Carrasco 5337869156 Removed duplicated calls 2012-09-26 13:06:28 -03:00
Agustin Carrasco f6a248803c No need to update the entry if the option is disabled 2012-09-26 13:04:21 -03:00
fossfreedom 41ccb60a87 ensure expander stays on bottom of screen 2012-09-26 16:24:43 +01:00
fossfreedom e0d9c2a318 refactor code 2012-09-26 14:56:18 +01:00
fossfreedom aeebf36052 merge upstream 2012-09-26 11:50:53 +01:00
fossfreedom 9692dc99d7 fixed terminal signal issues 2012-09-26 11:41:31 +01:00
Agustin Carrasco 608a980387 Removed the frame around the ScrolledWindow (not needed) and changed the frame arround the entryview for a GtkBox, this makes lower pane to shrink to it's minimum size when the expander and entryview are hidden (issue #35) 2012-09-25 18:40:26 -03:00
fossfreedom 94e81a7d56 corrected debian makefile install 2012-09-25 19:21:39 +01:00
Agustin Carrasco 472024e4ed Merge branch 'master' into entryview
Conflicts:
	coverart_browser.py
	coverart_browser_source.py

Merged refactoring changes into entryview to avoid problems in the future.
2012-09-25 13:41:55 -03:00
Agustin Carrasco 3052ec54b2 Refactor style and added comments on coverart_browse module 2012-09-25 13:29:40 -03:00
Agustin Carrasco dc389bcf6a Merge branch 'master' into entryview 2012-09-25 13:10:24 -03:00
fossfreedom ad197ed40a add shadow-in frames 2012-09-25 15:15:12 +01:00
fossfreedom febe41a42c add gtkpane 2012-09-25 13:10:59 +01:00
Agustin Carrasco 7b5e0acfdd More cleaning. Added docstrings to all methods on the Source 2012-09-24 21:46:02 -03:00
Agustin Carrasco 42fcadfd09 Code cleaning, making the style more homogenous and removing useless stuff 2012-09-24 21:27:04 -03:00
Agustin Carrasco aadb8e8c3a Another typo, what's wrong with me? 2012-09-24 21:26:08 -03:00
Agustin Carrasco bdec4be821 Bugfix: request bar would show all artist instead of album artist. When did this one come back around?? 2012-09-24 20:59:16 -03:00
Agustin Carrasco 4579972c00 Fixed typo 2012-09-24 19:55:38 -03:00
Agustin Carrasco 9d73532c2f Added a listener on the AlbumLoader progress property to show the progress of the loading on the statusbar. 2012-09-24 19:46:28 -03:00
fossfreedom b0c7998f71 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser into entryview 2012-09-24 23:38:43 +01:00
fossfreedom ab09499d12 link to preferences dialog 2012-09-24 23:36:28 +01:00
fossfreedom 266baa3bc2 initial prototype of entry-view 2012-09-24 22:09:35 +01:00
fossfreedom 29bf9adc93 Merge pull request #36 from mateuswetah/patch-2
Update po/pt_BR.po
2012-09-24 08:53:36 -07:00
Mateus Machado Luna f8ac8c9dfe Update po/pt_BR.po
Added a lot of strings for the Brazilian Portuguese translation, related to search and the statusbar.
2012-09-24 12:37:13 -03:00
Agustín Carrasco 664ffc2e75 Merge pull request #34 from jrbastien/master
Update French Canadian Translation
2012-09-23 19:56:39 -07:00
Jean-Rene Bastien 042f591cad Update po/fr_CA.po
Added missing translation for code made after release 0.3
2012-09-23 23:50:51 -03:00
fossfreedom 61e94c7324 update release note for v0.4 changes 2012-09-24 00:49:25 +02:00
Agustin Carrasco 77fbe2770b Added support for 32-bit user by using the base_query_model of the LibrarySource instead of querying the database directly (issue #22) 2012-09-23 19:09:43 -03:00
Agustin Carrasco 69dd9f077d Bugfix: check for duration different than 0 on an added entry before adding it to an album or creating a new one (fixes #31) 2012-09-23 18:34:25 -03:00
Agustin Carrasco af0be74f2a Bugfix: the argument on cover_search_menu_item_callback would conflict with gettext module 2012-09-23 18:34:25 -03:00
Agustin Carrasco af2b3c1116 Updated docstring on album.contains method 2012-09-23 18:34:25 -03:00
fossfreedom ee560830d3 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-09-23 21:09:59 +01:00
fossfreedom 136a35fd40 remove unwanted files 2012-09-23 21:09:10 +01:00
fossfreedom cff7844da4 tidy up installation 2012-09-23 21:07:25 +01:00
Agustin Carrasco 14aecce1f7 Updated spanish translation 2012-09-23 16:54:44 -03:00
fossfreedom e7cdabc8a4 updates for .plugin 2012-09-23 20:35:46 +01:00
fossfreedom 8d3b58e8e0 files requiring translation 2012-09-23 20:11:29 +01:00
Agustin Carrasco 4fe5e33ca2 Fixed bugs introduced by the merge with filter branch. (issue #12) 2012-09-23 15:47:03 -03:00
fossfreedom d341e1097e Merge branch 'filter'
Conflicts:
	coverart_browser_source.py
2012-09-23 19:17:53 +01:00
Agustin Carrasco 0b257bf8a2 Merged global_statusbar on master. Finished implementation of global statusbar (closes #19) 2012-09-23 13:34:11 -03:00
fossfreedom 849c7d2397 right click focus issue #29 2012-09-23 12:59:47 +01:00
fossfreedom 7cb38aaaa0 add track search - issue #12 2012-09-23 11:48:24 +01:00
fossfreedom a191f8744d add track artist search - issue #12 2012-09-23 11:24:07 +01:00
fossfreedom 27e66d0d0a tidy when changing filters 2012-09-23 10:50:49 +01:00
fossfreedom d18065ddff Merge branch 'filter' of https://github.com/fossfreedom/coverart-browser into filter 2012-09-23 10:44:28 +01:00
fossfreedom 7e5df0524a incorporate RBSearchEntry issue #30 2012-09-23 10:44:04 +01:00
Agustin Carrasco d2a4b6bac6 Minor changes, nothing important 2012-09-23 01:57:40 -03:00
Agustin Carrasco dd82552047 Moved signal connection for the source search menu item to the ui file 2012-09-22 23:31:49 -03:00
Agustin Carrasco fa58db6751 Bugfix: the full cover search item shouldn't get enabled after the model loading has finished if there's a cover request ongoing 2012-09-22 23:29:13 -03:00
Agustin Carrasco 50d26301e2 Finished implementation of optional source's custom statusbar (issue #19) 2012-09-22 23:24:17 -03:00
Agustin Carrasco 9128d74207 Bugfix: critical bug on coverart_album's allocate_entry wouldn't add new albums 2012-09-22 23:00:55 -03:00
Agustin Carrasco 6d9d54547f Binded the custom statusbar setting to the source new property 'custom_statusbar_enabled'. Next step is to implement the functionality given this setting 2012-09-22 22:17:08 -03:00
Agustin Carrasco e2405a08d9 Bugfix: the cover's request feedback statusbar should show album artist instead of list of artist (issue #26) 2012-09-22 20:38:32 -03:00
Agustin Carrasco fe15cae923 Bugfix: bug introduced on 4ac690f4 would break individual cover search feature 2012-09-22 20:30:23 -03:00
Agustin Carrasco a37856c2b3 Bugfix: when the filter is changed, the model should be refiltered (issue #26) 2012-09-22 19:39:58 -03:00
Agustin Carrasco 493c74ba7f Bugfix: ALBUM and ARTIST filters inverted (issue #26) 2012-09-22 19:36:44 -03:00
fossfreedom 2f86af0b57 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-09-22 23:27:46 +01:00
fossfreedom 12dc96def8 fix issue #27 2012-09-22 23:26:26 +01:00
Agustin Carrasco f222727793 The full cover search shouldn't be enabled until the source is fully loaded. 2012-09-22 19:17:36 -03:00
fossfreedom 3e78abd0cf add preliminary filter functionality issue #12 2012-09-22 22:59:00 +01:00
fossfreedom 7a14dec99d rework to allow translation of source popup - issue #25 2012-09-22 19:37:25 +01:00
fossfreedom b76d0b0be5 remove old xml file 2012-09-22 12:43:05 +01:00
fossfreedom 089984e37a corrected xml plugin path and installation 2012-09-22 12:42:32 +01:00
Agustin Carrasco 9e8139fc5b Updated spanish translation 2012-09-22 01:39:57 -03:00
Agustin Carrasco 97a33d8d1d Added the module and ui necesaries for the implementation of the plugin's preferences. It includes the option to enable the custom statusbar, althought the plugin doesn't use it yet 2012-09-22 01:12:27 -03:00
Agustin Carrasco d8b310bf52 Little modifications on the ui; readded the source statusbar 2012-09-21 23:55:49 -03:00
fossfreedom f8c73bd657 Merge branch 'master' of https://github.com/fossfreedom/coverart-browser 2012-09-21 23:54:36 +01:00
fossfreedom 4ac690f42d add missing translatable strings 2012-09-21 23:54:01 +01:00
Agustin Carrasco 6ef6e2bf22 Fixed typo 2012-09-21 19:00:52 -03:00
Agustin Carrasco 0b3d6b5290 Merge branch 'master' into global_statusbar
Updating global_statusbar with latest changes

Conflicts:
	coverart_browser_source.py
2012-09-21 18:57:07 -03:00
Agustin Carrasco 71d3e3bf44 Some fixes for bugs introduced in the last commit + update tooltip when an entry artist gets modified 2012-09-21 17:28:37 -03:00
Agustin Carrasco 5668823115 Added triggers to update album_artist 2012-09-21 17:18:46 -03:00
Agustin Carrasco 7e8071eb80 Added support to 'album artist' to the albums + some random style fixes 2012-09-21 17:00:26 -03:00
Agustin Carrasco f1fdd0b8db Emit album-modified signal when an album entry's artist got modified 2012-09-21 14:17:53 -03:00
Agustin Carrasco 8291f7ca32 Fixed incorrect album creation on _allocate_entry 2012-09-21 13:52:57 -03:00
Agustin Carrasco e6c532e58b Merge branch 'master' into multi_artist
Conflicts:
	coverart_album.py
2012-09-21 13:50:45 -03:00
Agustin Carrasco d8bec359d9 Bugfix: selected album doesn't get updated when it's albums get modified 2012-09-21 13:48:43 -03:00
Agustin Carrasco 9983e10eb6 Added callbacks to update the albums artists (issue #6) 2012-09-21 13:14:01 -03:00
Agustin Carrasco 7641da3ab5 Initial support for multi-artist support 2012-09-21 12:46:17 -03:00
Mateus Machado Luna 1a9324257a Update po/pt_BR.po
Updates with two new strings.
2012-09-20 23:09:00 -03:00
Agustin Carrasco 3479f109d2 Updated spanish translation (issue #14) 2012-09-20 22:01:07 -03:00
fossfreedom b857933eb2 latest translation strings added to po's 2012-09-20 21:24:48 +01:00
Agustin Carrasco 6e96d4e2ab Merge remote-tracking branch 'refs/remotes/origin/master' 2012-09-20 16:56:08 -03:00
Agustin Carrasco 96ae0f649c Merge remote-tracking branch 'refs/remotes/origin/master' 2012-09-20 16:54:15 -03:00
fossfreedom a65d2e0638 Update README.md 2012-09-20 21:53:48 +02:00
Agustin Carrasco 31b8fb91d7 Removed deprecated line on the ui creation method 2012-09-20 16:53:04 -03:00
Agustin Carrasco 29fe39b854 Added a check on the loader progress before reenabling the full cover search item 2012-09-20 16:52:27 -03:00
Agustin Carrasco 9ca1b1c7fc Merge branch 'master' into global_statusbar 2012-09-20 16:49:11 -03:00
Agustin Carrasco 39d08d2e49 Moved the cover_view popup menu creation to the ui file. Also, made the individual cover search and full cover search mutually exclusive to avoid problems (e.g. making and individual cover search when a full cover search is on progress). Maybe this breaks the translations? 2012-09-20 16:48:58 -03:00
fossfreedom 5b891bf3f9 release instructions for v0.3 2012-09-20 21:31:28 +02:00
fossfreedom 528f792c38 makefile for debian package install 2012-09-20 19:16:24 +01:00
fossfreedom 3f75c19281 add version 2012-09-20 19:11:27 +01:00
Agustin Carrasco 9cc4779ace Merge branch 'master' into global_statusbar 2012-09-20 12:47:57 -03:00
Agustin Carrasco e14fcbf6d6 Fixed typo 2012-09-20 12:47:47 -03:00
Agustin Carrasco 0a6e6b2688 Moved the status messages that show the current selected album information to the global Rhythmbox's status bar (issue #19) 2012-09-20 12:39:56 -03:00
Agustin Carrasco f0c1c4ec9e Added a progress property to the AlbumLoader that can be used to know the percentage of album's covers have been loaded until now. 2012-09-20 12:38:58 -03:00
Agustin Carrasco f114a014a3 Merge branch 'search_statusbar'
Finished implementation to retrieve one or all the covers. (closes issue #8)
2012-09-20 11:04:17 -03:00
fossfreedom 4d159114d1 script to generate all po's 2012-09-20 12:42:19 +01:00
Agustin Carrasco 2f188395c4 Moved the action to initiate the full album search to a MenuItem on the source Popup menu (issue #8) 2012-09-19 22:13:27 -03:00
fossfreedom c5933c5e09 Merge pull request #18 from mateuswetah/master
Updated pt_BR.po
2012-09-19 14:59:01 -07:00
Mateus Machado Luna 9215396ad2 Update po/pt_BR.po
Updated with fixes on the file, lines 49, 53, 57 and 61.
2012-09-19 18:16:57 -03:00
Agustin Carrasco c49acb2a83 Updated Spanish translation 2012-09-19 17:47:36 -03:00
Agustin Carrasco 8fd106c012 Finished the implementation of the full cover search with some ui for feedback. The ui is open to changes. (issue #8) 2012-09-19 17:42:25 -03:00
Agustin Carrasco 23f33b1cee Various changes: made AlbumLoader a GObject to make it able to have signals. For now, it haves a 'load-finished' signal to indicate the loading process has finished. Also, added the posibility to cancel the full album request (issue #8) 2012-09-19 17:38:41 -03:00
fossfreedom 10107656b6 Merge pull request #17 from mateuswetah/master
Adding the pt_BR.po file for the Brazilian Portuguese translation
2012-09-19 13:23:22 -07:00
Mateus ml 9a1a559aa7 Added the po/pt_BT.po file for translating to Brazilian Portuguese 2012-09-19 17:08:10 -03:00
fossfreedom fdd7d52dae fixed search locale issues #14 2012-09-19 21:06:00 +01:00
fossfreedom 176858ea06 minor updates issue #14 2012-09-19 16:51:17 +01:00
fossfreedom ba257ae906 attempt to ensure search bar is correctly localised issue #14 2012-09-19 15:04:53 +01:00
fossfreedom f49f2eb074 new dependency for installation 2012-09-19 13:59:54 +01:00
fossfreedom c2cac2a307 add routine to update existing po's when the template changes issue #14 2012-09-19 13:57:37 +01:00
fossfreedom 23ea9e99e4 Update TRANSLATE_README 2012-09-19 11:08:37 +02:00
Agustin Carrasco c38eea0452 Updated spanish translation (issue #14) 2012-09-19 00:07:05 -03:00
Agustin Carrasco 00c440f57d Initial implementation of full album search. (issue #8) 2012-09-18 19:27:31 -03:00
fossfreedom e961039344 updated TRANSLATE_README - issue #14 2012-09-18 23:23:20 +01:00
fossfreedom 8adef4ce36 preliminary translation support - issue #14 2012-09-18 23:00:40 +01:00
fossfreedom 1d7f0dd041 final strings issue #14 2012-09-17 23:22:59 +01:00
fossfreedom 355bd6301b revert 2012-09-17 22:09:31 +01:00
fossfreedom a50038c73d fixed error on label issue #14 2012-09-17 21:52:22 +01:00
fossfreedom 3e0e25c168 add translatable strings - issue #14 2012-09-17 21:48:04 +01:00
Agustin Carrasco 5a93b9006a Merge branch 'master' into search_statusbar 2012-09-17 13:29:19 -03:00
Agustin Carrasco 1c61509a66 Check the album really exists before updating the cover (issue #11) 2012-09-17 12:52:33 -03:00
fossfreedom 17cae43d23 remove double click error 2012-09-17 14:56:10 +01:00
Agustin Carrasco d9315745cc First try to add a status bar to indicate the album fetching status 2012-09-16 02:10:22 -03:00
266 arquivos alterados com 119817 adições e 2111 exclusões
+3
Ver Arquivo
@@ -7,6 +7,7 @@ dist
build
eggs
parts
.idea
bin
var
sdist
@@ -25,3 +26,5 @@ pip-log.txt
#Mr Developer
.mr.developer.cfg
img/usericons/popups.xml
+621
Ver Arquivo
@@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. {http://fsf.org/}
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. 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
them 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 prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. 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.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
+52
Ver Arquivo
@@ -0,0 +1,52 @@
DESTDIR=
SUBDIR=/usr/lib/rhythmbox/plugins/coverart_browser/
DATADIR=/usr/share/rhythmbox/plugins/coverart_browser/
LOCALEDIR=/usr/share/locale/
GLIB_SCHEME=org.gnome.rhythmbox.plugins.coverart_browser.gschema.xml
GLIB_DIR=/usr/share/glib-2.0/schemas/
all:
clean:
- rm *.pyc
install:
install -d $(DESTDIR)$(SUBDIR)
install -m 644 *.py $(DESTDIR)$(SUBDIR)
install -m 644 LICENSE.txt $(DESTDIR)$(SUBDIR)
install -d $(DESTDIR)$(DATADIR)img
install -m 644 img/*.png $(DESTDIR)$(DATADIR)img/
install -m 644 img/*.svg $(DESTDIR)$(DATADIR)img/
install -m 644 img/*.xml $(DESTDIR)$(DATADIR)img/
install -d $(DESTDIR)$(DATADIR)img/darker
install -m 644 img/darker/*.png $(DESTDIR)$(DATADIR)img/darker
install -d $(DESTDIR)$(DATADIR)img/dark
install -m 644 img/dark/*.png $(DESTDIR)$(DATADIR)img/dark
install -d $(DESTDIR)$(DATADIR)img/light
install -m 644 img/light/*.png $(DESTDIR)$(DATADIR)img/light
install -d $(DESTDIR)$(DATADIR)img/lighter
install -m 644 img/lighter/*.png $(DESTDIR)$(DATADIR)img/lighter
install -d $(DESTDIR)$(DATADIR)img/standard
install -m 644 img/standard/*.png $(DESTDIR)$(DATADIR)img/standard
install -d $(DESTDIR)$(DATADIR)img/links
install -m 644 img/links/*.png $(DESTDIR)$(DATADIR)img/links
install -d $(DESTDIR)$(DATADIR)template
install -m 644 template/*.xml $(DESTDIR)$(DATADIR)template
install -d $(DESTDIR)$(DATADIR)ui
install -m 644 ui/*.ui $(DESTDIR)$(DATADIR)ui/
install -m 644 ui/*.xml $(DESTDIR)$(DATADIR)ui/
install -m 644 ui/*.css $(DESTDIR)$(DATADIR)ui/
install -d $(DESTDIR)$(DATADIR)coverflow
install -d $(DESTDIR)$(DATADIR)coverflow/img
install -m 644 coverflow/*.css $(DESTDIR)$(DATADIR)coverflow/
install -m 644 coverflow/*.js $(DESTDIR)$(DATADIR)coverflow/
install -m 644 coverflow/*.html $(DESTDIR)$(DATADIR)coverflow/
install -m 644 coverflow/LICENSE $(DESTDIR)$(DATADIR)coverflow/
install -m 644 coverflow/img/* $(DESTDIR)$(DATADIR)coverflow/img/
install -m 644 coverart_browser.plugin* $(DESTDIR)$(SUBDIR)
install -d $(DESTDIR)$(DATADIR)tmpl
install -m 644 tmpl/* $(DESTDIR)$(DATADIR)tmpl/
install -d $(DESTDIR)$(GLIB_DIR)
install -m 644 schema/$(GLIB_SCHEME) $(DESTDIR)$(GLIB_DIR)
cd po;./install_all.sh $(DESTDIR)$(LOCALEDIR)
+124 -25
Ver Arquivo
@@ -1,29 +1,128 @@
coverart-browser
================
#coverart-browser - v2.2 development (Colonel K)
Browse your cover-art albums in Rhythmbox
Browse your coverart albums in Rhythmbox v3 and later.
![Imgur](http://i.imgur.com/2mzD5.png)
If you have reached here looking for the stable version of the plugin please read the README files for
- rhythmbox 2.96 - 2.99: https://github.com/fossfreedom/coverart-browser/tree/release-1.2
- rhythmbox 3.0+: https://github.com/fossfreedom/coverart-browser/tree/release-2.1
![Imgur](http://i.imgur.com/tTnHbE1.png)
-----------
##Authors
- asermax <asermax@gmail.com>, website - https://github.com/asermax
[![Flattr Button](http://api.flattr.com/button/button-compact-static-100x17.png "Flattr This!")](http://flattr.com/thing/1262052/asermax-on-GitHub "asermax")
- fossfreedom <foss.freedom@gmail.com>, website - https://github.com/fossfreedom
[![Flattr Button](http://api.flattr.com/button/button-compact-static-100x17.png "Flattr This!")](http://flattr.com/thing/1811704/ "fossfreedom") [![paypaldonate](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KBV682WJ3BDGL)
-----------
##Summary: whats new in this release
- Support for Alternative-Toolbar & Headerbar - add view switcher to headerbar and remove from source toolbars
- Support for Alternative-Toolbar - Toggle between views and sources in sidepane
- Export and Embed dialog remembers field values between openings
- Quicker startup of plugin
- chosen playlist are persistent between rhythmbox sessions
- Add CoverArt Playlist to the same menu-button as other views
- Remove separate CoverArt Playlist icon on track-view
- Rework CoverArt Playlist so that don't have to start CoverArt to play the last saved playlist
- various icons display correctly for both light and dark themes
- Translated into 25 languages and locales
- for developers - doxygen documentation: http://fossfreedom.github.io/coverart-browser/classes.html
*How it works:*
- Click the new CoverArt Browser source button (left hand side of screen)
- Albums are displayed as clickable buttons containing their album cover
- Right click menu option to play, queue & search for coverart for an album.
- Download Album & artist artwork via the properties toolbar button
- https://github.com/fossfreedom/coverart-browser/wiki/how-to-for-version-2.0
- https://github.com/fossfreedom/coverart-browser/wiki/Screenshots
*How to install - Rhythmbox 3.0 and later:*
N.B. for earlier Rhythmbox versions use version 1.x
Prerequisite is to use a distribution supporting GTK 3.10 or later - for example, Ubuntu 14.04, Arch or Fedora 20
for Debian & Debian-based distros such as Ubuntu & Mint:
sudo apt-get install git gettext python3-mako python3-lxml python3-gi-cairo python3-cairo gstreamer1.0-plugins-ugly gstreamer1.0-plugins-good gstreamer1.0-plugins-bad rhythmbox-plugins
for Fedora and similar:
sudo yum install git gettext python3-mako python3-lxml python3-cairo
NOTE: it is assumed that you have separately installed the patent encumbered codecs found in the good/bad & ugly packages
To install the plugin:
<pre>
rm -rf ~/.local/share/rhythmbox/plugins/coverart_browser
git clone https://github.com/fossfreedom/coverart-browser.git -b master
cd coverart-browser
./install.sh
</pre>
To uninstall the plugin:
<pre>
cd coverart-browser
./install.sh --uninstall
</pre>
Note 1 - the CoverArt Browser plugin also requires installing the following plugin:
- https://github.com/fossfreedom/coverart-search-providers
*For Ubuntu 14.04 and later:*
V2.0 is now available in my rhythmbox PPA - installation instructions in this AskUbuntu Q&A:
http://askubuntu.com/questions/147942/how-do-i-install-third-party-rhythmbox-plugins
Note - installing the package `rhythmbox-plugin-coverart-browser` will also install `rhythmbox-plugin-coverart-search`
**Please help out with translating**
We need you to help us translate the english text to your native language.
Don't worry - it is easier that you think. Just visit:
- https://translations.launchpad.net/coverartbrowser
Remember to set your preferred language and then just submit your translation.
-------
Credits:
- thanks to Luqman Aden <laden@uwaterloo.ca> for the coverart-search plugin which our cover-search pane is based upon
- thanks to Canonical for the Star widget which the ratings capabilities use
- our Translators: Launchpad Translation team - individual credits for each locale is shown in the plugin preferences dialog
- Button Icons - [jrbastien](https://github.com/jrbastien) for the five toolbar icon-sets
- Flow view is based upon [Contentflow](http://jacksasylum.eu/ContentFlow)
Licenses:
This plugin code is released under the GPL3+ license.
Contentflow source is released under the MIT license
All translations are released under the BSD license
Genre icon-set:
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/deed.en_US"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-nd/3.0/80x15.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/StillImage" property="dct:title" rel="dct:type">Music Genre Icons</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://meghnlofing.com" property="cc:attributionName" rel="cc:attributionURL">Meghn Lofing</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/deed.en_US">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License</a>
Contrast of the iconset has been altered as agreed by the author. Thanks Meghn!
------
GTK3 port of code.google.com/p/rhythmbox-cover-art-browser
How it works:
1. Click the new CoverArt source button (left hand side of screen)
2. Albums are displayed as clickable buttons containing their album cover
3. Right click menu option to play, queue & search for cover art for an album.
How to install (64bit linux distro users only):
1. install git
N.B. for debian - sudo apt-get install git
2. git clone https://github.com/fossfreedom/coverart-browser.git
3. cd coverart-browser
4. sh ./install.sh
N.B. 32bit users have a bug that prevents querying the database - this prevents this plugin from working. Sorry!
Notes:
- this is a port of the GUI cover-art browser capability.
+65
Ver Arquivo
@@ -0,0 +1,65 @@
# This README is dividied into two sections -
# first section is for the coverart-browser developers
# second section is for Translators
# Section 1: Developers Only
#+++++++++++++++++++++++++++
#for each ui file run the following to create translation .h files
intltool-extract --local --type=gettext/glade ui/coverart_artistview.ui
intltool-extract --local --type=gettext/glade ui/coverart_artist_pop_rb3.ui
intltool-extract --local --type=gettext/glade ui/coverart_browser_pop_rb3.ui
intltool-extract --local --type=gettext/glade ui/coverart_browser_prefs.ui
intltool-extract --local --type=gettext/glade ui/coverart_browser.ui
intltool-extract --local --type=gettext/glade ui/coverart_entryview_compact_pop_rb3.ui
intltool-extract --local --type=gettext/glade ui/coverart_entryview_full_pop_rb3.ui
intltool-extract --local --type=gettext/glade ui/coverart_exportembed.ui
intltool-extract --local --type=gettext/glade ui/coverart_leftsidebar.ui
intltool-extract --local --type=gettext/glade ui/coverart_listwindow.ui
intltool-extract --local --type=gettext/glade ui/coverart_play_pop_rb3.ui
intltool-extract --local --type=gettext/glade ui/coverart_rightsidebar.ui
intltool-extract --local --type=gettext/glade ui/coverart_topbar.ui
intltool-extract --local --type=gettext/xml img/popups.xml.in
#create a new template file called po/package.pot by running below
#create a template file for the mako templates
pybabel extract -F babel.cfg -o po/coverartbrowser.pot -c "TRANSLATORS:" .
# po/files_to_be_translated are all the .h files generated by intltool
xgettext -c -a -j -f po/files_to_be_translated -o po/coverartbrowser.pot
# po/py_files_to_be_translated are all the python files to be translated
xgettext -c -j -f po/py_files_to_be_translated -o po/coverartbrowser.pot
#now update existing po's with changes in the template file package.pot
cd po
./update_all_po.sh
#cleanup
cd ..
rm -rf tmp
# Section 2: Translators
#+++++++++++++++++++++++
The best way to create translations is to visit our Launchpad site
- https://translations.launchpad.net/coverartbrowser
Set your preferred language and then just begin translating
If you dont want to use Launchpad, use the following instructions
# Carry out the following - one or the other (or both!)
#create a new locale file from this template:
cd po; msginit --no-translator
#create a new specific (e.g. spanish) locale file from this template:
cd po; msginit --no-translator -l es
#Take special care with "Fuzzy" translations. "Fuzzy" lines should be
#removed - the string should be carefully examined since these are often
#automated translations.
#run lang.sh to compile and install the po files
sudo ./lang.sh /usr/share/locale/
+3
Ver Arquivo
@@ -0,0 +1,3 @@
# Extraction from Genshi HTML and text templates
[mako: **/tmpl/**.html]
input_encoding = utf-8
+1812 -368
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+56 -6
Ver Arquivo
@@ -1,9 +1,59 @@
[Plugin]
Loader=python
Loader=python3
Module=coverart_browser
IAge=2
Name=Cover Art Browser
Description=Browse and play your albums.
Authors=fossfreedom based on the work of E.Wagner & Alexandre Rosenfeld <airmind@gmail.com>
Copyright=Copyright © 2012 fossfreedom, 2007 Alexandre Rosenfeld
Website=http://github.com/fossfreedom
Depends=rb;coverart_search_providers
Name=CoverArt Browser
Name[ast]=Navegador de portaes
Name[az]=CoverArt gəzgini
Name[bg]=CoverArt Browser
Name[ca]=Navegador de Portades
Name[cs]=Prohlížeč CoverArt
Name[de]=CoverArt Browser
Name[en_AU]=CoverArt Browser
Name[en_GB]=CoverArt Browser
Name[en_US]=CoverArt Browser
Name[es]=Navegador de carátulas
Name[fi]=Kansikuvaselain
Name[fr]=Navigateur de jaquettes
Name[fr_CA]=Navigateur de pochettes
Name[gl]=Navegador de cubertas
Name[hr]=CoverArt Preglednik
Name[it]=Gestore di CoverArt
Name[ko]=앨범 표지 찾아보기
Name[ms]=Pelayar CoverArt
Name[pl]=Przeglądarka okładek
Name[pt]=Arte das Capas
Name[pt_BR]=Arte das Capas
Name[ro]=Navigator CoverArt
Name[ru]=Браузер обложек
Name[zh_CN]=封面浏览器
Description=Browse and play your albums through their covers
Description[ast]=Navegar y reproducir los álbumes per aciu de les portaes
Description[az]=Üz şəklinə görə albomlara bax və oxud
Description[bg]=Търсете и слушайте албумите си посредством обложките им
Description[ca]=Navega i reprodueix els àlbums mitjançant les seues portades
Description[de]=Durchsuchen und geben Sie Ihre Alben über deren Cover wieder
Description[en_AU]=Browse and play your albums through their covers
Description[en_GB]=Browse and play your albums through their covers
Description[en_US]=Browse and play your albums through their covers
Description[es]=Navegue y reproduzca sus álbumes mediante sus carátulas
Description[fi]=Selaa ja toista levyjäsi kansikuvien kautta
Description[fr]=Parcourir les jaquettes de vos albums et les jouer
Description[fr_CA]=Parcourir les pochettes de vos albums et les jouer
Description[gl]=Buscar e reproducir os álbums a través das cubertas
Description[hr]=Pregledavajte i slušajte albume preko omota
Description[it]=Sfoglia e riproduce gli album per copertina
Description[ko]=앨범을 표지로 찾아보고 연주합니다.
Description[ms]=Layar dan mainkan album anda menerusi kulit album mereka
Description[pl]=Przeglądaj i odtwarzaj Twoje albumy według ich okładek
Description[pt]=Navegue e toque seus álbums através de suas capas
Description[pt_BR]=Navegue e toque seus álbums através de suas capas
Description[ro]=Parcurge și redă albumele prin intermediul coperților lor
Description[ru]=Просматривайте и воспроизводите альбомы по обложкам
Description[zh_CN]=浏览封面并播放专辑
Authors=fossfreedom <foss.freedom@gmail.com>, Agustín Carrasco <asermax@gmail.com>
Copyright=© 2012 fossfreedom, Agustín Carrasco © 2007 Alexandre Rosenfeld
Website=http://github.com/fossfreedom/coverart-browser
Help=https://github.com/fossfreedom/coverart-browser/blob/release-2.0/README.md
Version=2.0
+12
Ver Arquivo
@@ -0,0 +1,12 @@
[Plugin]
Loader=python3
Module=coverart_browser
IAge=2
Depends=rb;coverart_search_providers
_Name=CoverArt Browser
_Description=Browse and play your albums through their covers
Authors=fossfreedom <foss.freedom@gmail.com>, Agustín Carrasco <asermax@gmail.com>
Copyright=© 2012 fossfreedom, Agustín Carrasco © 2007 Alexandre Rosenfeld
Website=http://github.com/fossfreedom/coverart-browser
Help=https://github.com/fossfreedom/coverart-browser/blob/release-2.0/README.md
Version=2.0
+509 -84
Ver Arquivo
@@ -1,84 +1,509 @@
# -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import rb
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import RB
from gi.repository import GdkPixbuf
from gi.repository import Peas
from coverart_browser_source import CoverArtBrowserSource
class CoverArtBrowserEntryType(RB.RhythmDBEntryType):
def __init__(self):
RB.RhythmDBEntryType.__init__(self, name='CoverArtBrowserEntryType')
class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable):
__gtype_name = 'CoverArtBrowserPlugin'
object = GObject.property(type=GObject.Object)
def __init__(self):
GObject.Object.__init__(self)
def do_activate(self):
print "CoverArtBrowser DEBUG - do_activate"
self.shell = self.object
self.db = self.shell.props.db
try:
entry_type = CoverArtBrowserEntryType()
self.db.register_entry_type(entry_type)
except NotImplementedError:
entry_type = db.entry_register_type("CoverArtBrowserEntryType")
entry_type.category = RB.RhythmDBEntryCategory.NORMAL
# load plugin icon
theme = Gtk.IconTheme.get_default()
rb.append_plugin_source_path(theme, "/icons")
what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.LARGE_TOOLBAR)
pxbf = GdkPixbuf.Pixbuf.new_from_file_at_size(rb.find_plugin_file(self, "covermgr.png"), width, height)
group = RB.DisplayPageGroup.get_by_id ("library")
self.source = GObject.new ( CoverArtBrowserSource,
shell=self.shell,
name=_("CoverArt"),
entry_type=entry_type,
plugin=self,
pixbuf=pxbf)
self.shell.register_entry_type_for_source(self.source, entry_type)
self.shell.append_display_page(self.source, group)
print "CoverArtBrowser DEBUG - end do_activate"
def do_deactivate(self):
print "CoverArtBrowser DEBUG - do_deactivate"
manager = self.shell.props.ui_manager
manager.ensure_update()
self.source.delete_thyself()
self.shell = None
self.source = None
print "CoverArtBrowser DEBUG - end do_deactivate"
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
# define plugin
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import RB
from gi.repository import Peas
from gi.repository import Gio
from gi.repository import GLib
import rb
from coverart_browser_prefs import GSetting
from coverart_browser_prefs import CoverLocale
from coverart_browser_prefs import Preferences
from coverart_browser_source import CoverArtBrowserSource
from coverart_listview import ListView
from coverart_queueview import QueueView
from coverart_playsourceview import PlaySourceView
from coverart_toolbar import TopToolbar
from coverart_play_source import CoverArtPlaySource
class CoverArtBrowserEntryType(RB.RhythmDBEntryType):
'''
Entry type for our source.
'''
def __init__(self):
'''
Initializes the entry type.
'''
RB.RhythmDBEntryType.__init__(self, name='CoverArtBrowserEntryType')
class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable):
'''
Main class of the plugin. Manages the activation and deactivation of the
plugin.
'''
__gtype_name = 'CoverArtBrowserPlugin'
object = GObject.property(type=GObject.Object)
def __init__(self):
'''
Initialises the plugin object.
'''
GObject.Object.__init__(self)
self._externalmenu = None
def do_activate(self):
'''
Called by Rhythmbox when the plugin is activated. It creates the
plugin's source and connects signals to manage the plugin's
preferences.
'''
print("CoverArtBrowser DEBUG - do_activate")
self.shell = self.object
self.db = self.shell.props.db
self.entry_type = CoverArtBrowserEntryType()
self.db.register_entry_type(self.entry_type)
# we do some specific functionality when working with alternative toolbar
# variables defined by the externalpluginmenu
self.using_alternative_toolbar = False
self.using_headerbar = False
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.entry_type.category = RB.RhythmDBEntryCategory.NORMAL
group = RB.DisplayPageGroup.get_by_id('library')
theme = Gtk.IconTheme.get_default()
theme.append_search_path(rb.find_plugin_file(self, 'img'))
iconfile = Gio.ThemedIcon(name = 'coverart-icon-symbolic')
# our plugin model shared between sources
self.source_query_model = RB.RhythmDBQueryModel.new_empty(self.shell.props.db)
self.source = CoverArtBrowserSource(
shell=self.shell,
name=_("CoverArt"),
entry_type=self.entry_type,
plugin=self,
icon=iconfile,
query_model=self.shell.props.library_source.props.base_query_model)
self.shell.register_entry_type_for_source(self.source, self.entry_type)
self.source.props.visibility = False
self.shell.append_display_page(self.source, group)
self.playlist_source = GObject.new(
CoverArtPlaySource,
name=_("CoverArt Playlist"),
shell=self.shell,
plugin=self,
entry_type=self.entry_type)
self.shell.append_display_page(self.playlist_source, self.source)
self.shell.props.db.connect('load-complete', self.load_complete)
# GLib.timeout_add_seconds(3, self.load_complete) # kludge - if plugin activated after RB has loaded then do stuff
def delayed(*args):
if self.shell.props.selected_page:
self._externalmenu = ExternalPluginMenu(self)
return False
else:
return True
GLib.timeout_add(100, delayed)
cl.switch_locale(cl.Locale.RB)
print("CoverArtBrowser DEBUG - end do_activate")
def do_deactivate(self):
'''
Called by Rhythmbox when the plugin is deactivated. It makes sure to
free all the resources used by the plugin.
'''
print("CoverArtBrowser DEBUG - do_deactivate")
self.source.delete_thyself()
if self._externalmenu:
self._externalmenu.cleanup(full_cleanup=True)
del self.shell
del self.db
del self.source
print("CoverArtBrowser DEBUG - end do_deactivate")
def load_complete(self, *args, **kwargs):
'''
Called by Rhythmbox when it has completed loading all data
Used to automatically switch to the browser if the user
has set in the preferences
'''
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
if setting[gs.PluginKey.AUTOSTART]:
self._externalmenu.autostart_source()
def _translation_helper(self):
'''
a method just to help out with translation strings
it is not meant to be called by itself
'''
# define .plugin text strings used for translation
plugin = _('CoverArt Browser')
desc = _('Browse and play your albums through their covers')
# . TRANSLATORS: This is the icon-grid view that the user sees
tile = _('Tiles')
#. TRANSLATORS: This is the cover-flow view the user sees - they can swipe album covers from side-to-side
artist = _('Flow')
#. TRANSLATORS: percentage size that the image will be expanded
scale = _('Scale by %:')
# stop PyCharm removing the Preference import on optimisation
pref = Preferences()
class ExternalPluginMenu(GObject.Object):
toolbar_pos = GObject.property(type=str, default=TopToolbar.name)
def __init__(self, plugin):
super(ExternalPluginMenu, self).__init__()
self.plugin = plugin
self.shell = plugin.shell
self.source = plugin.source
self.app_id = None
self.locations = ['library-toolbar', 'queue-toolbar', 'playsource-toolbar']
from coverart_browser_source import Views
self._views = Views(self.shell)
self._use_standard_control = True
self.plugin.using_alternative_toolbar = hasattr(self.shell, 'alternative_toolbar')
if self.plugin.using_alternative_toolbar:
from alttoolbar_type import AltToolbarHeaderBar
self.plugin.using_headerbar = isinstance(self.shell.alternative_toolbar.toolbar_type, AltToolbarHeaderBar)
if self.plugin.using_headerbar:
self._use_standard_control = False
# register with headerbar to complete the setup for coverart-browser
print ("registering")
self.shell.alternative_toolbar.toolbar_type.setup_completed_async(self._headerbar_toolbar_completed)
if self._use_standard_control:
# ... otherwise just use the standard menubutton approach
self.source.props.visibility = True # make the source visible
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
Gio.SettingsBindFlags.GET)
self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
self.shell.props.display_page_tree.connect(
"selected", self.on_page_change
)
self._create_menu()
def autostart_source(self):
self.source.props.visibility = True
if self._use_standard_control:
GLib.timeout_add(1000, self.shell.props.display_page_tree.select,
self.source)
else:
# mimic user clicking category button and cover switch
self.shell.alternative_toolbar.toolbar_type.library_browser_radiobutton.set_active(True)
self.shell.alternative_toolbar.toolbar_type.stack.set_visible_child_name("coverview")
def _headerbar_toolbar_completed(self, *args):
print ("headerbar_toolbar_completed")
# if we are using the alternative_toolbar and headerbar then setup the switch
# which will control access to the various views
self._sh_hcc = self.shell.alternative_toolbar.toolbar_type.connect('song-category-clicked',
self._headerbar_category_clicked)
self._add_coverart_header_switch()
sources = { self.shell.props.queue_source,
self.shell.props.library_source,
self.source }
for source in sources:
self.shell.alternative_toolbar.toolbar_type.add_always_visible_source(source)
def _on_notify_toolbar_pos(self, *args):
# for standard menu control ... when moving the toolbar position reposition the menubutton
if self.toolbar_pos == TopToolbar.name:
self._create_menu()
else:
self.cleanup()
def cleanup(self, full_cleanup = False):
# for standard menu control, cleanup where necessary
if self.app_id:
app = Gio.Application.get_default()
for location in self.locations:
app.remove_plugin_menu_item(location, self.app_id)
self.app_id = None
if not self._use_standard_control and full_cleanup:
self.shell.alternative_toolbar.toolbar_type.stack.disconnect(self._sh_stack_id)
self.shell.alternative_toolbar.toolbar_type.stack.remove(self._box_coverview)
self.shell.alternative_toolbar.toolbar_type.disconnect(self._sh_hcc)
self.shell.alternative_toolbar.toolbar_type.headerbar.remove(self.stack_switcher)
self.stack_switcher = None
self._sh_stack_id = None
self._sh_hcc = None
def _create_menu(self):
# for the standard menu control button add the button
# to all supported view types
app = Gio.Application.get_default()
self.app_id = 'coverart-browser'
action_name = 'coverart-browser-views'
self.action = Gio.SimpleAction.new_stateful(
action_name, GLib.VariantType.new('s'),
self._views.get_action_name(ListView.name)
)
self.action.connect("activate", self.view_change_cb)
app.add_action(self.action)
menu_item = Gio.MenuItem()
section = Gio.Menu()
menu = Gio.Menu()
toolbar_item = Gio.MenuItem()
for view_name in self._views.get_view_names():
menu_item.set_label(self._views.get_menu_name(view_name))
menu_item.set_action_and_target_value(
'app.' + action_name, self._views.get_action_name(view_name)
)
section.append_item(menu_item)
menu.append_section(None, section)
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
toolbar_item.set_label('')
cl.switch_locale(cl.Locale.RB)
toolbar_item.set_submenu(menu)
for location in self.locations:
app.add_plugin_menu_item(location, self.app_id, toolbar_item)
def _add_coverart_header_switch(self):
# define the header switch control + stack control for coverart
self._box_coverview = Gtk.Box()
image_name = 'view-cover-symbolic'
stack = self.shell.alternative_toolbar.toolbar_type.stack
stack.add_named(self._box_coverview, "coverview")
stack.child_set_property(self._box_coverview, "icon-name", image_name)
self.stack_switcher = Gtk.StackSwitcher()
self.stack_switcher.set_stack(stack)
self.stack_switcher.show_all()
self.stack_switcher.set_sensitive(False)
self.shell.alternative_toolbar.toolbar_type.headerbar.pack_start(self.stack_switcher)
# create a treeview and store for all views coverart supports
self._store = Gtk.ListStore(str, str)
for view_name in self._views.get_view_names():
self._store.append([self._views.get_menu_name(view_name), view_name])
tree = Gtk.TreeView(self._store)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(_("CoverArt"), renderer, text=0)
tree.append_column(column)
tree.connect('button-press-event', self._tree_row_click)
self.tree = tree
self._box_coverview.pack_start(tree, True, True, 0)
self._sh_stack_id = stack.connect('notify::visible-child-name', self._change_stack)
stack.show_all()
self.stack = stack
self._current_tree_view = None
def _change_stack(self, widget, value):
print ("changed stack")
child_name = self.stack.get_visible_child_name()
print (child_name)
if child_name == "listview":
self.source.props.visibility = False
# if we've toggled to listview then we are no longer in coverart so reset back to songview
self._current_tree_view = None
self._select_view(ListView.name)
if self.shell.alternative_toolbar.toolbar_type.library_song_radiobutton.get_active():
self.stack_switcher.set_sensitive(False)
return
self.source.props.visibility = True
# so we are in coverview so we need to reset the coverview to what was last selected when in this mode
selection = self.tree.get_selection()
liststore, list_iter = selection.get_selected()
if not list_iter:
# nothing was selected to set the view back to what was remembered
self._current_tree_view = self._select_view(None)
treeiter = liststore.get_iter_first()
while treeiter != None:
if liststore[treeiter][1] == self._current_tree_view:
print ("about to set treeview")
print (treeiter)
path = liststore.get_path(treeiter)
print (path)
#self.tree.row_activated(liststore.get_path(treeiter), 0)
self.tree.set_cursor(path)
break
treeiter = liststore.iter_next(treeiter)
else:
# we have been here before so set the view correctly
path = liststore.get_path(list_iter)
self._current_tree_view = liststore[path][1]
self._select_view(liststore[path][1])
def _headerbar_category_clicked(self, headerbar, song_category):
print ("clicked headerbar song-category buttons")
if self.stack.get_visible_child_name() == 'coverview' and song_category:
# if we've clicked song when in coverview then we disable the switcher
# and set the view back to song
#self.stack.set_visible_child_name('listview')
#if self.shell.props.display_page_tree.select != self.shell.props.library_source:
# self._select_view(ListView.name)
#self.stack_switcher.set_sensitive(not song_category)
#self.stack_switcher.set_sensitive(False)
self.source.props.visibility = True
self._select_view(ListView.name)
if self.stack.get_visible_child_name() == 'listview' and not song_category:
# if we've clicked category when in listview then we enable the switcher
self.stack_switcher.set_sensitive(True)
self.source.props.visibility = False
if self.stack.get_visible_child_name() == 'listview' and song_category:
# if we've clicked song when in listview then we disable the switcher
self.stack_switcher.set_sensitive(False)
self.source.props.visibility = False
if self.stack.get_visible_child_name() == 'coverview' and not song_category:
# if we've clicked category when in coverview then we move to the last coverart view
# and ensure the switcher is still enabled
self.source.props.visibility = True
self._select_view(None)
self.stack_switcher.set_sensitive(True)
def _tree_row_click(self, widget, event):
'''
event called when clicking on a row in the header treeview
'''
print('_tree_row_click')
try:
treepath, treecolumn, cellx, celly = widget.get_path_at_pos(event.x, event.y)
except:
return
print (self._store[treepath][1])
self._current_tree_view = self._store[treepath][1]
self._select_view(self._store[treepath][1])
def on_page_change(self, display_page_tree, page):
'''
standard menubutton - Called when the display page changes. Grabs query models and sets the
active view.
'''
print ("on_page_change")
if page == self.shell.props.library_source:
self.action.set_state(self._views.get_action_name(ListView.name))
elif page == self.shell.props.queue_source:
self.action.set_state(self._views.get_action_name(QueueView.name))
elif page == self.plugin.playlist_source:
self.action.set_state(self._views.get_action_name(PlaySourceView.name))
def view_change_cb(self, action, current):
'''
standard menubutton - Called when the view state on a page is changed. Sets the new
state.
'''
print ("view_change_cb")
action.set_state(current)
view_name = self._views.get_view_name_for_action(current)
self._select_view(view_name)
def _select_view(self, view_name):
'''
with the view_name decide which view to be displayed
or if view_name is None then use the last remembered view_name
return view_name
'''
if not self.shell.props.display_page_tree:
return
print ("_select_view")
print (view_name)
if view_name != ListView.name and \
view_name != QueueView.name and \
view_name != PlaySourceView.name:
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
if view_name:
setting[gs.PluginKey.VIEW_NAME] = view_name
else:
view_name = setting[gs.PluginKey.VIEW_NAME]
player = self.shell.props.shell_player
player.set_selected_source(self.source) #.playlist_source)
GLib.idle_add(self.shell.props.display_page_tree.select,
self.source)
elif view_name == ListView.name:
GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.library_source)
elif view_name == QueueView.name:
GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.queue_source)
elif view_name == PlaySourceView.name:
GLib.idle_add(self.shell.props.display_page_tree.select,
self.plugin.playlist_source)
return view_name
-73
Ver Arquivo
@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEntry" id="search_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="invisible_char">•</property>
<property name="primary_icon_stock">gtk-find</property>
<property name="secondary_icon_stock">gtk-clear</property>
<property name="primary_icon_tooltip_text" translatable="yes">Search through your albums</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Clear the search text</property>
<property name="placeholder_text">Search album</property>
<signal name="changed" handler="searchchanged_callback" swapped="no"/>
<signal name="icon-press" handler="icon_press_callback" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<signal name="size-allocate" handler="update_iconview_callback" swapped="no"/>
<child>
<object class="GtkIconView" id="covers_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_column">0</property>
<property name="pixbuf_column">1</property>
<signal name="button-press-event" handler="mouseclick_callback" swapped="no"/>
<signal name="selection-changed" handler="selectionchanged_callback" swapped="no"/>
<signal name="item-activated" handler="coverdoubleclicked_callback" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="status_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="justify">center</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>
+778
Ver Arquivo
@@ -0,0 +1,778 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import locale
import gettext
import os
import shutil
import webbrowser
from gi.repository import Gio
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import PeasGtk
from gi.repository import Peas
from gi.repository import RB
from gi.repository import Gdk
from gi.repository import GLib
import rb
from stars import ReactiveStar
from stars import StarSize
import coverart_rb3compat as rb3compat
def webkit_support():
'''
function that returns True/False if webkit technology is supported
'''
gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN)
return settings[gs.PluginKey.WEBKIT]
class CoverLocale:
'''
This class manages the locale
'''
# storage for the instance reference
__instance = None
class __impl:
""" Implementation of the singleton interface """
# below public variables and methods that can be called for CoverLocale
def __init__(self):
'''
Initializes the singleton interface, assigning all the constants
used to access the plugin's settings.
'''
self.Locale = self._enum(
RB='rhythmbox',
LOCALE_DOMAIN='coverart_browser')
def switch_locale(self, locale_type):
'''
Change the locale
'''
locale.setlocale(locale.LC_ALL, '')
locale.bindtextdomain(locale_type, RB.locale_dir())
locale.textdomain(locale_type)
gettext.bindtextdomain(locale_type, RB.locale_dir())
gettext.textdomain(locale_type)
gettext.install(locale_type)
def get_locale(self):
'''
return the string representation of the users locale
for example
en_US
'''
return locale.getdefaultlocale()[0]
def _enum(self, **enums):
'''
Create an enumn.
'''
return type('Enum', (), enums)
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if CoverLocale.__instance is None:
# Create and remember instance
CoverLocale.__instance = CoverLocale.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_CoverLocale__instance'] = CoverLocale.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
class GSetting:
'''
This class manages the different settings that the plugin has to
access to read or write.
'''
# storage for the instance reference
__instance = None
class __impl:
""" Implementation of the singleton interface """
# below public variables and methods that can be called for GSetting
def __init__(self):
'''
Initializes the singleton interface, assigning all the constants
used to access the plugin's settings.
'''
self.Path = self._enum(
PLUGIN='org.gnome.rhythmbox.plugins.coverart_browser',
RBSOURCE='org.gnome.rhythmbox.sources')
self.RBSourceKey = self._enum(VISIBLE_COLS='visible-columns')
self.PluginKey = self._enum(
CUSTOM_STATUSBAR='custom-statusbar',
DISPLAY_TEXT='display-text',
DISPLAY_TEXT_POS='display-text-pos',
RANDOM='random-queue',
DISPLAY_TEXT_LOADING='display-text-loading',
DISPLAY_TEXT_ELLIPSIZE='display-text-ellipsize',
DISPLAY_TEXT_ELLIPSIZE_LENGTH='display-text-ellipsize-length',
DISPLAY_FONT_SIZE='display-font-size',
COVER_SIZE='cover-size',
ADD_SHADOW='add-shadow',
SHADOW_IMAGE='shadow-image',
PANED_POSITION='paned-position',
SORT_BY='sort-by',
SORT_ORDER='sort-order',
SORT_BY_ARTIST='sort-by-artist',
SORT_ORDER_ARTIST='sort-order-artist',
RATING='rating-threshold',
AUTOSTART='autostart',
TOOLBAR_POS='toolbar-pos',
BUTTON_RELIEF='button-relief',
THEME='theme',
NEW_GENRE_ICON='new-genre-icon',
ICON_PADDING='icon-padding',
ICON_SPACING='icon-spacing',
ICON_AUTOMATIC='icon-automatic',
VIEW_NAME='view-name',
FLOW_APPEARANCE='flow-appearance',
FLOW_HIDE_CAPTION='flow-hide-caption',
FLOW_SCALE='flow-scale',
FLOW_BACKGROUND_COLOUR='flow-background-colour',
FLOW_AUTOMATIC='flow-automatic',
FLOW_WIDTH='flow-width',
FLOW_MAX='flow-max-albums',
WEBKIT='webkit-support',
ARTIST_PANED_POSITION='artist-paned-pos',
USE_FAVOURITES='use-favourites',
ARTIST_INFO_PANED_POSITION='artist-info-paned-pos',
LAST_GENRE_FOLDER='last-genre-folder',
ENTRY_VIEW_MODE='entry-view-mode',
FOLLOWING='following',
ACTIVATIONS='activations',
TEXT_ALIGNMENT='text-alignment')
self.setting = {}
def get_setting(self, path):
'''
Return an instance of Gio.Settings pointing at the selected path.
'''
try:
setting = self.setting[path]
except:
self.setting[path] = Gio.Settings.new(path)
setting = self.setting[path]
return setting
def get_value(self, path, key):
'''
Return the value saved on key from the settings path.
'''
return self.get_setting(path)[key]
def set_value(self, path, key, value):
'''
Set the passed value to key in the settings path.
'''
self.get_setting(path)[key] = value
def _enum(self, **enums):
'''
Create an enumn.
'''
return type('Enum', (), enums)
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if GSetting.__instance is None:
# Create and remember instance
GSetting.__instance = GSetting.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_GSetting__instance'] = GSetting.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
class Preferences(GObject.Object, PeasGtk.Configurable):
'''
Preferences for the CoverArt Browser Plugins. It holds the settings for
the plugin and also is the responsible of creating the preferences dialog.
'''
__gtype_name__ = 'CoverArtBrowserPreferences'
object = GObject.property(type=GObject.Object)
GENRE_POPUP = 1
GENRE_LIST = 2
def __init__(self):
'''
Initialises the preferences, getting an instance of the settings saved
by Gio.
'''
GObject.Object.__init__(self)
gs = GSetting()
self.settings = gs.get_setting(gs.Path.PLUGIN)
self._first_run = True
self._cover_size = 0
self._cover_size_delay = 0
def do_create_configure_widget(self):
'''
Creates the plugin's preferences dialog
'''
return self._create_display_contents(self)
def display_preferences_dialog(self, plugin):
print("DEBUG - display_preferences_dialog")
if self._first_run:
self._first_run = False
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self._dialog = Gtk.Dialog(modal=True, destroy_with_parent=True)
self._dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
self._dialog.set_title(_('Browser Preferences'))
content_area = self._dialog.get_content_area()
content_area.pack_start(self._create_display_contents(plugin), True, True, 0)
helpbutton = self._dialog.add_button(Gtk.STOCK_HELP, Gtk.ResponseType.HELP)
helpbutton.connect('clicked', self._display_help)
self._dialog.show_all()
print("shown")
while True:
response = self._dialog.run()
print("and run")
if response != Gtk.ResponseType.HELP:
break
self._dialog.hide()
print("DEBUG - display_preferences_dialog end")
def _display_help(self, *args):
peas = Peas.Engine.get_default()
uri = peas.get_plugin_info('coverart_browser').get_help_uri()
webbrowser.open(uri)
def _create_display_contents(self, plugin):
print("DEBUG - create_display_contents")
# create the ui
self._first_run = True
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
builder = Gtk.Builder()
builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
builder.add_from_file(rb.find_plugin_file(plugin,
'ui/coverart_browser_prefs.ui'))
self.launchpad_button = builder.get_object('show_launchpad')
self.launchpad_label = builder.get_object('launchpad_label')
builder.connect_signals(self)
# . TRANSLATORS: Do not translate this string.
translators = _('translator-credits')
if translators != "translator-credits":
self.launchpad_label.set_text(translators)
else:
self.launchpad_button.set_visible(False)
gs = GSetting()
# bind the toggles to the settings
toggle_statusbar = builder.get_object('custom_statusbar_checkbox')
self.settings.bind(gs.PluginKey.CUSTOM_STATUSBAR,
toggle_statusbar, 'active', Gio.SettingsBindFlags.DEFAULT)
toggle_text = builder.get_object('display_text_checkbox')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT, toggle_text, 'active',
Gio.SettingsBindFlags.DEFAULT)
box_text = builder.get_object('display_text_box')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT, box_text, 'sensitive',
Gio.SettingsBindFlags.GET)
self.display_text_pos = self.settings[gs.PluginKey.DISPLAY_TEXT_POS]
self.display_text_under_radiobutton = builder.get_object('display_text_under_radiobutton')
self.display_text_within_radiobutton = builder.get_object('display_text_within_radiobutton')
if self.display_text_pos:
self.display_text_under_radiobutton.set_active(True)
else:
self.display_text_within_radiobutton.set_active(True)
random_scale = builder.get_object('random_adjustment')
self.settings.bind(gs.PluginKey.RANDOM, random_scale, 'value',
Gio.SettingsBindFlags.DEFAULT)
toggle_text_ellipsize = builder.get_object(
'display_text_ellipsize_checkbox')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE,
toggle_text_ellipsize, 'active', Gio.SettingsBindFlags.DEFAULT)
box_text_ellipsize_length = builder.get_object(
'display_text_ellipsize_length_box')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE,
box_text_ellipsize_length, 'sensitive', Gio.SettingsBindFlags.GET)
spinner_text_ellipsize_length = builder.get_object(
'display_text_ellipsize_length_spin')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH,
spinner_text_ellipsize_length, 'value',
Gio.SettingsBindFlags.DEFAULT)
spinner_font_size = builder.get_object(
'display_font_spin')
self.settings.bind(gs.PluginKey.DISPLAY_FONT_SIZE,
spinner_font_size, 'value',
Gio.SettingsBindFlags.DEFAULT)
cover_size_scale = builder.get_object('cover_size_adjustment')
#self.settings.bind(gs.PluginKey.COVER_SIZE, cover_size_scale, 'value',
# Gio.SettingsBindFlags.DEFAULT)
self._cover_size = self.settings[gs.PluginKey.COVER_SIZE]
cover_size_scale.set_value(self._cover_size)
cover_size_scale.connect('value-changed', self.on_cover_size_scale_changed)
add_shadow = builder.get_object('add_shadow_checkbox')
self.settings.bind(gs.PluginKey.ADD_SHADOW, add_shadow, 'active',
Gio.SettingsBindFlags.DEFAULT)
rated_box = builder.get_object('rated_box')
self.stars = ReactiveStar(size=StarSize.BIG)
self.stars.connect('changed', self.rating_changed_callback)
align = Gtk.Alignment.new(0.5, 0, 0, 0.1)
align.add(self.stars)
rated_box.add(align)
self.stars.set_rating(self.settings[gs.PluginKey.RATING])
autostart = builder.get_object('autostart_checkbox')
self.settings.bind(gs.PluginKey.AUTOSTART,
autostart, 'active', Gio.SettingsBindFlags.DEFAULT)
toolbar_pos_combo = builder.get_object('show_in_combobox')
renderer = Gtk.CellRendererText()
toolbar_pos_combo.pack_start(renderer, True)
toolbar_pos_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.TOOLBAR_POS, toolbar_pos_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT)
light_source_combo = builder.get_object('light_source_combobox')
renderer = Gtk.CellRendererText()
light_source_combo.pack_start(renderer, True)
light_source_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.SHADOW_IMAGE, light_source_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT)
combo_liststore = builder.get_object('combo_liststore')
from coverart_utils import Theme
for theme in Theme(self).themes:
combo_liststore.append([theme, theme])
theme_combo = builder.get_object('theme_combobox')
renderer = Gtk.CellRendererText()
theme_combo.pack_start(renderer, True)
theme_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.THEME, theme_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT)
button_relief = builder.get_object('button_relief_checkbox')
self.settings.bind(gs.PluginKey.BUTTON_RELIEF, button_relief, 'active',
Gio.SettingsBindFlags.DEFAULT)
# create user data files
cachedir = RB.user_cache_dir() + "/coverart_browser/usericons"
if not os.path.exists(cachedir):
os.makedirs(cachedir)
popup = cachedir + "/popups.xml"
temp = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml')
# lets see if there is a legacy file - if necessary copy it to the cache dir
if os.path.isfile(temp) and not os.path.isfile(popup):
shutil.copyfile(temp, popup)
if not os.path.isfile(popup):
template = rb.find_plugin_file(plugin, 'template/popups.xml')
folder = os.path.split(popup)[0]
if not os.path.exists(folder):
os.makedirs(folder)
shutil.copyfile(template, popup)
# now prepare the genre tab
from coverart_utils import GenreConfiguredSpriteSheet
from coverart_utils import get_stock_size
self._sheet = GenreConfiguredSpriteSheet(plugin, "genre", get_stock_size())
self.alt_liststore = builder.get_object('alt_liststore')
self.alt_user_liststore = builder.get_object('alt_user_liststore')
self._iters = {}
for key in list(self._sheet.keys()):
store_iter = self.alt_liststore.append([key, self._sheet[key]])
self._iters[(key, self.GENRE_POPUP)] = store_iter
for key, value in self._sheet.genre_alternate.items():
if key.genre_type == GenreConfiguredSpriteSheet.GENRE_USER:
store_iter = self.alt_user_liststore.append([key.name,
self._sheet[self._sheet.genre_alternate[key]],
self._sheet.genre_alternate[key]])
self._iters[(key.name, self.GENRE_LIST)] = store_iter
self.amend_mode = False
self.blank_iter = None
self.genre_combobox = builder.get_object('genre_combobox')
self.genre_entry = builder.get_object('genre_entry')
self.genre_view = builder.get_object('genre_view')
self.save_button = builder.get_object('save_button')
self.filechooserdialog = builder.get_object('filechooserdialog')
last_genre_folder = self.settings[gs.PluginKey.LAST_GENRE_FOLDER]
if last_genre_folder != "":
self.filechooserdialog.set_current_folder(last_genre_folder)
padding_scale = builder.get_object('padding_adjustment')
self.settings.bind(gs.PluginKey.ICON_PADDING, padding_scale, 'value',
Gio.SettingsBindFlags.DEFAULT)
spacing_scale = builder.get_object('spacing_adjustment')
self.settings.bind(gs.PluginKey.ICON_SPACING, spacing_scale, 'value',
Gio.SettingsBindFlags.DEFAULT)
icon_automatic = builder.get_object('icon_automatic_checkbox')
self.settings.bind(gs.PluginKey.ICON_AUTOMATIC,
icon_automatic, 'active', Gio.SettingsBindFlags.DEFAULT)
#flow tab
flow_combo = builder.get_object('flow_combobox')
renderer = Gtk.CellRendererText()
flow_combo.pack_start(renderer, True)
flow_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.FLOW_APPEARANCE, flow_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT)
flow_hide = builder.get_object('hide_caption_checkbox')
self.settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION,
flow_hide, 'active', Gio.SettingsBindFlags.DEFAULT)
flow_scale = builder.get_object('cover_scale_adjustment')
self.settings.bind(gs.PluginKey.FLOW_SCALE, flow_scale, 'value',
Gio.SettingsBindFlags.DEFAULT)
flow_width = builder.get_object('cover_width_adjustment')
self.settings.bind(gs.PluginKey.FLOW_WIDTH, flow_width, 'value',
Gio.SettingsBindFlags.DEFAULT)
flow_max = builder.get_object('flow_max_adjustment')
self.settings.bind(gs.PluginKey.FLOW_MAX, flow_max, 'value',
Gio.SettingsBindFlags.DEFAULT)
flow_automatic = builder.get_object('automatic_checkbox')
self.settings.bind(gs.PluginKey.FLOW_AUTOMATIC,
flow_automatic, 'active', Gio.SettingsBindFlags.DEFAULT)
self.background_colour = self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR]
self.white_radiobutton = builder.get_object('white_radiobutton')
self.black_radiobutton = builder.get_object('black_radiobutton')
if self.background_colour == 'W':
self.white_radiobutton.set_active(True)
else:
self.black_radiobutton.set_active(True)
self.text_alignment = self.settings[gs.PluginKey.TEXT_ALIGNMENT]
self.text_alignment_left_radiobutton = builder.get_object('left_alignment_radiobutton')
self.text_alignment_centre_radiobutton = builder.get_object('centre_alignment_radiobutton')
self.text_alignment_right_radiobutton = builder.get_object('right_alignment_radiobutton')
if self.text_alignment == 0:
self.text_alignment_left_radiobutton.set_active(True)
elif self.text_alignment == 1:
self.text_alignment_centre_radiobutton.set_active(True)
else:
self.text_alignment_right_radiobutton.set_active(True)
# return the dialog
self._first_run = False
print("end create dialog contents")
return builder.get_object('main_notebook')
def on_cover_size_scale_changed(self, scale):
self._cover_size = scale.get_value()
def delay(*args):
print('delay')
print(self._cover_size_delay)
self._cover_size_delay = self._cover_size_delay + 1
if self._cover_size_delay >= 8:
gs = GSetting()
self.settings[gs.PluginKey.COVER_SIZE] = self._cover_size
self._cover_size_delay = 0
return False
return True
if self._cover_size_delay == 0:
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100, delay, None)
else:
self._cover_size_delay = 1
def on_flow_combobox_changed(self, combobox):
current_val = combobox.get_model()[combobox.get_active()][0]
gs = GSetting()
if self.settings[gs.PluginKey.FLOW_APPEARANCE] != current_val:
if current_val == 'flow-vert':
default_size = 150
else:
default_size = 600
self.settings[gs.PluginKey.FLOW_WIDTH] = default_size
if current_val == 'carousel':
self.settings[gs.PluginKey.FLOW_HIDE_CAPTION] = True
def on_background_radio_toggled(self, button):
if button.get_active():
gs = GSetting()
if button == self.white_radiobutton:
self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'W'
else:
self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'B'
def on_display_text_pos_radio_toggled(self, button):
if self._first_run:
return
if button.get_active():
gs = GSetting()
if button == self.display_text_under_radiobutton:
self.settings[gs.PluginKey.DISPLAY_TEXT_POS] = True
else:
self.settings[gs.PluginKey.DISPLAY_TEXT_POS] = False
self.settings[gs.PluginKey.ADD_SHADOW] = False
def on_text_alignment_radiobutton_toggled(self, button):
if self._first_run:
return
if button.get_active():
gs = GSetting()
if button == self.text_alignment_left_radiobutton:
self.settings[gs.PluginKey.TEXT_ALIGNMENT] = 0
elif button == self.text_alignment_centre_radiobutton:
self.settings[gs.PluginKey.TEXT_ALIGNMENT] = 1
else:
self.settings[gs.PluginKey.TEXT_ALIGNMENT] = 2
def on_add_shadow_checkbox_toggled(self, button):
if button.get_active():
# gs = GSetting()
#self.settings[gs.PluginKey.DISPLAY_TEXT_POS] = True
self.display_text_under_radiobutton.set_active(True)
def rating_changed_callback(self, stars):
print("rating_changed_callback")
gs = GSetting()
self.settings[gs.PluginKey.RATING] = self.stars.get_rating()
def on_save_button_clicked(self, button):
'''
action when genre edit area is saved
'''
entry_value = self.genre_entry.get_text()
treeiter = self.genre_combobox.get_active_iter()
icon_value = self.alt_liststore[treeiter][0]
# model 0 is the icon name, model 1 is the pixbuf
if self.amend_mode:
key = self._sheet.amend_genre_info(self.current_genre,
entry_value, icon_value)
self.alt_user_liststore[self._iters[(self.current_genre,
self.GENRE_LIST)]][1] = self._sheet[self._sheet.genre_alternate[key]]
self.alt_user_liststore[self._iters[(self.current_genre,
self.GENRE_LIST)]][0] = key.name
store_iter = self._iters[(self.current_genre, self.GENRE_LIST)]
del self._iters[(self.current_genre, self.GENRE_LIST)]
self._iters[(key.name, self.GENRE_LIST)] = store_iter
else:
self.amend_mode = True
key = self._sheet.amend_genre_info('',
entry_value, icon_value)
self.current_genre = key.name
store_iter = self.alt_user_liststore.append([key.name,
self._sheet[self._sheet.genre_alternate[key]],
self._sheet.genre_alternate[key]])
self._iters[(key.name, self.GENRE_LIST)] = store_iter
selection = self.genre_view.get_selection()
selection.select_iter(store_iter)
self.save_button.set_sensitive(False)
self._toggle_new_genre_state()
def on_genre_filechooserbutton_file_set(self, filechooser):
'''
action when genre new icon button is pressed
'''
key = self._sheet.add_genre_icon(self.filechooserdialog.get_filename())
store_iter = self.alt_liststore.append([key.name, self._sheet[key.name]])
self._iters[(key.name, self.GENRE_POPUP)] = store_iter
gs = GSetting()
last_genre_folder = self.filechooserdialog.get_current_folder()
print(last_genre_folder)
print(self.filechooserdialog.get_filename())
if last_genre_folder:
self.settings[gs.PluginKey.LAST_GENRE_FOLDER] = last_genre_folder
def on_genre_view_selection_changed(self, view):
'''
action when user selects a row in the list of genres
'''
model, genre_iter = view.get_selected()
if genre_iter:
self.genre_entry.set_text(model[genre_iter][0])
index = model[genre_iter][2]
if index != '':
self.genre_combobox.set_active_iter(self._iters[(index, self.GENRE_POPUP)])
self.amend_mode = True
self.current_genre = rb3compat.unicodestr(model[genre_iter][0], 'utf-8')
else:
self.genre_entry.set_text('')
self.genre_combobox.set_active_iter(None)
self.amend_mode = False
if self.blank_iter and self.amend_mode:
try:
index = model[self.blank_iter][0]
if index == '':
model.remove(self.blank_iter)
self.blank_iter = None
except:
self.blank_iter = None
def on_add_button_clicked(self, button):
'''
action when a new genre is added to the table
'''
self.genre_entry.set_text('')
self.genre_combobox.set_active(-1)
self.amend_mode = False
self.blank_iter = self.alt_user_liststore.append(['', None, ''])
selection = self.genre_view.get_selection()
selection.select_iter(self.blank_iter)
def on_delete_button_clicked(self, button):
'''
action when a genre is to be deleted
'''
selection = self.genre_view.get_selection()
model, genre_iter = selection.get_selected()
if genre_iter:
index = rb3compat.unicodestr(model[genre_iter][0], 'utf-8')
model.remove(genre_iter)
if index:
del self._iters[(index, self.GENRE_LIST)]
self._sheet.delete_genre(index)
self._toggle_new_genre_state()
def set_save_sensitivity(self, _):
'''
action to toggle the state of the save button depending
upon the values entered in the genre edit fields
'''
entry_value = self.genre_entry.get_text()
treeiter = self.genre_combobox.get_active_iter()
entry_value = rb3compat.unicodestr(entry_value, 'utf-8')
enable = False
try:
test = self._iters[(entry_value, self.GENRE_LIST)]
if RB.search_fold(self.current_genre) == RB.search_fold(entry_value):
# if the current entry is the same then could save
enable = True
except:
# reach here if this is a brand new entry
enable = True
if treeiter == None or entry_value == None or entry_value == "":
# no icon chosen, or no entry value then nothing to save
enable = False
self.save_button.set_sensitive(enable)
def _toggle_new_genre_state(self):
'''
fire an event - uses gsettings and an object such as a
controller connects to receive the signal that a new or amended
genre has been made
'''
gs = GSetting()
test = self.settings[gs.PluginKey.NEW_GENRE_ICON]
if test:
test = False
else:
test = True
self.settings[gs.PluginKey.NEW_GENRE_ICON] = test
def on_show_launchpad_toggled(self, button):
self.launchpad_label.set_visible(button.get_active())
+1361 -174
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+849
Ver Arquivo
@@ -0,0 +1,849 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from datetime import date
from collections import OrderedDict
from collections import namedtuple
from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import RB
from gi.repository import Gio
from gi.repository import GLib
from coverart_browser_prefs import CoverLocale
from coverart_browser_prefs import GSetting
from coverart_utils import create_pixbuf_from_file_at_size
from coverart_utils import GenreConfiguredSpriteSheet
from coverart_utils import ConfiguredSpriteSheet
from coverart_utils import get_stock_size
from coverart_utils import CaseInsensitiveDict
from coverart_utils import Theme
import rb
MenuNodeT = namedtuple('MenuNode', 'label menutype typevalue')
def MenuNode(label, menutype=None, typevalue=None):
return MenuNodeT(label, menutype, typevalue)
class OptionsController(GObject.Object):
# properties
options = GObject.property(type=object, default=None)
current_key = GObject.property(type=str, default=None)
update_image = GObject.property(type=bool, default=False)
enabled = GObject.property(type=bool, default=True)
def __init__(self):
super(OptionsController, self).__init__()
# connect the variations on the current key to the controllers action
self.connect('notify::current-key', self._do_action)
def get_current_key_index(self):
return self.options.index(self.current_key)
def option_selected(self, key):
if key != self.current_key:
# update the current value
self.current_key = key
def _do_action(self, *args):
self.do_action()
def do_action(self):
pass
def get_current_image(self):
return None
def get_current_description(self):
return self.current_key
def update_images(self, *args):
pass
def create_spritesheet(self, plugin, sheet, typestr):
'''
helper function to create a specific spritesheet
'''
if sheet:
del sheet
return ConfiguredSpriteSheet(plugin, typestr, get_stock_size())
def create_button_image(self, plugin, image, icon_name):
'''
helper function to create a button image
'''
if image:
del image
path = 'img/' + Theme(self.plugin).current + '/'
return create_pixbuf_from_file_at_size(
rb.find_plugin_file(self.plugin, path + icon_name),
*get_stock_size())
class PlaylistPopupController(OptionsController):
def __init__(self, plugin, album_model):
super(PlaylistPopupController, self).__init__()
self._album_model = album_model
shell = plugin.shell
self.plugin = plugin
# get the library name and initialize the superclass with it
self._library_name = shell.props.library_source.props.name
# get the queue name
self._queue_name = shell.props.queue_source.props.name
if " (" in self._queue_name:
self._queue_name = self._queue_name[0:self._queue_name.find(" (")]
self._spritesheet = None
self._update_options(shell)
# get the playlist model so we can monitor changes
playlist_model = shell.props.display_page_model
# connect signals to update playlists
playlist_model.connect('row-inserted', self._update_options, shell)
playlist_model.connect('row-deleted', self._update_options, shell)
playlist_model.connect('row-changed', self._update_options, shell)
def update_images(self, *args):
self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'playlist')
if args[-1]:
self.update_image = True
def _update_options(self, *args):
shell = args[-1]
self.update_images(False)
playlist_manager = shell.props.playlist_manager
still_exists = self.current_key == self._library_name or \
self.current_key == self._queue_name
# retrieve the options
values = OrderedDict()
# library and play queue sources
values[self._library_name] = None
values[self._queue_name] = shell.props.queue_source
# playlists
playlists_entries = playlist_manager.get_playlists()
for playlist in playlists_entries:
if playlist.props.is_local:
name = playlist.props.name
values[name] = playlist
still_exists = still_exists or name == self.current_key
self.values = values
self.options = list(values.keys())
self.current_key = self.current_key if still_exists else \
self._library_name
def do_action(self):
playlist = self.values[self.current_key]
if not playlist:
self._album_model.remove_filter('model')
else:
self._album_model.replace_filter('model',
playlist.get_query_model())
def get_current_image(self):
playlist = self.values[self.current_key]
if self.current_key == self._library_name:
image = self._spritesheet['music']
elif self._queue_name in self.current_key:
image = self._spritesheet['queue']
elif isinstance(playlist, RB.StaticPlaylistSource):
image = self._spritesheet['playlist']
else:
image = self._spritesheet['smart']
return image
class GenrePopupController(OptionsController):
# properties
new_genre_icon = GObject.property(type=bool, default=False)
def __init__(self, plugin, album_model):
super(GenrePopupController, self).__init__()
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self._album_model = album_model
shell = plugin.shell
self.plugin = plugin
# create a new property model for the genres
genres_model = RB.RhythmDBPropertyModel.new(shell.props.db,
RB.RhythmDBPropType.GENRE)
query = shell.props.library_source.props.base_query_model
genres_model.props.query_model = query
# initial genre
self._initial_genre = _('All Genres')
self._spritesheet = None
self._default_image = None
self._unrecognised_image = None
self._connect_properties()
self._connect_signals(query, genres_model)
# generate initial popup
self._update_options(genres_model)
def update_images(self, *args):
if self._spritesheet:
del self._spritesheet
self._spritesheet = GenreConfiguredSpriteSheet(self.plugin,
'genre', get_stock_size())
self._default_image = self.create_button_image(self.plugin,
self._default_image, 'default_genre.png')
self._unrecognised_image = self.create_button_image(self.plugin,
self._unrecognised_image, 'unrecognised_genre.png')
if args[-1]:
self.update_image = True
def _connect_signals(self, query, genres_model):
# connect signals to update genres
self.connect('notify::new-genre-icon', self._update_options, genres_model)
query.connect('row-inserted', self._update_options, genres_model)
query.connect('row-deleted', self._update_options, genres_model)
query.connect('row-changed', self._update_options, genres_model)
def _connect_properties(self):
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.NEW_GENRE_ICON, self, 'new_genre_icon',
Gio.SettingsBindFlags.GET)
def _update_options(self, *args):
genres_model = args[-1]
self.update_images(False)
still_exists = False
# retrieve the options
options = []
row_num = 0
for row in genres_model:
if row_num == 0:
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
genre = _('All Genres')
row_num = row_num + 1
else:
genre = row[0]
options.append(genre)
still_exists = still_exists or genre == self.current_key
self.options = options
self.current_key = self.current_key if still_exists else \
self._initial_genre
def do_action(self):
'''
called when genre popup menu item chosen
return None if the first entry in popup returned
'''
if self.current_key == self._initial_genre:
self._album_model.remove_filter('genre')
else:
self._album_model.replace_filter('genre', self.current_key)
def get_current_image(self):
test_genre = self.current_key.lower()
if test_genre == self._initial_genre.lower():
image = self._default_image
else:
image = self._find_alternates(test_genre)
if image == self._unrecognised_image and \
test_genre in self._spritesheet:
image = self._spritesheet[test_genre]
return image
def _find_alternates(self, test_genre):
# the following genre checks are required
# 1. if we have user defined genres
# 2. then check locale specific system genres
# 3. then check local specific alternates
# 4. then check if we system genres
# where necessary check if any of the genres are a substring
# of test_genre - check in reverse order so that we
# test largest strings first (prevents spurious matches with
# short strings)
# N.B. we use RB.search_fold since the strings can be
# in a mixture of cases, both unicode (normalized or not) and str
# and as usual python cannot mix and match these types.
test_genre = RB.search_fold(test_genre)
ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_USER)
if ret:
return sprite
for genre in sorted(self._spritesheet.locale_names,
key=lambda b: (-len(b), b)):
if RB.search_fold(genre) in test_genre:
return self._spritesheet[self._spritesheet.locale_names[genre]]
# next check locale alternates
ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_LOCALE)
if ret:
return sprite
ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_SYSTEM)
if ret:
return sprite
# check if any of the default genres are a substring
# of test_genre - check in reverse order so that we
# test largest strings first (prevents spurious matches with
# short strings)
for genre in sorted(self._spritesheet.names,
key=lambda b: (-len(b), b)):
if RB.search_fold(genre) in test_genre:
return self._spritesheet[genre]
# if no matches then default to unrecognised image
return self._unrecognised_image
def _match_genres(self, test_genre, genre_type):
case_search = CaseInsensitiveDict(
dict((k.name, v) for k, v in self._spritesheet.genre_alternate.items()
if k.genre_type == genre_type))
if test_genre in case_search:
return (True, self._spritesheet[case_search[test_genre]])
else:
return (False, None)
def get_current_description(self):
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
if self.current_key == self._initial_genre:
return _('All Genres')
else:
return self.current_key
class SortPopupController(OptionsController):
def __init__(self, plugin, viewmgr):
super(SortPopupController, self).__init__()
self._viewmgr = viewmgr
self.plugin = plugin
# sorts dictionary
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.values = OrderedDict([(_('Sort by album name'), 'name'),
(_('Sort by album artist'), 'artist'),
(_('Sort by year'), 'year'),
(_('Sort by rating'), 'rating')])
self.options = list(self.values.keys())
# get the current sort key and initialise the superclass
gs = GSetting()
source_settings = gs.get_setting(gs.Path.PLUGIN)
value = source_settings[gs.PluginKey.SORT_BY]
self._spritesheet = None
self.update_images(False)
self.current_key = list(self.values.keys())[
list(self.values.values()).index(value)]
def update_images(self, *args):
self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'sort')
if args[-1]:
self.update_image = True
def do_action(self):
sort = self.values[self.current_key]
gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN)
settings[gs.PluginKey.SORT_BY] = sort
self._viewmgr.current_view.get_default_manager().emit('sort', "album")
def get_current_image(self):
sort = self.values[self.current_key]
return self._spritesheet[sort]
class ArtistSortPopupController(OptionsController):
def __init__(self, plugin, viewmgr):
super(ArtistSortPopupController, self).__init__()
self._viewmgr = viewmgr
self.plugin = plugin
# sorts dictionary
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.values = OrderedDict([(_('Sort by album name'), 'name_artist'),
(_('Sort by year'), 'year_artist'),
(_('Sort by rating'), 'rating_artist')])
self.options = list(self.values.keys())
# get the current sort key and initialise the superclass
gs = GSetting()
source_settings = gs.get_setting(gs.Path.PLUGIN)
value = source_settings[gs.PluginKey.SORT_BY_ARTIST]
if value not in list(self.values.values()):
print("here")
value = 'name_artist'
source_settings[gs.PluginKey.SORT_BY_ARTIST] = value
self._spritesheet = None
self.update_images(False)
self.current_key = list(self.values.keys())[
list(self.values.values()).index(value)]
print(self.current_key)
def update_images(self, *args):
self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'sort_artist')
if args[-1]:
self.update_image = True
def do_action(self):
sort = self.values[self.current_key]
gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN)
settings[gs.PluginKey.SORT_BY_ARTIST] = sort
self._viewmgr.current_view.get_default_manager().emit('sort', "artist")
def get_current_image(self):
sort = self.values[self.current_key]
return self._spritesheet[sort]
class PropertiesMenuController(OptionsController):
favourites = GObject.property(type=bool, default=False)
follow = GObject.property(type=bool, default=False)
def __init__(self, plugin, source):
super(PropertiesMenuController, self).__init__()
self._source = source
self.plugin = plugin
self._connect_properties()
# sorts dictionary
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
# options
self.values = OrderedDict()
self.values[MenuNode(_('Download all covers'))] = 'download'
self.values[MenuNode(_('Play random album'))] = 'random'
self.values[MenuNode(_('Follow playing song'), 'check',
(True if self.follow else False))] = 'follow'
self.values[MenuNode('separator1', 'separator')] = ''
self.values[MenuNode(_('Use favourites only'), 'check',
(True if self.favourites else False))] = 'favourite'
self.values[MenuNode('separator2', 'separator')] = ''
self.values[MenuNode(_('Browser Preferences'))] = 'browser prefs'
self.values[MenuNode(_('Search Preferences'))] = 'search prefs'
self.options = list(self.values.keys())
self.update_images(False)
if self.favourites:
self._source.propertiesbutton_callback('favourite')
if self.follow:
self._source.propertiesbutton_callback('follow')
self.current_key = None
def _connect_properties(self):
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(
gs.PluginKey.USE_FAVOURITES,
self,
'favourites',
Gio.SettingsBindFlags.DEFAULT)
setting.bind(
gs.PluginKey.FOLLOWING,
self,
'follow',
Gio.SettingsBindFlags.DEFAULT)
def _change_key(self, dict, old, new):
for i in range(len(dict)):
k, v = dict.popitem(False)
dict[new if old == k else k] = v
def update_images(self, *args):
self._image = self.create_button_image(self.plugin,
None, 'properties.png')
if args[-1]:
self.update_image = True
def do_action(self):
if self.current_key:
key = [node for node in self.values if node.label == self.current_key]
if self.current_key == _('Use favourites only'):
self.favourites = not self.favourites
if self.current_key == _('Follow playing song'):
self.follow = not self.follow
self._source.propertiesbutton_callback(self.values[key[0]])
self.current_key = None
def get_current_image(self):
return self._image
def get_current_description(self):
return _('Properties')
class DecadePopupController(OptionsController):
def __init__(self, plugin, album_model):
super(DecadePopupController, self).__init__()
self._album_model = album_model
self.plugin = plugin
self._spritesheet = None
# decade options
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.values = OrderedDict()
self.values[_('All Decades')] = [-1, 'All Decades']
# '20s' as in the decade 2010
self.values[_('20s')] = [2020, '20s']
#'10s' as in the decade 2010
self.values[_('10s')] = [2010, '10s']
#'00s' as in the decade 2000
self.values[_('00s')] = [2000, '00s']
#'90s' as in the decade 1990
self.values[_('90s')] = [1990, '90s']
#'80s' as in the decade 1980
self.values[_('80s')] = [1980, '80s']
#'70s' as in the decade 1970
self.values[_('70s')] = [1970, '70s']
#'60s' as in the decade 1960
self.values[_('60s')] = [1960, '60s']
#'50s' as in the decade 1950
self.values[_('50s')] = [1950, '50s']
#'40s' as in the decade 1940
self.values[_('40s')] = [1940, '40s']
#'30s' as in the decade 1930
self.values[_('30s')] = [1930, '30s']
#'Older' as in 'older than the year 1930'
self.values[_('Older')] = [-1, 'Older']
self.options = list(self.values.keys())
# if we aren't on the 20s yet, remove it
if date.today().year < 2020:
self.options.remove(_('20s'))
# define a initial decade an set the initial key
self._initial_decade = self.options[0]
self.update_images(False)
self.current_key = self._initial_decade
def update_images(self, *args):
self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'decade')
if args[-1]:
self.update_image = True
def do_action(self):
if self.current_key == self._initial_decade:
self._album_model.remove_filter('decade')
else:
self._album_model.replace_filter('decade',
self.values[self.current_key][0])
def get_current_image(self):
decade = self.values[self.current_key][1]
return self._spritesheet[decade]
def get_current_description(self):
return self.current_key
class SortOrderToggleController(OptionsController):
toolbar_type = "album"
def __init__(self, plugin, viewmgr):
super(SortOrderToggleController, self).__init__()
self._viewmgr = viewmgr
self.plugin = plugin
# options
self.values = OrderedDict([(_('Sort in descending order'), False),
(_('Sort in ascending order'), True)])
self.options = list(self.values.keys())
self._images = []
# set the current key
self.gs = GSetting()
self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
self.key = self.get_key()
sort_order = self.settings[self.key]
self.current_key = list(self.values.keys())[
list(self.values.values()).index(sort_order)]
self.update_images(False)
def get_key(self):
return self.gs.PluginKey.SORT_ORDER
def update_images(self, *args):
# initialize images
if len(self._images) > 0:
del self._images[:]
self._images.append(self.create_button_image(self.plugin,
None, 'arrow_down.png'))
self._images.append(self.create_button_image(self.plugin,
None, 'arrow_up.png'))
if args[-1]:
self.update_image = True
def do_action(self):
sort_order = self.values[self.current_key]
self.settings[self.key] = sort_order
self._viewmgr.current_view.get_default_manager().emit('sort', self.toolbar_type)
def get_current_image(self):
return self._images[self.get_current_key_index()]
class ArtistSortOrderToggleController(SortOrderToggleController):
toolbar_type = "artist"
def __init__(self, plugin, model):
super(ArtistSortOrderToggleController, self).__init__(plugin, model)
def get_key(self):
return self.gs.PluginKey.SORT_ORDER_ARTIST
class AlbumSearchEntryController(OptionsController):
# properties
search_text = GObject.property(type=str, default='')
def __init__(self, album_model):
super(AlbumSearchEntryController, self).__init__()
self._album_model = album_model
self._filter_type = 'all'
# options
self.values = OrderedDict()
self.values[_('Search all fields')] = 'all'
self.values[_('Search album artists')] = 'album_artist'
self.values[_('Search track artists')] = 'artist'
self.values[_('Search composers')] = 'composers'
self.values[_('Search albums')] = 'album_name'
self.values[_('Search titles')] = 'track'
self.options = list(self.values.keys())
self.current_key = list(self.values.keys())[0]
self._typing = False
self._typing_counter = 0
self._current_search_text = ""
def do_action(self):
# remove old filter
self._album_model.remove_filter(self._filter_type, False)
# assign the new filter
self._filter_type = self.values[self.current_key]
self.do_search(self.search_text, True)
def _search_typing(self, *args):
self._typing_counter = self._typing_counter + 1
if self._typing_counter >= 4 and self._typing:
self._typing = False
self._change_filter(self._current_search_text, False)
return self._typing
def _change_filter(self, search_text, force):
# self.search_text = search_text
self._current_search_text = search_text
if search_text:
self._album_model.replace_filter(self._filter_type,
search_text)
elif not force:
self._album_model.remove_filter(self._filter_type)
def do_search(self, search_text, force=False):
'''
if self.search_text != search_text or force:
self.search_text = search_text
if search_text:
self._album_model.replace_filter(self._filter_type,
search_text)
elif not force:
self._album_model.remove_filter(self._filter_type)
'''
# self.search_text = search_text
if force:
self._typing_counter = 99
self._typing = False
self._change_filter(search_text, force)
return
if self._current_search_text != search_text:
#self.search_text = search_text
self._current_search_text = search_text
self._typing_counter = 0
if not self._typing:
self._typing = True
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
self._search_typing)
class AlbumQuickSearchController(object):
def __init__(self, album_manager):
self._album_manager = album_manager
def connect_quick_search(self, quick_search):
quick_search.connect('quick-search', self._on_quick_search)
quick_search.connect('arrow-pressed', self._on_arrow_pressed)
quick_search.connect('hide', self._on_hide)
def _on_quick_search(self, quick_search, search_text, *args):
album = self._album_manager.model.find_first_visible('album_name',
search_text)
if album:
path = self._album_manager.model.get_path(album)
self._album_manager.current_view.select_and_scroll_to_path(path)
def _on_arrow_pressed(self, quick_search, key, *args):
current = self._album_manager.current_view.get_selected_objects()[0]
search_text = quick_search.get_text()
album = None
if key == Gdk.KEY_Up:
album = self._album_manager.model.find_first_visible(
'album_name', search_text, current, True)
elif key == Gdk.KEY_Down:
album = self._album_manager.model.find_first_visible(
'album_name', search_text, current)
if album:
path = self._album_manager.model.get_path(album)
self._album_manager.current_view.select_and_scroll_to_path(path)
def _on_hide(self, quick_search, *args):
self._album_manager.current_view.grab_focus()
class ViewController(OptionsController):
def __init__(self, shell, viewmgr):
super(ViewController, self).__init__()
self._viewmgr = viewmgr
from coverart_browser_source import Views
views = Views(shell)
self.values = OrderedDict()
for view_name in views.get_view_names():
self.values[views.get_menu_name(view_name)] = view_name
print(view_name)
self.options = list(self.values.keys())
viewmgr.connect('new-view', self.on_notify_view_name)
def on_notify_view_name(self, *args):
for key in self.options:
if self.values[key] == self._viewmgr.view_name:
self.current_key = key
def do_action(self):
if self._viewmgr.view_name != self.values[self.current_key]:
self._viewmgr.view_name = self.values[self.current_key]
+434
Ver Arquivo
@@ -0,0 +1,434 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import json
import os
from xml.sax.saxutils import escape
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import Gio
from coverart_browser_prefs import GSetting
from coverart_browser_prefs import webkit_support
from coverart_widgets import AbstractView
from coverart_widgets import PanedCollapsible
import rb
class FlowShowingPolicy(GObject.Object):
'''
Policy that mostly takes care of how and when things should be showed on
the view that makes use of the `AlbumsModel`.
'''
def __init__(self, flow_view):
super(FlowShowingPolicy, self).__init__()
self._flow_view = flow_view
self.counter = 0
self._has_initialised = False
def initialise(self, album_manager):
if self._has_initialised:
return
self._has_initialised = True
self._album_manager = album_manager
self._model = album_manager.model
class CoverFlowView(AbstractView):
__gtype_name__ = "CoverFlowView"
name = 'coverflowview'
# properties
flow_background = GObject.property(type=str, default='W')
flow_automatic = GObject.property(type=bool, default=False)
flow_scale = GObject.property(type=int, default=100)
flow_hide = GObject.property(type=bool, default=False)
flow_width = GObject.property(type=int, default=600)
flow_appearance = GObject.property(type=str, default='coverflow')
flow_max = GObject.property(type=int, default=100)
panedposition = PanedCollapsible.Paned.EXPAND
def __init__(self):
super(CoverFlowView, self).__init__()
self.show_policy = FlowShowingPolicy(self)
if webkit_support():
from gi.repository import WebKit
self.view = WebKit.WebView()
else:
self.view = None
self._last_album = None
self._has_initialised = False
self._filter_changed_inprogress = False
self._on_first_use = True
def _connect_properties(self):
gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN)
settings.bind(gs.PluginKey.FLOW_APPEARANCE, self,
'flow_appearance', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self,
'flow_hide', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_SCALE, self,
'flow_scale', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self,
'flow_automatic', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_BACKGROUND_COLOUR, self,
'flow_background', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_WIDTH, self,
'flow_width', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_MAX, self,
'flow_max', Gio.SettingsBindFlags.GET)
def _connect_signals(self, source):
self.connect('notify::flow-background',
self.filter_changed)
self.connect('notify::flow-scale',
self.filter_changed)
self.connect('notify::flow-hide',
self.filter_changed)
self.connect('notify::flow-width',
self.filter_changed)
self.connect('notify::flow-appearance',
self.filter_changed)
self.connect('notify::flow-max',
self.filter_changed)
def filter_changed(self, *args):
# we can get several filter_changed calls per second
# lets simplify the processing & potential flickering when the
# call to this method has slowed stopped
self._filter_changed_event = True
if self._filter_changed_inprogress:
return
self._filter_changed_inprogress = True
def filter_events(*args):
if not self._filter_changed_event:
self._filter_changed()
self._filter_changed_inprogress = False
else:
self._filter_changed_event = False
return True
GLib.timeout_add(250, filter_events, None)
def _filter_changed(self, *args):
path = rb.find_plugin_file(self.plugin, 'coverflow/index.html')
f = open(path)
string = f.read()
f.close()
if self.flow_background == 'W':
background_colour = 'white'
if len(self.album_manager.model.store) <= self.flow_max:
foreground_colour = 'white'
else:
foreground_colour = 'black'
else:
background_colour = 'black'
if len(self.album_manager.model.store) <= self.flow_max:
foreground_colour = 'black'
else:
foreground_colour = 'white'
string = string.replace('#BACKGROUND_COLOUR', background_colour)
string = string.replace('#FOREGROUND_COLOUR', foreground_colour)
string = string.replace('#FACTOR', str(float(self.flow_scale) / 100))
if self.flow_hide:
caption = ""
else:
caption = '<div class="globalCaption"></div>'
string = string.replace('#GLOBAL_CAPTION', caption)
addon = background_colour
if self.flow_appearance == 'flow-vert':
addon += " vertical"
elif self.flow_appearance == 'carousel':
addon += " carousel"
elif self.flow_appearance == 'roundabout':
addon += " roundabout"
string = string.replace('#ADDON', addon)
string = string.replace('#WIDTH', str(self.flow_width))
identifier = self.flow.get_identifier(self.last_album)
if not identifier:
identifier = "'start'"
else:
identifier = str(identifier)
string = string.replace('#START', identifier)
#TRANSLATORS: for example 'Number of covers limited to 150'
display_message = _("Number of covers limited to %d") % self.flow_max
string = string.replace('#MAXCOVERS',
'<p>' + display_message + '</p>')
items = self.flow.initialise(self.album_manager.model, self.flow_max)
string = string.replace('#ITEMS', items)
base = os.path.dirname(path) + "/"
#Gdk.threads_enter()
print(string)
self.view.load_string(string, "text/html", "UTF-8", "file://" + base)
#Gdk.threads_leave()
if self._on_first_use:
self._on_first_use = False
GLib.timeout_add(250, self.source.show_hide_pane, (self.last_album, PanedCollapsible.Paned.EXPAND))
def get_view_icon_name(self):
return "flowview.png"
def initialise(self, source):
if self._has_initialised:
return
self._has_initialised = True
super(CoverFlowView, self).initialise(source)
self.album_manager = source.album_manager
self.ext_menu_pos = 6
self._connect_properties()
self._connect_signals(source)
# lets check that all covers have finished loading before
# initialising the flowcontrol and other signals
if not self.album_manager.cover_man.has_finished_loading:
self.album_manager.cover_man.connect('load-finished', self._covers_loaded)
else:
self._covers_loaded()
def _covers_loaded(self, *args):
self.flow = FlowControl(self)
self.view.connect("notify::title", self.flow.receive_message_signal)
#self.album_manager.model.connect('album-updated', self.flow.update_album, self.view)
#self.album_manager.model.connect('visual-updated', self.flow.update_album, self.view)
self.album_manager.model.connect('album-updated', self.filter_changed)
self.album_manager.model.connect('visual-updated', self.filter_changed)
self.album_manager.model.connect('filter-changed', self.filter_changed)
self.filter_changed()
@property
def last_album(self):
return self._last_album
@last_album.setter
def last_album(self, new_album):
if self._last_album != new_album:
self._last_album = new_album
self.source.click_count = 0
self.selectionchanged_callback()
def item_rightclicked_callback(self, album):
self.last_album = album
self.popup.popup(self.source, 'popup_menu', 3, Gtk.get_current_event_time())
def item_clicked_callback(self, album):
'''
Callback called when the user clicks somewhere on the flow_view.
Along with source "show_hide_pane", takes care of showing/hiding the bottom
pane after a second click on a selected album.
'''
# to expand the entry view
if self.flow_automatic:
self.source.click_count += 1
self.last_album = album
if self.source.click_count == 1:
GLib.timeout_add(250, self.source.show_hide_pane, album)
def item_activated_callback(self, album):
'''
Callback called when the flow view is double clicked. It plays the selected album
'''
self.last_album = album
self.source.play_selected_album()
return True
def item_drop_callback(self, album, webpath):
'''
Callback called when something is dropped onto the flow view - hopefully a webpath
to a picture
'''
print("item_drop_callback %s" % webpath)
print("dropped on album %s" % album)
self.album_manager.cover_man.update_cover(album, uri=webpath)
def get_selected_objects(self):
if self.last_album:
return [self.last_album]
else:
return []
def select_and_scroll_to_path(self, path):
album = self.source.album_manager.model.get_from_path(path)
self.flow.scroll_to_album(album, self.view)
self.item_clicked_callback(album)
def switch_to_view(self, source, album):
self.initialise(source)
self.show_policy.initialise(source.album_manager)
self.last_album = album
self.scroll_to_album(self.last_album)
def grab_focus(self):
self.view.grab_focus()
def scroll_to_album(self, album):
self.flow.scroll_to_album(album, self.view)
class FlowControl(object):
def __init__(self, callback_view):
self.callback_view = callback_view
self.album_identifier = {}
def get_identifier(self, album):
index = -1
for row in self.album_identifier:
if self.album_identifier[row] == album:
index = row
break
if index == -1:
return None
else:
return row
def update_album(self, model, album_path, album_iter, webview):
album = model.get_from_path(album_path)
index = -1
for row in self.album_identifier:
if self.album_identifier[row] == album:
index = row
break
if index == -1:
return
obj = {}
obj['filename'] = album.cover.original
obj['title'] = album.artist
obj['caption'] = album.name
obj['identifier'] = str(index)
webview.execute_script("update_album('%s')" % json.dumps(obj))
def receive_message_signal(self, webview, param):
# this will be key to passing stuff back and forth - need
# to develop some-sort of message protocol to distinguish "events"
title = webview.get_title()
if (not title) or (title == '"clear"'):
return
args = json.loads(title)
try:
signal = args["signal"]
except:
print("unhandled: %s " % title)
return
if signal == 'clickactive':
self.callback_view.item_clicked_callback(self.album_identifier[int(args['param'][0])])
elif signal == 'rightclickactive':
self.callback_view.item_rightclicked_callback(
self.album_identifier[int(args['param'][0])])
elif signal == 'doubleclickactive':
self.callback_view.item_activated_callback(self.album_identifier[int(args['param'][0])])
elif signal == 'dropactive':
self.callback_view.item_drop_callback(self.album_identifier[int(args['param'][0])],
args['param'][1])
else:
print("unhandled signal: %s" % signal)
def scroll_to_album(self, album, webview):
for row in self.album_identifier:
if self.album_identifier[row] == album:
webview.execute_script("scroll_to_identifier('%s')" % str(row))
break
def initialise(self, model, max_covers):
album_col = model.columns['album']
index = 0
items = ""
self.album_identifier = {}
def html_elements(fullfilename, title, caption, identifier):
return '<div class="item"><img class="content" src="' + \
escape(fullfilename) + '" title="' + \
escape(title) + '" identifier="' + \
identifier + '"/> <div class="caption">' + \
escape(caption) + '</div> </div>'
for row in model.store:
cover = row[album_col].cover.original
cover = cover.replace(
'rhythmbox-missing-artwork.svg',
'rhythmbox-missing-artwork.png') # # need a white vs black when we change the background colour
self.album_identifier[index] = row[album_col]
items += html_elements(
fullfilename=cover,
caption=row[album_col].name,
title=row[album_col].artist,
identifier=str(index))
index += 1
if index == max_covers:
break
if index != 0:
# self.callback_view.last_album = self.album_identifier[0]
pass
else:
self.callback_view.last_album = None
return items
+764
Ver Arquivo
@@ -0,0 +1,764 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import gettext
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Pango
from gi.repository import PangoCairo
from gi.repository import GdkPixbuf
from coverart_widgets import EnhancedIconView
from coverart_browser_prefs import GSetting
from coverart_browser_prefs import CoverLocale
from coverart_album import AlbumsModel
from coverart_widgets import AbstractView
from coverart_widgets import PanedCollapsible
import rb
PLAY_SIZE_X = 30
PLAY_SIZE_Y = 30
class CellRendererThumb(Gtk.CellRendererPixbuf):
markup = GObject.property(type=str, default="")
def __init__(self, font_description, cell_area_source):
super(CellRendererThumb, self).__init__()
self.font_description = font_description
self.cell_area_source = cell_area_source
def do_render(self, cr, widget,
background_area,
cell_area,
flags):
x_offset = cell_area.x + 1
y_offset = cell_area.y + 1
# first paint the cover
pixbuf = self.props.pixbuf.scale_simple(cell_area.width - 2, cell_area.height - 2,
GdkPixbuf.InterpType.NEAREST)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, x_offset, y_offset)
cr.paint()
alpha = 0.40
if ((flags & Gtk.CellRendererState.PRELIT) == Gtk.CellRendererState.PRELIT):
# if the cursor is over the cell then slightly dim
alpha -= 0.15
if self.cell_area_source.hover_pixbuf:
# if a hover pixbuf is given then paint this as well either just above the cover album info
# of at the bottom of the cell area if album info is not within the cover area
full, calc_x_offset, calc_y_offset = self.cell_area_source.calc_play_icon_offset(x_offset, y_offset)
Gdk.cairo_set_source_pixbuf(cr,
self.cell_area_source.hover_pixbuf,
calc_x_offset,
calc_y_offset - PLAY_SIZE_Y)
cr.paint()
if not (self.cell_area_source.display_text and self.cell_area_source.display_text_pos == False):
return
# the rest of the routine paints the contents of text within a cover if specified
# PANGO LAYOUT
layout_width = cell_area.width - 2
pango_layout = PangoCairo.create_layout(cr)
pango_layout.set_markup(self.markup, -1)
pango_layout.set_alignment(self.cell_area_source.text_alignment)
pango_layout.set_font_description(self.font_description)
pango_layout.set_width(int(layout_width * Pango.SCALE))
pango_layout.set_wrap(Pango.WrapMode.WORD_CHAR)
wi, he = pango_layout.get_pixel_size()
rect_offset = y_offset + (int((2.0 * self.cell_area_source.cover_size) / 3.0))
rect_height = int(self.cell_area_source.cover_size / 3.0)
if he > rect_height:
pango_layout.set_ellipsize(Pango.EllipsizeMode.END)
pango_layout.set_height(int((self.cell_area_source.cover_size / 3.0) * Pango.SCALE))
wi, he = pango_layout.get_pixel_size()
# RECTANGLE
cr.set_source_rgba(0.0, 0.0, 0.0, alpha)
cr.set_line_width(0)
cr.rectangle(x_offset,
rect_offset,
cell_area.width - 1,
rect_height - 1)
cr.fill()
# DRAW FONT
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.move_to(x_offset,
y_offset
+ 2.0 * self.cell_area_source.cover_size / 3.0
+ (((self.cell_area_source.cover_size / 3.0) - he) / 2.0)
)
PangoCairo.show_layout(cr, pango_layout)
class AlbumArtCellArea(Gtk.CellAreaBox):
font_family = GObject.property(type=str, default="Sans")
font_size = GObject.property(type=int, default=10)
cover_size = GObject.property(type=int, default=0)
display_text_pos = GObject.property(type=bool, default=False)
display_text = GObject.property(type=bool, default=False)
add_shadow = GObject.property(type=bool, default=False)
hover_pixbuf = GObject.property(type=object, default=None)
text_alignment = GObject.property(type=int, default=1)
def __init__(self, ):
super(AlbumArtCellArea, self).__init__()
self.font_description = Pango.FontDescription.new()
self.font_description.set_family(self.font_family)
self.font_description.set_size(int(self.font_size * Pango.SCALE))
self._connect_properties()
# Add own cellrenderer
renderer_thumb = CellRendererThumb(self.font_description, self)
self.pack_start(renderer_thumb, False, False, False)
self.attribute_connect(renderer_thumb, "pixbuf", AlbumsModel.columns['pixbuf'])
self.attribute_connect(renderer_thumb, "markup", AlbumsModel.columns['markup'])
self.props.spacing = 2
def _connect_properties(self):
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.ADD_SHADOW, self, 'add-shadow',
Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.TEXT_ALIGNMENT, self, 'text-alignment',
Gio.SettingsBindFlags.GET)
def calc_play_icon_offset(self, initial_x_offset, initial_y_offset):
'''
calculates the x & y offset for the play hover icon
:param initial_x_offset: current x_offset
:param initial_y_offset: current y_offset
:return: bool, x & y offset where bool is the full cover position
'''
full_cover = False
if not (self.display_text and self.display_text_pos == False):
y_offset = initial_y_offset + self.cover_size - 10
full_cover = True
else:
y_offset = initial_y_offset + (int((2.0 * self.cover_size) / 3.0))
x_offset = initial_x_offset
if self.add_shadow:
x_offset = initial_x_offset + 10
y_offset = y_offset - 10
return full_cover, x_offset, y_offset
class AlbumShowingPolicy(GObject.Object):
'''
Policy that mostly takes care of how and when things should be showed on
the view that makes use of the `AlbumsModel`.
'''
def __init__(self, cover_view):
super(AlbumShowingPolicy, self).__init__()
self._cover_view = cover_view # this will need to be reworked for all views
self._visible_paths = None
self._has_initialised = False
def initialise(self, album_manager):
if self._has_initialised:
return
self._album_manager = album_manager
self._model = album_manager.model
self._connect_signals()
self._has_initialised = True
def _connect_signals(self):
self._cover_view.props.vadjustment.connect('value-changed',
self._viewport_changed)
self._model.connect('album-updated', self._album_updated)
self._model.connect('visual-updated', self._album_updated)
def _viewport_changed(self, *args):
visible_range = self._cover_view.get_visible_range()
if visible_range:
init, end = visible_range
# i have to use the tree iter instead of the path to iterate since
# for some reason path.next doesn't work with the filtermodel
tree_iter = self._model.store.get_iter(init)
self._visible_paths = []
while init and init != end:
self._visible_paths.append(init)
tree_iter = self._model.store.iter_next(tree_iter)
init = self._model.store.get_path(tree_iter)
self._visible_paths.append(end)
def _album_updated(self, model, album_path, album_iter):
# get the currently showing paths
if not self._visible_paths:
self._viewport_changed()
if (album_path and self._visible_paths) and album_path in self._visible_paths:
# if our path is on the viewport, emit the signal to update it
self._cover_view.queue_draw()
class CoverIconView(EnhancedIconView, AbstractView):
__gtype_name__ = "CoverIconView"
icon_spacing = GObject.property(type=int, default=0)
icon_padding = GObject.property(type=int, default=0)
icon_automatic = GObject.property(type=bool, default=True)
display_text_enabled = GObject.property(type=bool, default=False)
display_text_pos = GObject.property(type=bool, default=False)
name = 'coverview'
panedposition = PanedCollapsible.Paned.COLLAPSE
text_alignment = GObject.property(type=int, default=1)
__gsignals__ = {
'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
}
def __init__(self, *args, **kwargs):
super(CoverIconView, self).__init__(cell_area=AlbumArtCellArea(), *args, **kwargs)
self.gs = GSetting()
# custom text renderer
self._text_renderer = None
self.show_policy = AlbumShowingPolicy(self)
self.view = self
self._has_initialised = False
self._last_path = None
self._calc_motion_step = 0
self.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
self.object_column = AlbumsModel.columns['album']
def initialise(self, source):
if self._has_initialised:
return
self._has_initialised = True
self.view_name = "covers_view"
super(CoverIconView, self).initialise(source)
self.shell = source.shell
self.album_manager = source.album_manager
# setup iconview drag&drop support
# first drag and drop on the coverart view to receive coverart
self.enable_model_drag_dest([], Gdk.DragAction.COPY)
self.drag_dest_add_image_targets()
self.drag_dest_add_text_targets()
self.connect('drag-drop', self.on_drag_drop)
self.connect('drag-data-received',
self.on_drag_data_received)
self.source.paned.connect("expanded", self.bottom_expander_expanded_callback)
# lastly support drag-drop from coverart to devices/nautilus etc
self.connect('drag-begin', self.on_drag_begin)
self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
[], Gdk.DragAction.COPY)
# targets = Gtk.TargetList.new([Gtk.TargetEntry.new("application/x-rhythmbox-entry", 0, 0),
# Gtk.TargetEntry.new("text/uri-list", 0, 1) ])
targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0)])
# N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c
targets.add_uri_targets(1)
self.drag_source_set_target_list(targets)
self.connect("drag-data-get", self.on_drag_data_get)
# set the model to the view
# self.set_pixbuf_column(AlbumsModel.columns['pixbuf'])
self.set_model(self.album_manager.model.store)
# setup view to monitor mouse movements
self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
self.hover_pixbufs = {
'button_play': None,
'button_play_hover': None,
'button_playpause': None,
'button_playpause_hover': None,
'button_queue': None,
'button_queue_hover': None,
}
for pixbuf_type in self.hover_pixbufs:
filename = 'img/' + pixbuf_type + '.png'
filename = rb.find_plugin_file(self.plugin, filename)
self.hover_pixbufs[pixbuf_type] = GdkPixbuf.Pixbuf.new_from_file_at_size(filename,
PLAY_SIZE_X,
PLAY_SIZE_Y)
self._connect_properties()
self._connect_signals()
self._activate_markup()
self.on_notify_icon_padding()
self.on_notify_icon_spacing()
def _connect_properties(self):
setting = self.gs.get_setting(self.gs.Path.PLUGIN)
setting.bind(
self.gs.PluginKey.ICON_SPACING,
self,
'icon_spacing',
Gio.SettingsBindFlags.GET)
setting.bind(
self.gs.PluginKey.ICON_PADDING,
self,
'icon_padding',
Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.DISPLAY_TEXT, self,
'display_text_enabled', Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self,
'icon_automatic', Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.DISPLAY_TEXT_POS, self,
'display-text-pos', Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.TEXT_ALIGNMENT, self,
'text-alignment', Gio.SettingsBindFlags.GET)
def _connect_signals(self):
self.connect("item-clicked", self.item_clicked_callback)
self.connect("selection-changed", self.selectionchanged_callback)
self.connect("item-activated", self.item_activated_callback)
self.connect('notify::icon-spacing',
self.on_notify_icon_spacing)
self.connect('notify::icon-padding',
self.on_notify_icon_padding)
self.connect('notify::display-text-enabled',
self._activate_markup)
self.connect('notify::display-text-pos',
self._activate_markup)
self.connect('notify::text-alignment',
self._create_and_configure_renderer)
self.connect("motion-notify-event", self.on_pointer_motion)
self.add_events(Gdk.EventMask.SCROLL_MASK)
self.connect("scroll-event", self.on_scroll_event)
def get_view_icon_name(self):
return "iconview.png"
def resize_icon(self, cover_size):
'''
Callback called when to resize the icon
[common to all views]
'''
self.set_item_width(cover_size)
def on_scroll_event(self, widget, scroll_event):
if scroll_event.state & Gdk.ModifierType.CONTROL_MASK:
settings = self.gs.get_setting(self.gs.Path.PLUGIN)
cover_size = settings[self.gs.PluginKey.COVER_SIZE]
if scroll_event.direction == Gdk.ScrollDirection.UP:
if cover_size <= 195:
settings[self.gs.PluginKey.COVER_SIZE] = cover_size + 5
elif scroll_event.direction == Gdk.ScrollDirection.DOWN:
if cover_size >= 55:
settings[self.gs.PluginKey.COVER_SIZE] = cover_size - 5
elif scroll_event.direction == Gdk.ScrollDirection.SMOOTH:
delta = scroll_event.delta_y
print (delta)
if delta < 0 and cover_size <= 195: # negative delta means scroll up
settings[self.gs.PluginKey.COVER_SIZE] = cover_size - int(delta * 5)
if delta > 0 and cover_size >= 55: # positive delta means scroll down
settings[self.gs.PluginKey.COVER_SIZE] = cover_size - int(delta * 5)
GLib.idle_add(self.queue_draw)
return True
def on_drag_drop(self, widget, context, x, y, time):
'''
Callback called when a drag operation finishes over the cover view
of the source. It decides if the dropped item can be processed as
an image to use as a cover.
'''
# stop the propagation of the signal (deactivates superclass callback)
widget.stop_emission_by_name('drag-drop')
# obtain the path of the icon over which the drag operation finished
path, pos = widget.get_dest_item_at_pos(x, y)
result = path is not None
if result:
target = self.drag_dest_find_target(context, None)
widget.drag_get_data(context, target, time)
return result
def on_drag_data_received(self, widget, drag_context, x, y, data, info,
time):
'''
Callback called when the drag source has prepared the data (pixbuf)
for us to use.
'''
# stop the propagation of the signal (deactivates superclass callback)
widget.stop_emission_by_name('drag-data-received')
# get the album and the info and ask the loader to update the cover
path, pos = widget.get_dest_item_at_pos(x, y)
album = widget.get_model()[path][2]
pixbuf = data.get_pixbuf()
if pixbuf:
self.album_manager.cover_man.update_cover(album, pixbuf)
else:
uri = data.get_text()
self.album_manager.cover_man.update_cover(album, uri=uri)
# call the context drag_finished to inform the source about it
drag_context.finish(True, False, time)
def on_drag_data_get(self, widget, drag_context, data, info, time):
'''
Callback called when the drag destination (playlist) has
requested what album (icon) has been dragged
'''
uris = []
for album in widget.get_selected_objects():
for track in album.get_tracks():
uris.append(track.location)
sel = data.set_uris(uris)
# stop the propagation of the signal (deactivates superclass callback)
widget.stop_emission_by_name('drag-data-get')
def on_drag_begin(self, widget, context):
'''
Callback called when the drag-drop from coverview has started
Changes the drag icon as appropriate
'''
album_number = len(widget.get_selected_objects())
if album_number == 1:
item = Gtk.STOCK_DND
else:
item = Gtk.STOCK_DND_MULTIPLE
widget.drag_source_set_icon_stock(item)
widget.stop_emission_by_name('drag-begin')
def _cover_play_hotspot(self, path, in_vacinity=False):
if path:
valid, rect = self.get_cell_rect(path, None) # rect of widget coords
cursor_x, cursor_y = self.get_pointer() # returns widget coords
c_x = cursor_x - rect.x - (self.icon_padding / 2) - (self.icon_spacing / 2)
c_y = cursor_y - rect.y - (self.icon_padding / 2) - (self.icon_spacing / 2)
sizing = (rect.width / 3) if in_vacinity else 0
full, x_offset, y_offset = self.props.cell_area.calc_play_icon_offset(0, 0)
if full and c_y > y_offset:
return False
y_offset = y_offset - PLAY_SIZE_Y
if (y_offset - PLAY_SIZE_Y) < 0:
return False
if c_x < (PLAY_SIZE_X + sizing + x_offset) and \
c_y < (PLAY_SIZE_Y + sizing + y_offset) and \
c_x > x_offset and \
c_y > (y_offset - sizing):
return True
# c_y 0 value at top - largest at bottom of the cover
return False
def on_pointer_motion(self, widget, event):
self._current_mouse_x = event.x
self._current_mouse_y = event.y
if self._calc_motion_step == 0:
self._calc_motion_step = 1
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
self._calculate_hotspot)
else:
path = self.get_path_at_pos(self._current_mouse_x,
self._current_mouse_y)
if not self._last_path or self._last_path != path:
self._display_icon(None, self._last_path)
def _display_icon(self, icon, path):
self.props.cell_area.hover_pixbuf = icon
if path and self.props.window:
valid, rect = self.get_cell_rect(path, None)
self.props.window.invalidate_rect(rect, True)
self.queue_draw()
def _calculate_hotspot(self, *args):
path = self.get_path_at_pos(self._current_mouse_x,
self._current_mouse_y)
# if the current path was not the same as the last path then
# reset the counter
if not self._last_path or self._last_path != path:
self._display_icon(None, self._last_path)
self._last_path = path
self._calc_motion_step = 0
return False
self._calc_motion_step = self._calc_motion_step + 1
# if havent yet reached the requisite number of steps then
# let the thread roll to the next increment
if self._calc_motion_step < 8:
return True
if not self._cover_play_hotspot(path, in_vacinity=True):
# we are not near the hot-spot so decrement the counter
# hoping next time around we are near
self._calc_motion_step = self._calc_motion_step - 1
self._display_icon(None, self._last_path)
return True
# from here on in, we are going to display a hotspot icon
# so lets decide which one
(_, playing) = self.shell.props.shell_player.get_playing()
calc_path = -1
if playing:
entry = self.shell.props.shell_player.get_playing_entry()
album = self.album_manager.model.get_from_dbentry(entry)
calc_path = self.album_manager.model.get_path(album)
if playing and calc_path == path:
icon = 'button_playpause'
elif playing:
icon = 'button_queue'
else:
icon = 'button_play'
# now we've got the icon - lets double check that we are
# actually hovering exactly on the hotspot because the icon will visually change
exact_hotspot = self._cover_play_hotspot(path)
if exact_hotspot:
icon = icon + '_hover'
hover = self.hover_pixbufs[icon]
self._display_icon(hover, path)
self._calc_motion_step = self._calc_motion_step - 1
return True
def item_clicked_callback(self, iconview, event, path):
'''
Callback called when the user clicks somewhere on the cover_view.
Along with source "show_hide_pane", takes care of showing/hiding the bottom
pane after a second click on a selected album.
'''
# first test if we've clicked on the cover-play icon
if self._cover_play_hotspot(path):
(_, playing) = self.shell.props.shell_player.get_playing()
# first see if anything is playing...
if playing:
entry = self.shell.props.shell_player.get_playing_entry()
album = self.album_manager.model.get_from_dbentry(entry)
# if the current playing entry corresponds to the album
# we are hovering over then we are requesting to pause
if self.album_manager.model.get_from_path(path) == album:
self._last_path = path
self.shell.props.shell_player.pause()
self.on_pointer_motion(self, event)
return
# this must be a new album so we are asking just
# to play this new album ... just need a short interval
# for the selection event to kick in first
def delay(*args):
if playing: # if we are playing then queue up the next album
self.source.queue_selected_album(None, self.source.favourites)
album = self.get_selected_objects()[0]
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
message = gettext.gettext('Album has added to list of playing albums')
self.display_notification(album.name,
message,
album.cover.original)
else: # otherwise just play it
self._last_path = path
self.source.play_selected_album(self.source.favourites)
icon = 'button_play_hover'
self.props.cell_area.hover_pixbuf = \
self.hover_pixbufs[icon]
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
delay, None)
return
# to expand the entry view
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
shift = event.state & Gdk.ModifierType.SHIFT_MASK
if self.icon_automatic:
self.source.click_count += 1 if not ctrl and not shift else 0
if self.source.click_count == 1:
album = self.album_manager.model.get_from_path(path) \
if path else None
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
self.source.show_hide_pane, album)
def item_activated_callback(self, iconview, path):
'''
Callback called when the cover view is double clicked or space-bar
is pressed. It plays the selected album
'''
self.source.play_selected_album(self.source.favourites)
return True
def on_notify_icon_padding(self, *args):
'''
Callback called when the icon-padding gsetting value is changed
'''
self.set_item_padding(self.icon_padding)
def on_notify_icon_spacing(self, *args):
'''
Callback called when the icon-spacing gsetting value is changed
'''
self.set_row_spacing(self.icon_spacing)
self.set_column_spacing(self.icon_spacing)
def _create_and_configure_renderer(self, *args):
if not self._text_renderer:
# Add own cellrenderer
self._text_renderer = Gtk.CellRendererText()
self._text_renderer.props.alignment = self.text_alignment
self._text_renderer.props.wrap_mode = Pango.WrapMode.WORD
if self.text_alignment == 1:
self._text_renderer.props.xalign = 0.5
elif self.text_alignment == 0:
self._text_renderer.props.xalign = 0
else:
self._text_renderer.props.xalign = 1
self._text_renderer.props.yalign = 0
self._text_renderer.props.width = \
self.album_manager.cover_man.cover_size
self._text_renderer.props.wrap_width = \
self.album_manager.cover_man.cover_size
def _activate_markup(self, *args):
'''
Utility method to activate/deactivate the markup text on the
cover view.
'''
if self.display_text_enabled and self.display_text_pos:
if not self._text_renderer:
# create and configure the custom cell renderer
self._create_and_configure_renderer()
# set the renderer
self.pack_end(self._text_renderer, False)
self.add_attribute(self._text_renderer,
'markup', AlbumsModel.columns['markup'])
elif self._text_renderer:
# remove the cell renderer
self.props.cell_area.remove(self._text_renderer)
if self.display_text_enabled:
self.set_tooltip_column(-1) # turnoff tooltips
else:
self.set_tooltip_column(AlbumsModel.columns['tooltip'])
def bottom_expander_expanded_callback(self, paned, expand):
'''
Callback connected to expanded signal of the paned GtkExpander
'''
if expand:
# accommodate the viewport if there's an album selected
if self.source.last_selected_album:
def scroll_to_album(*args):
# accommodate the viewport if there's an album selected
path = self.album_manager.model.get_path(
self.source.last_selected_album)
self.scroll_to_path(path, False, 0, 0)
return False
Gdk.threads_add_idle(GObject.PRIORITY_DEFAULT_IDLE,
scroll_to_album, None)
def switch_to_view(self, source, album):
self.initialise(source)
self.show_policy.initialise(source.album_manager)
self.scroll_to_album(album)
def grab_focus(self):
super(EnhancedIconView, self).grab_focus()
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+363
Ver Arquivo
@@ -0,0 +1,363 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of thie GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import shutil
import os
import sys
import subprocess
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import RB
from gi.repository import Gdk
from gi.repository import Peas
from gi.repository import Gst
from coverart_utils import NaturalString
import rb
import coverart_rb3compat as rb3compat
class CoverArtExport(GObject.Object):
'''
This class provides for various export routines
'''
TARGET_BITRATE = 128
def __init__(self, plugin, shell, album_manager):
self.plugin = plugin
self.shell = shell
self.album_manager = album_manager
self._gstreamer_has_initialised = False
self.has_opened_previously = False
self._values = {}
def is_search_plugin_enabled(self):
peas = Peas.Engine.get_default()
loaded_plugins = peas.get_loaded_plugins()
result = False
if 'coverart_search_providers' in loaded_plugins:
info = peas.get_plugin_info('coverart_search_providers')
version = info.get_version()
if NaturalString(version) >= "0.9":
result = True
return result
def embed_albums(self, selected_albums):
'''
method to export and embed coverart to chosen albums
:selected_albums: `Album` - array of albums
'''
self._initialise_gstreamer()
from coverart_search_tracks import CoverArtTracks
search_tracks = CoverArtTracks()
playlist_manager = self.shell.props.playlist_manager
playlists_entries = playlist_manager.get_playlists()
ui = Gtk.Builder()
ui.add_from_file(rb.find_plugin_file(self.plugin,
'ui/coverart_exportembed.ui'))
ui.connect_signals(self)
embeddialog = ui.get_object('exportembeddialog')
embeddialog.set_transient_for(self.shell.props.window)
folderchooserbutton = ui.get_object('folderchooserbutton')
use_album_name_checkbutton = ui.get_object('use_album_name_checkbutton')
open_filemanager_checkbutton = ui.get_object('open_filemanager_checkbutton')
convert_checkbutton = ui.get_object('convert_checkbutton')
bitrate_spinbutton = ui.get_object('bitrate_spinbutton')
resize_checkbutton = ui.get_object('resize_checkbutton')
resize_spinbutton = ui.get_object('resize_spinbutton')
# predefine values if not previously opened the dialog
if self.has_opened_previously:
print (self._values)
if not self._values['toresize']:
resize_spinbutton.set_value(128)
else:
resize_spinbutton.set_value(self._values['resize'])
if not self._values['convert']:
bitrate_spinbutton.set_value(self.TARGET_BITRATE)
else:
bitrate_spinbutton.set_value(self._values['bitrate'])
folderchooserbutton.set_current_folder(self._values['final_folder_store'])
use_album_name_checkbutton.set_active(self._values['use_album_name'])
open_filemanager_checkbutton.set_active(self._values['open_filemanager'])
convert_checkbutton.set_active(self._values['convert'])
resize_checkbutton.set_active(self._values['toresize'])
else:
bitrate_spinbutton.set_value(self.TARGET_BITRATE)
resize_spinbutton.set_value(128)
downloads_dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD)
folderchooserbutton.set_current_folder(downloads_dir)
response = embeddialog.run()
if response != Gtk.ResponseType.OK:
embeddialog.destroy()
return
self.has_opened_previously = True
# ok pressed - now fetch values from the dialog
final_folder_store = folderchooserbutton.get_current_folder()
use_album_name = use_album_name_checkbutton.get_active()
open_filemanager = open_filemanager_checkbutton.get_active()
convert = convert_checkbutton.get_active()
bitrate = bitrate_spinbutton.get_value()
toresize = resize_checkbutton.get_active()
if toresize:
resize = int(resize_spinbutton.get_value())
else:
resize = -1
self._values['bitrate'] = bitrate
self._values['resize'] = resize
self._values['final_folder_store'] = final_folder_store
self._values['use_album_name'] = use_album_name
self._values['open_filemanager'] = open_filemanager
self._values['convert'] = convert
self._values['toresize'] = toresize
print (self._values)
embeddialog.destroy()
albums = {}
total = 0
for album in selected_albums:
albums[album] = album.get_tracks()
total = total + len(albums[album])
self._track_count = 1
def complete():
self.album_manager.progress = 1
if open_filemanager:
#code taken from http://stackoverflow.com/questions/1795111/is-there-a-cross-platform-way-to-open-a-file-browser-in-python
if sys.platform == 'win32':
import winreg
path = r('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon')
for root in (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE):
try:
with winreg.OpenKey(root, path) as k:
value, regtype = winreg.QueryValueEx(k, 'Shell')
except WindowsError:
pass
else:
if regtype in (winreg.REG_SZ, winreg.REG_EXPAND_SZ):
shell = value
break
else:
shell = 'Explorer.exe'
subprocess.Popen([shell, final_folder_store])
elif sys.platform == 'darwin':
subprocess.Popen(['open', final_folder_store])
else:
subprocess.Popen(['xdg-open', final_folder_store])
self._albumiter = iter(albums)
self._tracknumber = 0
self._album = next(self._albumiter)
def idle_call(data):
exit_idle = True
track = albums[self._album][self._tracknumber]
if not process_track(self._album, track):
exit_idle = False
self._tracknumber = self._tracknumber + 1
if self._tracknumber >= len(albums[self._album]):
try:
self._tracknumber = 0
self._album = next(self._albumiter)
except StopIteration:
exit_idle = False
if not exit_idle:
complete()
return exit_idle
def process_track(album, track):
self.album_manager.progress = self._track_count / total
self._track_count = self._track_count + 1
key = album.create_ext_db_key()
finalPath = rb3compat.unquote(track.location)[7:]
album_name = RB.search_fold(album.name)
if use_album_name:
folder_store = final_folder_store + '/' + album_name
else:
folder_store = final_folder_store
try:
if not os.path.exists(folder_store):
os.makedirs(folder_store)
if convert:
self.convert_to_mp3(finalPath, folder_store, bitrate)
finalPath = self._calc_mp3_filename(finalPath, folder_store)
print(finalPath)
else:
shutil.copy(finalPath, folder_store)
except IOError as err:
print(err.args[0])
return False
dest = os.path.join(folder_store, os.path.basename(finalPath))
desturi = 'file://' + rb3compat.pathname2url(dest)
return search_tracks.embed(desturi, key, resize)
data = None
Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, idle_call, data)
def _initialise_gstreamer(self):
if self._gstreamer_has_initialised:
return
self._gstreamer_has_initialised = True
Gst.init(None)
def on_new_decoded_pad(dbin, pad):
decode = pad.get_parent()
pipeline = decode.get_parent()
convert = pipeline.get_by_name('convert')
decode.link(convert)
# we are going to mimic the following
# gst-launch-1.0 filesrc location="02 - ABBA - Knowing Me, Knowing You.ogg" !
# decodebin ! audioconvert ! audioresample ! lamemp3enc target=bitrate bitrate=128 !
# xingmux ! id3v2mux ! filesink location="mytrack.mp3"
converter = Gst.Pipeline.new('converter')
source = Gst.ElementFactory.make('filesrc', None)
decoder = Gst.ElementFactory.make('decodebin', 'decoder')
convert = Gst.ElementFactory.make('audioconvert', 'convert')
sample = Gst.ElementFactory.make('audioresample', 'sample')
encoder = Gst.ElementFactory.make('lamemp3enc', 'encoder')
encoder.set_property('target', 'bitrate')
encoder.set_property('bitrate', self.TARGET_BITRATE)
xing = Gst.ElementFactory.make('xingmux', 'xing') # needed to make bitrate more accurate
mux = Gst.ElementFactory.make('id3v2mux', 'mux')
if not mux:
# use id3mux where not available
mux = Gst.ElementFactory.make('id3mux', 'mux')
sink = Gst.ElementFactory.make('filesink', 'sink')
converter.add(source)
converter.add(decoder)
converter.add(convert)
converter.add(sample)
converter.add(encoder)
converter.add(xing)
converter.add(mux)
converter.add(sink)
Gst.Element.link(source, decoder)
#note - a decodebin cannot be linked at compile since
#it doesnt have source-pads (http://stackoverflow.com/questions/2993777/gstreamer-of-pythons-gst-linkerror-problem)
decoder.connect("pad-added", on_new_decoded_pad)
Gst.Element.link(convert, sample)
Gst.Element.link(sample, encoder)
Gst.Element.link(encoder, xing)
Gst.Element.link(xing, mux)
Gst.Element.link(mux, sink)
self.converter = converter
self.source = source
self.sink = sink
self.encoder = encoder
def _calc_mp3_filename(self, filename, save_folder):
finalname = os.path.basename(filename)
finalname = finalname.rsplit('.')[0] + ".mp3"
return save_folder + "/" + finalname
def convert_to_mp3(self, filename, save_folder, bitrate):
self.source.set_property('location', filename)
self.sink.set_property('location', self._calc_mp3_filename(filename, save_folder))
print(bitrate)
if bitrate < 32:
bitrate = self.TARGET_BITRATE
self.encoder.set_property('bitrate', int(bitrate))
print(bitrate)
# Start playing
ret = self.converter.set_state(Gst.State.PLAYING)
if ret == Gst.StateChangeReturn.FAILURE:
print("Unable to set the pipeline to the playing state.", sys.stderr)
exit(-1)
# Wait until error or EOS
bus = self.converter.get_bus()
try:
msg = bus.timed_pop_filtered(
Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS)
except:
# for some reason in ubuntu 12.04 Gst.CLOCK_TIME_NONE fails
msg = bus.timed_pop_filtered(
18446744073709551615, Gst.MessageType.ERROR | Gst.MessageType.EOS)
# Parse message
if (msg):
if msg.type == Gst.MessageType.ERROR:
err, debug = msg.parse_error()
print("Error received from element %s: %s" % (
msg.src.get_name(), err), sys.stderr)
print("Debugging information: %s" % debug, sys.stderr)
elif msg.type == Gst.MessageType.EOS:
print("End-Of-Stream reached.")
else:
print("Unexpected message received.", sys.stderr)
# Free resources
self.converter.set_state(Gst.State.NULL)
+244
Ver Arquivo
@@ -0,0 +1,244 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of thie GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import Peas
from gi.repository import GObject
import lxml.etree as ET
import rb
from coverart_rb3compat import ActionGroup
from coverart_rb3compat import ApplicationShell
from coverart_utils import CaseInsensitiveDict
class ExternalPlugin(GObject.Object):
'''
class for all supported ExternalPlugins
'''
def __init__(self, **kargs):
super(ExternalPlugin, self).__init__(**kargs)
# dict of attributes associated with the external plugin
self.attributes = {}
self.attributes['is_album_menu'] = False
self.attributes['new_menu_name'] = ''
self.attributes['action_type'] = ''
self.attributes['action_group_name'] = ''
def appendattribute(self, key, val):
'''
append another attribute to the dict
:param key: `str` name of attribute
:param val: `str` value of attribute
'''
if key == 'is_album_menu':
if val == 'yes':
self.attributes[key] = True
else:
self.attributes[key] = False
else:
self.attributes[key] = val
def is_activated(self):
'''
method to test whether the plugin is actually loaded. Returns a bool
'''
peas = Peas.Engine.get_default()
loaded_plugins = peas.get_loaded_plugins()
if self.attributes['plugin_name'] in CaseInsensitiveDict(loaded_plugins):
print("found %s" % self.attributes['plugin_name'])
return True
print("search for %s" % self.attributes['plugin_name'])
print(loaded_plugins)
return False
def create_menu_item(self, menubar, section_name, at_position,
save_actiongroup, save_menu, for_album=False):
'''
method to create the menu item appropriate to the plugin.
A plugin can have many menu items - all menuitems are enclosed
in a section.
:param menubar: `str` name for the GtkMenu - ignored for RB2.99
:param section_name: `str` unique name of the section holding the menu items
:param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99
:param save_actiongroup: `ActionGroup` container for all menu-item Actions
:param save_menu: `Menu` whole popupmenu including sub-menus
:param for_album: `bool` create the menu for the album - if not given
then its assumed the menu item is appropriate just for tracks
'''
if for_album and not self.attributes['is_album_menu']:
return False
if not self.is_activated():
return False
action = ApplicationShell(save_menu.shell).lookup_action(self.attributes['action_group_name'],
self.attributes['action_name'],
self.attributes['action_type'])
if action:
self.attributes['action'] = action
if self.attributes['new_menu_name'] != '':
self.attributes['label'] = self.attributes['new_menu_name']
else:
self.attributes['label'] = action.label
# self.attributes['sensitive']=action.get_sensitive()
else:
print("action not found")
print(self.attributes)
return False
action = save_actiongroup.add_action(func=self.menuitem_callback,
action_name=self.attributes['action_name'], album=for_album,
shell=save_menu.shell, label=self.attributes['label'])
new_menu_item = save_menu.insert_menu_item(menubar, section_name,
at_position, action)
return new_menu_item
def do_deactivate(self):
pass
def set_entry_view_selected_entries(self, shell):
'''
method called just before the external plugin action is activated
Normally only called for album menus to mimic selecting all the
EntryView rows
'''
page = shell.props.selected_page
if not hasattr(page, "get_entry_view"):
return
page.get_entry_view().select_all()
def activate(self, shell):
'''
method called to initiate the external plugin action
the action is defined by defining the action_group_name, action_name and action_type
'''
action = ApplicationShell(shell).lookup_action(self.attributes['action_group_name'],
self.attributes['action_name'],
self.attributes['action_type'])
if action:
action.activate()
def menuitem_callback(self, action, param, args):
'''
method called when a menu-item is clicked. Basically, an Action
is activated by the user
:param action: `Gio.SimpleAction` or `Gtk.Action`
:param param: Not used
:param args: dict associated with the action
'''
for_album = args['album']
shell = args['shell']
if for_album:
self.set_entry_view_selected_entries(shell)
self.attributes['action'].activate()
class CreateExternalPluginMenu(GObject.Object):
'''
This is the key class called to initialise all supported plugins
:param section_name: `str` unique name of the section holding the menu items
:param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99
:param popup: `Menu` whole popupmenu including sub-menus
'''
def __init__(self, section_name, at_position, popup, **kargs):
super(CreateExternalPluginMenu, self).__init__(**kargs)
self.menu = popup
self.section_name = section_name
self.at_position = at_position
self._actiongroup = ActionGroup(popup.shell, section_name + '_externalplugins')
# all supported plugins will be defined in the following array by parsing
# the plugins XML file for the definition.
self.supported_plugins = []
extplugins = rb.find_plugin_file(popup.plugin, 'ui/coverart_external_plugins.xml')
root = ET.parse(open(extplugins)).getroot()
base = 'rb3/plugin'
for elem in root.xpath(base):
pluginname = elem.attrib['name']
basemenu = base + "[@name='" + pluginname + "']/menu"
for menuelem in root.xpath(basemenu):
ext = ExternalPlugin()
ext.appendattribute('plugin_name', pluginname)
label = menuelem.attrib['label']
if label != "":
ext.appendattribute('new_menu_name', label)
baseattrib = basemenu + "[@label='" + label + "']/attribute"
else:
baseattrib = basemenu + "/attribute"
for attribelem in root.xpath(baseattrib):
key = attribelem.attrib['name']
val = attribelem.text
ext.appendattribute(key, val)
self.supported_plugins.append(ext)
def create_menu(self, menu_name, for_album=False):
'''
method to create the menu items for all supported plugins
:param menu_name: `str` unique name (GtkMenu) id for the menu to create
:for_album: `bool` - create a menu applicable for Albums
by default a menu is assumed to be applicable to a track in an
EntryView
'''
self.menu_name = menu_name
self._actiongroup.remove_actions()
self.menu.remove_menu_items(self.menu_name, self.section_name)
items_added = False
for plugin in self.supported_plugins:
new_menu_item = plugin.create_menu_item(self.menu_name, self.section_name,
self.at_position, self._actiongroup, self.menu, for_album)
if (not items_added) and new_menu_item:
items_added = True
if items_added:
self.menu.insert_separator(self.menu_name, self.at_position)
+80
Ver Arquivo
@@ -0,0 +1,80 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import GObject
from gi.repository import GLib
from coverart_widgets import AbstractView
class ListShowingPolicy(GObject.Object):
'''
Policy that mostly takes care of how and when things should be showed on
the view that makes use of the `AlbumsModel`.
'''
def __init__(self, list_view):
super(ListShowingPolicy, self).__init__()
self.counter = 0
self._has_initialised = False
def initialise(self, album_manager):
if self._has_initialised:
return
self._has_initialised = True
class ListView(AbstractView):
__gtype_name__ = "ListView"
name = 'listview'
use_plugin_window = False
def __init__(self):
super(ListView, self).__init__()
self.view = self
self._has_initialised = False
self.show_policy = ListShowingPolicy(self)
def initialise(self, source):
if self._has_initialised:
return
self._has_initialised = True
self.view_name = "list_view"
super(ListView, self).initialise(source)
# self.album_manager = source.album_manager
self.shell = source.shell
def switch_to_view(self, source, album):
self.initialise(source)
GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.library_source)
def get_selected_objects(self):
'''
finds what has been selected
returns an array of `Album`
'''
return []
+258
Ver Arquivo
@@ -0,0 +1,258 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
# define plugin
from gi.repository import Gtk
from gi.repository import RB
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gdk
from coverart_rb3compat import Menu
from coverart_external_plugins import CreateExternalPluginMenu
from coverart_entryview import CoverArtEntryView
from coverart_rb3compat import ActionGroup
from coverart_rb3compat import ApplicationShell
from coverart_browser_prefs import CoverLocale
from coverart_widgets import PressButton
from coverart_utils import create_button_image
import xml.etree.ElementTree as ET
import rb
import os
class CoverArtPlayEntryView(CoverArtEntryView):
__hash__ = GObject.__hash__
def __init__(self, shell, source):
'''
Initializes the entryview.
'''
super(CoverArtPlayEntryView, self).__init__(shell, source)
def define_menu(self):
popup = Menu(self.plugin, self.shell)
popup.load_from_file('N/A',
'ui/coverart_play_pop_rb3.ui')
signals = {
'remove_from_playlist_menu_item': self.remove_from_playlist_menu_item_callback
}
popup.connect_signals(signals)
popup.connect('pre-popup', self.pre_popup_menu_callback)
self.popup = popup
def pre_popup_menu_callback(self, *args):
'''
Callback when the popup menu is about to be displayed
'''
if not self.external_plugins:
self.external_plugins = \
CreateExternalPluginMenu("playlist_entry_view", 1, self.popup)
self.external_plugins.create_menu('play_popup_menu')
def remove_from_playlist_menu_item_callback(self, *args):
print("remove_from_playlist_menu_item_callback")
entries = self.get_selected_entries()
for entry in entries:
print(entry)
self.source.source_query_model.remove_entry(entry)
def do_show_popup(self, over_entry):
if over_entry:
print("CoverArtBrowser DEBUG - do_show_popup()")
self.popup.popup(self.source,
'play_popup_menu', 0, Gtk.get_current_event_time())
return over_entry
def play_track_menu_item_callback(self, *args):
print("CoverArtBrowser DEBUG - play_track_menu_item_callback()")
selected = self.get_selected_entries()
entry = selected[0]
# Start the music
player = self.shell.props.shell_player
player.play_entry(entry, self.source)
print("CoverArtBrowser DEBUG - play_track_menu_item_callback()")
class CoverArtPlaySource(RB.BrowserSource):
def __init__(self, **kwargs):
'''
Initializes the source.
'''
super(CoverArtPlaySource, self).__init__(**kwargs)
#self.external_plugins = None
self.hasActivated = False
self.save_in_progress = False
self.save_interrupt = False
self.filename = RB.user_cache_dir() + "/coverart_browser/playlist.xml"
def do_selected(self):
'''
Called by Rhythmbox when the source is selected. It makes sure to
create the ui the first time the source is showed.
'''
print("CoverArtBrowser DEBUG - do_selected")
# first time of activation -> add graphical stuff
if not self.hasActivated:
self.do_impl_activate()
# indicate that the source was activated before
self.hasActivated = True
print("CoverArtBrowser DEBUG - end do_selected")
def do_impl_activate(self):
'''
Called by do_selected the first time the source is activated.
It creates all the source ui and connects the necessary signals for it
correct behavior.
'''
print('do_impl_activate')
self.plugin = self.props.plugin
self.shell = self.props.shell
player = self.shell.props.shell_player
player.set_playing_source(self)
player.set_selected_source(self)
# define a query model that we'll use for playing
self.source_query_model = self.plugin.source_query_model
grid = Gtk.Grid()
self.entryview = self.get_entry_view()
child = self.get_children()
print (child)
grid = child[0]
self.rbsourcetoolbar = grid.get_children()[1] # need to remember the reference to stop crashes when python cleans up unlinked objects
grid.remove(grid.get_children()[1])
self.get_entry_view().set_model(self.source_query_model)
'''
# enable sorting on the entryview
entryview.set_columns_clickable(True)
self.shell.props.library_source.get_entry_view().set_columns_clickable(
True)
'''
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
location = rb.find_plugin_file(self.plugin, 'ui/playsource-toolbar.ui')
ui = Gtk.Builder()
ui.set_translation_domain(cl.Locale.RB)
ui.add_from_file(location)
toolbar_menu = ui.get_object('playsource-toolbar')
app = self.shell.props.application
app.link_shared_menus(toolbar_menu)
self.toolbar = RB.ButtonBar.new(toolbar_menu, toolbar_menu)
self.toolbar.props.hexpand_set = False
grid.attach(self.toolbar, 0, 0, 1, 1)
grid.show_all()
appshell = ApplicationShell(self.shell)
action_group = ActionGroup(self.shell, 'PlaySourceActions')
action_group.add_action(func=self.clear_playsource,
action_name='playsource-clear', action_state=ActionGroup.STANDARD,
action_type='app')
action_group.add_action(func=self.shuffle_playsource,
action_name='playsource-shuffle', action_state=ActionGroup.STANDARD,
action_type='app')
appshell.insert_action_group(action_group)
# if the alternative-toolbar is loaded then lets connect to the toolbar-visibility signal
# to control our sources toolbar visibility
#if hasattr(self.shell, 'alternative_toolbar'):
# self.shell.alternative_toolbar.connect('toolbar-visibility', self._visibility)
self._load_model()
self.source_query_model.connect('row-inserted', self.save_changed_model)
self.source_query_model.connect('row-changed', self.save_changed_model)
self.source_query_model.connect('row-deleted', self.save_changed_model)
def _load_model(self):
if not os.path.isfile(self.filename):
return
parser = ET.XMLParser(encoding="utf-8")
tree = ET.parse(self.filename, parser=parser)
root = tree.getroot()
for child in root.findall('./entry/text'):
location = child.text
entry = self.shell.props.db.entry_lookup_by_location(location)
if entry:
self.source_query_model.add_entry(entry, -1)
self.props.query_model = self.source_query_model
def clear_playsource(self, *args):
for row in self.get_entry_view().props.model:
self.get_entry_view().props.model.remove_entry(row[0])
def shuffle_playsource(self, *args):
self.get_entry_view().props.model.shuffle_entries()
self._save_model()
def save_changed_model(self, *args):
if self.save_in_progress:
self.save_interrupt = True
return
self.save_in_progress = True
Gdk.threads_add_timeout_seconds(GLib.PRIORITY_DEFAULT_IDLE, 1, self._save_model, None)
def _save_model(self, *args):
if self.save_interrupt:
self.save_interrupt = False
return True
root = ET.Element('root')
element = ET.SubElement(root, 'entry')
for row in self.source_query_model:
location = row[0].get_string(RB.RhythmDBPropType.LOCATION)
subelement = ET.SubElement(element, 'text')
subelement.text = location
tree = ET.ElementTree(root)
tree.write(self.filename)
self.save_in_progress = False
return False
GObject.type_register(CoverArtPlayEntryView)
+377
Ver Arquivo
@@ -0,0 +1,377 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import urllib.parse
import json
import os
import random
from gi.repository import RB
from gi.repository import Gtk
from coverart_utils import idle_iterator
import rb
LOAD_CHUNK = 50
class WebPlaylist(object):
MAX_TRACKS_TO_ADD = 3 # number of tracks to add to a source for each fetch
MIN_TRACKS_TO_FETCH = 5 # number of tracks in source before a fetch will be required
TOTAL_TRACKS_REMEMBERED = 25 # total number of tracks for all artists before a fetch is allowed
MAX_TRACKS_PER_ARTIST = 3 # number of tracks allowed to be remembered per artist
def __init__(self, shell, source, playlist_name):
self.shell = shell
# lets fill up the queue with artists
self.candidate_artist = {}
self.shell.props.shell_player.connect('playing-song-changed', self.playing_song_changed)
self.source = source
self.search_entry = None
self.playlist_started = False
self.played_artist = {}
self.tracks_not_played = 0
# cache for artist information: valid for a month, can be used indefinitely
# if offline, discarded if unused for six months
self.info_cache = rb.URLCache(name=playlist_name,
path=os.path.join('coverart_browser', playlist_name),
refresh=30,
discard=180)
self.info_cache.clean()
def playing_song_changed(self, player, entry):
if not entry:
return
if player.get_playing_source() != self.source:
self.playlist_started = False
self.played_artist.clear()
self.tracks_not_played = 0
if self.playlist_started and len(self.source.props.query_model) < self.MIN_TRACKS_TO_FETCH:
self.start(entry)
def start(self, seed_entry, reinitialise=False):
artist = seed_entry.get_string(RB.RhythmDBPropType.ARTIST)
if reinitialise:
self.played_artist.clear()
self.tracks_not_played = 0
self.playlist_started = False
player = self.shell.props.shell_player
_, is_playing = player.get_playing()
if is_playing:
player.stop()
for row in self.source.props.query_model:
self.source.props.query_model.remove_entry(row[0])
if self.tracks_not_played > self.TOTAL_TRACKS_REMEMBERED:
print(("we have plenty of tracks to play yet - no need to fetch more %d", self.tracks_not_played))
self.add_tracks_to_source()
return
search_artist = urllib.parse.quote(artist.encode("utf8"))
if search_artist in self.played_artist:
print("we have already searched for that artist")
return
self.search_entry = seed_entry
self.played_artist[search_artist] = True
self.playlist_started = True
self._running = False
self._start_process()
def _start_process(self):
if not self._running:
self._running = True
self.search_website()
def search_website(self):
pass
def _clear_next(self):
self.search_artists = ""
self._running = False
@idle_iterator
def _load_albums(self):
def process(row, data):
entry = data['model'][row.path][0]
lookup = entry.get_string(RB.RhythmDBPropType.ARTIST_FOLDED)
lookup_title = entry.get_string(RB.RhythmDBPropType.TITLE_FOLDED)
if lookup in self.artist and \
lookup_title in \
self.artist[lookup]:
if lookup not in self.candidate_artist:
self.candidate_artist[lookup] = []
# N.B. every artist has an array of dicts with a known format of track & add-to-source elements
# the following extracts the track-title and add-to-source to form a dict of track-title and a value
# of the add-to-source
d = dict((i['track-title'], i['add-to-source']) for i in self.candidate_artist[lookup])
if len(d) < self.MAX_TRACKS_PER_ARTIST and lookup_title not in d:
# we only append a max of three tracks to each artist
self.candidate_artist[lookup].append({
'track': entry,
'add-to-source': False,
'track-title': lookup_title})
self.tracks_not_played = self.tracks_not_played + 1
def after(data):
# update the progress
pass
def error(exception):
print(('Error processing entries: ' + str(exception)))
def finish(data):
self.add_tracks_to_source()
self._clear_next()
return LOAD_CHUNK, process, after, error, finish
def display_error_message(self):
dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO,
Gtk.ButtonsType.OK,
_("No matching tracks have been found"))
dialog.run()
dialog.destroy()
def add_tracks_to_source(self):
entries = []
for artist in self.candidate_artist:
d = dict((i['track'], (self.candidate_artist[artist].index(i),
i['add-to-source'],
artist)) for i in self.candidate_artist[artist])
for entry, elements in d.items():
element_pos, add_to_source, artist = elements
if not add_to_source:
entries.append({entry: elements})
random.shuffle(entries)
count = 0
for row in entries:
print(row)
entry, elements = list(row.items())[0]
element_pos, add_to_source, artist = elements
self.source.add_entry(entry, -1)
self.candidate_artist[artist][element_pos]['add-to-source'] = True
count = count + 1
self.tracks_not_played = self.tracks_not_played - 1
if count == self.MAX_TRACKS_TO_ADD:
break
player = self.shell.props.shell_player
_, is_playing = player.get_playing()
if len(self.source.props.query_model) > 0 and not is_playing:
player.play_entry(self.source.props.query_model[0][0], self.source)
class LastFMTrackPlaylist(WebPlaylist):
def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "lastfm_trackplaylist")
def search_website(self):
# unless already cached - directly fetch from lastfm similar track information
apikey = "844353bce568b93accd9ca47674d6c3e"
url = "http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&api_key={0}&artist={1}&track={2}&format=json"
artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST)
title = self.search_entry.get_string(RB.RhythmDBPropType.TITLE)
artist = urllib.parse.quote(artist.encode("utf8"))
title = urllib.parse.quote(title.encode("utf8"))
formatted_url = url.format(urllib.parse.quote(apikey),
artist,
title)
print(formatted_url)
cachekey = "artist:%s:title:%s" % (artist, title)
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _):
if not data:
print("nothing to do")
self.display_error_message()
self._clear_next()
return
similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned
self.artist = {}
if 'similartracks' not in similar:
print("No matching data returned from LastFM")
self.display_error_message()
self._clear_next()
return
for song in similar['similartracks']['track']:
name = RB.search_fold(song['artist']['name'])
if name not in self.artist:
self.artist[name] = []
self.artist[name].append(RB.search_fold(song['name']))
if len(self.artist) == 0:
print("no artists returned")
self._clear_next()
return
# loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.)
class EchoNestPlaylist(WebPlaylist):
def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "echonest_playlist")
def search_website(self):
# unless already cached - directly fetch from echonest similar artist information
apikey = "N685TONJGZSHBDZMP"
url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&artist={1}&format=json&results=100&type=artist-radio&limited_interactivity=true"
artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST)
artist = urllib.parse.quote(artist.encode("utf8"))
formatted_url = url.format(urllib.parse.quote(apikey),
artist)
print(formatted_url)
cachekey = "artist:%s" % artist
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _):
if not data:
print("nothing to do")
self.display_error_message()
self._clear_next()
return
similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned
self.artist = {}
if 'songs' not in similar['response']:
print("No matching data returned from EchoNest")
self.display_error_message()
self._clear_next()
return
for song in similar['response']['songs']:
name = RB.search_fold(song['artist_name'])
if name not in self.artist:
self.artist[name] = []
self.artist[name].append(RB.search_fold(song['title']))
if len(self.artist) == 0:
print("no artists returned")
self._clear_next()
return
# loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.)
class EchoNestGenrePlaylist(WebPlaylist):
def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "echonest_genre_playlist")
def search_website(self):
# unless already cached - directly fetch from echonest similar artist information
apikey = "N685TONJGZSHBDZMP"
url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&genre={1}&format=json&results=100&type=genre-radio&limited_interactivity=true"
genre = self.search_entry.get_string(RB.RhythmDBPropType.GENRE).lower()
genre = urllib.parse.quote(genre.encode("utf8"))
formatted_url = url.format(urllib.parse.quote(apikey),
genre)
print(formatted_url)
cachekey = "genre:%s" % genre
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _):
if not data:
print("nothing to do")
self.display_error_message()
self._clear_next()
return
similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned
self.artist = {}
if 'songs' not in similar['response']:
print("No matching data returned from EchoNest")
self.display_error_message()
self._clear_next()
return
for song in similar['response']['songs']:
name = RB.search_fold(song['artist_name'])
if name not in self.artist:
self.artist[name] = []
self.artist[name].append(RB.search_fold(song['title']))
if len(self.artist) == 0:
print("no artists returned")
self._clear_next()
return
# loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.)
+80
Ver Arquivo
@@ -0,0 +1,80 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import GObject
from gi.repository import GLib
from coverart_widgets import AbstractView
class PlaySourceShowingPolicy(GObject.Object):
'''
Policy that mostly takes care of how and when things should be showed on
the view that makes use of the `AlbumsModel`.
'''
def __init__(self, list_view):
super(PlaySourceShowingPolicy, self).__init__()
self.counter = 0
self._has_initialised = False
def initialise(self, album_manager):
if self._has_initialised:
return
self._has_initialised = True
class PlaySourceView(AbstractView):
__gtype_name__ = "PlaySourceView"
name = 'playsourceview'
use_plugin_window = False
def __init__(self):
super(PlaySourceView, self).__init__()
self.view = self
self._has_initialised = False
self.show_policy = PlaySourceShowingPolicy(self)
def initialise(self, source):
if self._has_initialised:
return
self._has_initialised = True
self.view_name = "playsource_view"
super(PlaySourceView, self).initialise(source)
# self.album_manager = source.album_manager
self.shell = source.shell
def switch_to_view(self, source, album):
self.initialise(source)
GLib.idle_add(self.shell.props.display_page_tree.select,
source.plugin.playlist_source)
def get_selected_objects(self):
'''
finds what has been selected
returns an array of `Album`
'''
return []
+80
Ver Arquivo
@@ -0,0 +1,80 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import GObject
from gi.repository import GLib
from coverart_widgets import AbstractView
class QueueShowingPolicy(GObject.Object):
'''
Policy that mostly takes care of how and when things should be showed on
the view that makes use of the `AlbumsModel`.
'''
def __init__(self, list_view):
super(QueueShowingPolicy, self).__init__()
self.counter = 0
self._has_initialised = False
def initialise(self, album_manager):
if self._has_initialised:
return
self._has_initialised = True
class QueueView(AbstractView):
__gtype_name__ = "QueueView"
name = 'queueview'
use_plugin_window = False
def __init__(self):
super(QueueView, self).__init__()
self.view = self
self._has_initialised = False
self.show_policy = QueueShowingPolicy(self)
def initialise(self, source):
if self._has_initialised:
return
self._has_initialised = True
self.view_name = "queue_view"
super(QueueView, self).initialise(source)
# self.album_manager = source.album_manager
self.shell = source.shell
def switch_to_view(self, source, album):
self.initialise(source)
GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.queue_source)
def get_selected_objects(self):
'''
finds what has been selected
returns an array of `Album`
'''
return []
+887
Ver Arquivo
@@ -0,0 +1,887 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# IMPORTANT - WHILST THIS MODULE IS USED BY SEVERAL OTHER PLUGINS
# THE MASTER AND MOST UP-TO-DATE IS FOUND IN THE COVERART BROWSER
# PLUGIN - https://github.com/fossfreedom/coverart-browser
# PLEASE SUBMIT CHANGES BACK TO HELP EXPAND THIS API
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import sys
import xml.etree.ElementTree as ET
from gi.repository import Gtk
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import RB
import rb
def gtk_version():
'''
returns float of the major and minor parts of the GTK version
e.g. return float(3.10)
'''
return float(str(Gtk.get_major_version())+"."+str(Gtk.get_minor_version()))
def pygobject_version():
'''
returns float of the major and minor parts of a pygobject version
e.g. version (3, 9, 5) return float(3.9)
'''
to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version)
return float(str_version.rsplit('.', 1)[0])
def compare_pygobject_version(version):
'''
return True if version is less than pygobject_version
i.e. 3.9 < 3.11
'''
to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version)
split = str_version.rsplit('.', 2)
split_compare = version.rsplit('.', 2)
if int(split_compare[0]) < int(split[0]):
return True
if int(split_compare[1]) < int(split[1]):
return True
return False
PYVER = sys.version_info[0]
if PYVER >= 3:
import urllib.request, urllib.parse, urllib.error
else:
import urllib
from urlparse import urlparse as rb2urlparse
if PYVER >= 3:
import http.client
else:
import httplib
def responses():
if PYVER >= 3:
return http.client.responses
else:
return httplib.responses
def unicodestr(param, charset):
if PYVER >= 3:
return param # str(param, charset)
else:
return unicode(param, charset)
def unicodeencode(param, charset):
if PYVER >= 3:
return param # str(param).encode(charset)
else:
return unicode(param).encode(charset)
def unicodedecode(param, charset):
if PYVER >= 3:
return param
else:
return param.decode(charset)
def urlparse(uri):
if PYVER >= 3:
return urllib.parse.urlparse(uri)
else:
return rb2urlparse(uri)
def url2pathname(url):
if PYVER >= 3:
return urllib.request.url2pathname(url)
else:
return urllib.url2pathname(url)
def urlopen(filename):
if PYVER >= 3:
return urllib.request.urlopen(filename)
else:
return urllib.urlopen(filename)
def pathname2url(filename):
if PYVER >= 3:
return urllib.request.pathname2url(filename)
else:
return urllib.pathname2url(filename)
def unquote(uri):
if PYVER >= 3:
return urllib.parse.unquote(uri)
else:
return urllib.unquote(uri)
def quote(uri, safe=None):
if PYVER >= 3:
if safe:
return urllib.parse.quote(uri, safe=safe)
else:
return urllib.parse.quote(uri)
else:
if safe:
return urllib.quote(uri, safe=safe)
else:
return urllib.quote(uri)
def quote_plus(uri):
if PYVER >= 3:
return urllib.parse.quote_plus(uri)
else:
return urllib.quote_plus(uri)
def is_rb3(*args):
if hasattr(RB.Shell.props, 'ui_manager'):
return False
else:
return True
class Menu(GObject.Object):
'''
Menu object used to create window popup menus
'''
__gsignals__ = {
'pre-popup': (GObject.SIGNAL_RUN_LAST, None, ())
}
def __init__(self, plugin, shell):
'''
Initializes the menu.
'''
super(Menu, self).__init__()
self.plugin = plugin
self.shell = shell
self._unique_num = 0
self._rbmenu_items = {}
self._rbmenu_objects = {}
def add_menu_item(self, menubar, section_name, action):
'''
add a new menu item to the popup
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param section_name: `str` is the name of the section to add the item to (RB2.99+)
:param action: `Action` to associate with the menu item
'''
return self.insert_menu_item(menubar, section_name, -1, action)
def insert_menu_item(self, menubar, section_name, position, action):
'''
add a new menu item to the popup
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param section_name: `str` is the name of the section to add the item to (RB2.99+)
:param position: `int` position to add to GtkMenu (ignored for RB2.99+)
:param action: `Action` to associate with the menu item
'''
label = action.label
if is_rb3(self.shell):
app = self.shell.props.application
item = Gio.MenuItem()
action.associate_menuitem(item)
item.set_label(label)
if not section_name in self._rbmenu_items:
self._rbmenu_items[section_name] = []
self._rbmenu_items[section_name].append(label)
app.add_plugin_menu_item(section_name, label, item)
else:
item = Gtk.MenuItem(label=label)
action.associate_menuitem(item)
self._rbmenu_items[label] = item
bar = self.get_menu_object(menubar)
if position == -1:
bar.append(item)
else:
bar.insert(item, position)
bar.show_all()
uim = self.shell.props.ui_manager
uim.ensure_update()
return item
def insert_separator(self, menubar, at_position):
'''
add a separator to the popup (only required for RB2.98 and earlier)
:param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
:param position: `int` position to add to GtkMenu (ignored for RB2.99+)
'''
if not is_rb3(self.shell):
menu_item = Gtk.SeparatorMenuItem().new()
menu_item.set_visible(True)
self._rbmenu_items['separator' + str(self._unique_num)] = menu_item
self._unique_num = self._unique_num + 1
bar = self.get_menu_object(menubar)
bar.insert(menu_item, at_position)
bar.show_all()
uim = self.shell.props.ui_manager
uim.ensure_update()
def remove_menu_items(self, menubar, section_name):
'''
utility function to remove all menuitems associated with the menu section
:param menubar: `str` is the name of the GtkMenu containing the menu items (ignored for RB2.99+)
:param section_name: `str` is the name of the section containing the menu items (for RB2.99+ only)
'''
if is_rb3(self.shell):
if not section_name in self._rbmenu_items:
return
app = self.shell.props.application
for menu_item in self._rbmenu_items[section_name]:
app.remove_plugin_menu_item(section_name, menu_item)
if self._rbmenu_items[section_name]:
del self._rbmenu_items[section_name][:]
else:
if not self._rbmenu_items:
return
uim = self.shell.props.ui_manager
bar = self.get_menu_object(menubar)
for menu_item in self._rbmenu_items:
bar.remove(self._rbmenu_items[menu_item])
bar.show_all()
uim.ensure_update()
def load_from_file(self, rb2_ui_filename, rb3_ui_filename):
'''
utility function to load the menu structure
:param rb2_ui_filename: `str` RB2.98 and below UI file
:param rb3_ui_filename: `str` RB2.99 and higher UI file
'''
self.builder = Gtk.Builder()
try:
from coverart_browser_prefs import CoverLocale
cl = CoverLocale()
self.builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
except:
pass
if is_rb3(self.shell):
ui_filename = rb3_ui_filename
else:
ui_filename = rb2_ui_filename
self.ui_filename = ui_filename
self.builder.add_from_file(rb.find_plugin_file(self.plugin,
ui_filename))
def _connect_rb3_signals(self, signals):
def _menu_connect(action_name, func):
action = Gio.SimpleAction(name=action_name)
action.connect('activate', func)
action.set_enabled(True)
self.shell.props.window.add_action(action)
for key, value in signals.items():
_menu_connect(key, value)
def _connect_rb2_signals(self, signals):
def _menu_connect(menu_item_name, func):
menu_item = self.get_menu_object(menu_item_name)
menu_item.connect('activate', func)
for key, value in signals.items():
_menu_connect(key, value)
def connect_signals(self, signals):
'''
connect all signal handlers with their menuitem counterparts
:param signals: `dict` key is the name of the menuitem
and value is the function callback when the menu is activated
'''
if is_rb3(self.shell):
self._connect_rb3_signals(signals)
else:
self._connect_rb2_signals(signals)
def get_gtkmenu(self, source, popup_name):
'''
utility function to obtain the GtkMenu from the menu UI file
:param popup_name: `str` is the name menu-id in the UI file
'''
if popup_name in self._rbmenu_objects:
return self._rbmenu_objects[popup_name]
item = self.builder.get_object(popup_name)
if is_rb3(self.shell):
app = self.shell.props.application
app.link_shared_menus(item)
popup_menu = Gtk.Menu.new_from_model(item)
popup_menu.attach_to_widget(source, None)
else:
popup_menu = item
self._rbmenu_objects[popup_name] = popup_menu
return popup_menu
def get_menu_object(self, menu_name_or_link):
'''
utility function returns the GtkMenuItem/Gio.MenuItem
:param menu_name_or_link: `str` to search for in the UI file
'''
if menu_name_or_link in self._rbmenu_objects:
return self._rbmenu_objects[menu_name_or_link]
item = self.builder.get_object(menu_name_or_link)
if is_rb3(self.shell):
if item:
popup_menu = item
else:
app = self.shell.props.application
popup_menu = app.get_plugin_menu(menu_name_or_link)
else:
popup_menu = item
print(menu_name_or_link)
self._rbmenu_objects[menu_name_or_link] = popup_menu
return popup_menu
def set_sensitive(self, menu_or_action_item, enable):
'''
utility function to enable/disable a menu-item
:param menu_or_action_item: `GtkMenuItem` or `Gio.SimpleAction`
that is to be enabled/disabled
:param enable: `bool` value to enable/disable
'''
if is_rb3(self.shell):
item = self.shell.props.window.lookup_action(menu_or_action_item)
item.set_enabled(enable)
else:
item = self.get_menu_object(menu_or_action_item)
item.set_sensitive(enable)
def popup(self, source, menu_name, button, time):
'''
utility function to show the popup menu
'''
self.emit('pre-popup')
menu = self.get_gtkmenu(source, menu_name)
menu.popup(None, None, None, None, button, time)
class ActionGroup(object):
'''
container for all Actions used to associate with menu items
'''
# action_state
STANDARD = 0
TOGGLE = 1
def __init__(self, shell, group_name):
'''
constructor
:param shell: `RBShell`
:param group_name: `str` unique name for the object to create
'''
self.group_name = group_name
self.shell = shell
self._actions = {}
if is_rb3(self.shell):
self.actiongroup = Gio.SimpleActionGroup()
else:
self.actiongroup = Gtk.ActionGroup(group_name)
uim = self.shell.props.ui_manager
uim.insert_action_group(self.actiongroup)
@property
def name(self):
return self.group_name
def remove_actions(self):
'''
utility function to remove all actions associated with the ActionGroup
'''
for action in self.actiongroup.list_actions():
self.actiongroup.remove_action(action)
def get_action(self, action_name):
'''
utility function to obtain the Action from the ActionGroup
:param action_name: `str` is the Action unique name
'''
return self._actions[action_name]
def add_action_with_accel(self, func, action_name, accel, **args):
'''
Creates an Action with an accelerator and adds it to the ActionGroup
:param func: function callback used when user activates the action
:param action_name: `str` unique name to associate with an action
:param accel: `str` accelerator
:param args: dict of arguments - this is passed to the function callback
Notes:
see notes for add_action
'''
args['accel'] = accel
return self.add_action(func, action_name, **args)
def add_action(self, func, action_name, **args):
'''
Creates an Action and adds it to the ActionGroup
:param func: function callback used when user activates the action
:param action_name: `str` unique name to associate with an action
:param args: dict of arguments - this is passed to the function callback
Notes:
key value of "label" is the visual menu label to display
key value of "action_type" is the RB2.99 Gio.Action type ("win" or "app")
by default it assumes all actions are "win" type
key value of "action_state" determines what action state to create
'''
if 'label' in args:
label = args['label']
else:
label = action_name
if 'accel' in args:
accel = args['accel']
else:
accel = None
state = ActionGroup.STANDARD
if 'action_state' in args:
state = args['action_state']
if is_rb3(self.shell):
if state == ActionGroup.TOGGLE:
action = Gio.SimpleAction.new_stateful(action_name, None,
GLib.Variant('b', False))
else:
action = Gio.SimpleAction.new(action_name, None)
action_type = 'win'
if 'action_type' in args:
if args['action_type'] == 'app':
action_type = 'app'
app = Gio.Application.get_default()
if action_type == 'app':
app.add_action(action)
else:
self.shell.props.window.add_action(action)
self.actiongroup.add_action(action)
if accel:
app.add_accelerator(accel, action_type + "." + action_name, None)
else:
if 'stock_id' in args:
stock_id = args['stock_id']
else:
stock_id = Gtk.STOCK_CLEAR
if state == ActionGroup.TOGGLE:
action = Gtk.ToggleAction(label=label,
name=action_name,
tooltip='', stock_id=stock_id)
else:
action = Gtk.Action(label=label,
name=action_name,
tooltip='', stock_id=stock_id)
if accel:
self.actiongroup.add_action_with_accel(action, accel)
else:
self.actiongroup.add_action(action)
act = Action(self.shell, action)
act.connect('activate', func, args)
act.label = label
act.accel = accel
self._actions[action_name] = act
return act
class ApplicationShell(object):
'''
Unique class that mirrors RB.Application & RB.Shell menu functionality
'''
# storage for the instance reference
__instance = None
class __impl:
""" Implementation of the singleton interface """
def __init__(self, shell):
self.shell = shell
if is_rb3(self.shell):
self._uids = {}
else:
self._uids = []
self._action_groups = {}
def insert_action_group(self, action_group):
'''
Adds an ActionGroup to the ApplicationShell
:param action_group: `ActionGroup` to add
'''
self._action_groups[action_group.name] = action_group
def lookup_action(self, action_group_name, action_name, action_type='app'):
'''
looks up (finds) an action created by another plugin. If found returns
an Action or None if no matching Action.
:param action_group_name: `str` is the Gtk.ActionGroup name (ignored for RB2.99+)
:param action_name: `str` unique name for the action to look for
:param action_type: `str` RB2.99+ action type ("win" or "app")
'''
if is_rb3(self.shell):
if action_type == "app":
action = self.shell.props.application.lookup_action(action_name)
else:
action = self.shell.props.window.lookup_action(action_name)
else:
uim = self.shell.props.ui_manager
ui_actiongroups = uim.get_action_groups()
actiongroup = None
for actiongroup in ui_actiongroups:
if actiongroup.get_name() == action_group_name:
break
action = None
if actiongroup:
action = actiongroup.get_action(action_name)
if action:
return Action(self.shell, action)
else:
return None
def add_app_menuitems(self, ui_string, group_name, menu='tools'):
'''
utility function to add application menu items.
For RB2.99 all application menu items are added to the "tools" section of the
application menu. All Actions are assumed to be of action_type "app".
For RB2.98 or less, it is added however the UI_MANAGER string
is defined.
:param ui_string: `str` is the Gtk UI definition. There is not an
equivalent UI definition in RB2.99 but we can parse out menu items since
this string is in XML format
:param group_name: `str` unique name of the ActionGroup to add menu items to
:param menu: `str` RB2.99 menu section to add to - nominally either
'tools' or 'view'
'''
if is_rb3(self.shell):
root = ET.fromstring(ui_string)
for elem in root.findall(".//menuitem"):
action_name = elem.attrib['action']
item_name = elem.attrib['name']
group = self._action_groups[group_name]
act = group.get_action(action_name)
item = Gio.MenuItem()
item.set_detailed_action('app.' + action_name)
item.set_label(act.label)
item.set_attribute_value("accel", GLib.Variant("s", act.accel))
app = Gio.Application.get_default()
index = menu + action_name
app.add_plugin_menu_item(menu,
index, item)
self._uids[index] = menu
else:
uim = self.shell.props.ui_manager
self._uids.append(uim.add_ui_from_string(ui_string))
uim.ensure_update()
def add_browser_menuitems(self, ui_string, group_name):
'''
utility function to add popup menu items to existing browser popups
For RB2.99 all menu items are are assumed to be of action_type "win".
For RB2.98 or less, it is added however the UI_MANAGER string
is defined.
:param ui_string: `str` is the Gtk UI definition. There is not an
equivalent UI definition in RB2.99 but we can parse out menu items since
this string is in XML format
:param group_name: `str` unique name of the ActionGroup to add menu items to
'''
if is_rb3(self.shell):
root = ET.fromstring(ui_string)
for elem in root.findall("./popup"):
popup_name = elem.attrib['name']
menuelem = elem.find('.//menuitem')
action_name = menuelem.attrib['action']
item_name = menuelem.attrib['name']
group = self._action_groups[group_name]
act = group.get_action(action_name)
item = Gio.MenuItem()
item.set_detailed_action('win.' + action_name)
item.set_label(act.label)
app = Gio.Application.get_default()
if popup_name == 'QueuePlaylistViewPopup':
plugin_type = 'queue-popup'
elif popup_name == 'BrowserSourceViewPopup':
plugin_type = 'browser-popup'
elif popup_name == 'PlaylistViewPopup':
plugin_type = 'playlist-popup'
elif popup_name == 'PodcastViewPopup':
plugin_type = 'podcast-episode-popup'
else:
print("unknown type %s" % plugin_type)
index = plugin_type + action_name
app.add_plugin_menu_item(plugin_type, index, item)
self._uids[index] = plugin_type
else:
uim = self.shell.props.ui_manager
self._uids.append(uim.add_ui_from_string(ui_string))
uim.ensure_update()
def cleanup(self):
'''
utility remove any menuitems created.
'''
if is_rb3(self.shell):
for uid in self._uids:
Gio.Application.get_default().remove_plugin_menu_item(self._uids[uid],
uid)
else:
uim = self.shell.props.ui_manager
for uid in self._uids:
uim.remove_ui(uid)
uim.ensure_update();
def __init__(self, shell):
""" Create singleton instance """
# Check whether we already have an instance
if ApplicationShell.__instance is None:
# Create and remember instance
ApplicationShell.__instance = ApplicationShell.__impl(shell)
# Store instance reference as the only member in the handle
self.__dict__['_ApplicationShell__instance'] = ApplicationShell.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
class Action(object):
'''
class that wraps around either a Gio.Action or a Gtk.Action
'''
def __init__(self, shell, action):
'''
constructor.
:param shell: `RBShell`
:param action: `Gio.Action` or `Gtk.Action`
'''
self.shell = shell
self.action = action
self._label = ''
self._accel = ''
self._current_state = False
self._do_update_state = True
def connect(self, address, func, args):
self._connect_func = func
self._connect_args = args
if address == 'activate':
func = self._activate
if is_rb3(self.shell):
self.action.connect(address, func, args)
else:
self.action.connect(address, func, None, args)
def _activate(self, action, *args):
if self._do_update_state:
self._current_state = not self._current_state
self.set_state(self._current_state)
self._connect_func(action, None, self._connect_args)
@property
def label(self):
'''
get the menu label associated with the Action
for RB2.99+ actions dont have menu labels so this is managed
manually
'''
if not is_rb3(self.shell):
return self.action.get_label()
else:
return self._label
@label.setter
def label(self, new_label):
if not is_rb3(self.shell):
self.action.set_label(new_label)
self._label = new_label
@property
def accel(self):
'''
get the accelerator associated with the Action
'''
return self._accel
@accel.setter
def accel(self, new_accelerator):
if new_accelerator:
self._accel = new_accelerator
else:
self._accel = ''
def get_sensitive(self):
'''
get the sensitivity (enabled/disabled) state of the Action
returns boolean
'''
if is_rb3(self.shell):
return self.action.get_enabled()
else:
return self.action.get_sensitive()
def set_state(self, value):
'''
set the state of a stateful action - this is applicable only
to RB2.99+
'''
if is_rb3(self.shell) and self.action.props.state_type:
self.action.change_state(GLib.Variant('b', value))
def activate(self):
'''
invokes the activate signal for the action
'''
if is_rb3(self.shell):
self.action.activate(None)
else:
self.action.activate()
def set_active(self, value):
'''
activate or deactivate a stateful action signal
For consistency with earlier RB versions, this will fire the
activate signal for the action
:param value: `boolean` state value
'''
if is_rb3(self.shell):
self.action.change_state(GLib.Variant('b', value))
self._current_state = value
self._do_update_state = False
self.activate()
self._do_update_state = True
else:
self.action.set_active(value)
def get_active(self):
'''
get the state of the action
returns `boolean` state value
'''
if is_rb3(self.shell):
returnval = self._current_state
else:
returnval = self.action.get_active()
return returnval
def associate_menuitem(self, menuitem):
'''
links a menu with the action
'''
if is_rb3(self.shell):
menuitem.set_detailed_action('win.' + self.action.get_name())
else:
menuitem.set_related_action(self.action)
+188
Ver Arquivo
@@ -0,0 +1,188 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
# Based on Rupesh Kumar's and Luqman Aden'a AlbumArtSearch plugin
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import Gtk
from mako.template import Template
import rb
import coverart_rb3compat as rb3compat
from coverart_album import Album
from coverart_browser_prefs import webkit_support
class CoverSearchPane(Gtk.Box):
'''
This UI represents a pane where different covers can be presented
given an album or artist to look for. It also allows to make custom image searchs,
customize the default search and select covers from the pane and use them
as the covers (either with a double click or dragging them).
'''
def __init__(self, plugin, selection_color):
'''
Initializes the pane, loading it's html templates and it's ui.
'''
super(CoverSearchPane, self).__init__()
self.set_orientation(Gtk.Orientation.VERTICAL)
self.selection_color = selection_color
self.file = ""
self.basepath = 'file://' + plugin.plugin_info.get_data_dir()
self.load_templates(plugin)
if webkit_support():
self.init_gui()
# init the pane with the empty template
self.clear()
def load_templates(self, plugin):
'''
Loads the templates and stylesheets to be used by the pane.
'''
# input_encoding='utf-8',
path = rb.find_plugin_file(plugin,
'tmpl/albumartsearch-tmpl.html')
self.template = Template(filename=path,
default_filters=['decode.utf8'],
module_directory='/tmp/',
encoding_errors='replace')
path = rb.find_plugin_file(plugin,
'tmpl/albumartsearchempty-tmpl.html')
self.empty_template = Template(filename=path,
default_filters=['decode.utf8'],
module_directory='/tmp/',
encoding_errors='replace')
path = rb.find_plugin_file(plugin,
'tmpl/artistartsearch-tmpl.html')
self.artist_template = Template(filename=path,
default_filters=['decode.utf8'],
module_directory='/tmp/',
encoding_errors='replace')
self.styles = rb.find_plugin_file(plugin, 'tmpl/main.css')
def init_gui(self):
'''
Initializes the pane ui.
'''
# ---- set up webkit pane -----#
from gi.repository import WebKit
self.webview = WebKit.WebView()
settings = self.webview.get_settings()
settings.set_property('enable-default-context-menu', False)
self.webview.set_settings(settings)
scroll = Gtk.ScrolledWindow()
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
scroll.add(self.webview)
self.pack_start(scroll, expand=True, fill=True, padding=0)
self.show_all()
# connect the title changed signal
self.webview.connect('notify::title', self.set_cover)
def do_search(self, coverobject, callback):
'''
When this method is called, the webview gets refreshed with the info
of the album or artist passed.
'''
print("coverart-search do_search")
if coverobject is self.current_searchobject:
return
self.current_searchobject = coverobject
self.callback = callback
if isinstance(coverobject, Album):
artist = coverobject.artist
album_name = coverobject.name
if album_name.upper() == "UNKNOWN":
album_name = ""
if artist.upper() == "UNKNOWN":
artist = ""
if not (album_name == "" and artist == ""):
artist = rb3compat.unicodestr(artist.replace('&', '&amp;'),
'utf-8')
album_name = rb3compat.unicodestr(album_name.replace('&', '&amp;'), 'utf-8')
self.render_album_art_search(artist, album_name)
else:
artist_name = coverobject.name
if artist_name.upper() == "UNKNOWN":
artist_name = ""
if not (artist_name == ""):
artist = rb3compat.unicodestr(artist_name.replace('&', '&amp;'),
'utf-8')
self.render_artist_art_search(artist)
def render_album_art_search(self, artist, album_name):
'''
Renders the template on the webview.
'''
temp_file = self.template.render(artist=artist, album=album_name,
stylesheet=self.styles, selection_color=self.selection_color)
print("here")
self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath)
def render_artist_art_search(self, artist):
'''
Renders the template on the webview.
'''
temp_file = self.artist_template.render(artist=artist,
stylesheet=self.styles, selection_color=self.selection_color)
print("here")
self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath)
def clear(self):
'''
Clears the webview of any specific info/covers.
'''
self.current_searchobject = None
temp_file = self.empty_template.render(stylesheet=self.styles)
self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath)
def set_cover(self, webview, arg):
'''
Callback called when a image in the pane is double-clicked. It takes
care of updating the searched object cover.
Some titles have spurious characters beginning with % - remove these
'''
# update the cover
title = webview.get_title()
print(title)
if title:
# self.album_manager.cover_man.update_cover(self.current_searchobject,
# uri=title)
self.callback(self.current_searchobject, uri=title)
+263
Ver Arquivo
@@ -0,0 +1,263 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2012 - fossfreedom
# Copyright (C) 2012 - Agustin Carrasco
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import RB
from gi.repository import Gio
from coverart_browser_prefs import GSetting
from coverart_browser_prefs import CoverLocale
from coverart_utils import Theme
from coverart_controllers import PlaylistPopupController
from coverart_controllers import GenrePopupController
from coverart_controllers import SortPopupController
from coverart_controllers import ArtistSortPopupController
from coverart_controllers import PropertiesMenuController
from coverart_controllers import DecadePopupController
from coverart_controllers import SortOrderToggleController
from coverart_controllers import ArtistSortOrderToggleController
from coverart_controllers import AlbumSearchEntryController
from coverart_widgets import SearchEntry
from coverart_browser_prefs import webkit_support
import rb
class Toolbar(GObject.Object):
def __init__(self, plugin, mainbox, controllers):
super(Toolbar, self).__init__()
self.plugin = plugin
self.mainbox = mainbox
cl = CoverLocale()
ui_file = rb.find_plugin_file(plugin, self.ui)
# create the toolbar
builder = Gtk.Builder()
builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
print (ui_file)
builder.add_from_file(ui_file)
# assign the controllers to the buttons
for button, controller in controllers.items():
if button != 'search':
builder.get_object(button).controller = controller
if not webkit_support():
# button = builder.get_object('flowview_button')
#button.set_visible(False)
separator = builder.get_object('properties_separator')
if separator:
separator.set_visible(False)
# workaround to translate the search entry tooltips
cl.switch_locale(cl.Locale.RB)
search_entry = SearchEntry(has_popup=True)
search_entry.show_all()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
# add it to the ui
align = builder.get_object('entry_search_alignment')
align.add(search_entry)
# assign the controller
search_entry.controller = controllers['search']
Theme(self.plugin).connect('theme_changed', self._theme_changed,
controllers)
self.builder = builder.get_object('toolbar')
# now theme the toolbar including child objects such as the button popups
style_context = self.builder.get_style_context()
style_context.add_class(Gtk.STYLE_CLASS_TOOLBAR)
view_button = builder.get_object(ToolbarObject.VIEW)
view_button.set_visible(not self.plugin.using_headerbar)
def _theme_changed(self, toolbar, controllers):
for controller in list(controllers.values()):
controller.update_images(True)
class TopToolbar(Toolbar):
ui = 'ui/coverart_topbar.ui'
name = 'main'
def hide(self):
if self.builder.get_visible():
self.builder.hide()
def show(self):
self.mainbox.pack_start(self.builder, False, True, 0)
self.mainbox.reorder_child(self.builder, 0)
self.builder.show()
class LeftToolbar(Toolbar):
ui = 'ui/coverart_leftsidebar.ui'
name = 'left'
def hide(self):
if self.builder.get_visible():
self.builder.hide()
self.plugin.shell.remove_widget(self.builder,
RB.ShellUILocation.SIDEBAR)
def show(self):
self.plugin.shell.add_widget(self.builder,
RB.ShellUILocation.SIDEBAR, expand=False, fill=False)
self.builder.show()
class RightToolbar(Toolbar):
ui = 'ui/coverart_rightsidebar.ui'
name = 'right'
def hide(self):
if self.builder.get_visible():
self.builder.hide()
self.plugin.shell.remove_widget(self.builder,
RB.ShellUILocation.RIGHT_SIDEBAR)
def show(self):
self.plugin.shell.add_widget(self.builder,
RB.ShellUILocation.RIGHT_SIDEBAR, expand=False, fill=False)
self.builder.show()
class ToolbarObject(object):
# properties
PROPERTIES = 'properties_button'
SORT_BY = 'sort_by'
SORT_ORDER = 'sort_order'
SORT_BY_ARTIST = 'sort_by_artist'
SORT_ORDER_ARTIST = 'sort_order_artist'
GENRE = 'genre_button'
PLAYLIST = 'playlist_button'
DECADE = 'decade_button'
SEARCH = 'search'
VIEW = 'view_button'
class ToolbarManager(GObject.Object):
# properties
toolbar_pos = GObject.property(type=str, default=TopToolbar.name)
def __init__(self, plugin, main_box, viewmgr):
super(ToolbarManager, self).__init__()
self.plugin = plugin
# create the buttons controllers
controllers = self._create_controllers(plugin, viewmgr)
# initialize toolbars
self._bars = {}
self._bars[TopToolbar.name] = TopToolbar(plugin, main_box,
controllers)
self._bars[LeftToolbar.name] = LeftToolbar(plugin, main_box,
controllers)
self._bars[RightToolbar.name] = RightToolbar(plugin, main_box,
controllers)
self.last_toolbar_pos = None
# if the alternative-toolbar is loaded then lets connect to the toolbar-visibility signal
# to control our sources toolbar visibility
if self.plugin.using_alternative_toolbar:
if self.plugin.using_headerbar:
self.toolbar_pos = TopToolbar.name # we dont allow other toolbar position with headerbar
self._on_notify_toolbar_pos()
self.plugin.shell.alternative_toolbar.connect('toolbar-visibility', self._visibility)
# connect signal and properties
self._connect_signals()
self._connect_properties()
self._controllers = controllers
def _visibility(self, altplugin, value):
if value:
self._bars[self.toolbar_pos].show()
else:
self._bars[self.toolbar_pos].hide()
def set_enabled(self, enabled, toolbar_object=None):
'''
enable or disable the toolbar object.
:param enabled: `bool` value.
:param toolbar_object: `ToolbarObject`
None if enabled is to apply to all objects in the toolbar
'''
if toolbar_object:
self._controllers[toolbar_object].enabled = enabled
else:
for controller in self._controllers:
self._controllers[controller].enabled = enabled
def _connect_signals(self):
if not self.plugin.using_headerbar:
self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
def _connect_properties(self):
if not self.plugin.using_headerbar:
gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
Gio.SettingsBindFlags.GET)
def _create_controllers(self, plugin, viewmgr):
controllers = {}
album_model = viewmgr.source.album_manager.model
controllers[ToolbarObject.PROPERTIES] = \
PropertiesMenuController(plugin, viewmgr.source)
controllers[ToolbarObject.SORT_BY] = \
SortPopupController(plugin, viewmgr)
controllers[ToolbarObject.SORT_ORDER] = \
SortOrderToggleController(plugin, viewmgr)
controllers[ToolbarObject.SORT_BY_ARTIST] = \
ArtistSortPopupController(plugin, viewmgr)
controllers[ToolbarObject.SORT_ORDER_ARTIST] = \
ArtistSortOrderToggleController(plugin, viewmgr)
controllers[ToolbarObject.GENRE] = \
GenrePopupController(plugin, album_model)
controllers[ToolbarObject.PLAYLIST] = \
PlaylistPopupController(plugin, album_model)
controllers[ToolbarObject.DECADE] = \
DecadePopupController(plugin, album_model)
controllers[ToolbarObject.SEARCH] = \
AlbumSearchEntryController(album_model)
controllers[ToolbarObject.VIEW] = viewmgr.controller
return controllers
def _on_notify_toolbar_pos(self, *args):
if self.last_toolbar_pos:
self._bars[self.last_toolbar_pos].hide()
self._bars[self.toolbar_pos].show()
self.last_toolbar_pos = self.toolbar_pos
+838
Ver Arquivo
@@ -0,0 +1,838 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from bisect import bisect_left, bisect_right
import collections
import re
import logging
import sys
from collections import namedtuple
from gi.repository import GdkPixbuf
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import RB
from gi.repository import GObject
from gi.repository import Gio
import lxml.etree as ET
import rb
from coverart_browser_prefs import CoverLocale
from coverart_browser_prefs import GSetting
import coverart_rb3compat as rb3compat
from coverart_search_providers import lastfm_connected
from coverart_search_providers import get_search_providers
class FauxTb(object):
def __init__(self, tb_frame, tb_lineno, tb_next):
self.tb_frame = tb_frame
self.tb_lineno = tb_lineno
self.tb_next = tb_next
def current_stack(skip=0):
try:
1 / 0
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame
for i in range(skip + 2):
f = f.f_back
lst = []
while f is not None:
lst.append((f, f.f_lineno))
f = f.f_back
return lst
def extend_traceback(tb, stack):
"""Extend traceback with stack info."""
head = tb
for tb_frame, tb_lineno in stack:
head = FauxTb(tb_frame, tb_lineno, head)
return head
def full_exc_info():
"""Like sys.exc_info, but includes the full traceback."""
t, v, tb = sys.exc_info()
full_tb = extend_traceback(tb, current_stack(1))
return t, v, full_tb
def dumpstack(message):
''' dumps the current stack - useful of debugging
'''
logging.error(message, exc_info=full_exc_info())
def uniquify_and_sort(iterable):
''' Removes duplicates of an iterables and returns a list of unique
elements.
'''
uniques = []
for element in iterable:
if element not in uniques:
uniques.append(element)
return sorted(uniques)
GenreType = namedtuple("GenreType", ["name", "genre_type"])
class NaturalString(str):
'''
this class implements an object that can naturally compare
strings
i.e. "15 album" < "100 album"
'''
def __init__(self, string):
super(NaturalString, self).__init__()
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)',
key)]
self._string_elements = alphanum_key(string)
def __lt__(self, other):
if type(other) is str:
return super(NaturalString, self).__lt__(other)
else:
return self._string_elements < other._string_elements
def __le__(self, other):
if type(other) is str:
return super(NaturalString, self).__le__(other)
else:
return self._string_elements <= other._string_elements
def __gt__(self, other):
if type(other) is str:
return super(NaturalString, self).__gt__(other)
else:
return self._string_elements > other._string_elements
def __ge__(self, other):
if type(other) is str:
return super(NaturalString, self).__ge__(other)
else:
return self._string_elements >= other._string_elements
class SortedCollection(object):
'''Sequence sorted by a key function.
SortedCollection() is much easier to work with than using bisect() directly.
It supports key functions like those use in sorted(), min(), and max().
The result of the key function call is saved so that keys can be searched
efficiently.
Instead of returning an insertion-point which can be hard to interpret, the
five find-methods return a specific item in the sequence. They can scan for
exact matches, the last item less-than-or-equal to a key, or the first item
greater-than-or-equal to a key.
Once found, an item's ordinal position can be located with the index() method.
New items can be added with the insert() and insert_right() methods.
Old items can be deleted with the remove() method.
The usual sequence methods are provided to support indexing, slicing,
length lookup, clearing, copying, forward and reverse iteration, contains
checking, item counts, item removal, and a nice looking repr.
Finding and indexing are O(log n) operations while iteration and insertion
are O(n). The initial sort is O(n log n).
The key function is stored in the 'key' attibute for easy introspection or
so that you can assign a new key function (triggering an automatic re-sort).
In short, the class was designed to handle all of the common use cases for
bisect but with a simpler API and support for key functions.
>>> from pprint import pprint
>>> from operator import itemgetter
>>> s = SortedCollection(key=itemgetter(2))
>>> for record in [
... ('roger', 'young', 30),
... ('angela', 'jones', 28),
... ('bill', 'smith', 22),
... ('david', 'thomas', 32)]:
... s.insert(record)
>>> pprint(list(s)) # show records sorted by age
[('bill', 'smith', 22),
('angela', 'jones', 28),
('roger', 'young', 30),
('david', 'thomas', 32)]
>>> s.find_le(29) # find oldest person aged 29 or younger
('angela', 'jones', 28)
>>> s.find_lt(28) # find oldest person under 28
('bill', 'smith', 22)
>>> s.find_gt(28) # find youngest person over 28
('roger', 'young', 30)
>>> r = s.find_ge(32) # find youngest person aged 32 or older
>>> s.index(r) # get the index of their record
3
>>> s[3] # fetch the record at that index
('david', 'thomas', 32)
>>> s.key = itemgetter(0) # now sort by first name
>>> pprint(list(s))
[('angela', 'jones', 28),
('bill', 'smith', 22),
('david', 'thomas', 32),
('roger', 'young', 30)]
'''
def __init__(self, iterable=(), key=None):
self._given_key = key
key = (lambda x: x) if key is None else key
decorated = sorted((key(item), item) for item in iterable)
self._keys = [k for k, item in decorated]
self._items = [item for k, item in decorated]
self._key = key
def _getkey(self):
return self._key
def _setkey(self, key):
if key is not self._key:
self.__init__(self._items, key=key)
def _delkey(self):
self._setkey(None)
key = property(_getkey, _setkey, _delkey, 'key function')
def clear(self):
self.__init__([], self._key)
def copy(self):
return self.__class__(self, self._key)
def __len__(self):
return len(self._items)
def __getitem__(self, i):
return self._items[i]
def __iter__(self):
return iter(self._items)
def __reversed__(self):
return ReversedSortedCollection(self)
def __repr__(self):
return '%s(%r, key=%s)' % (
self.__class__.__name__,
self._items,
getattr(self._given_key, '__name__', repr(self._given_key))
)
def __reduce__(self):
return self.__class__, (self._items, self._given_key)
def __contains__(self, item):
k = self._key(item)
i = bisect_left(self._keys, k)
j = bisect_right(self._keys, k)
return item in self._items[i:j]
def index(self, item):
'Find the position of an item. Raise ValueError if not found.'
k = self._key(item)
i = bisect_left(self._keys, k)
j = bisect_right(self._keys, k)
return self._items[i:j].index(item) + i
def count(self, item):
'Return number of occurrences of item'
k = self._key(item)
i = bisect_left(self._keys, k)
j = bisect_right(self._keys, k)
return self._items[i:j].count(item)
def insert(self, item):
'Insert a new item. If equal keys are found, add to the left'
k = self._key(item)
i = bisect_left(self._keys, k)
self._keys.insert(i, k)
self._items.insert(i, item)
return i
def reorder(self, item):
'''Reorder an item. If its key changed, then the item is
repositioned, otherwise the item stays untouched'''
index = self._items.index(item)
new_index = -1
if self._keys[index] != self._key(item):
del self._keys[index]
del self._items[index]
new_index = self.insert(item)
return new_index
def insert_all(self, items):
for item in items:
self.insert(item)
def remove(self, item):
'Remove first occurence of item. Raise ValueError if not found'
i = self.index(item)
del self._keys[i]
del self._items[i]
class ReversedSortedCollection(object):
def __init__(self, sorted_collection):
self._sorted_collection = sorted_collection
def __getattr__(self, name):
return getattr(self._sorted_collection, name)
def copy(self):
return self.__class__(self._sorted_collection)
def _getkey(self):
return self._key
def _setkey(self, key):
if key is not self._key:
self.__init__(SortedCollection(self._items, key=key))
def _delkey(self):
self._setkey(None)
key = property(_getkey, _setkey, _delkey, 'key function')
def __len__(self):
return len(self._sorted_collection)
def __getitem__(self, i):
return self._items[len(self) - i - 1]
def __iter__(self):
return iter(reversed(self._items))
def __reversed__(self):
return self._sorted_collection
def __repr__(self):
return '%s(%r, key=%s)' % (
self.__class__.__name__,
reversed(self._items),
getattr(self._given_key, '__name__', repr(self._given_key))
)
def __reduce__(self):
return self.__class__, (reversed(self._items), self._given_key)
def insert(self, item):
'Insert a new item. If equal keys are found, add to the left'
i = self._sorted_collection.insert(item)
return len(self) - i - 1
def index(self, item):
'Find the position of an item. Raise ValueError if not found.'
return len(self) - self._sorted_collection.index(item) - 1
class IdleCallIterator(object):
def __init__(self, chunk, process, after=None, error=None, finish=None):
default = lambda *_: None
self._chunk = chunk
self._process = process
self._after = after if after else default
self._error = error if error else default
self._finish = finish if finish else default
self._stop = False
def __call__(self, iterator, **data):
self._iter = iterator
#Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, self._idle_call, data)
GLib.idle_add(self._idle_call, data)
def _idle_call(self, data):
if self._stop:
return False
for i in range(self._chunk):
try:
next_elem = next(self._iter)
self._process(next_elem, data)
except StopIteration:
self._finish(data)
return False
except Exception as e:
self._error(e)
self._after(data)
return True
def stop(self):
self._stop = True
def idle_iterator(func):
def iter_function(obj, iterator, **data):
idle_call = IdleCallIterator(*func(obj))
idle_call(iterator, **data)
return idle_call
return iter_function
class Theme:
'''
This class manages the theme details
'''
# storage for the instance reference
__instance = None
class _impl(GObject.Object):
""" Implementation of the singleton interface """
# properties
theme = GObject.property(type=str, default="standard")
# signals
'''
changed = signal emitted when a theme has changed
'''
__gsignals__ = {
'theme_changed': (GObject.SIGNAL_RUN_LAST, None, ())
}
# below public variables and methods that can be called for Theme
def __init__(self, plugin):
'''
Initializes the singleton interface, assigning all the constants
used to access the plugin's settings.
'''
super(Theme._impl, self).__init__()
self.plugin = plugin
popups = rb.find_plugin_file(plugin, 'img/popups.xml')
root = ET.parse(open(popups)).getroot()
base = 'theme/theme'
self.themes = []
for elem in root.xpath(base):
self.themes.append(elem.attrib['folder_name'])
self.gs = GSetting()
self.setting = self.gs.get_setting(self.gs.Path.PLUGIN)
# connect properties and signals
self._connect_properties()
self._connect_signals()
@property
def current(self):
return self.setting[self.gs.PluginKey.THEME]
def _connect_properties(self):
self.setting.bind(self.gs.PluginKey.THEME, self,
'theme', Gio.SettingsBindFlags.GET)
def _connect_signals(self):
self.connect('notify::theme', self._on_theme_changed,
None)
def _on_theme_changed(self, *args):
self.emit('theme_changed')
def __init__(self, plugin):
""" Create singleton instance """
# Check whether we already have an instance
if Theme.__instance is None:
# Create and remember instance
Theme.__instance = Theme._impl(plugin)
# Store instance reference as the only member in the handle
self.__dict__['_Theme__instance'] = Theme.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
class SpriteSheet(object):
def __init__(self, image, icon_width, icon_height, x_spacing, y_spacing,
x_start, y_start, across_dimension, down_dimension,
alpha_color=None, size=None):
# load the image
base_image = GdkPixbuf.Pixbuf.new_from_file(image)
if alpha_color:
base_image = base_image.add_alpha(True, *alpha_color)
delta_y = icon_height + y_spacing
delta_x = icon_width + x_spacing
self._sprites = []
for y in range(0, down_dimension):
for x in range(0, across_dimension):
sprite = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True,
8, icon_width, icon_height)
base_image.copy_area(x_start + (x * delta_x),
y_start + (y * delta_y), icon_width, icon_height,
sprite, 0, 0)
if size:
sprite = sprite.scale_simple(size[0], size[1],
GdkPixbuf.InterpType.BILINEAR)
self._sprites.append(sprite)
def __len__(self):
return len(self._sprites)
def __getitem__(self, index):
return self._sprites[index]
class ConfiguredSpriteSheet(object):
def __init__(self, plugin, sprite_name, size=None):
popups = rb.find_plugin_file(plugin, 'img/popups.xml')
root = ET.parse(open(popups)).getroot()
base = 'theme/theme[@folder_name="' + Theme(plugin).current \
+ '"]/spritesheet[@name="' + sprite_name + '"]/'
image = rb.find_plugin_file(plugin, 'img/' + Theme(plugin).current \
+ '/' + root.xpath(base + 'image')[0].text)
icon_width = int(root.xpath(base + 'icon')[0].attrib['width'])
icon_height = int(root.xpath(base + 'icon')[0].attrib['height'])
x_spacing = int(root.xpath(base + 'spacing')[0].attrib['x'])
y_spacing = int(root.xpath(base + 'spacing')[0].attrib['y'])
x_start = int(root.xpath(base + 'start-position')[0].attrib['x'])
y_start = int(root.xpath(base + 'start-position')[0].attrib['y'])
across_dimension = int(root.xpath(base + 'dimension')[0].attrib['across'])
down_dimension = int(root.xpath(base + 'dimension')[0].attrib['down'])
try:
alpha_color = list(map(int,
root.xpath(base + 'alpha')[0].text.split(' ')))
except:
alpha_color = None
self.names = []
self.locale_names = {}
cl = CoverLocale()
lang = cl.get_locale()
base = sprite_name + '/' + sprite_name + \
'[@spritesheet="' + sprite_name + '"]'
for elem in root.xpath(base + '[not(@xml:lang)]'):
self.names.append(elem.text)
for elem in root.xpath(base + '[@xml:lang="' + lang + '"]'):
self.locale_names[elem.text] = elem.attrib['name']
if (not self.locale_names) and len(lang) > 2:
for elem in root.xpath(base + '[@xml:lang="' + \
lang[0:2] + '"]'):
self.locale_names[elem.text] = elem.attrib['name']
self._sheet = SpriteSheet(image, icon_width, icon_height, x_spacing,
y_spacing, x_start, y_start, across_dimension, down_dimension,
alpha_color, size)
self._genre_db = RB.ExtDB(name='cb_genre')
def __len__(self):
return len(self._sheet)
def __getitem__(self, name):
try:
return self._sheet[self.names.index(name)]
except:
return None
def __contains__(self, name):
return name in self.names
def keys(self):
return self.names
class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
'''
A sprite-sheet of genres. Creates a pixbuf representation of a picture
that has several icons in a regular pattern. This uses the file
'popups.xml' for its definition
:plugin: rhythmbox plugin
:sprite_name: `str` containing name of the spritesheet pattern in
popups.xml
:size: `int` array dimension of the final sprite which is to be used.
output:
:names: `str` array of sprite names
'''
# types of genre
GENRE_USER = 1
GENRE_SYSTEM = 2
GENRE_LOCALE = 3
def __init__(self, plugin, sprite_name, size=None):
super(GenreConfiguredSpriteSheet, self).__init__(plugin, sprite_name,
size)
self.genre_alternate = {} # contains GenreType tuples
self._alt_icons = {}
self._sprite_name = sprite_name
self._size = size
popups = rb.find_plugin_file(plugin, 'img/popups.xml')
root = ET.parse(open(popups)).getroot()
self._parse_popups(plugin, root, self.GENRE_SYSTEM)
try:
# self._user_popups = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml')
self._user_popups = RB.user_cache_dir() + "/coverart_browser/usericons/popups.xml"
root = ET.parse(open(self._user_popups)).getroot()
self._parse_popups(plugin, root, self.GENRE_USER)
elem = root.xpath(self._sprite_name + '/index')
curr_index = int(elem[0].text)
for index in range(0, curr_index + 1):
key = RB.ExtDBKey.create_lookup('icon', str(index))
icon_location = self._genre_db.lookup(key)
sprite = GdkPixbuf.Pixbuf.new_from_file(icon_location)
if self._size:
sprite = sprite.scale_simple(self._size[0], self._size[1],
GdkPixbuf.InterpType.BILINEAR)
self._alt_icons[str(index)] = sprite
self.names.append(str(index))
except:
pass
def __getitem__(self, name):
try:
return self._alt_icons[name]
except:
return self._sheet[self.names.index(name)]
def _parse_popups(self, plugin, root, genre_type):
icon_names = {}
cl = CoverLocale()
lang = cl.get_locale()
base = self._sprite_name + '/alt'
for elem in root.xpath(base + '[not(@xml:lang)]/alt'):
self.genre_alternate[GenreType(name=elem.text, genre_type=genre_type)] = elem.attrib['genre']
for elem in root.xpath(base + '[@xml:lang="' + lang + '"]/alt'):
self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_LOCALE)] = elem.attrib['genre']
# if (not self.locale_alternate) and len(lang) > 2:
if len(lang) > 2:
for elem in root.xpath(base + '[@xml:lang="' + \
lang[0:2] + '"]/alt'):
self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_LOCALE)] = elem.attrib['genre']
def add_genre_icon(self, filename):
root = ET.parse(open(self._user_popups)).getroot()
elem = root.xpath(self._sprite_name + '/index')
next_index = int(elem[0].text)
elem[0].text = str(next_index + 1)
tree = ET.ElementTree(root)
tree.write(self._user_popups, pretty_print=True, xml_declaration=True)
key = RB.ExtDBKey.create_storage('icon', str(next_index))
uri = "file://" + rb3compat.pathname2url(filename)
self._genre_db.store_uri(key, RB.ExtDBSourceType.USER_EXPLICIT, uri)
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
new_genre = GenreType(name=str(next_index), genre_type=self.GENRE_USER)
if self._size:
pixbuf = pixbuf.scale_simple(self._size[0], self._size[1],
GdkPixbuf.InterpType.BILINEAR)
self._alt_icons[new_genre.name] = pixbuf
self.names.append(new_genre.name)
return new_genre
def delete_genre(self, current_genre):
root = ET.parse(open(self._user_popups)).getroot()
base = self._sprite_name + '/alt/alt'
found = False
for elem in root.xpath(base):
if RB.search_fold(elem.text) == RB.search_fold(current_genre):
found = True
break
if found:
elem.getparent().remove(elem)
tree = ET.ElementTree(root)
tree.write(self._user_popups, pretty_print=True, xml_declaration=True)
else:
print("not found to delete")
def amend_genre_info(self, current_genre, new_genre, icon_name):
root = ET.parse(open(self._user_popups)).getroot()
base = self._sprite_name + '/alt/alt'
found = False
if current_genre != "":
for elem in root.xpath(base):
if RB.search_fold(elem.text) == RB.search_fold(current_genre):
found = True
del self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_USER)]
break
else:
elem = ET.SubElement(root.xpath(self._sprite_name + '/alt')[0], "alt")
if elem != None:
found = True
if found:
elem.text = rb3compat.unicodestr(new_genre, 'utf-8')
elem.attrib['genre'] = icon_name
tree = ET.ElementTree(root)
tree.write(self._user_popups, pretty_print=True, xml_declaration=True)
self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_USER)] = icon_name
return GenreType(name=elem.text, genre_type=self.GENRE_USER)
else:
print("nothing found to amend")
return None
def get_stock_size():
what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.BUTTON)
return width, height
def create_pixbuf_from_file_at_size(filename, width, height):
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, width, height)
if pixbuf.get_width() != width or pixbuf.get_height() != height:
pixbuf = pixbuf.scale_simple(width, height,
GdkPixbuf.InterpType.BILINEAR)
return pixbuf
'''
class to search through a dict without case-sensitivity nor
unicode vs string issues
'''
class CaseInsensitiveDict(collections.Mapping):
def __init__(self, d):
self._d = d
self._s = dict((RB.search_fold(k), k) for k in d)
def __contains__(self, k):
return RB.search_fold(k) in self._s
def __len__(self):
return len(self._s)
def __iter__(self):
return iter(self._s)
def __getitem__(self, k):
return self._d[self._s[RB.search_fold(k)]]
def actual_key_case(self, k):
return self._s.get(RB.search_fold(k))
def check_lastfm(force_check=False):
'''
check validity of lastfm connection
returns True if connected with an account
Also returns True if lastFM is not in the list of search providers
'''
providers = get_search_providers()
print(providers)
print(force_check)
if force_check or 'lastfm-search' in providers:
connected = lastfm_connected()
print(connected)
return connected
elif not 'lastfm-search' in providers:
print("not lastm-search")
return True
else:
print("returning default")
return False
def create_button_image_symbolic(style_context, icon_name):
'''
create a pixbuf for the given symbolic icon_name sized according to the stock icon size
'''
theme = Gtk.IconTheme()
default = theme.get_default()
iconinfo = default.lookup_icon(icon_name, 128, 0)
pixbuf, symbol = iconinfo.load_symbolic_for_context(style_context)
width, height = get_stock_size()
pixbuf = pixbuf.scale_simple(width, height,
GdkPixbuf.InterpType.BILINEAR)
return pixbuf
def create_button_image(plugin, image_filename):
'''
create a pixbuf for the given image_filename sized according to the stock icon size
'''
path = 'img/'
return create_pixbuf_from_file_at_size(
rb.find_plugin_file(plugin, path + image_filename),
*get_stock_size())
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+230
Ver Arquivo
@@ -0,0 +1,230 @@
# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2014 - fossfreedom
# GTK3 port https://github.com/exaile-dev/exaile/blob/master/xlgui/cover.py
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GObject
from coverart_browser_prefs import CoverLocale
import rb
class CoverWindow(GObject.Object):
"""Shows the cover in a simple image viewer"""
# signals
__gsignals__ = {
'close-window': (GObject.SIGNAL_RUN_LAST, None, ())
}
def __init__(self, plugin, parent, savedir=None):
"""Initializes and shows the cover
:param plugin: source
:type plugin: RBSource
:param parent: Parent window to attach to
:type parent: Gtk.Window
:param savedir: Initial directory for the Save As functionality
:type savedir: basestring
"""
super(CoverWindow, self).__init__()
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.builder = Gtk.Builder()
self.builder.add_from_file(rb.find_plugin_file(plugin,
'ui/coverart_window.ui'))
self.builder.connect_signals(self)
self.cover_window = self.builder.get_object('CoverWindow')
self.cover_window.connect('destroy', self.send_destroy_signal)
self.layout = self.builder.get_object('layout')
self.toolbar = self.builder.get_object('toolbar')
self.save_as_button = self.builder.get_object('save_as_button')
self.zoom_in_button = self.builder.get_object('zoom_in_button')
self.zoom_out_button = self.builder.get_object('zoom_out_button')
self.zoom_100_button = self.builder.get_object('zoom_100_button')
self.zoom_fit_button = self.builder.get_object('zoom_fit_button')
self.close_button = self.builder.get_object('close_button')
self.image = self.builder.get_object('image')
self.statusbar = self.builder.get_object('statusbar')
self.scrolledwindow = self.builder.get_object('scrolledwindow')
self.scrolledwindow.set_hadjustment(self.layout.get_hadjustment())
self.scrolledwindow.set_vadjustment(self.layout.get_vadjustment())
self.savedir = savedir
if parent:
self.cover_window.set_transient_for(parent)
self.cover_window_width = 500
self.cover_window_height = 500 + self.toolbar.size_request().height + \
self.statusbar.size_request().height
self.cover_window.set_default_size(self.cover_window_width, \
self.cover_window_height)
self.min_percent = 1
self.max_percent = 500
self.ratio = 1.5
self.image_interp = GdkPixbuf.InterpType.BILINEAR
self.image_fitted = True
def send_destroy_signal(self, *args):
self.emit('close-window')
def show_all(self, title, pixbuf):
self.image_original_pixbuf = pixbuf
self.image_pixbuf = self.image_original_pixbuf
self.cover_window.set_title(title)
self.cover_window.show_all()
self.set_ratio_to_fit()
self.update_widgets()
def available_image_width(self):
"""Returns the available horizontal space for the image"""
return self.cover_window.get_size()[0]
def available_image_height(self):
"""Returns the available vertical space for the image"""
return self.cover_window.get_size()[1] - \
self.toolbar.size_request().height - \
self.statusbar.size_request().height
def center_image(self):
"""Centers the image in the layout"""
new_x = max(0, int((self.available_image_width() - \
self.image_pixbuf.get_width()) / 2))
new_y = max(0, int((self.available_image_height() - \
self.image_pixbuf.get_height()) / 2))
self.layout.move(self.image, new_x, new_y)
def update_widgets(self):
"""Updates image, layout, scrolled window, tool bar and status bar"""
# if self.cover_window.window:
# self.cover_window.window.freeze_updates()
self.apply_zoom()
self.layout.set_size(self.image_pixbuf.get_width(), \
self.image_pixbuf.get_height())
if self.image_fitted or \
(self.image_pixbuf.get_width() == self.available_image_width() and \
self.image_pixbuf.get_height() == self.available_image_height()):
self.scrolledwindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)
else:
self.scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC,
Gtk.PolicyType.AUTOMATIC)
percent = int(100 * self.image_ratio)
message = str(self.image_original_pixbuf.get_width()) + " x " + \
str(self.image_original_pixbuf.get_height()) + \
" pixels " + str(percent) + '%'
self.zoom_in_button.set_sensitive(percent < self.max_percent)
self.zoom_out_button.set_sensitive(percent > self.min_percent)
self.statusbar.pop(self.statusbar.get_context_id(''))
self.statusbar.push(self.statusbar.get_context_id(''), message)
self.image.set_from_pixbuf(self.image_pixbuf)
self.center_image()
#if self.cover_window.window:
# self.cover_window.window.thaw_updates()
def apply_zoom(self):
"""Scales the image if needed"""
new_width = int(self.image_original_pixbuf.get_width() * \
self.image_ratio)
new_height = int(self.image_original_pixbuf.get_height() * \
self.image_ratio)
if new_width != self.image_pixbuf.get_width() or \
new_height != self.image_pixbuf.get_height():
self.image_pixbuf = self.image_original_pixbuf.scale_simple(new_width, \
new_height, self.image_interp)
def set_ratio_to_fit(self):
"""Calculates and sets the needed ratio to show the full image"""
width_ratio = float(self.image_original_pixbuf.get_width()) / \
self.available_image_width()
height_ratio = float(self.image_original_pixbuf.get_height()) / \
self.available_image_height()
self.image_ratio = 1 / max(1, width_ratio, height_ratio)
def on_save_as_button_clicked(self, widget):
"""
Saves image to user-specified location
"""
dialog = Gtk.FileChooserDialog(_("Save File"), self.cover_window,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT))
filename = 'cover.png'
dialog.set_current_name(filename)
if self.savedir:
dialog.set_current_folder(self.savedir)
if dialog.run() == Gtk.ResponseType.ACCEPT:
filename = dialog.get_filename()
lowfilename = filename.lower()
if lowfilename.endswith('.jpg') or lowfilename.endswith('.jpeg'):
type_ = 'jpeg'
else:
type_ = 'png'
self.image_pixbuf.savev(filename, type_, [None], [None])
dialog.destroy()
def on_zoom_in_button_clicked(self, widget):
"""
Zooms into the image
"""
self.image_fitted = False
self.image_ratio *= self.ratio
self.update_widgets()
def on_zoom_out_button_clicked(self, widget):
"""
Zooms out of the image
"""
self.image_fitted = False
self.image_ratio *= 1 / self.ratio
self.update_widgets()
def on_zoom_100_button_clicked(self, widget):
"""
Restores the original image zoom
"""
self.image_fitted = False
self.image_ratio = 1
self.update_widgets()
def on_zoom_fit_button_clicked(self, widget):
"""
Zooms the image to fit the window width
"""
self.image_fitted = True
self.set_ratio_to_fit()
self.update_widgets()
def on_close_button_clicked(self, widget):
"""
Hides the window
"""
self.cover_window.hide()
def cover_window_size_allocate(self, widget, allocation):
if self.cover_window_width != allocation.width or \
self.cover_window_height != allocation.height:
if self.image_fitted:
self.set_ratio_to_fit()
self.update_widgets()
self.cover_window_width = allocation.width
self.cover_window_height = allocation.height
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 7.5 KiB

+81
Ver Arquivo
@@ -0,0 +1,81 @@
/* ContentFlowAddOn_black, version 2.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*
*--------------------------------------------------------------------------*/
/* ========== ContentFlow ========== */
/*
* Within this file you can ajust the styling of ContentFlow
* to your personal needs. The default styling is the same as found on the
* projectpage.
*
*/
.ContentFlowAddOn_black {
background: black;
}
/* ----- styling of items ----- */
.ContentFlowAddOn_black .flow .item .caption {
background: url(img/1x1_0.5_black.png);
}
* html .ContentFlowAddOn_black .flow .item .caption {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/1x1_0.5_black.png');
}
.ContentFlowAddOn_black .flow .item .caption a,
.ContentFlowAddOn_black .flow .item .caption a:link,
.ContentFlowAddOn_black .flow .item .caption a:visited,
.ContentFlowAddOn_black .flow .item .caption a:active,
.ContentFlowAddOn_black .flow .item .caption a:hover {
color: black;
}
/* ----- scrollbar ----- */
.ContentFlowAddOn_black .scrollbar {
background: url(img/scrollbar_white.png) left center repeat-x;
}
.ContentFlowAddOn_black .scrollbar .slider {
background: url(img/slider_white.png) center center no-repeat;
}
/* only for IE <= 6 and a alphatransparent slider image */
* html .ContentFlowAddOn_black .scrollbar .slider { background-image: none; }
* html .ContentFlowAddOn_black .scrollbar .slider .virtualSlider {
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='img/slider_white.png');
}
.ContentFlowAddOn_black .scrollbar .slider .position {
color:silver;
}
/* ----- global caption ----- */
.ContentFlowAddOn_black .globalCaption {
color: white;
}
.ContentFlowAddOn_black .globalCaption .caption a,
.ContentFlowAddOn_black .globalCaption .caption a:link,
.ContentFlowAddOn_black .globalCaption .caption a:visited,
.ContentFlowAddOn_black .globalCaption .caption a:active,
.ContentFlowAddOn_black .globalCaption .caption a:hover {
color: white;
}
/* ----- load indicator ----- */
.ContentFlowAddOn_black .loadIndicator {
background: url(img/1x1_0.5_black.png);
}
* html .ContentFlowAddOn_black .loadIndicator {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/1x1_0.5_black.png');
}
.ContentFlowAddOn_black .loadIndicator .indicator {
background: url(img/loader_black.gif) center center no-repeat;
}
/* ================================= */
+19
Ver Arquivo
@@ -0,0 +1,19 @@
/* ContentFlowAddOn_black, version 2.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*/
new ContentFlowAddOn ('black', {
init: function () {
this.addStylesheet();
},
ContentFlowConf: {
reflectionColor: "#000000" // none, transparent, overlay or hex RGB CSS style #RRGGBB
}
});
+65
Ver Arquivo
@@ -0,0 +1,65 @@
/* ContentFlowAddOn_carousel, version 1.1
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*
*--------------------------------------------------------------------------*/
.ContentFlowAddOn_carousel {
border: 5px solid #767676;
margin: 0 25px;
padding: 25px 0px;
overflow: visible;
/*overflow: hidden;*/
}
.ContentFlowAddOn_carousel #preButton,
.ContentFlowAddOn_carousel #nextButton {
position: absolute;
top: 50%;
margin-top: -25px;
width: 50px;
height: 50px;
}
.ContentFlowAddOn_carousel #preButton {
background: url(img/pre_h.png) center no-repeat;
left: -25px;
left: -28px;
}
* html .ContentFlowAddOn_carousel #preButton {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/pre_h.png');
}
.ContentFlowAddOn_carousel #preButton:hover {
background: url(img/pre_h.png) center no-repeat;
}
.ContentFlowAddOn_carousel #nextButton {
background: url(img/next_h.png) center no-repeat;
right: -25px;
right: -28px;
}
* html .ContentFlowAddOn_carousel #nextButton {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/next_h.png');
}
.ContentFlowAddOn_carousel #nextButton:hover {
background: url(img/next_h.png) center no-repeat;
}
/* ----- styling of items ----- */
.ContentFlowAddOn_carousel .showCaption .item .caption {
display: block !important;
}
/* ----- global caption ----- */
.ContentFlowAddOn_carousel .globalCaption {
margin-top: -3em;
}
/* ================================= */
+131
Ver Arquivo
@@ -0,0 +1,131 @@
/* ContentFlowAddOn_carousel, version 1.1
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*/
new ContentFlowAddOn ('carousel', {
conf: {
shownItems: 3,
showCaption: true,
width: 75,
height: 75,
space:0.0
},
init: function() {
this.addStylesheet();
},
onloadInit: function (flow) {
},
afterContentFlowInit: function (flow) {
var SI = flow.getAddOnConf('carousel').shownItems;
var c = flow.Container;
var ac = flow.getAddOnConf('carousel')
if (ac.showCaption) {
$CF(flow.Flow).addClassName('showCaption');
}
var p = document.createElement('div');
p.id = "preButton";
var pre = function () {
var item = flow._activeItem;
for (var i=0; i< SI; i++) { item = item.pre; }
flow.moveToItem(item);
}
p.onclick = pre;
c.appendChild(p);
var n = document.createElement('div');
n.id = "nextButton";
var next = function () {
var item = flow._activeItem;
for (var i=0; i< SI; i++) { item = item.next; }
flow.moveToItem(item);
}
n.onclick = next;
c.appendChild(n);
flow.Flow.style.fontSize = 12*(flow.maxHeight / 150) +"px";
if (flow.Browser.IE) {
window.setTimeout(function () {flow.Flow.style.overflow = "hidden"}, 1000);
}
else {
flow.Flow.style.overflow = "hidden";
}
flow.setConfig({visibleItems: Math.ceil((flow.getAddOnConf('carousel').shownItems - 1)/2) + 1});
},
ContentFlowConf: {
scaleFactorLandscape: "max", // scale factor of landscape images ('max' := height= maxItemHeight)
scaleFactorPortrait: "max",
fixItemSize: true,
relativeItemPosition: "center", // align top/above, bottom/below, left, right, center of position coordinate
visibleItems: 2, // how man item are visible on each side (-1 := auto)
reflectionHeight: 0, // float (relative to original image height)
/* ==================== actions ==================== */
onclickInactiveItem : function (item) {
this.conf.onclickActiveItem(item);
return false;
},
/* ==================== calculations ==================== */
calcStepWidth: function(diff) {
var vI = this.conf.visibleItems;
var items = this.items.length;
items = items == 0 ? 1 : items;
var absDiff = Math.abs(diff);
if (absDiff > vI) {
if (diff > 0) {
var stepwidth = diff - vI;
} else {
var stepwidth = diff + vI;
}
} else if (vI >= items) {
var stepwidth = diff / items;
} else {
var c = this.getAddOnConf('carousel');
var f = 0.1 * 2/3 * c.shownItems * diff/absDiff;
var d = diff * ( vI / items);
var stepwidth = absDiff > 0.1 ? f : d*8;
}
return stepwidth;
},
calcSize: function (item) {
var c = this.getAddOnConf('carousel');
var a = c.width / c.height;
//if (this.conf.verticalFlow) a = 1/a;
var h = 3/c.shownItems / a;
//if (this.conf.verticalFlow) h *= 2/3;
var w = h * a;
return {width: w, height: h};
},
calcCoordinates: function (item) {
var rP = item.relativePosition;
var c = this.getAddOnConf('carousel');
var w = item.size.width;
//if (this.conf.verticalFlow) w = item.size.height;
var x = rP*w/2*(1 + c.space) *this.conf.scaleFactor - w* (c.shownItems % 2 ? 0 : 0.5) / 1.4;
if (this.conf.verticalFlow) x *= 2*2/3;
var y = 0;
return {x: x, y: y};
}
}
});
+52
Ver Arquivo
@@ -0,0 +1,52 @@
/* ContentFlowAddOn_roundabout, version 3.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*/
new ContentFlowAddOn ('roundabout', {
ContentFlowConf: {
circularFlow: true,
visibleItems: -1,
relativeItemPosition: "top center",
endOpacity: 0.5,
/*
* calculates the size of the item at its relative position x
* returns a size object
*/
calcSize: function (item) {
var rP = item.relativePosition;
//var rPN = relativePositionNormed;
//var vI = rPN != 0 ? rP/rPN : 0 ; // visible Items
var h = 1/(Math.abs(rP)+1);
var w = h;
return {width: w, height: h};
},
/*
* calculates the position of an item within the flow element
* returns a vector object
*/
calcCoordinates: function (item) {
var rP = item.relativePosition;
var rPN = item.relativePositionNormed;
var vI = rPN != 0 ? rP/rPN : 0 ; // visible Items
var f = 1 - 1/Math.exp( Math.abs(rP)*0.75);
var x = item.side * vI/(vI+1)* f;
var y = 1;
var f = Math.sin(Math.PI * (rP*(1+1/(rP*rP+1))) / (vI+1));
var x = vI/(vI+1)* f;
var y = 1 - Math.abs(rP)*1.5/(vI+1);
return {x: x, y: y};
}
}
});
+31
Ver Arquivo
@@ -0,0 +1,31 @@
/* ContentFlowAddOn_vertical, version 2.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*/
new ContentFlowAddOn ('vertical', {
ContentFlowConf: {
relativeItemPosition: "center", // top, bottom, left, right, center
verticalFlow: true, // turn ContentFlow 90 degree counterclockwise
reflectionHeight: 0,
calcCoordinates: function (item) {
var rP = item.relativePosition;
var rPN = item.relativePositionNormed;
var vI = rPN != 0 ? rP/rPN : 0 ; // visible Items
var f = 1 - 1/Math.exp( Math.abs(rP)*0.75);
var x = item.side * vI/(vI+1)* f;
var y = 0;
return {x: x, y: y};
}
}
});
+80
Ver Arquivo
@@ -0,0 +1,80 @@
/* ContentFlowAddOn_white, version 2.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*
*--------------------------------------------------------------------------*/
/* ========== ContentFlow ========== */
/*
* Within this file you can ajust the styling of ContentFlow
* to your personal needs. The default styling is the same as found on the
* projectpage.
*
*/
.ContentFlowAddOn_white {
background: white;
}
/* ----- styling of items ----- */
.ContentFlowAddOn_white .flow .item .caption {
background: url(img/1x1_0.5_white.png);
}
* html .ContentFlowAddOn_white .flow .item .caption {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/1x1_0.5_white.png');
}
.ContentFlowAddOn_white .flow .item .caption a,
.ContentFlowAddOn_white .flow .item .caption a:link,
.ContentFlowAddOn_white .flow .item .caption a:visited,
.ContentFlowAddOn_white .flow .item .caption a:active,
.ContentFlowAddOn_white .flow .item .caption a:hover {
color: black;
}
/* ----- scrollbar ----- */
.ContentFlowAddOn_white .scrollbar {
background: url(img/scrollbar_black.png) left center repeat-x;
}
.ContentFlowAddOn_white .scrollbar .slider {
background: url(img/slider_black.png) center center no-repeat;
}
/* only for IE <= 6 and a alphatransparent slider image */
* html .ContentFlowAddOn_white .scrollbar .slider { background-image: none; }
* html .ContentFlowAddOn_white .scrollbar .slider .virtualSlider {
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='img/slider_black.png');
}
.ContentFlowAddOn_white .scrollbar .slider .position {
color:gray;
}
/* ----- global caption ----- */
.ContentFlowAddOn_white .globalCaption {
color: black;
}
.ContentFlowAddOn_white .globalCaption .caption a,
.ContentFlowAddOn_white .globalCaption .caption a:link,
.ContentFlowAddOn_white .globalCaption .caption a:visited,
.ContentFlowAddOn_white .globalCaption .caption a:active,
.ContentFlowAddOn_white .globalCaption .caption a:hover {
color: black;
}
/* ----- load indicator ----- */
.ContentFlowAddOn_white .loadIndicator {
background: url(img/1x1_0.5_white.png);
}
* html .ContentFlowAddOn_white .loadIndicator {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/1x1_0.5_white.png');
}
.ContentFlowAddOn_white .loadIndicator .indicator {
background: url(img/loader_white.gif) center center no-repeat;
}
/* ================================= */
+19
Ver Arquivo
@@ -0,0 +1,19 @@
/* ContentFlowAddOn_white, version 2.0
* (c) 2008 - 2010 Sebastian Kutsch
* <http://www.jacksasylum.eu/ContentFlow/>
*
* This file is distributed under the terms of the MIT license.
* (see http://www.jacksasylum.eu/ContentFlow/LICENSE)
*/
new ContentFlowAddOn ('white', {
init: function () {
this.addStylesheet();
},
ContentFlowConf: {
reflectionColor: "#ffffff" // none, transparent, overlay or hex RGB CSS style #RRGGBB
}
});
+19
Ver Arquivo
@@ -0,0 +1,19 @@
Copyright (c) 2007 - 2010 Sebastian Kutsch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+250
Ver Arquivo
@@ -0,0 +1,250 @@
/* ========== ContentFlow ========== */
/*
* default style to look nice
*/
.ContentFlow {
}
.ContentFlow .flow {
/*border: 1px solid green;*/
}
.ContentFlow .flow * {
}
.ContentFlow .flow .item {
/*border: 1px solid red;*/
}
.ContentFlow .flow .item canvas.content {
height: 100%;
width: 100%;
/*border: 1px solid yellow;*/
}
.ContentFlow .flow .item img.content {
/*border: 1px solid yellow;*/
width: 100%;
}
.ContentFlow .flow .item img.reflection,
.ContentFlow .flow .item canvas.reflection {
width: 100%;
}
/* ----- styling of items ----- */
.ContentFlow .flow .item.active {
cursor: pointer;
}
.ContentFlow .flow .item .caption {
font-size: 100%;
font-weight: bold;
text-align: center;
color: white;
max-height: 30%;
bottom: 10%;
background: url(img/1x1_0.5_black.png);
width: 100%;
}
* html .ContentFlow .flow .item .caption {
background-image: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=scale, src='img/1x1_0.5_black.png');
}
.ContentFlow .flow .item .caption a,
.ContentFlow .flow .item .caption a:link,
.ContentFlow .flow .item .caption a:visited,
.ContentFlow .flow .item .caption a:active,
.ContentFlow .flow .item .caption a:hover {
text-decoration: none;
color: white;
font-style: italic;
font-size: 0.8em;
}
.ContentFlow .flow .item .caption a:hover {
text-decoration: underline;
}
.ContentFlow .flow .item.active .caption {
/*display: block;*/ /* uncomment to show caption inside item */
}
/* ----- scrollbar ----- */
.ContentFlow .scrollbar {
width: 50%;
margin: 0px auto;
margin-top: 10px;
height: 16px;
background: url(img/scrollbar_white.png) left center repeat-x;
position: relative;
overflow: visible;
}
.ContentFlow .scrollbar .slider {
width: 16px;
height: 16px;
background: url(img/slider_white.png) center center no-repeat;
cursor: move;
}
/* only for IE <= 6 and a alphatransparent slider image */
* html .ContentFlow .scrollbar .slider { background-image: none; }
* html .ContentFlow .scrollbar .slider .virtualSlider {
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='img/slider_white.png');
}
.ContentFlow .scrollbar .slider .position {
top: 120%;
font-size: 16px;
font-weight: bold;
color: silver
}
/* ----- global caption ----- */
.ContentFlow .globalCaption {
text-align: center;
font-weight: bold;
color: white;
font-size: 14px;
height: 20px;
margin: 2em auto;
}
.ContentFlow .globalCaption .caption {
}
.ContentFlow .globalCaption .caption a,
.ContentFlow .globalCaption .caption a:link,
.ContentFlow .globalCaption .caption a:visited,
.ContentFlow .globalCaption .caption a:active,
.ContentFlow .globalCaption .caption a:hover {
text-decoration: none;
color: white;
font-style: italic;
font-size: 0.8em;
}
.ContentFlow .globalCaption .caption a:hover {
text-decoration: underline;
}
/* ----- load indicator ----- */
.ContentFlow .loadIndicator {
width: 100%;
height: 100%;
top: 0px;
left: 0px;
background: black;
}
.ContentFlow .loadIndicator .indicator {
background: url(img/loader.gif) center center no-repeat;
width: 100%;
height: 100%;
}
* html .ContentFlow .loadIndicator .indicator {
height: 100px;
}
/* ================================= */
/* ========== ContentFlow ========== */
/*
* This is the basic CSS file needed for the correct functioning of ContentFlow.
* DON'T CHANGE IT.
*
*/
.ContentFlow {
position: relative; /* needed so overlay dimensions are constrained to the ContentFlow */
overflow: hidden;
}
.ContentFlow * {
margin: 0px;
padding: 0px;
/*border: none;*/
}
.ContentFlow img {
-ms-interpolation-mode: bicubic;
}
.ContentFlow .mouseoverCheckElement {
position: absolute;
width: 0px;
height: 0px;
left: 0px;
/*display: none;*/
visibility: hidden;
}
.ContentFlow:hover .mouseoverCheckElement {
left: 1px;
/*width: 1px;*/
/*left: -1px;*/
/*background-color: red;*/
}
.ContentFlow .flow {
position: relative; /* needed so that items can be positioned relative to flow*/
z-index: 0; /* need so every item has a z-index relative to the flow-box */
visibility: hidden; /* needed so that content is hidden while loading */
width: 100%; /* needed for IE6 */
margin: 0 auto;
}
.ContentFlow .flow.hidden {
visibility: hidden;
}
.ContentFlow .flow .item {
position: absolute; /* needed */
visibility: hidden;
top: 0px;
left: 0px;
}
.ContentFlow .flow .item.active {
}
.ContentFlow .flow .item .content {
display: block;
}
.ContentFlow .flow .item div.content {
width: 100%;
height: 100%;
}
.ContentFlow .flow .item .label {
display: none;
}
.ContentFlow .flow .item .reflection {
display: block;
}
.ContentFlow .flow .item canvas.reflection {
margin-top: -1px; /* for FF */
}
.ContentFlow .flow .item .caption {
position: absolute; /* needed */
display: none; /* needed to hide it on inactive items */
}
.ContentFlow .flow .item.active .caption {
/*display: block;*/ /* uncomment to show caption inside item */
}
/* ----- scrollbar ----- */
.ContentFlow .scrollbar {
position: relative; /* needed for z-index */
z-index: 1; /* set above flow */
visibility: hidden;
}
.ContentFlow .scrollbar .slider {
position: absolute; /* needed */
}
* html .ContentFlow .scrollbar .slider .virtualSlider {
height: 100%;
}
.ContentFlow .scrollbar .slider .position {
position: absolute; /* needed */
text-align: center;
}
/* ----- global caption ----- */
.ContentFlow .globalCaption {
position: relative; /* needed for z-index */
z-index: 1; /* set above flow */
}
/* ----- load indicator ----- */
.ContentFlow .loadIndicator {
position: absolute; /* needed */
z-index: 65000; /* set above everything */
}
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+44
Ver Arquivo
@@ -0,0 +1,44 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<link rel="stylesheet" title="Standard" href="styles.css" type="text/css" media="screen" />
<!--<style>
</style> -->
<style type="text/css">
.className{
width:270px;
height:150px;
position:absolute;
left:50%;
top:50%;
margin:-75px 0 0 -135px;
}
.className p{
font-size:22px;
margin:45px 10px 10px;
color: #BACKGROUND_COLOUR;
text-align:center;
position:absolute;
}
body{
background: #BACKGROUND_COLOUR;
font-size:0.825em;
font-family:Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<div class="className">
<p>Use the Search and Filter options to display covers
</p>
</div>
</body>
</html>
Arquivo binário não exibido.
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 82 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 82 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 43 B

+241
Ver Arquivo
@@ -0,0 +1,241 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
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="744.09448819"
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.47 r22583"
version="1.1"
sodipodi:docname="New document 1.2009_11_04_18_16_23.0.2009_11_29_20_35_24.0.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient3612">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3614" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3616" />
</linearGradient>
<linearGradient
id="linearGradient3157">
<stop
style="stop-color:#ffffff;stop-opacity:0.57391304;"
offset="0"
id="stop3159" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3161" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3157"
id="radialGradient3163"
cx="307.14285"
cy="582.36218"
fx="307.14285"
fy="582.36218"
r="158.57143"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3157"
id="radialGradient3187"
gradientUnits="userSpaceOnUse"
cx="307.14285"
cy="582.36218"
fx="307.14285"
fy="582.36218"
r="158.57143" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3195">
<path
sodipodi:type="arc"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path3197"
sodipodi:cx="268.57144"
sodipodi:cy="569.50507"
sodipodi:rx="171.42857"
sodipodi:ry="171.42857"
d="M 440.00002,569.50507 A 171.42857,171.42857 0 1 1 97.142868,569.50507 A 171.42857,171.42857 0 1 1 440.00002,569.50507 z"
transform="matrix(0.5151267,0,0,0.5151267,47.101979,154.22678)" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3205">
<path
sodipodi:type="arc"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path3207"
sodipodi:cx="268.57144"
sodipodi:cy="569.50507"
sodipodi:rx="171.42857"
sodipodi:ry="171.42857"
d="M 440.00002,569.50507 A 171.42857,171.42857 0 1 1 97.142868,569.50507 A 171.42857,171.42857 0 1 1 440.00002,569.50507 z"
transform="matrix(0.5151267,0,0,0.5151267,385.50521,158.17142)" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3612"
id="radialGradient3618"
cx="307.14285"
cy="582.36218"
fx="307.14285"
fy="582.36218"
r="158.57143"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3612"
id="radialGradient3639"
gradientUnits="userSpaceOnUse"
cx="307.14285"
cy="582.36218"
fx="307.14285"
fy="582.36218"
r="158.57143" />
</defs>
<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="0.35"
inkscape:cx="-159.28571"
inkscape:cy="405.71429"
inkscape:document-units="px"
inkscape:current-layer="g3620"
showgrid="false"
inkscape:window-width="1400"
inkscape:window-height="1002"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<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></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g3620">
<g
id="g2835"
transform="matrix(-1,0,0,1,370.9006,0)">
<path
d="m 440.00002,569.50507 c 0,94.67738 -76.75119,171.42857 -171.42858,171.42857 -94.67739,0 -171.428572,-76.75119 -171.428572,-171.42857 0,-94.67739 76.751182,-171.42858 171.428572,-171.42858 94.67739,0 171.42858,76.75119 171.42858,171.42858 z"
sodipodi:ry="171.42857"
sodipodi:rx="171.42857"
sodipodi:cy="569.50507"
sodipodi:cx="268.57144"
id="path3173"
style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd;stroke:none"
sodipodi:type="arc"
transform="matrix(0.5151267,0,0,0.5151267,47.101979,154.22678)" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 193.02128,416.31621 0,17.11698 -69.31988,0 0,28.32175 69.31988,0 0,17.11698 27.09543,-15.63248 27.08251,-15.64537 -27.08251,-15.63248 -27.09543,-15.64538 z"
id="rect3165" />
<path
d="m 440.00002,569.50507 c 0,94.67738 -76.75119,171.42857 -171.42858,171.42857 -94.67739,0 -171.428572,-76.75119 -171.428572,-171.42857 0,-94.67739 76.751182,-171.42858 171.428572,-171.42858 94.67739,0 171.42858,76.75119 171.42858,171.42858 z"
sodipodi:ry="171.42857"
sodipodi:rx="171.42857"
sodipodi:cy="569.50507"
sodipodi:cx="268.57144"
id="path3175"
style="fill:none;stroke:#808080;stroke-width:10.80000019;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc"
transform="matrix(0.4679068,0,0,0.4679068,59.783914,181.11879)" />
</g>
<path
transform="matrix(0.5847384,0,0,0.5847384,30.872504,70.269726)"
d="m 465.71428,582.36218 a 158.57143,158.57143 0 1 1 -317.14285,0 158.57143,158.57143 0 1 1 317.14285,0 z"
sodipodi:ry="158.57143"
sodipodi:rx="158.57143"
sodipodi:cy="582.36218"
sodipodi:cx="307.14285"
id="path2385"
style="fill:url(#radialGradient3618);fill-opacity:1;fill-rule:evenodd;stroke:none"
sodipodi:type="arc" />
</g>
<g
id="g3627"
transform="translate(314.28571,5.7142857)">
<g
id="g3629">
<path
transform="matrix(0.5151267,0,0,0.5151267,47.101979,154.22678)"
sodipodi:type="arc"
style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path3631"
sodipodi:cx="268.57144"
sodipodi:cy="569.50507"
sodipodi:rx="171.42857"
sodipodi:ry="171.42857"
d="m 440.00002,569.50507 c 0,94.67738 -76.75119,171.42857 -171.42858,171.42857 -94.67739,0 -171.428572,-76.75119 -171.428572,-171.42857 0,-94.67739 76.751182,-171.42858 171.428572,-171.42858 94.67739,0 171.42858,76.75119 171.42858,171.42858 z" />
<path
id="path3633"
d="m 193.02128,416.31621 0,17.11698 -69.31988,0 0,28.32175 69.31988,0 0,17.11698 27.09543,-15.63248 27.08251,-15.64537 -27.08251,-15.63248 -27.09543,-15.64538 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
transform="matrix(0.4679068,0,0,0.4679068,59.783914,181.11879)"
sodipodi:type="arc"
style="fill:none;stroke:#808080;stroke-width:10.80000019;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3635"
sodipodi:cx="268.57144"
sodipodi:cy="569.50507"
sodipodi:rx="171.42857"
sodipodi:ry="171.42857"
d="m 440.00002,569.50507 c 0,94.67738 -76.75119,171.42857 -171.42858,171.42857 -94.67739,0 -171.428572,-76.75119 -171.428572,-171.42857 0,-94.67739 76.751182,-171.42858 171.428572,-171.42858 94.67739,0 171.42858,76.75119 171.42858,171.42858 z" />
</g>
<path
sodipodi:type="arc"
style="fill:url(#radialGradient3639);fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path3637"
sodipodi:cx="307.14285"
sodipodi:cy="582.36218"
sodipodi:rx="158.57143"
sodipodi:ry="158.57143"
d="m 465.71428,582.36218 c 0,87.57658 -70.99485,158.57143 -158.57143,158.57143 -87.57658,0 -158.57142,-70.99485 -158.57142,-158.57143 0,-87.57658 70.99484,-158.57142 158.57142,-158.57142 87.57658,0 158.57143,70.99484 158.57143,158.57142 z"
transform="matrix(0.5847384,0,0,0.5847384,30.872504,70.269726)" />
</g>
</g>
</svg>

Depois

Largura:  |  Altura:  |  Tamanho: 9.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 8.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 8.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 8.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 2.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.9 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 82 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 82 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 175 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 178 B

+55
Ver Arquivo
@@ -0,0 +1,55 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<link rel="stylesheet" title="Standard" href="styles.css" type="text/css" media="screen" />
<!-- styles.css contains white for background colour - we'll need an equivalent css statement for a black background -->
<script language="JavaScript" type="text/javascript" src="contentflow.js" load="#BACKGROUND_COLOUR #ADDON"></script>
<script style="text/javascript">
var cf = new ContentFlow('contentFlow',
{reflectionColor: "#000000",
endOpacity : 0.3,
circularFlow: true,
startItem: #START,
scaleFactor: #FACTOR,
visibleItems: 7
});
</script>
<style>
body{
background: #BACKGROUND_COLOUR;
color: #FOREGROUND_COLOUR;
}
</style>
</head>
<body>
#MAXCOVERS
<div class="maincontent">
<div style="width: #WIDTHpx; margin: 0px auto;">
<!-- ===== FLOW ===== -->
<div id="contentFlow" class="ContentFlow">
<!-- should be place before flow so that contained images will be loaded first -->
<div class="loadIndicator"><div class="indicator"></div></div>
<div class="flow">
#ITEMS
</div>
#GLOBAL_CAPTION
<!--
<div class="scrollbar">
<div class="slider"></div>
</div>
-->
</div>
</div>
</div>
</body>
</html>
+231
Ver Arquivo
@@ -0,0 +1,231 @@
body {
background: white;
color: white;
font-size: 8pt;
font-family: sans-serif;
margin: 0;
padding: 0 7%;
}
.className{
background-color:#338BC7;
width:270px;
height:150px;
position:relative;
-moz-border-radius:6px;
-webkit-border-radius:6px;
border-radius:6px;
}
a,
a:link,
a:visited,
a:active,
a:hover {
text-decoration: none;
color: white;
font-weight: bold;
}
a:hover {
text-decoration: underline;
}
.clear { clear: both; }
img { border: none; }
h1 {
text-align: center;
text-decoration: underline;
font-family: serif;
color: white;
font-size: 1.8em;
}
h2 {
margin-top: 2.5em;
font-size: 1.7em;
text-decoration: underline;
}
h3 {
margin-top: 2em;
font-size: 1.3em;
text-decoration: underline;
}
p {
line-height: 150%;
text-align: justify;
}
pre {
font-family: sans-serif;
background: #222;
}
.simpleBlack {
background: black;
width: 80ex;
margin: 0 auto;
font-family: sans-serif;
}
code {
font-family: monospace;
font-size: 0.9em;
line-height: 150%;
}
dl {
margin-left: 4ex;
}
dl dt {
font-size: 0.9em;
font-weight: bold;
color: #eee;
font-family: monospace;
}
dl dd {
margin-bottom: 1.5em;
color: #ccc;
font-size: 0.85em;
line-height: 1.5em;
}
ol {
}
ol li {
margin-bottom: 1em;
line-height: 150%;
}
ul {
}
ul li {
margin-bottom: 0;
}
/* ------------------------------------------------------------------------- */
#title {
margin: 0px auto;
}
#sponsor {
position: absolute;
right: 7%;
font-size: 10px;
height: 66px;
line-height: 66px;
padding: 0 20px;
}
div.maincontent {
margin: 0px auto 20pt auto;
}
#menu {
display: block;
text-align: center;
background: #222;
padding: 1em;
margin: 2em auto 4em auto;
}
#menu li {
display: inline;
padding: 0px 20px;
}
.totop {
text-align: center;
margin: 4em 10%;
padding: 0.25em;
background: #161616;
}
.totop a {
margin-right: 7%;
color: silver;
}
.block {
display: none;
}
#browserComp {
border-collapse: collapse;
margin: 40px auto;
}
#browserComp caption {
text-align: center;
margin: 20px auto;
font-size: 1.1em;
font-weight: bold;
}
#browserComp th {
font-size: 10px;
padding: 5px 10px;
border-bottom: 1px solid silver;
}
#browserComp th img {
width: 22px;
}
#browserComp td {
text-align: center;
}
#browserComp th.feature,
#browserComp td.feature {
text-align: right;
padding: 5px;
padding-right: 10px;
border-right: 1px solid silver;
}
.addon {
border: 1px solid #222;
padding: 20px;
margin-bottom: 20px;
background: #222;
}
.addon .flowBox {
width: 500px;
margin-right: 40px;
float: left;
}
.addon .discription {
margin-left: 540px;
}
.addon .title {
line-height: 1.3em;
}
.addon .title h3 {
margin: 0;
display: inline;
}
.addon .title .by {
margin-left: 2em;
font-size: 0.8em;
text-decoration: none;
}
.addon p {
font-size: 0.9em;
}
.addon .comment {
margin-top: 2em;
font-style: italic;
}
.addon .download {
font-size: 0.8em;
float: right;
margin: 0 0 2em 4em;
line-height: 1.5em;
}
.addon .download a {
font-weight: normal;
}
#info { /* for example.php */
color: white;
/*display: none;*/
}
BIN
Ver Arquivo
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 60 KiB

+56
Ver Arquivo
@@ -0,0 +1,56 @@
import gi
from gi.repository import Pango
from gi.repository import Gtk
gi.require_version("Gtk", "3.0")
import logging
LOG = logging.getLogger(__name__)
def get_em(size=""):
# calc the height of a character, use as 1em
if size:
m = '<%s>M</%s>' % (size, size)
else:
m = 'M'
l = Gtk.Label()
l.set_markup(m)
w, h = l.get_layout().get_size()
return h / Pango.SCALE
def get_small_em():
return get_em("small")
def get_big_em():
return get_em("big")
EM = get_em()
SMALL_EM = get_small_em()
BIG_EM = get_big_em()
LOG.debug("EM's: %s %s %s" % (EM, SMALL_EM, BIG_EM))
def em(multiplier=1, min=1):
return max(int(min), int(round(EM * multiplier, 0)))
def small_em(multiplier=1, min=1):
return max(int(min), int(round(SMALL_EM * multiplier, 0)))
def big_em(multiplier=1, min=1):
return max(int(min), int(round(BIG_EM * multiplier, 0)))
# common values
class StockEms:
XLARGE = em(1.33, 5)
LARGE = em(min=3)
MEDIUM = em(0.666, 2)
SMALL = em(0.333, 1)
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 14 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 9.6 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 8.5 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 7.6 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 9.0 KiB

+93
Ver Arquivo
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/jrbastien/Dropbox/CoverArt/Issue_225/coverart_monochrome_icon5.png"
sodipodi:docname="coverart_icon_monochrome.svg"
inkscape:version="0.48.4 r9939"
version="1.1"
width="16"
height="16"
id="svg7384">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1313"
inkscape:window-height="744"
id="base"
showgrid="false"
inkscape:zoom="22.627417"
inkscape:cx="7.8121502"
inkscape:cy="8.1026068"
inkscape:window-x="53"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg7384">
<inkscape:grid
type="xygrid"
id="grid2984" />
</sodipodi:namedview>
<defs
id="defs13" />
<metadata
id="metadata90">
<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>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<path
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
d="M 0 1 L 0 15 L 16 15 L 16 1 L 0 1 z M 3 2 L 15 2 L 15 14 L 3 14 L 3 2 z "
id="path3049" />
<path
id="path3145"
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
d="m 8.49454,6.9999998 c -0.1963888,0 -0.2708736,0.00458 -0.421926,0.075312 C 7.8492631,7.1799014 7.6954236,7.3410447 7.5904128,7.5573095 7.5112238,7.7203905 7.5,7.8010382 7.5,7.9941194 c 0,0.1930808 0.011222,0.2737261 0.090413,0.4368099 0.1405533,0.2894579 0.401828,0.4949454 0.7233017,0.557309 0.1058087,0.020535 0.330263,0.013347 0.4369949,-0.015065 C 8.9273383,8.9261648 9.1300999,8.8031091 9.2479793,8.6719249 9.3497026,8.558718 9.4316453,8.391306 9.4740114,8.235115 c 0.034652,-0.1277581 0.034652,-0.3693021 0,-0.4970598 C 9.393561,7.4414403 9.2029191,7.2229953 8.9315348,7.0903743 8.7670195,7.0099746 8.6978322,6.9999998 8.49454,6.9999998 z m 0.00546,-3.2619392 c 0.3435847,0 0.6929605,0.032658 1.0213496,0.1135478 1.5301191,0.3769006 2.7439931,1.5920313 3.1207921,3.1225655 0.161741,0.6569562 0.161741,1.3868971 0,2.0438611 -0.413142,1.678183 -1.83062,2.926869 -3.5463542,3.179339 -0.2588467,0.03813 -0.7345973,0.05226 -0.9646085,0.02839 C 7.0640041,12.114865 6.1115479,11.676536 5.4075798,10.919964 4.646015,10.101478 4.2443755,9.103245 4.2443755,7.9961045 4.2443755,7.312468 4.3736153,6.7297403 4.6699382,6.1225653 5.2189083,4.9976584 6.2624431,4.1511883 7.4786511,3.8516084 7.8070437,3.7707188 8.1564165,3.7380606 8.5000013,3.7380606 z m 0,-0.738061 c -0.2467741,0 -0.4911568,0.00498 -0.6525293,0.028388 C 6.7061092,3.193961 5.780077,3.6778426 4.9820172,4.4761218 4.1839582,5.2743991 3.700631,6.2015307 3.5351045,7.3432048 c -0.046806,0.3228327 -0.046806,0.9829673 0,1.3058001 0.1655265,1.1416745 0.6488537,2.0688051 1.4469127,2.8670811 0.855663,0.855896 1.9055518,1.365449 3.1207923,1.476123 0.2703983,0.02463 0.8115804,-0.0132 1.1064627,-0.05677 1.0961058,-0.161943 2.0226018,-0.633028 2.8087138,-1.419348 0.798063,-0.798276 1.28138,-1.7254067 1.446912,-2.8670813 0.0468,-0.3228328 0.0468,-0.9829675 0,-1.3058001 C 13.299366,6.2015304 12.816049,5.2743988 12.017986,4.4761215 11.219926,3.6778423 10.293899,3.1939607 9.1525306,3.0283866 8.991163,3.0049817 8.7467754,2.9999996 8.5000013,2.9999996 z" />
<rect
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3809"
width="1.4146408"
height="13.103647"
x="-2.9486878"
y="2.1104977"
transform="matrix(0,-1,0.99999431,0.00337266,0,0)" />
<rect
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3809-0"
width="1.1411272"
height="13.103621"
x="-14.135278"
y="2.1503386"
transform="matrix(0,-1,0.9999963,0.00272058,0,0)" />
<rect
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3809-0-7"
width="1.1411272"
height="13.103621"
x="-15.180982"
y="-14.649317"
transform="matrix(-1,0,0.00272058,-0.9999963,0,0)" />
</svg>

Depois

Largura:  |  Altura:  |  Tamanho: 5.6 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.7 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 2.1 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 2.0 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 33 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 40 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 15 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 18 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.4 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 13 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 16 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 4.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.3 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 1.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 54 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 2.7 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 68 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 19 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.8 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 17 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 22 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 2.7 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.9 KiB

+115
Ver Arquivo
@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="entryview.svg"
inkscape:export-filename="/home/jrbastien/Dropbox/CoverArt/2.0/entryview17b.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="-5.40625"
inkscape:cy="9.34375"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1313"
inkscape:window-height="744"
inkscape:window-x="53"
inkscape:window-y="24"
inkscape:window-maximized="1">
<inkscape:grid
snapvisiblegridlinesonly="true"
enabled="true"
visible="true"
empspacing="5"
id="grid3833"
type="xygrid" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<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
transform="translate(0,-1028.3622)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Calque 1">
<path
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none"
d="M 1 4 L 1 20 L 17 20 L 17 16 L 16 16 L 16 19 L 2 19 L 2 5 L 16 5 L 16 9 L 17 9 L 17 4 L 1 4 z "
transform="translate(0,1028.3622)"
id="rect3048" />
<path
inkscape:transform-center-x="-1.3333345"
transform="matrix(0.34143645,0,0,0.3696158,10.73858,1033.6309)"
d="m 24.196071,26.328102 0,-13.527561 11.715211,6.76378 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="3.1415927"
sodipodi:arg1="2.0943951"
sodipodi:r2="3.9050703"
sodipodi:r1="7.8101406"
sodipodi:cy="19.564322"
sodipodi:cx="28.101141"
sodipodi:sides="3"
id="path3765-3-7"
style="color:#000000;fill:#bebebe;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
sodipodi:type="star"
inkscape:transform-center-y="4.6976063e-005" />
<rect
y="1040.3622"
x="11.697332"
height="1"
width="9.629981"
id="rect3090"
style="color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:transform-center-x="1.3333345"
transform="matrix(-0.34143645,0,0,0.3696158,21.26142,1033.6309)"
d="m 24.196071,26.328102 0,-13.527561 11.715211,6.76378 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="3.1415927"
sodipodi:arg1="2.0943951"
sodipodi:r2="3.9050703"
sodipodi:r1="7.8101406"
sodipodi:cy="19.564322"
sodipodi:cx="28.101141"
sodipodi:sides="3"
id="path3765-3-7-4"
style="color:#000000;fill:#bebebe;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
sodipodi:type="star"
inkscape:transform-center-y="4.6976063e-005" />
</g>
</svg>

Depois

Largura:  |  Altura:  |  Tamanho: 4.2 KiB

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais