/* 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pictureviewer2.h" #include "pictureswidget.h" #include "smglobals.h" #include "mappingtreemodel.h" #include "smtreeitem.h" #include "configurationdialog.h" #include "helper.h" PictureViewer2::PictureViewer2(QWidget *parent) : QGraphicsView(parent), mCur(0), mCurPos(0), mDefaultFile(":/picgone.png"), mFnItem(0), mMappingItem(0) { //behave like QDialog, but don't be one... setWindowFlags(QFlags(0x1|0x2|0x1000|0x2000|0x10000|0x8000000)); //initial file list PicData initialData; for(int i = 0; i < PicFilesModel::NumFields; ++i){ initialData << QVariant(); } initialData[PicFilesModel::FullPath] = mDefaultFile; mFiles << initialData; //picture show mSlideTimer = new QTimer(this); connect(mSlideTimer, SIGNAL(timeout()), this, SLOT(next())); //setup gui mScene = new QGraphicsScene(this); setScene(mScene); QDesktopWidget *dw = QApplication::desktop(); QSize screenSize = dw->availableGeometry().size(); //TODO: configure! mMinimunSize = QSize(screenSize.width() - 100, screenSize.height() - 100); setMinimumSize(mMinimunSize); move(50, 50); setVisible(false); readSettings(); mScene->setSceneRect(QRectF(0, 0, width() - 10, height() - 10)); showFile(mFiles.at(mCurPos)); } void PictureViewer2::addFiles(const PicDataList &files, bool clear){ if(clear){ mFiles.clear(); mFiles = files; mCurPos = 0; }else{ foreach(const PicData &f, files){ if(!mFiles.contains(f)){ mFiles.append(f); } } } if(!mCurPos >= mFiles.size()){ showFile(mFiles.at(mCurPos)); }else{ showFile(mFiles.at(0)); } } void PictureViewer2::addFiles(const QString &dir, bool clear){ QFileInfo fi(dir); if(!fi.isDir()){ return; } PicDataList pd; QDir directory = QDir(dir); QFileInfoList files = directory.entryInfoList(QDir::Files, QDir::Name); //foreach doesn't work here. Somehow it's casted to one single QFileInfo. //took some time to figure it out! for(int i = 0; i < files.size(); ++i){ pd << picData(files.at(i).absoluteFilePath()); } addFiles(pd, clear); } void PictureViewer2::setFile(const PicData &file){ addFiles(PicDataList() << file, true); showFile(mFiles.at(mCurPos)); } void PictureViewer2::setFile(const QString &fullPath){ PicData pd = picData(fullPath); setFile(pd); } PicData PictureViewer2::picData(const QString &fullPath){ QFileInfo fi(fullPath); if(!fi.exists()){ return PicData(); } PicData retval; //fields defined by PicFilesModel::Fields. retval << fi.fileName() << fi.size(); retval << Helper::mimeType(fullPath); retval << fi.absoluteFilePath(); retval << -1 << QDateTime(); retval << Helper::md5Sum(fullPath); QLocale l; retval << l.toString(fi.size()); return retval; } QSize PictureViewer2::sizeHint() const{ return mMinimunSize; } void PictureViewer2::next(){ if(mCurPos + 1 >= mFiles.size()){ mCurPos = 0; }else{ ++mCurPos; } showFile(mFiles.at(mCurPos)); } void PictureViewer2::previous(){ if(mCurPos - 1 < 0){ mCurPos = mFiles.size() - 1; }else{ --mCurPos; } showFile(mFiles.at(mCurPos)); } void PictureViewer2::slide(bool){ if(mSlideTimer->isActive()){ mSlideTimer->stop(); }else{ mSlideTimer->start(5000); } } void PictureViewer2::readSettings(){ QSettings s; mUseGradient = s.value("ui/pvgradient").toBool(); QVariant t = s.value("ui/pvbgcolor"); mBgColor = t.value(); mShowInfoItem = s.value("ui/showinfoitem").toBool(); mConfigInfoPos = s.value("ui/infoposition").toInt(); mInfoPos = s.value("ui/pvinfopos", QPointF(20, 20)).toPointF(); mShowMapItem = s.value("ui/showmapitem").toBool(); mConfigMapPos = s.value("ui/mappingposition").toInt(); mMappingPos = s.value("ui/pvmappingpos", QPointF(20, 20)).toPointF(); } void PictureViewer2::writeSettings(){ if(mFnItem){ QSettings s; s.setValue("ui/pvinfopos", mFnItem->scenePos()); } } void PictureViewer2::shuffle(){ std::random_shuffle(mFiles.begin(), mFiles.end()); } void PictureViewer2::initActions(){ foreach(QAction *a, actions()){ //never, ever forget this when casting to int //an invalid QVariant casts to a valid int! if(!a->data().isValid()){ continue; } if(a->data().toInt() == HideAction){ mHideA = a; } if(a->data().toInt() == SlideAction){ mSlideA = a; } } } void PictureViewer2::wheelEvent(QWheelEvent *event){ int steps = event->delta() / 8 / 15; if(steps < 0){ next(); }else{ previous(); } } void PictureViewer2::contextMenuEvent(QContextMenuEvent *e){ QMenu ctxMenu; foreach(QAction *a, actions()){ ctxMenu.addAction(a); } ctxMenu.exec(e->globalPos()); } void PictureViewer2::keyPressEvent(QKeyEvent *e){ if(e->key() == Qt::Key_Escape){ mHideA->toggle(); } if(e->key() == Qt::Key_Space){ mSlideA->toggle(); } e->accept(); } void PictureViewer2::hideEvent(QHideEvent *){ if(mSlideTimer->isActive()){ mSlideA->toggle(); } } void PictureViewer2::showFile(const PicData &file){ QPixmap pixmap(file.at(PicFilesModel::FullPath).toString()); if(pixmap.isNull()){ return; } if(mUseGradient){ setGradient(pixmap); }else{ setBackgroundBrush(QBrush(mBgColor)); } if((pixmap.height() > height()) || (pixmap.width() > width())){ pixmap = pixmap.scaled(QSize(width() - 3, height() - 10), Qt::KeepAspectRatio, Qt::SmoothTransformation); } if(mCur){ mScene->removeItem(mCur); delete mCur; mCur = 0; } mCur = new QGraphicsPixmapItem(pixmap); float cX = (width() / 2) - (pixmap.width() / 2); float cY = height() / 2 - pixmap.height() / 2; mScene->addItem(mCur); mCur->setPos(cX, cY); setWindowTitle(constructWindowTitle()); if(mShowInfoItem){ constructInfoItem(file, pixmap.size()); }else{ if(mFnItem){ mScene->removeItem(mFnItem); delete mFnItem; mFnItem = 0; } } if(mShowMapItem){ constructMappingItem(file); }else{ if(mMappingItem){ mScene->removeItem(mMappingItem); delete mMappingItem; mMappingItem = 0; } } } void PictureViewer2::constructInfoItem(const PicData &data, QSize picSize){ if(mFnItem){ mInfoPos = mFnItem->scenePos(); mScene->removeItem(mFnItem); delete mFnItem; } mFnItem = new PictureViewer2Item(data, mFiles.size(), picSize); mFnItem->setPos(getPos(mFnItem, mConfigInfoPos, mInfoPos)); mScene->addItem(mFnItem); } void PictureViewer2::constructMappingItem(const PicData &file){ MappingTreeModel *mappingModel = static_cast(SmGlobals::instance()->model("MappingTree")); QList mappings = mappingModel->mappingsForFile(file.at(PicFilesModel::Id)); QStringList mappingPaths; foreach(QVariant mId, mappings){ mappingPaths << mappingModel->mappingDataFromId(mId.toInt()).path.join("/"); } SmTreeItem *mappingTree = mappingModel->treeFromPaths(mappingPaths); if(mappingTree){ if(mMappingItem){ mMappingPos = mMappingItem->scenePos(); mScene->removeItem(mMappingItem); delete mMappingItem; } QTextDocument *mapString = treeToString(mappingTree); mMappingItem = new PictureViewer2Item(mapString); if(mConfigMapPos != ConfigurationDialog::SideBySide){ mMappingItem->setPos(getPos(mMappingItem, mConfigMapPos, mMappingPos)); }else{ if(!mShowInfoItem){ return; } } mScene->addItem(mMappingItem); } delete mappingTree; } void PictureViewer2::setGradient(const QPixmap &pic){ QPoint val1 = QPoint(qrand() % pic.width(), qrand() % pic.height()); QPoint val2 = QPoint(qrand() % pic.width(), qrand() % pic.height()); QImage img = pic.toImage(); QColor c1(img.pixel(val1)); QColor c2(img.pixel(val2)); QLinearGradient g(QPoint(0,0), QPoint(rect().bottomRight())); g.setColorAt(0, c1); g.setColorAt(1, c2); setBackgroundBrush(QBrush(g)); } QTextDocument *PictureViewer2::treeToString(const SmTreeItem *root) const{ QTextDocument *retval = new QTextDocument; retval->setIndentWidth(2); retval->setDocumentMargin(8); QTextCursor *cursor = new QTextCursor(retval); treeToStringRecursive(root, cursor, 0); return retval; } void PictureViewer2::treeToStringRecursive(const SmTreeItem *parent, QTextCursor *cursor, int indent) const{ for(int i = 0; i < parent->childCount(); ++i){ QTextBlockFormat fmt; fmt.setIndent(indent * 5); //to prevent a stupid empty line with a
... if(indent > 0){ cursor->insertBlock(fmt); } QChar bullet(0x2640); if(indent % 2){ bullet = QChar(0x2642); } cursor->insertText(QString("%1 %2").arg(bullet).arg(parent->child(i)->data(0).toString())); if(parent->child(i)->childCount()){ treeToStringRecursive(parent->child(i), cursor, indent + 1); } } } QPointF PictureViewer2::getPos(PictureViewer2Item *item, int pos, const QPointF &movPos){ QSizeF curSize = size(); item->setFlags(0); if(pos == ConfigurationDialog::TopLeft){ return QPointF(5, 5); } int rightOffset = curSize.width() - 15 - item->boundingRect().width(); int bottomOffset = curSize.height() - 15 - item->boundingRect().height(); if(pos == ConfigurationDialog::TopRight){ return QPointF(rightOffset, 5); } if(pos == ConfigurationDialog::BottomLeft){ return QPointF(5, bottomOffset); } if(pos == ConfigurationDialog::BottomRigth){ return QPointF(rightOffset, bottomOffset); } if(pos == ConfigurationDialog::Moveable){ item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); return movPos; } return QPointF(5, 5); } QString PictureViewer2::constructWindowTitle() const { QString retval = QString(tr("PicViewer 2 - [%1]")).arg(mFiles.at(mCurPos).at(PicFilesModel::FileName).toString()); return retval; } PictureViewer2Item::PictureViewer2Item(const PicData &data, const int numSelected, const QSize &picSize, QGraphicsItem *parent) : QGraphicsItem(parent), mDoc(0){ QStringList textList; //prevent QStaticText from wrapping filesnames with spaces //we shouldn't allow this in the first place textList << data.at(PicFilesModel::FileName).toString().replace(' ', '_'); textList << QString("%1x%2").arg(QString::number(picSize.width())).arg(QString::number(picSize.height())); QLocale l; textList << QString(QObject::tr("%1 bytes")).arg(l.toString(data.at(PicFilesModel::Size).toInt())); textList << l.toString(data.at(PicFilesModel::Added).toDate()); textList << data.at(PicFilesModel::MimeType).toString(); textList << QString(QObject::tr("%1 files selected")).arg(QString::number(numSelected)); mText = QStaticText(textList.join("
")); setZValue(1); } PictureViewer2Item::PictureViewer2Item(QTextDocument *doc, QGraphicsItem *parent) : QGraphicsItem(parent), mDoc(doc){ setZValue(1); } PictureViewer2Item::~PictureViewer2Item(){ delete mDoc; } QRectF PictureViewer2Item::boundingRect() const { QSizeF size; if(mDoc){ size = mDoc->size(); }else{ size = mText.size(); size += QSize(10, 10); } QRectF retval; retval.setWidth(size.width()); retval.setHeight(size.height()); return retval; } void PictureViewer2Item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ Q_UNUSED(option); Q_UNUSED(widget); painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::TextAntialiasing, true); QColor bgColor = QColor(Qt::white); bgColor.setAlpha(80); QColor fgColor = QColor(Qt::black); QBrush brush(bgColor); painter->setPen(QColor(Qt::yellow)); painter->setBrush(brush); painter->drawRoundedRect(boundingRect(), 15.0, 15.0); painter->setPen(QPen(fgColor)); if(mDoc){ mDoc->drawContents(painter); }else{ painter->drawStaticText(5, 5, mText); } painter->restore(); }