📄 launcherview.cpp
字号:
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.** ** This program is free software; you can redistribute it and/or modify it** under the terms of the GNU General Public License as published by the** Free Software Foundation; either version 2 of the License, or (at your** option) any later version.** ** A copy of the GNU GPL license version 2 is included in this package as ** LICENSE.GPL.**** This program is distributed in the hope that it will be useful, but** WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details.**** In addition, as a special exception Trolltech gives permission to link** the code of this program with Qtopia applications copyrighted, developed** and distributed by Trolltech under the terms of the Qtopia Personal Use** License Agreement. You must comply with the GNU General Public License** in all respects for all of the code used other than the applications** licensed under the Qtopia Personal Use License Agreement. If you modify** this file, you may extend this exception to your version of the file,** but you are not obligated to do so. If you do not wish to do so, delete** this exception statement from your version.** ** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "launcherview.h"#include <qtopia/qpeapplication.h>#include <qtopia/applnk.h>#include <qtopia/qpedebug.h>#include <qtopia/categories.h>#include <qtopia/categoryselect.h>#include <qtopia/menubutton.h>#include <qtopia/mimetype.h>#include <qtopia/resource.h>#include <qtopia/qpetoolbar.h>#include <qtopia/global.h>#include <qtopia/stringutil.h>//#include <qtopia/private/palmtoprecord.h>#include <qaction.h>#include <qtimer.h>#include <qtextstream.h>#include <qdict.h>#include <qfile.h>#include <qfileinfo.h>#include <qhbox.h>#include <qiconview.h>#include <qwidgetstack.h>#include <qpainter.h>#include <qregexp.h>#include <qtoolbutton.h>#include <qimage.h>#include <qlabel.h>#include <qobjectlist.h>// These define how the busy icon is animated and highlighted#define BRIGHTEN_BUSY_ICON//#define ALPHA_FADE_BUSY_ICON//#define USE_ANIMATED_BUSY_ICON_OVERLAY#define BOUNCE_BUSY_ICONclass BgPixmap{public: BgPixmap( const QPixmap &p ) : pm(p), ref(1) {} QPixmap pm; int ref;};static QMap<QString,BgPixmap*> *bgCache = 0;static void cleanup_cache(){ QMap<QString,BgPixmap*>::Iterator it = bgCache->begin(); while ( it != bgCache->end() ) { QMap<QString,BgPixmap*>::Iterator curr = it; ++it; delete (*curr); bgCache->remove( curr ); } delete bgCache; bgCache = 0;}class LauncherItem : public QIconViewItem{public: LauncherItem( QIconView *parent, AppLnk* applnk, bool bigIcon=TRUE ); ~LauncherItem(); AppLnk *appLnk() const { return app; } AppLnk *takeAppLnk() { AppLnk* r=app; app=0; return r; } void animateIcon(); void resetIcon(); virtual int compare ( QIconViewItem * i ) const; void paintItem( QPainter *p, const QColorGroup &cg ); void paintFocus( QPainter *, const QColorGroup & ) {}protected: bool isBigIcon; int iteration; AppLnk* app;private: void paintAnimatedIcon( QPainter *p );};#ifdef QTOPIA_PHONE// XXX share mestatic int phoneKeyMatchN(const QString& haystack, const QString& needle, int n){ // XXX cache me / load me QString phonekey[8]; phonekey[0] = "abcABC"; phonekey[1] = "defDEF"; phonekey[2] = "ghiGHI"; phonekey[3] = "jklJKL"; phonekey[4] = "mnoMNO"; phonekey[5] = "pqrsQPRS"; phonekey[6] = "tuvTUV"; phonekey[7] = "wxyzWXYZ"; for (int i=0; i<n; i++) { int pk = needle[i]-'2'; if ( pk >= 0 && pk < 8 ) { QChar ch = haystack[i].lower(); if ( !phonekey[pk].contains(ch) ) return ch.unicode() - phonekey[pk][0].unicode(); } } return 0; // match!}#endifclass LauncherIconView : public QIconView { Q_OBJECTpublic: LauncherIconView( QWidget* parent, const char* name=0 ) : QIconView(parent,name), tf(""), cf(-2), bsy(0), busyTimer(0), bigIcns(TRUE), bgColor(white) {#ifdef QTOPIA_PHONE keytimer = new QTimer(this); connect(keytimer, SIGNAL(timeout()), this, SLOT(keyTimeout()));#endif sortmeth = Name; hidden.setAutoDelete(TRUE); ike = FALSE; calculateGrid( Bottom ); disconnect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(vslide(int))); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(vertScroll(int))); connect(this, SIGNAL(myvslide(int)), this, SLOT(vslide(int))); } ~LauncherIconView() {#if 0 // debuggery QListIterator<AppLnk> it(hidden); AppLnk* l; while ((l=it.current())) { ++it; //qDebug("%p: hidden (should remove)",l); }#endif } QIconViewItem* busyItem() const { return bsy; }#ifdef USE_ANIMATED_BUSY_ICON_OVERLAY QPixmap busyPixmap() const { return busyPix; }#endif void setBigIcons( bool bi ) { bigIcns = bi;#ifdef USE_ANIMATED_BUSY_ICON_OVERLAY busyPix.resize(0,0);#endif } void updateCategoriesAndMimeTypes(); void doAutoScroll() { // We don't want rubberbanding (yet) } void setBusy(bool on) {#ifdef USE_ANIMATED_BUSY_ICON_OVERLAY if ( busyPix.isNull() ) { int size = ( bigIcns ) ? AppLnk::bigIconSize() : AppLnk::smallIconSize(); busyPix.convertFromImage( Resource::loadImage( "busy" ).smoothScale( size * 16, size ) ); }#endif if ( on ) { busyTimer = startTimer( 100 ); } else { if ( busyTimer ) { killTimer( busyTimer ); busyTimer = 0; } } LauncherItem *c = on ? (LauncherItem*)currentItem() : 0; if ( bsy != c ) { LauncherItem *oldBusy = bsy; bsy = c; if ( oldBusy ) oldBusy->resetIcon(); if ( bsy ) bsy->animateIcon(); } } bool inKeyEvent() const { return ike; } void keyPressEvent(QKeyEvent* e) { ike = TRUE; if ( e->key() == Key_F33 /* OK button */ || e->key() == Key_Space ) { if ( (e->state() & ShiftButton) ) emit mouseButtonPressed(ShiftButton, currentItem(), QPoint() ); else returnPressed(currentItem());#ifdef QTOPIA_PHONE } else if ( e->ascii() >= '2' && e->ascii() <= '9' ) { static const int ABC_AUTOEND_TIME=700; keytimer->start(ABC_AUTOEND_TIME, TRUE); keychars += e->ascii(); QIconViewItem* i = firstItem(); QIconViewItem* sel = 0; while (i) { QString n = i->text(); int m = phoneKeyMatchN(n,keychars,keychars.length()); if ( m == 0 ) { sel = i; break; } else if ( m > 0 ) { if ( !sel ) sel = i; } i = i->nextItem(); } if ( sel ) setCurrentItem(sel); } else { keychars = "";#endif } QIconView::keyPressEvent(e); ike = FALSE; }private:#ifdef QTOPIA_PHONE QString keychars; QTimer *keytimer;#endifprivate slots: void keyTimeout() {#ifdef QTOPIA_PHONE keychars = "";#endif }signals: void myvslide(int pos);public: LauncherItem *addItem(AppLnk* app, bool resort=TRUE); bool removeLink(const QString& linkfile); QStringList mimeTypes() const; QStringList categories() const; void clear() { bsy = 0; mimes.clear(); QIconView::clear(); hidden.clear(); } void addCatsAndMimes(AppLnk* app) { // No longer... // QStringList c = app->categories(); // for (QStringList::ConstIterator cit=c.begin(); cit!=c.end(); ++cit) { // cats.replace(*cit,(void*)1); // } QString maj=app->type(); int sl=maj.find('/'); if (sl>=0) { QString k; k = maj.left(12) == "application/" ? maj : maj.left(sl); mimes.replace(k,(void*)1); } } void setBackgroundOrigin( QWidget::BackgroundOrigin ) { } void setBackgroundPixmap( const QPixmap &pm ) { QIconView::setBackgroundPixmap(pm); bgPixmap = pm; } void setBackgroundColor( const QColor &c ) { bgColor = c; } void drawBackground( QPainter *p, const QRect &r ) { if ( !bgPixmap.isNull() ) { if (!hasStaticBackground()) { p->drawTiledPixmap( r, bgPixmap, QPoint( (r.x() + contentsX()) % bgPixmap.width(), (r.y() + contentsY()) % bgPixmap.height() ) ); } else { QPoint offs(0, 0); offs = mapToGlobal(offs); p->drawPixmap(r.x(), r.y(), bgPixmap, r.x()+offs.x(), r.y()+offs.y(), r.width(), r.height()); } } else {#ifdef QTOPIA_PHONE QIconView::drawBackground(p, r);#else p->fillRect( r, bgColor );#endif } } void setItemTextPos( ItemTextPos pos ) { calculateGrid( pos ); QIconView::setItemTextPos( pos ); } void hideOrShowItems(bool resort); void setTypeFilter(const QString& typefilter, bool resort) { tf = QRegExp(typefilter,FALSE,TRUE); hideOrShowItems(resort); } void setCategoryFilter( int catfilter, bool resort ) { Categories cat; cat.load( categoryFileName() ); QString str; cf = catfilter; hideOrShowItems(resort); } enum SortMethod { Name, Date, Type }; void setSortMethod( SortMethod m ) { if ( sortmeth != m ) { sortmeth = m; sort(); } } int compare(const AppLnk* a, const AppLnk* b) { switch (sortmeth) { case Name: return Qtopia::dehyphenate(a->name()).lower() .compare(Qtopia::dehyphenate(b->name()).lower()); case Date: { QFileInfo fa(a->linkFileKnown() ? a->linkFile() : a->file()); QFileInfo fb(b->linkFileKnown() ? b->linkFile() : b->file()); return fa.lastModified().secsTo(fb.lastModified()); } case Type: return a->type().compare(b->type()); } return 0; }protected: void timerEvent( QTimerEvent *te ) { if ( te->timerId() == busyTimer ) { if ( bsy ) bsy->animateIcon(); } else { QIconView::timerEvent( te ); } } void styleChange( QStyle &old ) { QIconView::styleChange( old ); calculateGrid( itemTextPos() ); } void calculateGrid( ItemTextPos pos ) { int dw = QApplication::desktop()->width(); int viewerWidth = dw-style().scrollBarExtent().width(); if ( pos == Bottom ) { int cols = 3; if ( viewerWidth <= 200 ) cols = 2; else if ( viewerWidth >= 400 ) cols = viewerWidth/96; setSpacing( 4 ); setGridX( (viewerWidth-(cols+1)*spacing())/cols ); setGridY( fontMetrics().height()*2+24 ); } else { int cols = 2;#ifdef QTOPIA_PHONE if ( viewerWidth < 240 )#else if ( viewerWidth < 150 )#endif cols = 1; else if ( viewerWidth >= 400 ) cols = viewerWidth/150; setSpacing( 2 ); setGridX( (viewerWidth-(cols+1)*spacing())/cols ); setGridY( fontMetrics().height()+2 ); } } void resizeEvent( QResizeEvent *e ) { QIconView::resizeEvent(e); if ((e->size().width() != e->oldSize().width()) || (e->size().height() != e->oldSize().height())) { calculateGrid(itemTextPos()); hideOrShowItems(FALSE); } } void focusInEvent( QFocusEvent * ) {} void focusOutEvent( QFocusEvent * ) {}private slots: void vertScroll(int pos) { if (hasStaticBackground()) { if (pos < verticalScrollBar()->maxValue()) { int step = gridY()+spacing(); pos = (pos + step/2) / step * step; } } emit myvslide(pos); }private: QList<AppLnk> hidden; QDict<void> mimes; SortMethod sortmeth; QRegExp tf; int cf; LauncherItem* bsy; int busyTimer; bool ike; bool bigIcns; QPixmap bgPixmap; QColor bgColor;#ifdef USE_ANIMATED_BUSY_ICON_OVERLAY QPixmap busyPix;#endif};bool LauncherView::bsy=FALSE;void LauncherView::setBusy(bool on){ icons->setBusy(on);}LauncherItem::LauncherItem( QIconView *parent, AppLnk *applnk, bool bigIcon ) : QIconViewItem( parent, applnk->name(), bigIcon ? applnk->bigPixmap() :applnk->pixmap() ), isBigIcon( bigIcon ), iteration(0), app(applnk) // Takes ownership{}LauncherItem::~LauncherItem(){ LauncherIconView* liv = (LauncherIconView*)iconView(); if ( liv->busyItem() == this ) liv->setBusy(FALSE); delete app;}int LauncherItem::compare ( QIconViewItem * i ) const{ LauncherIconView* view = (LauncherIconView*)iconView(); return view->compare(app,((LauncherItem *)i)->appLnk());}void LauncherItem::paintItem( QPainter *p, const QColorGroup &cg ){ LauncherIconView* liv = (LauncherIconView*)iconView(); QBrush oldBrush( liv->itemTextBackground() ); QColorGroup mycg( cg ); if ( liv->currentItem() == this ) { liv->setItemTextBackground( cg.brush( QColorGroup::Highlight ) ); mycg.setColor( QColorGroup::Text, cg.color( QColorGroup::HighlightedText ) ); } QIconViewItem::paintItem(p,mycg); // Paint animation overlay if ( liv->busyItem() == this ) paintAnimatedIcon(p); if ( liv->currentItem() == this ) liv->setItemTextBackground( oldBrush );}void LauncherItem::paintAnimatedIcon( QPainter *p ){ LauncherIconView* liv = (LauncherIconView*)iconView(); int w = pixmap()->width(), h = pixmap()->height(); QPixmap dblBuf( w, h + 4 ); QPainter p2( &dblBuf ); int x1, y1; if ( liv->itemTextPos() == QIconView::Bottom ) { x1 = x() + (width() - w) / 2 - liv->contentsX(); y1 = y() - liv->contentsY(); } else { x1 = x() - liv->contentsX(); y1 = y() + (height() - h) / 2 - liv->contentsY(); } y1 -= 2; p2.translate(-x1,-y1); liv->drawBackground( &p2, QRect(x1,y1,w,h+4) ); int bounceY = 2;#ifdef BOUNCE_BUSY_ICON bounceY = 4 - ((iteration+2)%8); bounceY = bounceY < 0 ? -bounceY : bounceY;#endif p2.drawPixmap( x1, y1 + bounceY, *pixmap() );#ifdef USE_ANIMATED_BUSY_ICON_OVERLAY int pic = iteration % 16; p2.drawPixmap( x1, y1 + bounceY, liv->busyPixmap(), w * pic, 0, w, h );#endif p->drawPixmap( x1, y1, dblBuf );}void LauncherItem::animateIcon(){ LauncherIconView* liv = (LauncherIconView*)iconView(); if ( liv->busyItem() != this || !app ) return; // Highlight the icon if ( iteration == 0 ) { QPixmap src = isBigIcon ? app->bigPixmap() : app->pixmap(); QImage img = src.convertToImage(); QRgb *rgb; int count; if ( img.depth() == 32 ) { rgb = (QRgb*)img.bits(); count = img.bytesPerLine()/sizeof(QRgb)*img.height(); } else { rgb = img.colorTable(); count = img.numColors(); } for ( int r = 0; r < count; r++, rgb++ ) {#if defined(BRIGHTEN_BUSY_ICON) QColor c(*rgb); int h, s, v; c.hsv(&h,&s,&v); c.setHsv(h,QMAX(s-24,0),QMIN(v+48,255)); *rgb = qRgba(c.red(),c.green(),c.blue(),qAlpha(*rgb));#elif defined(ALPHA_FADE_BUSY_ICON) *rgb = qRgba(qRed(*rgb),qGreen(*rgb),qBlue(*rgb),qAlpha(*rgb)/2);#endif } src.convertFromImage( img ); setPixmap( src ); } iteration++; // Paint animation overlay QPainter p( liv->viewport() ); paintAnimatedIcon( &p );}void LauncherItem::resetIcon(){ iteration = 0; setPixmap( isBigIcon ? app->bigPixmap() : app->pixmap() );}//===========================================================================QStringList LauncherIconView::mimeTypes() const{ QStringList r; QDictIterator<void> it(mimes); while (it.current()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -