📄 todotable.cpp
字号:
/************************************************************************ Copyright (C) 2000-2002 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** 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>#include <qasciidict.h>#include <qcombobox.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 <qsettings.h>#endif#include <errno.h>#include <stdlib.h>static int BoxSize = 14;static int RowHeight = 20;static Qt::ButtonState bState = Qt::NoButton;static int selectionBeginRow = -1;static QString applicationPath;static bool constructorDone = FALSE;static bool taskCompare( const PimTask &task, const QRegExp &r, int category );/* 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(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(TodoXmlIO *tasks, QWidget *parent, const char *name, const char *appPath ) : QTable( 0, 0, parent, name ), mCat( 0 ), currFindRow( -2 ){ applicationPath = appPath; 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 = tasks; mSel = NoSelection; d = new TablePrivate(); setCornerWidget( d->cornerButton(this) ); cornerWidget()->hide(); connect( d->cornerButton(this), SIGNAL( clicked() ), this, SLOT( cornerButtonClicked() ) ); mCat.load( categoryFileName() ); setSorting( TRUE ); QTable::setSelectionMode( QTable::NoSelection ); setLeftMargin( 0 );#ifndef QTOPIA_DESKTOP setFrameStyle( NoFrame );#endif verticalHeader()->hide(); horizontalHeader()->hide(); connect(horizontalHeader(), SIGNAL(clicked(int)), this, SLOT(headerClicked(int)) ); mSortColumn = -1; ascSort = FALSE; connect( this, SIGNAL( clicked( int, int, int, const QPoint & ) ), this, SLOT( slotClicked( int, int, int, const QPoint & ) ) ); connect( this, SIGNAL( pressed( int, int, int, const QPoint & ) ), this, SLOT( slotPressed( int, int, int, const QPoint & ) ) ); connect( this, SIGNAL( doubleClicked( int, int, int, const QPoint & ) ), this, SLOT( slotDoubleClicked( int, int, int, const QPoint & ) ) ); connect( this, SIGNAL( currentChanged( int, int ) ), this, SLOT( slotCurrentChanged( 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 ) { mSelected.clear(); refresh(); } mSel = m;}QValueList<QUuid> TodoTable::selectedTasks(){ QValueList<QUuid> list; if ( mSel == Single ) { if ( hasCurrentEntry() ) list.append( currentEntry().uid() ); } else if ( mSel == Extended ) { list = mSelected; // set current entry as selected when none is selected if ( !list.count() && hasCurrentEntry() ) list.append( currentEntry().uid() ); } return list;}QValueList<PimTask> TodoTable::selected(){ QValueList<PimTask> list; if ( mSel == Single ) { if ( hasCurrentEntry() ) list.append( currentEntry() ); } else if ( mSel == Extended ) { for ( QValueList<QUuid>::Iterator it = mSelected.begin(); it != mSelected.end(); ++it) { int i = pos( *it ); if ( i > -1 ) list.append( *mTasks->sortedTasks().at(i) ); } // set current entry as selected when none is selected if ( !list.count() && hasCurrentEntry() ) list.append( currentEntry() ); } return list;}void TodoTable::selectAll(){ if ( mSel == NoSelection || mSel == Single ) return; selectionBeginRow = -1; mSelected.clear(); for ( uint u = 0; u < mTasks->sortedTasks().count(); u++ ) { mSelected.append( mTasks->sortedTasks().at(u)->uid() ); } refresh();}// rework to support new selection modevoid TodoTable::setSelection(int /* row */){/* if ( mSel != NoSelection ) { PimTask task(*mTasks[row]); if ( mSel == Extended ) { QValueList<QUuid>::Iterator it = mSelected.find( task.uid() ); if ( (bState & Qt::ControlButton) || (bState & Qt::ShiftButton) ) { if ( it == mSelected.end() ) mSelected.append( task.uid() ); else mSelected.remove( task.uid() ); } else { mSelected.clear(); mSelected.append( task.uid() ); } bState = Qt::NoButton; } else if ( mSel == Single ) { mSelected.clear(); mSelected.append( task.uid() ); } if ( mSelected.count() == 0 ) emit currentChanged(); }*/}// 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){ // fromLow must be lower if ( toRow < fromRow ) { int t = toRow; toRow = fromRow; fromRow = t; } int row = fromRow; mSelected.clear(); while ( row <= toRow ) { mSelected.append( mTasks->sortedTasks().at(row)->uid() ); row++; }}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(); } mSelected.clear(); if ( mSortColumn > -1 ) { mTasks->setSorting( headerKeyFields[ mSortColumn ] , ascSort );// mTasks->sort(); } refresh(); setFocus(); // in case of inline widgets grabbing focus}int TodoTable::pos(const QUuid &id){ for ( uint u = 0; u < mTasks->sortedTasks().count(); u++ ) { if ( mTasks->sortedTasks().at(u)->uid() == id ) return u; } return -1;}void TodoTable::slotClicked( 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)mTasks->sortedTasks().count()) return; PimTask task(*mTasks->sortedTasks().at(row)); int field = headerKeyFields[ currentColumn() ]; switch ( field ) { case PimTask::CompletedField: { int x = pos.x() - columnPos( col ); int y = pos.y() - rowPos( row ); int w = columnWidth( col ); int h = rowHeight( row ); if ( x >= ( w - BoxSize ) / 2 && x <= ( w - BoxSize ) / 2 + BoxSize && y >= ( h - BoxSize ) / 2 && y <= ( h - BoxSize ) / 2 + BoxSize ) { task.setCompleted(!task.isCompleted()); task.setCompletedDate( QDate::currentDate() ); d->setModifiedTask( task.uid(), PimTask::CompletedField); emit updateTask( task ); return; } } break; case PimTask::Priority: { QWidget *w = beginEdit(row, col, FALSE); d->setEditorWidget(w, row, col ); QKeyEvent e(QEvent::KeyPress, 0x20, 0, Key_Space, " "); QPEApplication::sendEvent(w, &e); return; } break; default: menuTimer->stop(); emit clicked(); break; }}void TodoTable::keyPressEvent( QKeyEvent *e ){ if ( d->editorWidget() ) { endEdit(d->editorRow(), d->editorColumn(), FALSE, TRUE ); d->clearEditorWidget(); setFocus(); } int col = currentColumn(); int row = currentRow(); if (row < 0 || row >= (int)mTasks->sortedTasks().count()) return; if ( e->key() == Key_Space || e->key() == Key_Return ) { int field = headerKeyFields[ col ]; switch ( field ) { case PimTask::CompletedField: { PimTask task(*(mTasks->sortedTasks().at(row))); task.setCompleted(!task.isCompleted()); task.setCompletedDate( QDate::currentDate() ); d->setModifiedTask( task.uid(), PimTask::CompletedField); emit updateTask( task ); return; } break; case PimTask::Priority: { QWidget *w = beginEdit(row, col, FALSE); d->setEditorWidget(w, row, col ); QKeyEvent ek(QEvent::KeyPress, 0x20, 0, Key_Space, " "); QPEApplication::sendEvent(w, &ek); return; } break; default: emit clicked(); break; } } else { QTable::keyPressEvent( e ); }}void TodoTable::slotPressed( int row, int col, int, const QPoint &pos ){ if ( col == 2 && cellGeometry( row, col ).contains(pos) ) menuTimer->start( 750, TRUE );}void TodoTable::slotDoubleClicked(int, int, int, const QPoint &){ emit doubleClicked();}void TodoTable::slotCurrentChanged( int row, int ){// qDebug("slotCurrentChanged %d", row ); bool needRefresh = d->hasModifiedTask(); if ( mSel == Extended ) { if ( (bState & Qt::LeftButton) ) { if ( selectionBeginRow == -1 ) selectionBeginRow = row; else setSelection( selectionBeginRow, row); needRefresh = TRUE; } else { mSelected.clear(); needRefresh = TRUE; } } if ( needRefresh ) { d->clearModifiedTask(); refresh(); } menuTimer->stop(); emit currentChanged();}bool TodoTable::hasCurrentEntry(){ return mTasks->sortedTasks().count() != 0;}PimTask TodoTable::currentEntry(){ if (mTasks->sortedTasks().count() == 0) return PimTask(); if (currentRow() >= (int)mTasks->sortedTasks().count()) { setCurrentCell(mTasks->sortedTasks().count() - 1, currentColumn()); } else if (currentRow() < 0) { setCurrentCell(0, currentColumn()); } return PimTask(*(mTasks->sortedTasks().at(currentRow())));}void TodoTable::setCurrentEntry(const QUuid &u){ int rows, row; rows = numRows(); for ( row = 0; row < rows; row++ ) { if ( mTasks->sortedTasks().at(row)->uid() == u) { setCurrentCell(row, currentColumn()); break; } }}void TodoTable::sortColumn( int , bool, bool ){/* // external sort. switch(col) { case 0: ta.setSortOrder(SortedTasks::Completed); break; case 1: ta.setSortOrder(SortedTasks::Priority); break; case 2: ta.setSortOrder(SortedTasks::Description); break; case 3: ta.setSortOrder(SortedTasks::DueDate); break; } // gets QTable to repaint.... refresh();*/}void TodoTable::rowHeightChanged( int ){}void TodoTable::fontChange( const QFont &oldFont ){ 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; QTable::fontChange(oldFont);}void TodoTable::contentsMousePressEvent( QMouseEvent *e ){ if ( mSel == Extended ) { mSelected.clear(); bState = e->button(); } QTable::contentsMousePressEvent( e );}void TodoTable::contentsMouseReleaseEvent( QMouseEvent *e ){ if ( mSel == Extended ) { selectionBeginRow = -1; bState = Qt::NoButton; } QTable::contentsMouseReleaseEvent( e );}void TodoTable::resizeEvent( QResizeEvent *e ){ QTable::resizeEvent( e ); // we receive a resize event from qtable in the middle of the constrution, since // QTable::columnwidth does qApp->processEvents. Ignore this event as it causes // all sorts of init problems for us}void TodoTable::showEvent( QShowEvent *e){ QTable::showEvent(e);#ifdef QTOPIA_DESKTOP fitHeadersToWidth();#endif}void TodoTable::fitHeadersToWidth(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -