00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00077 #include "qxtflowview_p.h"
00078 #include <QWheelEvent>
00079
00080
00081
00082 QxtFlowView::QxtFlowView(QWidget* parent): QWidget(parent)
00083 {
00084 d = new QxtFlowViewPrivate;
00085
00086 d->model = 0;
00087 d->picrole = Qt::DecorationRole;
00088 d->textrole = Qt::DisplayRole;
00089 d->piccolumn = 0;
00090 d->textcolumn = 0;
00091
00092
00093
00094 d->state = new QxtFlowViewState;
00095 d->state->reset();
00096 d->state->reposition();
00097
00098 d->renderer = new QxtFlowViewSoftwareRenderer;
00099 d->renderer->state = d->state;
00100 d->renderer->widget = this;
00101 d->renderer->init();
00102
00103 d->animator = new QxtFlowViewAnimator;
00104 d->animator->state = d->state;
00105 QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
00106
00107 QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));
00108
00109 setAttribute(Qt::WA_StaticContents, true);
00110 setAttribute(Qt::WA_OpaquePaintEvent, true);
00111 setAttribute(Qt::WA_NoSystemBackground, true);
00112 }
00113
00114 QxtFlowView::~QxtFlowView()
00115 {
00116 delete d->renderer;
00117 delete d->animator;
00118 delete d->state;
00119 delete d;
00120 }
00121
00122 void QxtFlowView::setModel(QAbstractItemModel * model)
00123 {
00124 d->setModel(model);
00125 }
00126
00127 QAbstractItemModel * QxtFlowView::model()
00128 {
00129 return d->model;
00130 }
00131
00132
00133 QColor QxtFlowView::backgroundColor() const
00134 {
00135 return QColor(d->state->backgroundColor);
00136 }
00137
00138 void QxtFlowView::setBackgroundColor(const QColor& c)
00139 {
00140 d->state->backgroundColor = c.rgb();
00141 triggerRender();
00142 }
00143
00144 QSize QxtFlowView::slideSize() const
00145 {
00146 return QSize(d->state->slideWidth, d->state->slideHeight);
00147 }
00148
00149 void QxtFlowView::setSlideSize(QSize size)
00150 {
00151 d->state->slideWidth = size.width();
00152 d->state->slideHeight = size.height();
00153 d->state->reposition();
00154 triggerRender();
00155 }
00156
00157 QxtFlowView::ReflectionEffect QxtFlowView::reflectionEffect() const
00158 {
00159 return d->state->reflectionEffect;
00160 }
00161
00162 void QxtFlowView::setReflectionEffect(ReflectionEffect effect)
00163 {
00164 d->state->reflectionEffect = effect;
00165 d->reset();
00166 }
00167
00168
00169 int QxtFlowView::pictureRole()
00170 {
00171 return d->picrole;
00172 }
00173
00174 void QxtFlowView::setPictureRole(int a)
00175 {
00176 d->picrole = a;
00177 d->reset();
00178 }
00179
00180
00181
00182
00183
00184 int QxtFlowView::pictureColumn()
00185 {
00186 return d->piccolumn;
00187 }
00188
00189 void QxtFlowView::setPictureColumn(int a)
00190 {
00191 d->piccolumn = a;
00192 d->reset();
00193 }
00194
00195 #if 0
00196 int QxtFlowView::textRole()
00197 {
00198 return d->textrole;
00199 }
00200
00201 void QxtFlowView::setTextRole(int a)
00202 {
00203 d->textrole = a;
00204 d->reset();
00205 }
00206
00207 int QxtFlowView::textColumn()
00208 {
00209 return d->textcolumn;
00210 }
00211
00212 void QxtFlowView::setTextColumn(int a)
00213 {
00214 d->textcolumn = a;
00215 d->reset();
00216 }
00217 #endif
00218
00219
00220 QModelIndex QxtFlowView::rootIndex() const
00221 {
00222 return d->rootindex;
00223 }
00224
00225 void QxtFlowView::setRootIndex(QModelIndex index)
00226 {
00227 d->rootindex = index;
00228 }
00229
00230
00231
00232 QModelIndex QxtFlowView::currentIndex() const
00233 {
00234 if (!d->model)
00235 return QModelIndex();
00236 return d->currentcenter;
00237 }
00238
00239 void QxtFlowView::setCurrentIndex(QModelIndex index)
00240 {
00241 d->setCurrentIndex(index);
00242 }
00243
00244
00245 void QxtFlowView::render()
00246 {
00247 d->renderer->dirty = true;
00248 update();
00249 }
00250
00251 void QxtFlowView::triggerRender()
00252 {
00253 d->triggerRender();
00254 }
00255
00256
00257 void QxtFlowView::showPrevious()
00258 {
00259 int step = d->animator->step;
00260 int center = d->state->centerIndex;
00261
00262 if (step > 0)
00263 d->animator->start(center);
00264
00265 if (step == 0)
00266 if (center > 0)
00267 d->animator->start(center - 1);
00268
00269 if (step < 0)
00270 d->animator->target = qMax(0, center - 2);
00271 }
00272
00273 void QxtFlowView::showNext()
00274 {
00275 int step = d->animator->step;
00276 int center = d->state->centerIndex;
00277
00278 if (step < 0)
00279 d->animator->start(center);
00280
00281 if (step == 0)
00282 if (center < d->state->slideImages.count() - 1)
00283 d->animator->start(center + 1);
00284
00285 if (step > 0)
00286 d->animator->target = qMin(center + 2, d->state->slideImages.count() - 1);
00287 }
00288
00289 void QxtFlowView::showSlide(QModelIndex index)
00290 {
00291 int r = d->modelmap.indexOf(index);
00292 if (r < 0)
00293 return;
00294
00295 d->showSlide(r);
00296 }
00297
00298 void QxtFlowView::keyPressEvent(QKeyEvent* event)
00299 {
00300 if (event->key() == Qt::Key_Left)
00301 {
00302 if (event->modifiers() == Qt::ControlModifier)
00303 d->showSlide(currentIndex().row() - 10);
00304 else
00305 showPrevious();
00306 event->accept();
00307 return;
00308 }
00309
00310 if (event->key() == Qt::Key_Right)
00311 {
00312 if (event->modifiers() == Qt::ControlModifier)
00313 d->showSlide(currentIndex().row() + 10);
00314 else
00315 showNext();
00316 event->accept();
00317 return;
00318 }
00319
00320 event->ignore();
00321 }
00322
00323 void QxtFlowView::mousePressEvent(QMouseEvent* event)
00324 {
00325 d->lastgrabpos = event->pos();
00326 }
00327
00328
00329
00330 void QxtFlowView::mouseMoveEvent(QMouseEvent * event)
00331 {
00332 int i = (event->pos() - d->lastgrabpos).x() / (d->state->slideWidth / 4);
00333 if (i > 0)
00334 {
00335 showPrevious();
00336 d->lastgrabpos = event->pos();
00337 }
00338 if (i < 0)
00339 {
00340 showNext();
00341 d->lastgrabpos = event->pos();
00342 }
00343
00344 }
00345
00346 void QxtFlowView::mouseReleaseEvent(QMouseEvent* event)
00347 {
00348 Q_UNUSED(event);
00349
00350 }
00351
00352
00353 void QxtFlowView::paintEvent(QPaintEvent* event)
00354 {
00355 Q_UNUSED(event);
00356 d->renderer->paint();
00357 }
00358
00359 void QxtFlowView::resizeEvent(QResizeEvent* event)
00360 {
00361 triggerRender();
00362 QWidget::resizeEvent(event);
00363 }
00364
00365
00366
00367 void QxtFlowView::wheelEvent(QWheelEvent * event)
00368 {
00369
00370 if (event->orientation() == Qt::Horizontal)
00371 {
00372 event->ignore();
00373 }
00374 else
00375 {
00376 int numSteps = -((event->delta() / 8) / 15);
00377
00378
00379
00380 if (numSteps > 0)
00381 {
00382 for (int i = 0;i < numSteps;i++)
00383 {
00384 showNext();
00385 }
00386 }
00387 else
00388 {
00389 for (int i = numSteps;i < 0;i++)
00390 {
00391 showPrevious();
00392 }
00393 }
00394 event->accept();
00395 }
00396
00397
00398 }
00399
00400
00401
00402
00403 void QxtFlowView::updateAnimation()
00404 {
00405 int old_center = d->state->centerIndex;
00406 d->animator->update();
00407 triggerRender();
00408 if (d->state->centerIndex != old_center)
00409 {
00410 d->currentcenter = d->modelmap.at(d->state->centerIndex);
00411 emit currentIndexChanged(d->currentcenter);
00412 }
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 void QxtFlowViewPrivate::columnsAboutToBeInserted(const QModelIndex & parent, int start, int end)
00424 {
00425 Q_UNUSED(parent);
00426 Q_UNUSED(start);
00427 Q_UNUSED(end);
00428
00429 }
00430
00431 void QxtFlowViewPrivate::columnsAboutToBeRemoved(const QModelIndex & parent, int start, int end)
00432 {
00433 Q_UNUSED(parent);
00434 Q_UNUSED(start);
00435 Q_UNUSED(end);
00436
00437 }
00438
00439 void QxtFlowViewPrivate::columnsInserted(const QModelIndex & parent, int start, int end)
00440 {
00441 Q_UNUSED(parent);
00442 Q_UNUSED(start);
00443 Q_UNUSED(end);
00444
00445 }
00446
00447 void QxtFlowViewPrivate::columnsRemoved(const QModelIndex & parent, int start, int end)
00448 {
00449 Q_UNUSED(parent);
00450 Q_UNUSED(start);
00451 Q_UNUSED(end);
00452 }
00453
00454 void QxtFlowViewPrivate::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight)
00455 {
00456 Q_UNUSED(topLeft);
00457 Q_UNUSED(bottomRight);
00458
00459 if (topLeft.parent() != rootindex)
00460 return;
00461
00462 if (bottomRight.parent() != rootindex)
00463 return;
00464
00465
00466 int start = topLeft.row();
00467 int end = bottomRight.row();
00468
00469 for (int i = start;i <= end;i++)
00470 replaceSlide(i, qvariant_cast<QImage>(model->data(model->index(i, piccolumn, rootindex), picrole)));
00471 }
00472
00473 void QxtFlowViewPrivate::headerDataChanged(Qt::Orientation orientation, int first, int last)
00474 {
00475 Q_UNUSED(orientation);
00476 Q_UNUSED(first);
00477 Q_UNUSED(last);
00478
00479
00480
00481
00482
00483 }
00484
00485 void QxtFlowViewPrivate::layoutAboutToBeChanged()
00486 {
00487
00488 }
00489
00490 void QxtFlowViewPrivate::layoutChanged()
00491 {
00492 reset();
00493 setCurrentIndex(currentcenter);
00494 }
00495
00496 void QxtFlowViewPrivate::modelAboutToBeReset()
00497 {
00498 }
00499
00500 void QxtFlowViewPrivate::modelReset()
00501 {
00502 reset();
00503 }
00504
00505 void QxtFlowViewPrivate::rowsAboutToBeInserted(const QModelIndex & parent, int start, int end)
00506 {
00507 Q_UNUSED(parent);
00508 Q_UNUSED(start);
00509 Q_UNUSED(end);
00510 }
00511
00512 void QxtFlowViewPrivate::rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end)
00513 {
00514 Q_UNUSED(parent);
00515 Q_UNUSED(start);
00516 Q_UNUSED(end);
00517 }
00518
00519 void QxtFlowViewPrivate::rowsInserted(const QModelIndex & parent, int start, int end)
00520 {
00521 if (rootindex != parent)
00522 return;
00523 for (int i = start;i <= end;i++)
00524 {
00525 QModelIndex idx = model->index(i, piccolumn, rootindex);
00526 insertSlide(i, qvariant_cast<QImage>(model->data(idx, picrole)));
00527 modelmap.insert(i, idx);
00528 }
00529 }
00530
00531 void QxtFlowViewPrivate::rowsRemoved(const QModelIndex & parent, int start, int end)
00532 {
00533 if (rootindex != parent)
00534 return;
00535 for (int i = start;i <= end;i++)
00536 {
00537 removeSlide(i);
00538 modelmap.removeAt(i);
00539 }
00540
00541 }
00542
00543 void QxtFlowViewPrivate::setModel(QAbstractItemModel * m)
00544 {
00545
00546
00547 if (model)
00548 {
00549
00550 disconnect(this->model, SIGNAL(columnsAboutToBeInserted(const QModelIndex & , int , int)),
00551 this, SLOT(columnsAboutToBeInserted(const QModelIndex & , int , int)));
00552 disconnect(this->model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex & , int , int)),
00553 this, SLOT(columnsAboutToBeRemoved(const QModelIndex & , int , int)));
00554 disconnect(this->model, SIGNAL(columnsInserted(const QModelIndex & , int , int)),
00555 this, SLOT(columnsInserted(const QModelIndex & , int , int)));
00556 disconnect(this->model, SIGNAL(columnsRemoved(const QModelIndex & , int , int)),
00557 this, SLOT(columnsRemoved(const QModelIndex & , int , int)));
00558 disconnect(this->model, SIGNAL(dataChanged(const QModelIndex & , const QModelIndex &)),
00559 this, SLOT(dataChanged(const QModelIndex & , const QModelIndex &)));
00560 disconnect(this->model, SIGNAL(headerDataChanged(Qt::Orientation , int , int)),
00561 this, SLOT(headerDataChanged(Qt::Orientation , int , int)));
00562 disconnect(this->model, SIGNAL(layoutAboutToBeChanged()),
00563 this, SLOT(layoutAboutToBeChanged()));
00564 disconnect(this->model, SIGNAL(layoutChanged()),
00565 this, SLOT(layoutChanged()));
00566 disconnect(this->model, SIGNAL(modelAboutToBeReset()),
00567 this, SLOT(modelAboutToBeReset()));
00568 disconnect(this->model, SIGNAL(modelReset()),
00569 this, SLOT(modelReset()));
00570 disconnect(this->model, SIGNAL(rowsAboutToBeInserted(const QModelIndex & , int , int)),
00571 this, SLOT(rowsAboutToBeInserted(const QModelIndex & , int , int)));
00572 disconnect(this->model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex & , int , int)),
00573 this, SLOT(rowsAboutToBeRemoved(const QModelIndex & , int , int)));
00574 disconnect(this->model, SIGNAL(rowsInserted(const QModelIndex & , int , int)),
00575 this, SLOT(rowsInserted(const QModelIndex & , int , int)));
00576 disconnect(this->model, SIGNAL(rowsRemoved(const QModelIndex & , int , int)),
00577 this, SLOT(rowsRemoved(const QModelIndex & , int , int)));
00578 }
00579 model = m;
00580 if (model)
00581 {
00582 rootindex = model->parent(QModelIndex());
00583
00584 connect(this->model, SIGNAL(columnsAboutToBeInserted(const QModelIndex & , int , int)),
00585 this, SLOT(columnsAboutToBeInserted(const QModelIndex & , int , int)));
00586 connect(this->model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex & , int , int)),
00587 this, SLOT(columnsAboutToBeRemoved(const QModelIndex & , int , int)));
00588 connect(this->model, SIGNAL(columnsInserted(const QModelIndex & , int , int)),
00589 this, SLOT(columnsInserted(const QModelIndex & , int , int)));
00590 connect(this->model, SIGNAL(columnsRemoved(const QModelIndex & , int , int)),
00591 this, SLOT(columnsRemoved(const QModelIndex & , int , int)));
00592 connect(this->model, SIGNAL(dataChanged(const QModelIndex & , const QModelIndex &)),
00593 this, SLOT(dataChanged(const QModelIndex & , const QModelIndex &)));
00594 connect(this->model, SIGNAL(headerDataChanged(Qt::Orientation , int , int)),
00595 this, SLOT(headerDataChanged(Qt::Orientation , int , int)));
00596 connect(this->model, SIGNAL(layoutAboutToBeChanged()),
00597 this, SLOT(layoutAboutToBeChanged()));
00598 connect(this->model, SIGNAL(layoutChanged()),
00599 this, SLOT(layoutChanged()));
00600 connect(this->model, SIGNAL(modelAboutToBeReset()),
00601 this, SLOT(modelAboutToBeReset()));
00602 connect(this->model, SIGNAL(modelReset()),
00603 this, SLOT(modelReset()));
00604 connect(this->model, SIGNAL(rowsAboutToBeInserted(const QModelIndex & , int , int)),
00605 this, SLOT(rowsAboutToBeInserted(const QModelIndex & , int , int)));
00606 connect(this->model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex & , int , int)),
00607 this, SLOT(rowsAboutToBeRemoved(const QModelIndex & , int , int)));
00608 connect(this->model, SIGNAL(rowsInserted(const QModelIndex & , int , int)),
00609 this, SLOT(rowsInserted(const QModelIndex & , int , int)));
00610 connect(this->model, SIGNAL(rowsRemoved(const QModelIndex & , int , int)),
00611 this, SLOT(rowsRemoved(const QModelIndex & , int , int)));
00612 }
00613
00614 reset();
00615 }
00616
00617
00618 void QxtFlowViewPrivate::clear()
00619 {
00620 int c = state->slideImages.count();
00621 for (int i = 0; i < c; i++)
00622 delete state->slideImages[i];
00623 state->slideImages.resize(0);
00624
00625 state->reset();
00626 modelmap.clear();
00627 triggerRender();
00628 }
00629
00630
00631 void QxtFlowViewPrivate::triggerRender()
00632 {
00633 triggerTimer.setSingleShot(true);
00634 triggerTimer.start(0);
00635 }
00636
00637
00638
00639 void QxtFlowViewPrivate::insertSlide(int index, const QImage& image)
00640 {
00641 state->slideImages.insert(index, new QImage(image));
00642 triggerRender();
00643 }
00644
00645 void QxtFlowViewPrivate::replaceSlide(int index, const QImage& image)
00646 {
00647 Q_ASSERT((index >= 0) && (index < state->slideImages.count()));
00648
00649 QImage* i = image.isNull() ? 0 : new QImage(image);
00650 delete state->slideImages[index];
00651 state->slideImages[index] = i;
00652 triggerRender();
00653 }
00654
00655 void QxtFlowViewPrivate::removeSlide(int index)
00656 {
00657 delete state->slideImages[index];
00658 state->slideImages.remove(index);
00659 triggerRender();
00660 }
00661
00662
00663 void QxtFlowViewPrivate::showSlide(int index)
00664 {
00665 if (index == state->centerSlide.slideIndex)
00666 return;
00667 animator->start(index);
00668 }
00669
00670
00671
00672 void QxtFlowViewPrivate::reset()
00673 {
00674 clear();
00675 if (model)
00676 {
00677 for (int i = 0;i < model->rowCount(rootindex);i++)
00678 {
00679 QModelIndex idx = model->index(i, piccolumn, rootindex);
00680 insertSlide(i, qvariant_cast<QImage>(model->data(idx, picrole)));
00681 modelmap.insert(i, idx);
00682 }
00683 }
00684 triggerRender();
00685 }
00686
00687
00688
00689 void QxtFlowViewPrivate::setCurrentIndex(QModelIndex index)
00690 {
00691 if (model->parent(index) != rootindex)
00692 return;
00693
00694 int r = modelmap.indexOf(index);
00695 if (r < 0)
00696 return;
00697
00698 state->centerIndex = r;
00699 state->reset();
00700 animator->stop(r);
00701 triggerRender();
00702 }