From 71ca20fe227dcfbc79923fe1bd6221f40741581f Mon Sep 17 00:00:00 2001 From: Anna Udovichenko Date: Fri, 13 Apr 2012 20:14:28 +0300 Subject: [PATCH] Unstable branch init --- src/board/UBBoardPaletteManager.cpp | 4 + src/board/UBBoardPaletteManager.h | 3 + src/board/UBBoardView.cpp | 10 +- src/board/UBFeaturesController.cpp | 256 ++++++++++++ src/board/UBFeaturesController.h | 99 +++++ src/board/board.pri | 6 +- src/gui/UBFeaturesWidget.cpp | 618 ++++++++++++++++++++++++++++ src/gui/UBFeaturesWidget.h | 247 +++++++++++ src/gui/UBLibraryWidget.h | 1 + src/gui/gui.pri | 2 + 10 files changed, 1239 insertions(+), 7 deletions(-) create mode 100644 src/board/UBFeaturesController.cpp create mode 100644 src/board/UBFeaturesController.h create mode 100644 src/gui/UBFeaturesWidget.cpp create mode 100644 src/gui/UBFeaturesWidget.h diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp index f21c089b..e8f6aaa4 100644 --- a/src/board/UBBoardPaletteManager.cpp +++ b/src/board/UBBoardPaletteManager.cpp @@ -153,6 +153,10 @@ void UBBoardPaletteManager::setupDockPaletteWidgets() mRightPalette = new UBRightPalette(mContainer); // RIGHT palette widgets + + mRightPalette->registerWidget(mpFeaturesWidget); + mRightPalette->addTab(mpFeaturesWidget); + mRightPalette->registerWidget(mpLibWidget); mRightPalette->addTab(mpLibWidget); // The cache widget will be visible only if a cache is put on the page diff --git a/src/board/UBBoardPaletteManager.h b/src/board/UBBoardPaletteManager.h index 4e5e5d99..6a1c60a1 100644 --- a/src/board/UBBoardPaletteManager.h +++ b/src/board/UBBoardPaletteManager.h @@ -27,6 +27,7 @@ #include "gui/UBCachePropertiesWidget.h" #include "gui/UBDockDownloadWidget.h" #include "core/UBApplicationController.h" +#include "gui/UBFeaturesWidget.h" class UBStylusPalette; @@ -129,6 +130,8 @@ class UBBoardPaletteManager : public QObject /** The cache properties widget */ UBCachePropertiesWidget* mpCachePropWidget; + UBFeaturesWidget *mpFeaturesWidget; + /** The download widget */ UBDockDownloadWidget* mpDownloadWidget; // HACK: here we duplicate the lib widget for the desktop mode diff --git a/src/board/UBBoardView.cpp b/src/board/UBBoardView.cpp index 1e493cc2..c655ac3c 100644 --- a/src/board/UBBoardView.cpp +++ b/src/board/UBBoardView.cpp @@ -800,17 +800,17 @@ void UBBoardView::dropEvent (QDropEvent *event) QGraphicsItem* graphicsItemAtPos = itemAt(event->pos().x(),event->pos().y()); UBGraphicsWidgetItem* graphicsWidget = dynamic_cast(graphicsItemAtPos); - qDebug() << event->source(); - if (graphicsWidget && graphicsWidget->acceptDrops()) { + graphicsWidget->processDropEvent(event); event->acceptProposedAction(); - } - else if (!event->source() + } else if (!event->source() || dynamic_cast(event->source()) || dynamic_cast(event->source()) - || dynamic_cast(event->source())) { + || dynamic_cast(event->source())) + || dynamic_cast(event->source()) ) { + mController->processMimeData (event->mimeData (), mapToScene (event->pos ())); event->acceptProposedAction(); } diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp new file mode 100644 index 00000000..e7609d2a --- /dev/null +++ b/src/board/UBFeaturesController.cpp @@ -0,0 +1,256 @@ +#include +#include + +#include "core/UBApplication.h" +#include "board/UBBoardController.h" +#include "UBFeaturesController.h" +#include "core/UBSettings.h" +#include "tools/UBToolsManager.h" +#include "frameworks/UBFileSystemUtils.h" +#include "frameworks/UBPlatformUtils.h" + + +#include "core/UBDownloadManager.h" +#include "domain/UBAbstractWidget.h" +#include "domain/UBGraphicsScene.h" +#include "domain/UBGraphicsSvgItem.h" +#include "domain/UBGraphicsPixmapItem.h" +#include "domain/UBGraphicsVideoItem.h" +#include "domain/UBGraphicsWidgetItem.h" + +UBFeature::UBFeature(const QString &url, const QPixmap &icon, const QString &name, const QString &realPath, UBFeatureElementType type) +: virtualPath(url), mThumbnail(icon), mName(name), mPath(realPath), elementType(type) +{ + +} + +UBFeature::UBFeature(const UBFeature &f) +{ + virtualPath = f.getUrl(); + mPath = f.getPath(); + mThumbnail = f.getThumbnail(); + mName = f.getName(); + elementType = f.getType(); +} + + + +UBFeaturesController::UBFeaturesController(QWidget *pParentWidget) : + QObject(pParentWidget), + mLastItemOffsetIndex(0) +{ + rootPath = "/root"; + initDirectoryTree(); +} + +void UBFeaturesController::initDirectoryTree() +{ + mUserAudioDirectoryPath = UBSettings::settings()->userAudioDirectory(); + mUserVideoDirectoryPath = UBSettings::settings()->userVideoDirectory(); + mUserPicturesDirectoryPath = UBSettings::settings()->userImageDirectory(); + mUserInteractiveDirectoryPath = UBSettings::settings()->userInteractiveDirectory(); + mUserAnimationDirectoryPath = UBSettings::settings()->userAnimationDirectory(); + + mLibPicturesDirectoryPath = UBSettings::settings()->applicationImageLibraryDirectory(); + mLibInteractiveDirectoryPath = UBSettings::settings()->applicationInteractivesDirectory(); + mLibApplicationsDirectoryPath = UBSettings::settings()->applicationApplicationsLibraryDirectory(); + mLibShapesDirectoryPath = UBSettings::settings()->applicationShapeLibraryDirectory() ; + + featuresList = new QVector (); + + QList tools = UBToolsManager::manager()->allTools(); + + featuresList->push_back( UBFeature( "", QPixmap( ":images/libpalette/home.png" ), "root", "" ) ); + + appPath = rootPath + "/Applications"; + audiosPath = rootPath + "/Audios"; + moviesPath = rootPath + "/Movies"; + picturesPath = rootPath + "/Pictures"; + flashPath = rootPath + "/Animations"; + interactPath = rootPath + "/Interactivities"; + shapesPath = rootPath + "/Shapes"; + + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/AudiosCategory.svg"), "Audios" , mUserAudioDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/MoviesCategory.svg"), "Movies" , mUserVideoDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/PicturesCategory.svg"), "Pictures" , mUserPicturesDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/ApplicationsCategory.svg"), "Applications" , mUserInteractiveDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/FlashCategory.svg"), "Animations" , mUserAnimationDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/InteractivesCategory.svg"), "Interactivities" , mLibInteractiveDirectoryPath ) ); + featuresList->push_back( UBFeature( rootPath, QPixmap(":images/libpalette/ShapesCategory.svg"), "Shapes" , mLibShapesDirectoryPath ) ); + + foreach (UBToolsManager::UBToolDescriptor tool, tools) + { + featuresList->push_back( UBFeature( appPath, tool.icon, tool.label, mUserInteractiveDirectoryPath, FEATURE_INTERACTIVE ) ); + } + fileSystemScan( mUserInteractiveDirectoryPath, appPath ); + fileSystemScan( mUserAudioDirectoryPath, audiosPath ); + fileSystemScan( mUserPicturesDirectoryPath, picturesPath ); + fileSystemScan( mUserVideoDirectoryPath, moviesPath ); + fileSystemScan( mUserAnimationDirectoryPath, flashPath ); + + fileSystemScan( mLibApplicationsDirectoryPath, appPath ); + fileSystemScan( mLibPicturesDirectoryPath, picturesPath ); + fileSystemScan( mLibShapesDirectoryPath, shapesPath ); + fileSystemScan( mLibInteractiveDirectoryPath, interactPath ); + +} + +void UBFeaturesController::fileSystemScan(const QString & currentPath, const QString & currVirtualPath) +{ + QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currentPath); + + QFileInfoList::iterator fileInfo; + for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) + { + UBFeatureElementType fileType = fileInfo->isDir() ? FEATURE_FOLDER : FEATURE_ITEM; + + QString fileName = fileInfo->fileName(); + if ( UBFileSystemUtils::mimeTypeFromFileName(fileName).contains("application") ) { + fileType = FEATURE_INTERACTIVE; + } + QString itemName = (fileType != FEATURE_ITEM) ? fileName : fileInfo->completeBaseName(); + QPixmap icon = QPixmap(":images/libpalette/soundIcon.svg"); + QString fullFileName = currentPath + "/" + fileName; + + if ( fileType == FEATURE_FOLDER ) + { + icon = QPixmap(":images/libpalette/folder.svg"); + } + else if ( fileType == FEATURE_INTERACTIVE ) + { + icon = QPixmap( UBAbstractWidget::iconFilePath( QUrl::fromLocalFile(fullFileName) ) ); + } + else + { + if ( fullFileName.contains(".thumbnail.") ) + continue; + icon = thumbnailForFile( fullFileName ); + /*QString thumbnailPath = UBFileSystemUtils::thumbnailPath( fullFileName ); + + if (QFileInfo( thumbnailPath).exists() ) + icon = QPixmap( thumbnailPath ); + else icon = createThumbnail( fullFileName );*/ + } + featuresList->push_back( UBFeature( currVirtualPath, icon, fileName, currentPath, fileType ) ); + + if ( fileType == FEATURE_FOLDER ) + { + fileSystemScan( fullFileName, currVirtualPath + "/" + fileName ); + } + + } +} + +QPixmap UBFeaturesController::thumbnailForFile(const QString &path) +{ + QPixmap thumb; + QString thumbnailPath = UBFileSystemUtils::thumbnailPath( path ); + + if ( QFileInfo( thumbnailPath ).exists() ) + thumb = QPixmap( thumbnailPath ); + else thumb = createThumbnail( path ); + return thumb; +} + +QPixmap UBFeaturesController::createThumbnail(const QString &path) +{ + QString thumbnailPath = UBFileSystemUtils::thumbnailPath(path); + QString mimetype = UBFileSystemUtils::mimeTypeFromFileName(path); + QString extension = QFileInfo(path).completeSuffix(); + //UBApplication::showMessage(tr("Creating image thumbnail for %1.").arg(pElement->name())); + + if ( mimetype.contains("audio" )) + thumbnailPath = ":images/libpalette/soundIcon.svg"; + else if ( mimetype.contains("video") ) + thumbnailPath = ":images/libpalette/movieIcon.svg"; + else + { + if ( extension.startsWith("svg", Qt::CaseInsensitive) || extension.startsWith("svgz", Qt::CaseInsensitive) ) + { + thumbnailPath = path; + } + else + { + QPixmap pix(path); + if (!pix.isNull()) + { + pix = pix.scaledToWidth(qMin(UBSettings::maxThumbnailWidth, pix.width()), Qt::SmoothTransformation); + pix.save(thumbnailPath); + UBPlatformUtils::hideFile(thumbnailPath); + } + else{ + thumbnailPath = ":images/libpalette/notFound.png"; + } + } + } + + return QPixmap(thumbnailPath); +} + +void UBFeaturesController::addItemToPage(const UBFeature &item) +{ + UBApplication::boardController->downloadURL( QUrl::fromLocalFile( item.getFullPath() ) ); +} + +UBFeature UBFeaturesController::moveItemToFolder( const QUrl &url, const UBFeature &destination ) +{ + QString sourcePath = url.toLocalFile(); + + Q_ASSERT( QFileInfo( sourcePath ).exists() ); + + QString name = QFileInfo( sourcePath ).fileName(); + QString destPath = destination.getFullPath(); + QString destVirtualPath = destination.getUrl() + "/" + destination.getName(); + QString newFullPath = destPath + "/" + name; + QFile( sourcePath ).copy( newFullPath ); + QFile::remove( sourcePath ); + + QString thumbnailPath = UBFileSystemUtils::thumbnailPath( sourcePath ); + if (thumbnailPath.length() && QFileInfo( thumbnailPath ).exists()) + { + QFile::remove(thumbnailPath); + } + + QPixmap thumb = thumbnailForFile( newFullPath ); + + UBFeatureElementType type = UBFeatureElementType::FEATURE_ITEM; + if ( UBFileSystemUtils::mimeTypeFromFileName( newFullPath ).contains("application") ) + type = UBFeatureElementType::FEATURE_INTERACTIVE; + UBFeature newElement( destVirtualPath, thumb, name, destPath, type ); + return newElement; +} +/* +void UBFeaturesController::addImageToCurrentPage( const QString &path ) +{ + QPointF pos = UBApplication::boardController->activeScene()->normalizedSceneRect().center(); + mLastItemOffsetIndex = qMin(mLastItemOffsetIndex, 5); + + QGraphicsItem* itemInScene = 0; + + if ( UBApplication::boardController->activeScene() ) + { + QString mimeType = UBFileSystemUtils::mimeTypeFromFileName( path ); + + pos = QPointF( pos.x() + 50 * mLastItemOffsetIndex, pos.y() + 50 * mLastItemOffsetIndex ); + mLastItemOffsetIndex++; + //TODO UB 4.x move this logic to the scene .. + if (mimeType == "image/svg+xml") + { + itemInScene = UBApplication::boardController->activeScene()->addSvg( QUrl::fromLocalFile(path), pos ); + } + else + { + itemInScene = UBApplication::boardController->activeScene()->addPixmap( QPixmap(path), pos ); + } + } + + if (itemInScene) + { + itemInScene = UBApplication::boardController->activeScene()->scaleToFitDocumentSize(itemInScene, false, UBSettings::objectInControlViewMargin); + } +} +*/ + +UBFeaturesController::~UBFeaturesController() +{ +} diff --git a/src/board/UBFeaturesController.h b/src/board/UBFeaturesController.h new file mode 100644 index 00000000..cde23347 --- /dev/null +++ b/src/board/UBFeaturesController.h @@ -0,0 +1,99 @@ +#ifndef UBFEATURESCONTROLLER_H +#define UBFEATURESCONTROLLER_H + +#include +#include +#include +#include +#include +#include + +//#include "UBDockPaletteWidget.h" + +enum UBFeatureElementType +{ + FEATURE_CATEGORY, + FEATURE_VIRTUALFOLDER, + FEATURE_FOLDER, + FEATURE_INTERACTIVE, + FEATURE_ITEM +}; + +class UBFeature +{ +public: + UBFeature(){}; + UBFeature(const UBFeature &f); + UBFeature(const QString &url, const QPixmap &icon, const QString &name, const QString &realPath, UBFeatureElementType type = FEATURE_CATEGORY); + virtual ~UBFeature(){}; + QString getName() const { return mName; }; + QPixmap getThumbnail() const { + return mThumbnail; + }; + QString getUrl() const { return virtualPath; }; + QString getPath() const { return mPath; }; + QString getFullPath() const { return mPath + "/" + mName; }; + UBFeatureElementType getType() const { return elementType; } ; +private: + QString virtualPath; + QString mPath; + QPixmap mThumbnail; + QString mName; + UBFeatureElementType elementType; +}; +Q_DECLARE_METATYPE( UBFeature ) + + +class UBFeaturesController : public QObject +{ +Q_OBJECT +public: + UBFeaturesController(QWidget *parentWidget); + virtual ~UBFeaturesController(); + + QVector * getFeatures()const { return featuresList; }; + + QString getRootPath()const { return rootPath; }; + + void addItemToPage(const UBFeature &item); + static QPixmap thumbnailForFile( const QString &path ); + static UBFeature moveItemToFolder( const QUrl &url, const UBFeature &destination ); +private: + void initDirectoryTree(); + void fileSystemScan(const QString &currPath, const QString & currVirtualPath); + static QPixmap createThumbnail(const QString &path); + //void addImageToCurrentPage( const QString &path ); + + QVector *featuresList; + UBFeature *rootElement; + + QString mUserAudioDirectoryPath; + QString mUserVideoDirectoryPath; + QString mUserPicturesDirectoryPath; + QString mUserInteractiveDirectoryPath; + QString mUserAnimationDirectoryPath; + + QString libraryPath; + QString mLibAudioDirectoryPath; + QString mLibVideoDirectoryPath; + QString mLibPicturesDirectoryPath; + QString mLibInteractiveDirectoryPath; + QString mLibAnimationDirectoryPath; + QString mLibApplicationsDirectoryPath; + QString mLibShapesDirectoryPath; + + QString rootPath; + QString audiosPath; + QString moviesPath; + QString picturesPath; + QString appPath; + QString flashPath; + QString shapesPath; + QString interactPath; + + int mLastItemOffsetIndex; +}; + + + +#endif \ No newline at end of file diff --git a/src/board/board.pri b/src/board/board.pri index bf934a62..1208db87 100644 --- a/src/board/board.pri +++ b/src/board/board.pri @@ -3,13 +3,15 @@ HEADERS += src/board/UBBoardController.h \ src/board/UBBoardPaletteManager.h \ src/board/UBBoardView.h \ src/board/UBLibraryController.h \ - src/board/UBDrawingController.h + src/board/UBDrawingController.h \ + src/board/UBFeaturesController.h SOURCES += src/board/UBBoardController.cpp \ src/board/UBBoardPaletteManager.cpp \ src/board/UBBoardView.cpp \ src/board/UBLibraryController.cpp \ - src/board/UBDrawingController.cpp + src/board/UBDrawingController.cpp \ + src/board/UBFeaturesController.cpp diff --git a/src/gui/UBFeaturesWidget.cpp b/src/gui/UBFeaturesWidget.cpp new file mode 100644 index 00000000..dbdaa99b --- /dev/null +++ b/src/gui/UBFeaturesWidget.cpp @@ -0,0 +1,618 @@ +#include "UBFeaturesWidget.h" +#include "domain/UBAbstractWidget.h" +#include "gui/UBThumbnailWidget.h" +#include "frameworks/UBFileSystemUtils.h" +#include "core/UBApplication.h" +#include "core/UBDownloadManager.h" + +UBFeaturesWidget::UBFeaturesWidget(QWidget *parent, const char *name):UBDockPaletteWidget(parent) +{ + setObjectName(name); + mName = "FeaturesWidget"; + mVisibleState = true; + + setAttribute(Qt::WA_StyledBackground, true); + setStyleSheet(UBApplication::globalStyleSheet()); + + mIconToLeft = QPixmap(":images/library_open.png"); + mIconToRight = QPixmap(":images/library_close.png"); + setAcceptDrops(true); + + stackedWidget = new QStackedWidget(this); + layout = new QVBoxLayout(this); + + controller = new UBFeaturesController(this); + + featuresModel = new UBFeaturesModel(this); + featuresModel->setFeaturesList( controller->getFeatures() ); + featuresModel->setSupportedDragActions( Qt::CopyAction | Qt::MoveAction ); + featuresListView = new QListView(this); + pathListView = new QListView(this); + + + featuresProxyModel = new UBFeaturesProxyModel(this); + featuresProxyModel->setFilterFixedString( controller->getRootPath() ); + featuresProxyModel->setSourceModel( featuresModel ); + featuresProxyModel->setFilterCaseSensitivity( Qt::CaseInsensitive ); + + featuresSearchModel = new UBFeaturesSearchProxyModel(this); + featuresSearchModel->setSourceModel( featuresModel ); + featuresSearchModel->setFilterCaseSensitivity( Qt::CaseInsensitive ); + + featuresPathModel = new UBFeaturesPathProxyModel(this); + featuresPathModel->setPath( controller->getRootPath() ); + featuresPathModel->setSourceModel( featuresModel ); + + + featuresListView->setDragDropMode( QAbstractItemView::InternalMove ); + featuresListView->setModel( featuresProxyModel ); + + featuresListView->setResizeMode( QListView::Adjust ); + featuresListView->setViewMode( QListView::IconMode ); + itemDelegate = new UBFeaturesItemDelegate( this, featuresListView ); + featuresListView->setItemDelegate( itemDelegate ); + + featuresListView->setIconSize( QSize(40, 40) ); + featuresListView->setGridSize( QSize(70, 70) ); + + pathListView->setModel( featuresPathModel ); + pathListView->setViewMode( QListView::IconMode ); + pathListView->setIconSize( QSize(30, 30) ); + pathListView->setGridSize( QSize(50, 30) ); + pathListView->setFixedHeight( 60 ); + pathItemDelegate = new UBFeaturesPathItemDelegate( this ); + pathListView->setItemDelegate( pathItemDelegate ); + pathListView->setSelectionMode( QAbstractItemView::NoSelection ); + pathListView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + pathListView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + pathListView->setMovement( QListView::Static ); + pathListView->setDragDropMode( QAbstractItemView::DragDrop ); + + pathScene = new QGraphicsScene(this); + //pathViewer = new UBFeaturesPathViewer( QPixmap(":images/libpalette/home.png"), controller->getRootPath(), pathScene, this ); + featureProperties = new UBFeatureProperties(this); + + //layout->addWidget( pathViewer ); + //pathViewer->show(); + //layout->addWidget( featuresListView ); + layout->addWidget( pathListView ); + layout->addWidget( stackedWidget ); + + stackedWidget->addWidget( featuresListView ); + stackedWidget->addWidget( featureProperties ); + stackedWidget->setCurrentIndex(ID_LISTVIEW); + currentStackedWidget = ID_LISTVIEW; + + mActionBar = new UBLibActionBar(this); + layout->addWidget(mActionBar); + + /*connect(featuresListView->selectionModel(), SIGNAL(currentChanged ( const QModelIndex &, const QModelIndex & )), + this, SLOT(currentSelected(const QModelIndex &)));*/ + connect( featuresListView, SIGNAL(clicked ( const QModelIndex & ) ), + this, SLOT( currentSelected(const QModelIndex &) ) ); + connect( mActionBar, SIGNAL( searchElement(QString) ), this, SLOT( searchStarted(QString) ) ); + connect( pathListView, SIGNAL(clicked( const QModelIndex & ) ), + this, SLOT( currentPathChanged( const QModelIndex & ) ) ); +} + +void UBFeaturesWidget::searchStarted( QString pattern ) +{ + if ( pattern.isEmpty() ) + { + featuresListView->setModel( featuresProxyModel ); + featuresProxyModel->invalidate(); + } + else + { + featuresSearchModel->setFilterWildcard( "*" + pattern + "*" ); + featuresListView->setModel( featuresSearchModel ); + featuresSearchModel->invalidate(); + } +} + +void UBFeaturesWidget::currentSelected(const QModelIndex ¤t) +{ + if (current.isValid()) + { + QSortFilterProxyModel *model = dynamic_cast( featuresListView->model() ); + /*QString name = model->data(current).toString(); + QString path = model->data(current, Qt::UserRole).toString(); + eUBLibElementType type = (eUBLibElementType)model->data(current, Qt::UserRole + 1).toInt();*/ + UBFeature feature = model->data(current, Qt::UserRole + 1).value(); + if ( feature.getType() == UBFeatureElementType::FEATURE_FOLDER || feature.getType() == UBFeatureElementType::FEATURE_CATEGORY) + { + QString newPath = feature.getUrl() + "/" + feature.getName(); + //pathViewer->addPathElement( feature.getThumbnail(), newPath ); + + model->setFilterFixedString( newPath ); + model->invalidate(); + switchToListView(); + + featuresPathModel->setPath( newPath ); + featuresPathModel->invalidate(); + } + else + { + featureProperties->showElement( feature ); + switchToProperties(); + } + + } +} + +void UBFeaturesWidget::currentPathChanged(const QModelIndex &index) +{ + if ( index.isValid() ) + { + UBFeature feature = featuresPathModel->data(index, Qt::UserRole + 1).value(); + QString newPath = feature.getUrl() + "/" + feature.getName(); + + featuresPathModel->setPath( newPath ); + featuresPathModel->invalidate(); + + featuresListView->setModel( featuresProxyModel ); + featuresProxyModel->setFilterFixedString(newPath); + featuresProxyModel->invalidate(); + switchToListView(); + } +} + + +void UBFeaturesWidget::switchToListView() +{ + stackedWidget->setCurrentIndex(ID_LISTVIEW); + currentStackedWidget = ID_LISTVIEW; +} + +void UBFeaturesWidget::switchToProperties() +{ + stackedWidget->setCurrentIndex(ID_PROPERTIES); + currentStackedWidget = ID_PROPERTIES; +} + + + +void UBFeaturesWidget::currentPathChanged(const QString &path) +{ + int newDepth = path.count("/"); + pathViewer->truncatePath(newDepth); + featuresListView->setModel( featuresProxyModel ); + featuresProxyModel->setFilterFixedString(path); + featuresProxyModel->invalidate(); + switchToListView(); +} + + + +UBFeaturesWidget::~UBFeaturesWidget() +{ +} + +UBFeatureProperties::UBFeatureProperties( QWidget *parent, const char *name ) : QWidget(parent) + , mpLayout(NULL) + , mpButtonLayout(NULL) + , mpAddPageButton(NULL) + , mpAddToLibButton(NULL) + , mpSetAsBackgroundButton(NULL) + , mpObjInfoLabel(NULL) + , mpThumbnail(NULL) + , mpOrigPixmap(NULL) + , mpElement(NULL) +{ + setObjectName(name); + + setAttribute(Qt::WA_StyledBackground, true); + setStyleSheet(UBApplication::globalStyleSheet()); + + // Create the GUI + mpLayout = new QVBoxLayout(this); + setLayout(mpLayout); + + maxThumbHeight = height() / 4; + + mpThumbnail = new QLabel(); + QPixmap icon(":images/libpalette/notFound.png"); + icon.scaledToWidth(THUMBNAIL_WIDTH); + + mpThumbnail->setPixmap(icon); + mpThumbnail->setObjectName("DockPaletteWidgetBox"); + mpThumbnail->setStyleSheet("background:white;"); + mpThumbnail->setAlignment(Qt::AlignHCenter); + mpLayout->addWidget(mpThumbnail, 0); + + mpButtonLayout = new QHBoxLayout(); + mpLayout->addLayout(mpButtonLayout, 0); + + mpAddPageButton = new UBFeatureItemButton(); + mpAddPageButton->setText(tr("Add to page")); + mpButtonLayout->addWidget(mpAddPageButton); + + mpSetAsBackgroundButton = new UBFeatureItemButton(); + mpSetAsBackgroundButton->setText(tr("Set as background")); + mpButtonLayout->addWidget(mpSetAsBackgroundButton); + + mpAddToLibButton = new UBFeatureItemButton(); + mpAddToLibButton->setText(tr("Add to library")); + mpButtonLayout->addWidget(mpAddToLibButton); + + mpButtonLayout->addStretch(1); + + mpObjInfoLabel = new QLabel(tr("Object informations")); + mpObjInfoLabel->setStyleSheet(QString("color: #888888; font-size : 18px; font-weight:bold;")); + mpLayout->addWidget(mpObjInfoLabel, 0); + + connect(mpAddPageButton, SIGNAL(clicked()), this, SLOT(onAddToPage())); + +} + +void UBFeatureProperties::showElement( const UBFeature &elem ) +{ + if ( mpOrigPixmap ) + { + delete mpOrigPixmap; + mpOrigPixmap = NULL; + } + if ( mpElement ) + { + delete mpElement; + mpElement = NULL; + } + mpElement = new UBFeature( elem ); + mpOrigPixmap = new QPixmap( elem.getThumbnail() ); + mpThumbnail->setPixmap(elem.getThumbnail().scaledToWidth(THUMBNAIL_WIDTH)); + //populateMetadata(); + + if ( UBApplication::isFromWeb( elem.getUrl() ) ) + { + mpAddToLibButton->show(); + /*if(elem->metadatas()["Type"].toLower().contains("image")) + { + mpSetAsBackgroundButton->show(); + } + else + { + mpSetAsBackgroundButton->hide(); + }*/ + } + else + { + mpAddToLibButton->hide(); + if (UBFileSystemUtils::mimeTypeFromFileName( elem.getUrl() ).contains("image")) + { + mpSetAsBackgroundButton->show(); + } + else + { + mpSetAsBackgroundButton->hide(); + } + } +} + +void UBFeatureProperties::onAddToPage() +{ + if ( UBApplication::isFromWeb( mpElement->getUrl() ) ) + { + sDownloadFileDesc desc; + desc.isBackground = false; + desc.modal = true; + desc.name = QFileInfo( mpElement->getName() ).fileName(); + desc.url = mpElement->getUrl(); + UBDownloadManager::downloadManager()->addFileToDownload(desc); + + } + else + { + QWidget *w = parentWidget()->parentWidget(); + UBFeaturesWidget* featuresWidget = dynamic_cast( w ); + featuresWidget->getFeaturesController()->addItemToPage( *mpElement ); + } +} + +UBFeatureProperties::~UBFeatureProperties() +{ +} + +UBFeaturesPathViewer::UBFeaturesPathViewer(const QPixmap &root, const QString &rootPath, QGraphicsScene *sc, QWidget* parent, const char* name) : QGraphicsView(sc, parent) +{ + setObjectName(name); + + setAttribute(Qt::WA_StyledBackground, true); + setStyleSheet(UBApplication::globalStyleSheet()); + + layout = new QGraphicsLinearLayout(); + + container = new QGraphicsWidget(); + container->setMaximumWidth( width() - 20 ); + container->setLayout( layout ); + scene()->addItem( container ); + + UBFolderWidget* pIconLabel = new UBFolderWidget(); + pIconLabel->setStyleSheet(QString("background-color: transparent;")); + pIconLabel->setPixmap( root ); + pIconLabel->setPath(rootPath); + connect( pIconLabel, SIGNAL( clicked(const QString &) ), parent, SLOT( currentPathChanged(const QString &) ) ); + + QGraphicsProxyWidget *iconWidget = scene()->addWidget( pIconLabel ) ;; + layout->addItem( iconWidget ); + setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + setAlignment( Qt::AlignLeft ); + setFixedHeight( 70 ); + arrowPixmap = new QPixmap(":images/navig_arrow.png"); +} + +void UBFeaturesPathViewer::addPathElement(const QPixmap &p, const QString &s) +{ + UBFolderWidget* pIconLabel = new UBFolderWidget(); + pIconLabel->setStyleSheet(QString("background-color: transparent;")); + pIconLabel->setPixmap( *arrowPixmap ); + + QGraphicsProxyWidget *iconWidget = scene()->addWidget( pIconLabel ); + layout->addItem( iconWidget ); + + + pIconLabel = new UBFolderWidget(); + + pIconLabel->setStyleSheet(QString("background-color: transparent;")); + pIconLabel->setPixmap( p.scaledToHeight( height() - 30, Qt::SmoothTransformation) ); + pIconLabel->setPath(s); + connect( pIconLabel, SIGNAL( clicked(const QString &) ), parent(), SLOT( currentPathChanged(const QString &) ) ); + + iconWidget = scene()->addWidget( pIconLabel ); + layout->addItem( iconWidget ); + scene()->invalidate(); +} + +void UBFeaturesPathViewer::truncatePath(int number) +{ + QList items = scene()->items(); + int itemsToDel = items.size() - number * 2; + for ( QList ::iterator it = items.begin() ; it != items.begin() + itemsToDel; ++it ) + { + scene()->removeItem( (*it) ); + QGraphicsLayoutItem *layoutItem = dynamic_cast(*it); + Q_ASSERT(layout); + layout->removeItem(layoutItem); + delete layoutItem; + } + scene()->invalidate(); +} + +UBFeatureItemButton::UBFeatureItemButton(QWidget *parent, const char *name):QPushButton(parent) +{ + setObjectName(name); + setStyleSheet(QString("background-color : #DDDDDD; color : #555555; border-radius : 6px; padding : 5px; font-weight : bold; font-size : 12px;")); +} + +UBFeatureItemButton::~UBFeatureItemButton() +{ + +} + +QVariant UBFeaturesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) + return featuresList->at(index.row()).getName(); + else if (role == Qt::DecorationRole) + { + return QIcon( featuresList->at(index.row()).getThumbnail() ); + } + else if (role == Qt::UserRole) + { + return featuresList->at(index.row()).getUrl(); + } + else if (role == Qt::UserRole + 1) + { + //return featuresList->at(index.row()).getType(); + UBFeature f = featuresList->at(index.row()); + return QVariant::fromValue( f ); + } + + return QVariant(); +} + +QMimeData* UBFeaturesModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData(); + QList urlList; + + foreach (QModelIndex index, indexes) + { + if ( index.isValid() ) + { + UBFeature element = data( index, Qt::UserRole + 1 ).value(); + urlList.push_back( QUrl::fromLocalFile( element.getFullPath() ) ); + } + } + mimeData->setUrls( urlList ); + /*QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + foreach (QModelIndex index, indexes) { + if (index.isValid()) { + QString str = qVariantValue(data(index)); + stream << str; + } + } + + mimeData->setData("text/uri-list", encodedData);*/ + + return mimeData; +} + +bool UBFeaturesModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + if ( !mimeData->hasUrls() ) + return false; + if ( action == Qt::IgnoreAction ) + return true; + if ( column > 0 ) + return false; + + int endRow; + + if ( !parent.isValid() ) + { + return false; + /*if (row < 0) + endRow = featuresList->size(); + else + endRow = qMin( row, featuresList->size() );*/ + } + else + endRow = parent.row(); + + UBFeature parentFeature = parent.data( Qt::UserRole + 1).value(); + + QList urls = mimeData->urls(); + + foreach ( QUrl url, urls ) + { + UBFeature element = UBFeaturesController::moveItemToFolder( url, parentFeature ); + beginInsertRows( QModelIndex(), featuresList->size(), featuresList->size() ); + featuresList->push_back( element ); + endInsertRows(); + } + return true; +} + +bool UBFeaturesModel::removeRows( int row, int count, const QModelIndex & parent ) +{ + if ( row < 0 ) + return false; + if ( row + count >= featuresList->size() ) + return false; + beginRemoveRows( parent, row, row + count - 1 ); + featuresList->remove( row, count ); + endRemoveRows(); + return true; +} + +bool UBFeaturesModel::removeRow( int row, const QModelIndex & parent ) +{ + if ( row < 0 ) + return false; + if ( row >= featuresList->size() ) + return false; + beginRemoveRows( parent, row, row ); + featuresList->remove( row ); + endRemoveRows(); + return true; +} + +Qt::ItemFlags UBFeaturesModel::flags( const QModelIndex &index ) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + if ( index.isValid() ) + { + UBFeature item = index.data( Qt::UserRole + 1 ).value(); + if ( item.getType() == UBFeatureElementType::FEATURE_INTERACTIVE || + item.getType() == UBFeatureElementType::FEATURE_ITEM ) + return Qt::ItemIsDragEnabled | defaultFlags; + } + return defaultFlags | Qt::ItemIsDropEnabled; +} + + +QStringList UBFeaturesModel::mimeTypes() const +{ + QStringList types; + types << "text/uri-list"; + return types; +} + +int UBFeaturesModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + else + return featuresList->size(); +} + + +bool UBFeaturesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex & sourceParent )const +{ + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + QString path = index.data( Qt::UserRole ).toString(); + + return filterRegExp().exactMatch(path); +} + +bool UBFeaturesSearchProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex & sourceParent )const +{ + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + /*QString name = sourceModel()->data(index, Qt::DisplayRole).toString(); + eUBLibElementType type = (eUBLibElementType)sourceModel()->data(index, Qt::UserRole + 1).toInt();*/ + + UBFeature feature = sourceModel()->data(index, Qt::UserRole + 1).value(); + bool isFile = feature.getType() == UBFeatureElementType::FEATURE_INTERACTIVE || + feature.getType() == UBFeatureElementType::FEATURE_ITEM; + + return isFile && filterRegExp().exactMatch( feature.getName() ); +} + +bool UBFeaturesPathProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex & sourceParent )const +{ + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + /*QString name = sourceModel()->data(index, Qt::DisplayRole).toString(); + eUBLibElementType type = (eUBLibElementType)sourceModel()->data(index, Qt::UserRole + 1).toInt();*/ + + UBFeature feature = sourceModel()->data(index, Qt::UserRole + 1).value(); + bool isFolder = feature.getType() == UBFeatureElementType::FEATURE_CATEGORY || + feature.getType() == UBFeatureElementType::FEATURE_FOLDER; + QString virtualFullPath = feature.getUrl() + "/" + feature.getName(); + + return isFolder && path.startsWith( virtualFullPath ); +} + +QString UBFeaturesItemDelegate::displayText ( const QVariant & value, const QLocale & locale ) const +{ + QString text = value.toString(); + if (listView) + { + const QFontMetrics fm = listView->fontMetrics(); + const QSize iSize = listView->iconSize(); + + if ( iSize.width() > 0 && fm.width(text) > iSize.width() ) + { + while (fm.width(text) > iSize.width()) + text.resize(text.size()-1); + text += "..."; + } + } + return text; +} + +UBFeaturesPathItemDelegate::UBFeaturesPathItemDelegate(QWidget *parent) : QStyledItemDelegate(parent) +{ + arrowPixmap = new QPixmap(":images/navig_arrow.png"); +} + +QString UBFeaturesPathItemDelegate::displayText ( const QVariant & value, const QLocale & locale ) const +{ + return ""; +} + +void UBFeaturesPathItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + UBFeature feature = index.data( Qt::UserRole + 1 ).value(); + QRect rect = option.rect; + if ( !feature.getPath().isEmpty() ) + { + painter->drawPixmap( rect.left() - 10, rect.center().y() - 5, *arrowPixmap ); + } + painter->drawPixmap( rect.left() + 5, rect.center().y() - 5, feature.getThumbnail().scaledToHeight( 30, Qt::SmoothTransformation ) ); +} + +UBFeaturesPathItemDelegate::~UBFeaturesPathItemDelegate() +{ + if ( arrowPixmap ) + { + delete arrowPixmap; + arrowPixmap = NULL; + } +} \ No newline at end of file diff --git a/src/gui/UBFeaturesWidget.h b/src/gui/UBFeaturesWidget.h new file mode 100644 index 00000000..4e0c36df --- /dev/null +++ b/src/gui/UBFeaturesWidget.h @@ -0,0 +1,247 @@ +#ifndef UBFEATURESWIDGET_H +#define UBFEATURESWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UBDockPaletteWidget.h" +#include "UBLibActionBar.h" +#include "board/UBFeaturesController.h" + + +#define THUMBNAIL_WIDTH 400 +#define ID_LISTVIEW 0 +#define ID_PROPERTIES 1 + +class UBListModel; + +class UBFeaturesModel; +class UBFeaturesItemDelegate; +class UBFeaturesPathItemDelegate; +class UBFeaturesProxyModel; +class UBFeaturesSearchProxyModel; +class UBFeaturesPathProxyModel; +class UBFeaturesPathViewer; +class UBFeatureProperties; +class UBFeatureItemButton; + +class UBFeaturesWidget : public UBDockPaletteWidget +{ + Q_OBJECT +public: + UBFeaturesWidget(QWidget* parent=0, const char* name="UBFeaturesWidget"); + virtual ~UBFeaturesWidget(); + + bool visibleInMode(eUBDockPaletteWidgetMode mode) + { + return mode == eUBDockPaletteWidget_BOARD + || mode == eUBDockPaletteWidget_DESKTOP; + } + UBFeaturesController * getFeaturesController()const { return controller; }; +private: + void switchToListView(); + void switchToProperties(); + + UBFeaturesController *controller; + + UBFeaturesItemDelegate *itemDelegate; + UBFeaturesPathItemDelegate *pathItemDelegate; + + UBFeaturesModel *featuresModel; + UBFeaturesProxyModel *featuresProxyModel; + UBFeaturesSearchProxyModel *featuresSearchModel; + UBFeaturesPathProxyModel *featuresPathModel; + + QListView *featuresListView; + QListView *pathListView; + QVBoxLayout *layout; + UBFeaturesPathViewer *pathViewer; + QGraphicsScene *pathScene; + UBLibActionBar *mActionBar; + UBFeatureProperties *featureProperties; + QStackedWidget *stackedWidget; + + int currentStackedWidget; +private slots: + void currentSelected(const QModelIndex &); + void currentPathChanged(const QString &); + void currentPathChanged( const QModelIndex & ); + void searchStarted(QString); +}; + +class UBFeaturesPathViewer : public QGraphicsView +{ + Q_OBJECT +public: + UBFeaturesPathViewer(const QPixmap &root, const QString &rootPath, QGraphicsScene *sc, QWidget* parent=0, const char* name="UBFeaturesPathViewer"); + virtual ~UBFeaturesPathViewer() {} ; + void addPathElement(const QPixmap &p, const QString &s); + void truncatePath(int number); +private: + QGraphicsLinearLayout *layout; + QGraphicsWidget *container; + QPixmap *arrowPixmap; +}; + + +class UBFolderWidget : public QLabel +{ + Q_OBJECT +public: + UBFolderWidget( QWidget * parent = 0, Qt::WindowFlags f = 0 ) : QLabel( parent, f ) {}; + virtual ~UBFolderWidget() {}; + virtual QString getPath()const { return path; }; + virtual void setPath( const QString &p ) { path = p; }; +signals: + void clicked(const QString &); +protected: + virtual void mouseReleaseEvent ( QMouseEvent * ev ) + { + emit clicked(path); + }; + virtual void mousePressEvent ( QMouseEvent * ev ) + { + ev->accept(); + }; +private: + QString path; +}; + + +class UBFeatureProperties : public QWidget +{ + Q_OBJECT +public: + UBFeatureProperties(QWidget* parent=0, const char* name="UBFeatureProperties"); + ~UBFeatureProperties(); + + void showElement(const UBFeature &elem); + + +protected: + //void resizeEvent(QResizeEvent *event); + //void showEvent(QShowEvent *event); + +private slots: + void onAddToPage(); + //void onAddToLib(); + //void onSetAsBackground(); + //void onBack(); + +private: + QVBoxLayout* mpLayout; + QHBoxLayout* mpButtonLayout; + UBFeatureItemButton* mpAddPageButton; + UBFeatureItemButton* mpAddToLibButton; + UBFeatureItemButton* mpSetAsBackgroundButton; + QLabel* mpObjInfoLabel; + //QTreeWidget* mpObjInfos; + QLabel* mpThumbnail; + QPixmap* mpOrigPixmap; + int maxThumbHeight; + UBFeature *mpElement; + //QTreeWidgetItem* mpItem; +}; + + + + +class UBFeatureItemButton : public QPushButton +{ +public: + UBFeatureItemButton(QWidget* parent=0, const char* name="UBFeatureItemButton"); + ~UBFeatureItemButton(); +}; + +class UBFeaturesModel : public QAbstractListModel +{ + Q_OBJECT +public: + UBFeaturesModel( QObject *parent = 0 ) { }; + virtual ~UBFeaturesModel(){}; + + QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const; + QMimeData *mimeData( const QModelIndexList &indexes ) const; + QStringList mimeTypes() const; + int rowCount( const QModelIndex &parent ) const; + Qt::ItemFlags flags( const QModelIndex &index ) const; + bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent); + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + bool removeRow(int row, const QModelIndex &parent = QModelIndex()); + Qt::DropActions supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; }; + + void setFeaturesList( QVector *flist ) { featuresList = flist; }; +private: + QVector *featuresList; +}; + +class UBFeaturesProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + UBFeaturesProxyModel(QObject *parent = 0) { QSortFilterProxyModel::QSortFilterProxyModel(parent); }; + virtual ~UBFeaturesProxyModel() {}; +protected: + virtual bool filterAcceptsRow ( int sourceRow, const QModelIndex & sourceParent ) const; +}; + +class UBFeaturesSearchProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + UBFeaturesSearchProxyModel(QObject *parent = 0) { QSortFilterProxyModel::QSortFilterProxyModel(parent); }; + virtual ~UBFeaturesSearchProxyModel() {}; +protected: + virtual bool filterAcceptsRow ( int sourceRow, const QModelIndex & sourceParent ) const; +}; + +class UBFeaturesPathProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + UBFeaturesPathProxyModel(QObject *parent = 0) { QSortFilterProxyModel::QSortFilterProxyModel(parent); }; + virtual ~UBFeaturesPathProxyModel() {}; + void setPath( const QString &p ) { path = p; }; +protected: + virtual bool filterAcceptsRow ( int sourceRow, const QModelIndex & sourceParent ) const; +private: + QString path; +}; + +class UBFeaturesItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + UBFeaturesItemDelegate(QWidget *parent = 0, const QListView *lw = 0) : QStyledItemDelegate(parent) { listView = lw; }; + ~UBFeaturesItemDelegate() {}; + //UBFeaturesItemDelegate(const QListView *lw = 0) { listView = lw; }; + //void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + //QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual QString displayText ( const QVariant & value, const QLocale & locale ) const; +private: + const QListView *listView; +}; + +class UBFeaturesPathItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + UBFeaturesPathItemDelegate(QWidget *parent = 0); + ~UBFeaturesPathItemDelegate(); + virtual QString displayText ( const QVariant & value, const QLocale & locale ) const; + void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; +private: + QPixmap *arrowPixmap; +}; + +#endif // UBFEATURESWIDGET_H \ No newline at end of file diff --git a/src/gui/UBLibraryWidget.h b/src/gui/UBLibraryWidget.h index e4eb8d02..7f3bbeb4 100644 --- a/src/gui/UBLibraryWidget.h +++ b/src/gui/UBLibraryWidget.h @@ -29,6 +29,7 @@ #include #include "UBThumbnailWidget.h" +#include "board/UBLibraryController.h" class UBLibraryController; class UBChainedLibElement; diff --git a/src/gui/gui.pri b/src/gui/gui.pri index a901409f..2a033a4f 100644 --- a/src/gui/gui.pri +++ b/src/gui/gui.pri @@ -46,6 +46,7 @@ HEADERS += src/gui/UBThumbnailView.h \ src/gui/UBLibWebView.h \ src/gui/UBDownloadWidget.h \ src/gui/UBDockDownloadWidget.h \ + src/gui/UBFeaturesWidget.h\ src/gui/UBDockTeacherGuideWidget.h \ src/gui/UBTeacherGuideWidget.h \ src/gui/UBTeacherGuideWidgetsTools.h \ @@ -99,6 +100,7 @@ SOURCES += src/gui/UBThumbnailView.cpp \ src/gui/UBLibWebView.cpp \ src/gui/UBDownloadWidget.cpp \ src/gui/UBDockDownloadWidget.cpp \ + src/gui/UBFeaturesWidget.cpp\ src/gui/UBDockTeacherGuideWidget.cpp \ src/gui/UBTeacherGuideWidget.cpp \ src/gui/UBTeacherGuideWidgetsTools.cpp \