?? contextbrowser.cpp
字號:
// (c) 2004 Christian Muehlhaeuser <chris@chris.de>// (c) 2005 Reigo Reinmets <xatax@hot.ee>// (c) 2005 Mark Kretschmann <markey@web.de>// (c) 2006 Peter C. Ndikuwera <pndiku@gmail.com>// (c) 2006 Alexandre Pereira de Oliveira <aleprj@gmail.com>// (c) 2006 Maximilian Kossick <maximilian.kossick@googlemail.com>// License: GNU General Public License V2#define DEBUG_PREFIX "ContextBrowser"#include "amarok.h"#include "amarokconfig.h"#include "app.h"#include "browserToolBar.h"#include "debug.h"#include "clicklineedit.h"#include "collectiondb.h"#include "collectionbrowser.h"#include "colorgenerator.h"#include "contextbrowser.h"#include "coverfetcher.h"#include "covermanager.h"#include "cuefile.h"#include "enginecontroller.h"#include "htmlview.h"#include "lastfm.h"#include "mediabrowser.h"#include "metabundle.h"#include "mountpointmanager.h"#include "playlist.h" //appendMedia()#include "podcastbundle.h"#include "qstringx.h"#include "scriptmanager.h"#include "starmanager.h"#include "statusbar.h"#include "tagdialog.h"#include "threadmanager.h"#include <qbuffer.h>#include <qdatetime.h>#include <qdeepcopy.h>#include <qdom.h>#include <qimage.h>#include <qregexp.h>#include <qtextstream.h> // External CSS reading#include <qvbox.h> //wiki tab#include <qhbox.h>#include <qlayout.h>#include <qlineedit.h>#include <qlistview.h>#include <qtimer.h>#include <qtooltip.h>#include <kaction.h>#include <kapplication.h> //kapp#include <kcalendarsystem.h> // for Amarok::verboseTimeSince()#include <kconfig.h> // suggested/related/favorite box visibility#include <kdialog.h>#include <kfiledialog.h>#include <kglobal.h>#include <kiconloader.h>#include <kio/job.h>#include <kio/jobclasses.h>#include <kmdcodec.h> // for data: URLs#include <kmessagebox.h>#include <kpopupmenu.h>#include <kstandarddirs.h>#include <ktextedit.h>#include <ktoolbarbutton.h>#include <unistd.h> //usleep()namespace Amarok{ QString escapeHTML( const QString &s ) { return QString(s).replace( "&", "&" ).replace( "<", "<" ).replace( ">", ">" ); // .replace( "%", "%25" ) has to be the first(!) one, otherwise we would do things like converting spaces into %20 and then convert them into %25%20 } QString escapeHTMLAttr( const QString &s ) { return QString(s).replace( "%", "%25" ).replace( "'", "%27" ).replace( "\"", "%22" ).replace( "#", "%23" ).replace( "?", "%3F" ); } QString unescapeHTMLAttr( const QString &s ) { return QString(s).replace( "%3F", "?" ).replace( "%23", "#" ).replace( "%22", "\"" ).replace( "%27", "'" ).replace( "%25", "%" ); } QString verboseTimeSince( const QDateTime &datetime ) { const QDateTime now = QDateTime::currentDateTime(); const int datediff = datetime.daysTo( now ); if( datediff >= 6*7 /*six weeks*/ ) { // return absolute month/year const KCalendarSystem *cal = KGlobal::locale()->calendar(); const QDate date = datetime.date(); return i18n( "monthname year", "%1 %2" ).arg( cal->monthName(date), cal->yearString(date, false) ); } //TODO "last week" = maybe within 7 days, but prolly before last sunday if( datediff >= 7 ) // return difference in weeks return i18n( "One week ago", "%n weeks ago", (datediff+3)/7 ); if( datediff == -1 ) return i18n( "Tomorrow" ); const int timediff = datetime.secsTo( now ); if( timediff >= 24*60*60 /*24 hours*/ ) // return difference in days return datediff == 1 ? i18n( "Yesterday" ) : i18n( "One day ago", "%n days ago", (timediff+12*60*60)/(24*60*60) ); if( timediff >= 90*60 /*90 minutes*/ ) // return difference in hours return i18n( "One hour ago", "%n hours ago", (timediff+30*60)/(60*60) ); //TODO are we too specific here? Be more fuzzy? ie, use units of 5 minutes, or "Recently" if( timediff >= 0 ) // return difference in minutes return timediff/60 ? i18n( "One minute ago", "%n minutes ago", (timediff+30)/60 ) : i18n( "Within the last minute" ); return i18n( "The future" ); } QString verboseTimeSince( uint time_t ) { if( !time_t ) return i18n( "Never" ); QDateTime dt; dt.setTime_t( time_t ); return verboseTimeSince( dt ); } extern KConfig *config( const QString& ); /** * Function that must be used when separating contextBrowser escaped urls * detail can contain track/discnumber */ void albumArtistTrackFromUrl( QString url, QString &artist, QString &album, QString &detail ) { if ( !url.contains("@@@") ) return; //KHTML removes the trailing space! if ( url.endsWith( " @@@" ) ) url += ' '; const QStringList list = QStringList::split( " @@@ ", url, true ); int size = list.count(); Q_ASSERT( size>0 ); artist = size > 0 ? unescapeHTMLAttr( list[0] ) : ""; album = size > 1 ? unescapeHTMLAttr( list[1] ) : ""; detail = size > 2 ? unescapeHTMLAttr( list[2] ) : ""; }}using Amarok::QStringx;using Amarok::escapeHTML;using Amarok::escapeHTMLAttr;using Amarok::unescapeHTMLAttr;staticQString albumImageTooltip( const QString &albumImage, int size ){ if ( albumImage == CollectionDB::instance()->notAvailCover( false, size ) ) return escapeHTMLAttr( i18n( "Click to fetch cover from amazon.%1, right-click for menu." ).arg( CoverManager::amazonTld() ) ); return escapeHTMLAttr( i18n( "Click for information from Amazon, right-click for menu." ) );}ContextBrowser *ContextBrowser::s_instance = 0;QString ContextBrowser::s_wikiLocale = "en";ContextBrowser::ContextBrowser( const char *name ) : KTabWidget( 0, name ) , EngineObserver( EngineController::instance() ) , m_dirtyCurrentTrackPage( true ) , m_dirtyLyricsPage( true ) , m_dirtyWikiPage( true ) , m_emptyDB( CollectionDB::instance()->isEmpty() ) , m_wikiBackPopup( new KPopupMenu( this ) ) , m_wikiForwardPopup( new KPopupMenu( this ) ) , m_wikiJob( NULL ) , m_wikiConfigDialog( NULL ) , m_relatedOpen( true ) , m_suggestionsOpen( true ) , m_favoritesOpen( true ) , m_labelsOpen( true ) , m_showFreshPodcasts( true ) , m_showFavoriteAlbums( true ) , m_showNewestAlbums( true ) , m_browseArtists( false ) , m_browseLabels( false ) , m_cuefile( NULL ){ s_instance = this; s_wikiLocale = AmarokConfig::wikipediaLocale(); m_contextTab = new QVBox(this, "context_tab"); m_currentTrackPage = new HTMLView( m_contextTab, "current_track_page", true /* DNDEnabled */, true /*JScriptEnabled*/ ); m_lyricsTab = new QVBox(this, "lyrics_tab"); m_lyricsToolBar = new Browser::ToolBar( m_lyricsTab ); m_lyricsToolBar->setIconText( KToolBar::IconTextRight, false ); m_lyricsToolBar->insertButton( Amarok::icon( "refresh" ), LYRICS_REFRESH, true, i18n("Refresh") ); m_lyricsToolBar->insertButton( Amarok::icon( "add_lyrics" ), LYRICS_ADD, true, i18n("Add") ); m_lyricsToolBar->insertButton( Amarok::icon( "edit" ), LYRICS_EDIT, true, i18n("Edit") ); m_lyricsToolBar->setToggle( LYRICS_EDIT, true ); m_lyricsToolBar->insertButton( Amarok::icon( "search" ), LYRICS_SEARCH, true, i18n("Search") ); m_lyricsToolBar->setIconText( KToolBar::IconOnly, false ); m_lyricsToolBar->insertButton( Amarok::icon( "external" ), LYRICS_BROWSER, true, i18n("Open in external browser") ); { //Search text inside lyrics. Code inspired/copied from playlistwindow.cpp m_lyricsTextBar = new KToolBar( m_lyricsTab, "NotMainToolBar" ); m_lyricsTextBar->hide(); m_lyricsTextBarShowed=false; m_lyricsTextBar->setIconSize( 22, false ); //looks more sensible m_lyricsTextBar->setFlat( true ); //removes the ugly frame m_lyricsTextBar->setMovingEnabled( false ); //removes the ugly frame m_lyricsTextBar->boxLayout()->addStretch(); QWidget *button = new KToolBarButton( "locationbar_erase", 1, m_lyricsTextBar ); QLabel *filter_label = new QLabel( i18n("S&earch:") + ' ', m_lyricsTextBar ); m_lyricsSearchText = new ClickLineEdit( i18n( "Search in lyrics" ), m_lyricsTextBar ); filter_label->setBuddy( m_lyricsSearchText ); m_lyricsTextBar->setStretchableWidget(m_lyricsSearchText ); m_lyricsSearchText->setFrame( QFrame::Sunken ); m_lyricsSearchText->installEventFilter( this ); //we intercept keyEvents connect( button, SIGNAL(clicked()), m_lyricsSearchText, SLOT(clear()) ); QToolTip::add( button, i18n( "Clear search" ) ); QString filtertip = i18n( "Enter text to search for. Press enter to advance to the next match." ); QToolTip::add( m_lyricsSearchText, filtertip ); connect ( button, SIGNAL(clicked()), m_lyricsSearchText, SLOT(clear()) ); connect ( m_lyricsSearchText, SIGNAL(textChanged(const QString &)), this, SLOT(lyricsSearchText(const QString & )) ); connect ( m_lyricsSearchText, SIGNAL(returnPressed()), this, (SLOT(lyricsSearchTextNext())) ); Amarok::actionCollection()->setAutoConnectShortcuts ( true ); new KAction( i18n("Search text in lyrics"), KShortcut("/"), this,SLOT( lyricsSearchTextShow() ), Amarok::actionCollection(), "search_text_lyric"); Amarok::actionCollection()->setAutoConnectShortcuts ( false ); } m_lyricsPage = new HTMLView( m_lyricsTab, "lyrics_page", true /* DNDEnabled */, false /* JScriptEnabled*/ ); m_lyricsTextEdit = new KTextEdit ( m_lyricsTab, "lyrics_text_edit"); m_lyricsTextEdit->setTextFormat( Qt::PlainText ); m_lyricsTextEdit->hide(); m_wikiTab = new QVBox(this, "wiki_tab"); m_wikiToolBar = new Browser::ToolBar( m_wikiTab ); m_wikiToolBar->insertButton( "back", WIKI_BACK, false, i18n("Back") ); m_wikiToolBar->insertButton( "forward", WIKI_FORWARD, false, i18n("Forward") ); m_wikiToolBar->insertLineSeparator(); m_wikiToolBar->insertButton( Amarok::icon( "artist" ), WIKI_ARTIST, false, i18n("Artist Page") ); m_wikiToolBar->insertButton( Amarok::icon( "album" ), WIKI_ALBUM, false, i18n("Album Page") ); m_wikiToolBar->insertButton( Amarok::icon( "track" ), WIKI_TITLE, false, i18n("Title Page") ); m_wikiToolBar->insertLineSeparator(); m_wikiToolBar->insertButton( Amarok::icon( "external" ), WIKI_BROWSER, true, i18n("Open in external browser") ); m_wikiToolBar->insertButton( Amarok::icon( "change_language" ), WIKI_CONFIG, true, i18n("Change Locale") ); m_wikiToolBar->setDelayedPopup( WIKI_BACK, m_wikiBackPopup ); m_wikiToolBar->setDelayedPopup( WIKI_FORWARD, m_wikiForwardPopup ); m_wikiPage = new HTMLView( m_wikiTab, "wiki_page", true /* DNDEnabled */, false /* JScriptEnabled */ ); m_cuefile = CueFile::instance(); connect( m_cuefile, SIGNAL(metaData( const MetaBundle& )), EngineController::instance(), SLOT(currentTrackMetaDataChanged( const MetaBundle& )) ); connect( m_cuefile, SIGNAL(newCuePoint( long, long, long )), Scrobbler::instance(), SLOT(subTrack( long, long, long )) ); addTab( m_contextTab, SmallIconSet( Amarok::icon( "music" ) ), i18n( "Music" ) ); addTab( m_lyricsTab, SmallIconSet( Amarok::icon( "lyrics" ) ), i18n( "Lyrics" ) ); addTab( m_wikiTab, SmallIconSet( Amarok::icon( "artist" ) ), i18n( "Artist" ) ); setTabEnabled( m_lyricsTab, false ); setTabEnabled( m_wikiTab, false ); m_showRelated = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowRelated", true ); m_showSuggested = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowSuggested", true ); m_showFaves = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowFaves", true ); m_showLabels = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowLabels", true ); m_showFreshPodcasts = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowFreshPodcasts", true ); m_showNewestAlbums = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowNewestAlbums", true ); m_showFavoriteAlbums = Amarok::config( "ContextBrowser" )->readBoolEntry( "ShowFavoriteAlbums", true ); // Delete folder with the cached coverimage shadow pixmaps KIO::del( KURL::fromPathOrURL( Amarok::saveLocation( "covershadow-cache/" ) ), false, false ); connect( this, SIGNAL( currentChanged( QWidget* ) ), SLOT( tabChanged( QWidget* ) ) ); connect( m_currentTrackPage->browserExtension(), SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ), this, SLOT( openURLRequest( const KURL & ) ) ); connect( m_lyricsPage->browserExtension(), SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ), this, SLOT( openURLRequest( const KURL & ) ) );
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -