📄 todotable.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 "todotable.h"#include <qtopia/categoryselect.h>#include <qtopia/resource.h>#include <qtopia/qpeapplication.h>#include <qtopia/config.h>#include <qtopia/timestring.h>#ifdef QTOPIA_PHONE# include <qtopia/contextbar.h>#endif#include <qtopia/global.h>#include <qasciidict.h>#include <qcombobox.h>#include <qmessagebox.h>#include <qlistbox.h>#include <qfile.h>#include <qpainter.h>#include <qtextcodec.h>#include <qtimer.h>#include <qdatetime.h>#include <qstyle.h>#include <qheader.h>#include <qpushbutton.h>#include <qwidget.h>#include <qcursor.h>#include <qregexp.h>#ifdef QTOPIA_DESKTOP#include <qdconfig.h>#include <qsettings.h>#endif#include <errno.h>#include <stdlib.h>static const int cacheshift = 5; // cachsize = 1 << cacheshift//static const int cacheshift = 13;static int BoxSize = 14;static int RowHeight = 20;static Qt::ButtonState bState = Qt::NoButton;static int selectionBeginRow = -1;static int selectionEndRow = -1;static QString applicationPath;static bool constructorDone = FALSE;/* XPM */static char * menu_xpm[] = {"12 12 5 1"," c None",". c #000000","+ c #FFFDAD","@ c #FFFF00","# c #E5E100"," "," "," ......... "," .+++++++. "," .+@@@@#. "," .+@@@#. "," .+@@#. "," .+@#. "," .+#. "," .+. "," .. "," "};class TablePrivate{public: TablePrivate() { mEditedField = -1; mModified = FALSE; scrollButton = 0; wEditor = 0; } QUuid modifiedTask() { return mUid; } void clearModifiedTask() { mModified = FALSE; if ( scrollButton ) scrollButton->hide(); } QPushButton *cornerButton(QWidget *parent) { if ( !scrollButton ) { scrollButton = new QPushButton(parent); scrollButton->setPixmap( QPixmap( (const char**)menu_xpm) ); scrollButton->hide(); } return scrollButton; } void setModifiedTask(const QUuid &id, int field) { mUid = id; mEditedField = field; mModified = TRUE; if ( scrollButton ) scrollButton->show(); } int editedTaskField() { return mEditedField; } bool hasModifiedTask() { return mModified; } /* EditorWidget */ void setEditorWidget(QWidget *w, int row, int col) { wEditor = w; editRow = row; editCol = col; } void clearEditorWidget() { wEditor = 0; editRow = -1; editCol = -1; } QWidget *editorWidget() { return wEditor; } int editorColumn() { return editCol; } int editorRow() { return editRow; }private: int mEditedField; QUuid mUid; bool mModified; QPushButton *scrollButton; QWidget *wEditor; int editCol, editRow;};TodoTable::TodoTable(QWidget *parent, const char *name, const char *appPath , bool readonly ) : QTable( 0, 0, parent, name ), mCat( 0 ), mLastRowShown( -1 ), le(0), ro(readonly){ // value list iterators are uninialized until set to something. // need to set in case next is called before find. currFind = searchResults.end();#ifdef QTOPIA_PHONE setShowGrid(FALSE);#endif applicationPath = appPath; paletteChange(palette()); QFont f = font(); QFontMetrics fm(f); RowHeight = QMAX(20, fm.height() + 2); // keep it an even number, a bit over 3 / 4 of rowHeight. BoxSize = ( RowHeight * 3 ) / 4; BoxSize += BoxSize % 2; // do not!! put the below assignment in the constructor init, as the todoplugin for // qtopiadesktop fails to resolve the symbol mTasks = new TodoXmlIO(ro ? TaskIO::ReadOnly : TaskIO::ReadWrite); mSel = NoSelection; d = new TablePrivate();#ifndef QTOPIA_PHONE setCornerWidget( d->cornerButton(this) ); cornerWidget()->hide(); connect( d->cornerButton(this), SIGNAL( clicked() ), this, SLOT( cornerButtonClicked() ) );#endif mCat.load( categoryFileName() ); setSorting( TRUE ); QTable::setSelectionMode( QTable::NoSelection ); setLeftMargin( 0 );#ifndef QTOPIA_DESKTOP setFrameStyle( NoFrame );#endif verticalHeader()->hide(); horizontalHeader()->hide();#ifdef QTOPIA_PHONE horizontalHeader()->setResizeEnabled(FALSE); horizontalHeader()->setClickEnabled(FALSE);#endif connect(horizontalHeader(), SIGNAL(clicked(int)), this, SLOT(headerClicked(int)) ); mSortColumn = 0; ascSort = FALSE; connect( this, SIGNAL( clicked(int,int,int,const QPoint&) ), this, SLOT( activateCell(int,int,int,const QPoint&) ) ); connect( this, SIGNAL( pressed(int,int,int,const QPoint&) ), this, SLOT( startMenuTimer(int,int,int,const QPoint&) ) ); connect( this, SIGNAL( doubleClicked(int,int,int,const QPoint&) ), this, SIGNAL( doubleClicked() ) ); connect( this, SIGNAL( currentChanged(int,int) ), this, SLOT( refreshCell(int,int) ) ); //connect( &ta, SIGNAL( todolistUpdated() ), this, SLOT(refresh())); menuTimer = new QTimer( this ); connect( menuTimer, SIGNAL(timeout()), this, SIGNAL(pressed()) );#ifdef QTOPIA_DESKTOP readSettings();#else QTimer::singleShot(0, this, SLOT(readSettings()) );#endif}TodoTable::~TodoTable(){ saveSettings(); delete d;}void TodoTable::setSelectionMode(SelectionMode m){ if ( m == NoSelection && mSel != m ) { selectionBeginRow = -1; selectionEndRow = -1; refresh(); } mSel = m;}QValueList<int> TodoTable::selectedTasks(){ QValueList<int> list; if ( mSel == Single ) { if ( hasCurrentEntry() ) list.append( TodoXmlIO::uuidToInt(currentEntry().uid()) ); } else if ( mSel == Extended ) { int fromRow = QMIN(selectionBeginRow, selectionEndRow); int toRow = QMAX(selectionBeginRow, selectionEndRow); if (toRow != -1 && fromRow != -1) { int row = fromRow; while(row <= toRow) { list.append(TodoXmlIO::uuidToInt(mTasks->filteredItem(row).uid())); ++row; } } // set current entry as selected when none is selected if ( !list.count() && hasCurrentEntry() ) list.append( TodoXmlIO::uuidToInt(currentEntry().uid()) ); } return list;}/* not as bad as it looks value lists are implicitly shared.*/QValueList<PimTask> TodoTable::selected(){ QValueList<PimTask> list; if ( mSel == Single ) { if ( hasCurrentEntry() ) list.append( currentEntry() ); } else if ( mSel == Extended ) { int fromRow = QMIN(selectionBeginRow, selectionEndRow); int toRow = QMAX(selectionBeginRow, selectionEndRow); if (toRow != -1 && fromRow != -1) { int row = fromRow; while(row <= toRow) { PimTask t = mTasks->filteredItem(row); if (!t.uid().isNull()) list.append( t ); ++row; } } // set current entry as selected when none is selected if ( !list.count() && hasCurrentEntry() ) list.append( currentEntry() ); } return list;}void TodoTable::selectAll(){ setSelection(0, mFiltered.size() - 1); refresh();}// We clear the selection and loop through all the rows since currentChanged// will skip some rows if you move the pointing device fast enoughvoid TodoTable::setSelection(int fromRow, int toRow){ if ( mSel == NoSelection || mSel == Single ) return; selectionBeginRow = fromRow; selectionEndRow = toRow;}#ifdef Q_OS_UNIX#include <sys/time.h>#endifvoid TodoTable::saveData(bool force){ if (!ro) { if (!mTasks->saveData(force)) QMessageBox::information( this, tr( "Tasks" ), tr("<qt>Device full. Some changes may not be saved.</qt>")); }}void TodoTable::loadData(){ mTasks->ensureDataCurrent(TRUE);}bool TodoTable::categoriesChanged(const QArray<int> &cats){ bool changed = FALSE; QListIterator<PrTask> it(mTasks->tasks() ); for(; it.current(); ++it) { PimTask t( *(*it) ); if ( t.pruneDeadCategories( cats ) ) { mTasks->updateTask( t ); changed = TRUE; } } return changed;}void TodoTable::reload(){ // If the user applies outside filters we have to clear our internal state if ( d->editorWidget() ) { endEdit(d->editorRow(), d->editorColumn(), FALSE, TRUE ); d->clearEditorWidget(); } selectionBeginRow = -1; selectionEndRow = -1; /* Shouldnt' need to do this, only should need to do if sorting changes. */ if ( mSortColumn > -1 ) { mTasks->setSorting( headerKeyFields[ mSortColumn ] , ascSort ); }#ifdef Q_OS_UNIX struct timeval t1, t2, t3; gettimeofday(&t1, 0);#endif mFiltered.resize(mTasks->filteredCount());#ifdef Q_OS_UNIX gettimeofday(&t2, 0);#endif mFilteredLoaded.resize(1 + (mFiltered.size() >> cacheshift)); for (int i = 0; i < (int)mFilteredLoaded.size(); i++) mFilteredLoaded[i] = FALSE;#ifdef Q_OS_UNIX gettimeofday(&t3, 0); //qDebug("TIMING %ld:%ld, %ld:%ld, %ld:%ld", t1.tv_sec, t1.tv_usec, //t2.tv_sec, t2.tv_usec, //t3.tv_sec, t3.tv_usec);#endif refresh(); setFocus(); // in case of inline widgets grabbing focus emit currentChanged();}int TodoTable::pos(const int id){ int res = mTasks->filteredPos(id); return res;}class PriorityEdit : public QListBox { Q_OBJECTpublic: PriorityEdit(QWidget *parent) : QListBox(parent, "priorityedit", WType_Popup) { setAutoScrollBar( FALSE ); setBottomScrollBar( FALSE ); setAutoBottomScrollBar( FALSE ); // populate insertItem( "1" ); insertItem( "2" ); insertItem( "3" ); insertItem( "4" ); insertItem( "5" ); connect(this, SIGNAL(clicked(QListBoxItem*)), this, SLOT(internalSelectPriority())); } int currentPriority() const { return currentItem() + 1; }signals: void cancelEdit();private slots: void internalSelectPriority() { emit selected(currentItem()); }protected: void keyPressEvent(QKeyEvent *e) { switch (e->key()) {#ifdef QTOPIA_PHONE case Key_No: case Key_Back:#endif case Key_Escape: emit cancelEdit(); break; default: QListBox::keyPressEvent(e); } }};QWidget *TodoTable::priorityEdit(int row, int col){ if (!le) { le = new PriorityEdit(this);//, "priority_edit", WType_Popup); connect(le, SIGNAL(selected(int)), this, SLOT(delaySetCellContentFromEditor())); connect(le, SIGNAL(cancelEdit()), this, SLOT(delayCancelEdit())); } le->setCurrentItem( mTasks->filteredItem(row).priority() - 1 ); //size QWidget *desktop = QApplication::desktop(); int sh = desktop->height(); // screen height int x = 0; int y = 0; QPoint pos(columnPos(col), rowPos(row+1));//, x, y); // contentsToViewport seems buggy, always added 2000 to // each number for some strange reason. //pos = contentsToViewport(pos); pos = QPoint( pos.x() - contentsX(), pos.y() - contentsY() ); pos += QPoint(0, horizontalHeader()->height()); pos = mapToGlobal( pos ); // ### Similar code is in QPopupMenu le->resize(columnWidth(col) + le->frameWidth() * 2, 5 * le->item( 0 )->height(le) + le->frameWidth() * 2); x = pos.x(); y = pos.y(); int h = le->height(); if (y + h > sh ) { y -= h + rowHeight(row) - 2*le->frameWidth(); } le->move(x,y); //show le->raise(); le->show(); //connect return le;}void TodoTable::activateCell( int row, int col, int , const QPoint &pos ){ if ( d->editorWidget() ) { endEdit(d->editorRow(), d->editorColumn(), FALSE, TRUE ); d->clearEditorWidget(); } if ( !cellGeometry( row, col ).contains(pos) ) return; if (row < 0 || row >= (int)mFiltered.size()) return; PimTask task = mTasks->filteredItem(row); if (ro) { menuTimer->stop(); emit clicked(); } else { int field = headerKeyFields[ currentColumn() ]; switch ( field )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -