/* * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM) * * Copyright (C) 2013 Open Education Foundation * * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour * l'Education Numérique en Afrique (GIP ENA) * * This file is part of OpenBoard. * * OpenBoard 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, version 3 of the License, * with a specific linking exception for the OpenSSL project's * "OpenSSL" library (or with modified versions of it that use the * same license as the "OpenSSL" library). * * OpenBoard 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. * * You should have received a copy of the GNU General Public License * along with OpenBoard. If not, see . */ #include "UBBoardController.h" #include #include #include "frameworks/UBFileSystemUtils.h" #include "frameworks/UBPlatformUtils.h" #include "core/UBApplication.h" #include "core/UBSettings.h" #include "core/UBSetting.h" #include "core/UBPersistenceManager.h" #include "core/UBApplicationController.h" #include "core/UBDocumentManager.h" #include "core/UBMimeData.h" #include "core/UBDownloadManager.h" #include "network/UBHttpGet.h" #include "gui/UBMessageWindow.h" #include "gui/UBResources.h" #include "gui/UBToolbarButtonGroup.h" #include "gui/UBMainWindow.h" #include "gui/UBToolWidget.h" #include "gui/UBKeyboardPalette.h" #include "gui/UBMagnifer.h" #include "gui/UBDockPaletteWidget.h" #include "domain/UBGraphicsPixmapItem.h" #include "domain/UBGraphicsItemUndoCommand.h" #include "domain/UBGraphicsSvgItem.h" #include "domain/UBGraphicsWidgetItem.h" #include "domain/UBGraphicsMediaItem.h" #include "domain/UBGraphicsPDFItem.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBPageSizeUndoCommand.h" #include "domain/UBGraphicsGroupContainerItem.h" #include "domain/UBGraphicsStrokesGroup.h" #include "domain/UBItem.h" #include "board/UBFeaturesController.h" #include "gui/UBFeaturesWidget.h" #include "tools/UBToolsManager.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" #include "board/UBDrawingController.h" #include "board/UBBoardView.h" #include "podcast/UBPodcastController.h" #include "adaptors/UBMetadataDcSubsetAdaptor.h" #include "adaptors/UBSvgSubsetAdaptor.h" #include "UBBoardPaletteManager.h" #include "core/UBSettings.h" #include "core/memcheck.h" UBBoardController::UBBoardController(UBMainWindow* mainWindow) : UBDocumentContainer(mainWindow->centralWidget()) , mMainWindow(mainWindow) , mActiveScene(0) , mActiveSceneIndex(-1) , mPaletteManager(0) , mSoftwareUpdateDialog(0) , mMessageWindow(0) , mControlView(0) , mDisplayView(0) , mControlContainer(0) , mControlLayout(0) , mZoomFactor(1.0) , mIsClosing(false) , mSystemScaleFactor(1.0) , mCleanupDone(false) , mCacheWidgetIsEnabled(false) , mDeletingSceneIndex(-1) , mMovingSceneIndex(-1) , mActionGroupText(tr("Group")) , mActionUngroupText(tr("Ungroup")) , mAutosaveTimer(0) { mZoomFactor = UBSettings::settings()->boardZoomFactor->get().toDouble(); int penColorIndex = UBSettings::settings()->penColorIndex(); int markerColorIndex = UBSettings::settings()->markerColorIndex(); mPenColorOnDarkBackground = UBSettings::settings()->penColors(true).at(penColorIndex); mPenColorOnLightBackground = UBSettings::settings()->penColors(false).at(penColorIndex); mMarkerColorOnDarkBackground = UBSettings::settings()->markerColors(true).at(markerColorIndex); mMarkerColorOnLightBackground = UBSettings::settings()->markerColors(false).at(markerColorIndex); } void UBBoardController::init() { setupViews(); setupToolbar(); connect(UBApplication::undoStack, SIGNAL(canUndoChanged(bool)) , this, SLOT(undoRedoStateChange(bool))); connect(UBApplication::undoStack, SIGNAL(canRedoChanged (bool)) , this, SLOT(undoRedoStateChange(bool))); connect(UBDrawingController::drawingController(), SIGNAL(stylusToolChanged(int)) , this, SLOT(setToolCursor(int))); connect(UBDrawingController::drawingController(), SIGNAL(stylusToolChanged(int)) , this, SLOT(stylusToolChanged(int))); connect(UBApplication::app(), SIGNAL(lastWindowClosed()) , this, SLOT(lastWindowClosed())); connect(UBDownloadManager::downloadManager(), SIGNAL(downloadModalFinished()), this, SLOT(onDownloadModalFinished())); connect(UBDownloadManager::downloadManager(), SIGNAL(addDownloadedFileToBoard(bool,QUrl,QUrl,QString,QByteArray,QPointF,QSize,bool)), this, SLOT(downloadFinished(bool,QUrl,QUrl,QString,QByteArray,QPointF,QSize,bool))); UBDocumentProxy* doc = UBPersistenceManager::persistenceManager()->createDocument(); setActiveDocumentScene(doc); initBackgroundGridSize(); undoRedoStateChange(true); } UBBoardController::~UBBoardController() { delete mDisplayView; } /** * @brief Set the default background grid size to appear as roughly 1cm on screen */ void UBBoardController::initBackgroundGridSize() { // Besides adjusting for DPI, we also need to scale the grid size by the ratio of the control view size // to document size. However the control view isn't available as soon as the boardController is created, // so we approximate this ratio as (document resolution) / (screen resolution). // Later on, this is calculated by `updateSystemScaleFactor` and stored in `mSystemScaleFactor`. QDesktopWidget* desktop = UBApplication::desktop(); qreal dpi = (desktop->physicalDpiX() + desktop->physicalDpiY()) / 2.; //qDebug() << "dpi: " << dpi; // The display manager isn't initialized yet so we have to just assume the control view is on the main display qreal screenY = desktop->screenGeometry(mControlView).height(); qreal documentY = mActiveScene->nominalSize().height(); qreal resolutionRatio = documentY / screenY; //qDebug() << "resolution ratio: " << resolutionRatio; int gridSize = (resolutionRatio * 10. * dpi) / UBGeometryUtils::inchSize; UBSettings::settings()->crossSize = gridSize; UBSettings::settings()->defaultCrossSize = gridSize; mActiveScene->setBackgroundGridSize(gridSize); //qDebug() << "grid size: " << gridSize; } int UBBoardController::currentPage() { return mActiveSceneIndex + 1; } void UBBoardController::setupViews() { mControlContainer = new QWidget(mMainWindow->centralWidget()); mControlLayout = new QHBoxLayout(mControlContainer); mControlLayout->setContentsMargins(0, 0, 0, 0); mControlView = new UBBoardView(this, mControlContainer, true, false); mControlView->setObjectName(CONTROLVIEW_OBJ_NAME); mControlView->setInteractive(true); mControlView->setMouseTracking(true); mControlView->grabGesture(Qt::SwipeGesture); mControlView->setTransformationAnchor(QGraphicsView::NoAnchor); mControlLayout->addWidget(mControlView); mControlContainer->setObjectName("ubBoardControlContainer"); mMainWindow->addBoardWidget(mControlContainer); connect(mControlView, SIGNAL(resized(QResizeEvent*)), this, SLOT(boardViewResized(QResizeEvent*))); // TODO UB 4.x Optimization do we have to create the display view even if their is // only 1 screen // mDisplayView = new UBBoardView(this, UBItemLayerType::FixedBackground, UBItemLayerType::Tool, 0); mDisplayView->setInteractive(false); mDisplayView->setTransformationAnchor(QGraphicsView::NoAnchor); mPaletteManager = new UBBoardPaletteManager(mControlContainer, this); mMessageWindow = new UBMessageWindow(mControlContainer); mMessageWindow->hide(); connect(this, SIGNAL(activeSceneChanged()), mPaletteManager, SLOT(activeSceneChanged())); } void UBBoardController::setupLayout() { if(mPaletteManager) mPaletteManager->setupLayout(); } void UBBoardController::setBoxing(QRect displayRect) { if (displayRect.isNull()) { mControlLayout->setContentsMargins(0, 0, 0, 0); return; } qreal controlWidth = (qreal)mMainWindow->centralWidget()->width(); qreal controlHeight = (qreal)mMainWindow->centralWidget()->height(); qreal displayWidth = (qreal)displayRect.width(); qreal displayHeight = (qreal)displayRect.height(); qreal displayRatio = displayWidth / displayHeight; qreal controlRatio = controlWidth / controlHeight; if (displayRatio < controlRatio) { // Pillarboxing int boxWidth = (controlWidth - (displayWidth * (controlHeight / displayHeight))) / 2; mControlLayout->setContentsMargins(boxWidth, 0, boxWidth, 0); } else if (displayRatio > controlRatio) { // Letterboxing int boxHeight = (controlHeight - (displayHeight * (controlWidth / displayWidth))) / 2; mControlLayout->setContentsMargins(0, boxHeight, 0, boxHeight); } else { // No boxing mControlLayout->setContentsMargins(0, 0, 0, 0); } } QSize UBBoardController::displayViewport() { return mDisplayView->geometry().size(); } QSize UBBoardController::controlViewport() { return mControlView->geometry().size(); } QRectF UBBoardController::controlGeometry() { return mControlView->geometry(); } void UBBoardController::setupToolbar() { UBSettings *settings = UBSettings::settings(); // Setup color choice widget QList colorActions; colorActions.append(mMainWindow->actionColor0); colorActions.append(mMainWindow->actionColor1); colorActions.append(mMainWindow->actionColor2); colorActions.append(mMainWindow->actionColor3); colorActions.append(mMainWindow->actionColor4); UBToolbarButtonGroup *colorChoice = new UBToolbarButtonGroup(mMainWindow->boardToolBar, colorActions); mMainWindow->boardToolBar->insertWidget(mMainWindow->actionBackgrounds, colorChoice); connect(settings->appToolBarDisplayText, SIGNAL(changed(QVariant)), colorChoice, SLOT(displayText(QVariant))); connect(colorChoice, SIGNAL(activated(int)), this, SLOT(setColorIndex(int))); connect(UBDrawingController::drawingController(), SIGNAL(colorIndexChanged(int)), colorChoice, SLOT(setCurrentIndex(int))); connect(UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged()), colorChoice, SLOT(colorPaletteChanged())); connect(UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged()), this, SLOT(colorPaletteChanged())); colorChoice->displayText(QVariant(settings->appToolBarDisplayText->get().toBool())); colorChoice->colorPaletteChanged(); // Setup line width choice widget QList lineWidthActions; lineWidthActions.append(mMainWindow->actionLineSmall); lineWidthActions.append(mMainWindow->actionLineMedium); lineWidthActions.append(mMainWindow->actionLineLarge); UBToolbarButtonGroup *lineWidthChoice = new UBToolbarButtonGroup(mMainWindow->boardToolBar, lineWidthActions); connect(settings->appToolBarDisplayText, SIGNAL(changed(QVariant)), lineWidthChoice, SLOT(displayText(QVariant))); connect(lineWidthChoice, SIGNAL(activated(int)) , UBDrawingController::drawingController(), SLOT(setLineWidthIndex(int))); connect(UBDrawingController::drawingController(), SIGNAL(lineWidthIndexChanged(int)) , lineWidthChoice, SLOT(setCurrentIndex(int))); lineWidthChoice->displayText(QVariant(settings->appToolBarDisplayText->get().toBool())); mMainWindow->boardToolBar->insertWidget(mMainWindow->actionBackgrounds, lineWidthChoice); //-----------------------------------------------------------// // Setup eraser width choice widget QList eraserWidthActions; eraserWidthActions.append(mMainWindow->actionEraserSmall); eraserWidthActions.append(mMainWindow->actionEraserMedium); eraserWidthActions.append(mMainWindow->actionEraserLarge); UBToolbarButtonGroup *eraserWidthChoice = new UBToolbarButtonGroup(mMainWindow->boardToolBar, eraserWidthActions); mMainWindow->boardToolBar->insertWidget(mMainWindow->actionBackgrounds, eraserWidthChoice); connect(settings->appToolBarDisplayText, SIGNAL(changed(QVariant)), eraserWidthChoice, SLOT(displayText(QVariant))); connect(eraserWidthChoice, SIGNAL(activated(int)), UBDrawingController::drawingController(), SLOT(setEraserWidthIndex(int))); eraserWidthChoice->displayText(QVariant(settings->appToolBarDisplayText->get().toBool())); eraserWidthChoice->setCurrentIndex(settings->eraserWidthIndex()); mMainWindow->boardToolBar->insertSeparator(mMainWindow->actionBackgrounds); //-----------------------------------------------------------// UBApplication::app()->insertSpaceToToolbarBeforeAction(mMainWindow->boardToolBar, mMainWindow->actionBoard); UBApplication::app()->decorateActionMenu(mMainWindow->actionMenu); mMainWindow->actionBoard->setVisible(false); mMainWindow->webToolBar->hide(); mMainWindow->documentToolBar->hide(); connectToolbar(); initToolbarTexts(); UBApplication::app()->toolBarDisplayTextChanged(QVariant(settings->appToolBarDisplayText->get().toBool())); } void UBBoardController::setToolCursor(int tool) { if (mActiveScene) mActiveScene->setToolCursor(tool); mControlView->setToolCursor(tool); } void UBBoardController::connectToolbar() { connect(mMainWindow->actionAdd, SIGNAL(triggered()), this, SLOT(addItem())); connect(mMainWindow->actionNewPage, SIGNAL(triggered()), this, SLOT(addScene())); connect(mMainWindow->actionDuplicatePage, SIGNAL(triggered()), this, SLOT(duplicateScene())); connect(mMainWindow->actionClearPage, SIGNAL(triggered()), this, SLOT(clearScene())); connect(mMainWindow->actionEraseItems, SIGNAL(triggered()), this, SLOT(clearSceneItems())); connect(mMainWindow->actionEraseAnnotations, SIGNAL(triggered()), this, SLOT(clearSceneAnnotation())); connect(mMainWindow->actionEraseBackground,SIGNAL(triggered()),this,SLOT(clearSceneBackground())); connect(mMainWindow->actionUndo, SIGNAL(triggered()), UBApplication::undoStack, SLOT(undo())); connect(mMainWindow->actionRedo, SIGNAL(triggered()), UBApplication::undoStack, SLOT(redo())); connect(mMainWindow->actionRedo, SIGNAL(triggered()), this, SLOT(startScript())); connect(mMainWindow->actionBack, SIGNAL( triggered()), this, SLOT(previousScene())); connect(mMainWindow->actionForward, SIGNAL(triggered()), this, SLOT(nextScene())); connect(mMainWindow->actionSleep, SIGNAL(triggered()), this, SLOT(stopScript())); connect(mMainWindow->actionSleep, SIGNAL(triggered()), this, SLOT(blackout())); connect(mMainWindow->actionVirtualKeyboard, SIGNAL(triggered(bool)), this, SLOT(showKeyboard(bool))); connect(mMainWindow->actionImportPage, SIGNAL(triggered()), this, SLOT(importPage())); } void UBBoardController::startScript() { freezeW3CWidgets(false); } void UBBoardController::stopScript() { freezeW3CWidgets(true); } void UBBoardController::saveData(SaveFlags fls) { bool verbose = fls | sf_showProgress; if (verbose) { UBApplication::showMessage(tr("Saving document...")); } if (mActiveScene && mActiveScene->isModified()) { persistCurrentScene(true); } if (verbose) { UBApplication::showMessage(tr("Document has just been saved...")); } } void UBBoardController::initToolbarTexts() { QList allToolbarActions; allToolbarActions << mMainWindow->boardToolBar->actions(); allToolbarActions << mMainWindow->webToolBar->actions(); allToolbarActions << mMainWindow->documentToolBar->actions(); foreach(QAction* action, allToolbarActions) { QString nominalText = action->text(); QString shortText = truncate(nominalText, 48); QPair texts(nominalText, shortText); mActionTexts.insert(action, texts); } } void UBBoardController::setToolbarTexts() { bool highResolution = mMainWindow->width() > 1024; QSize iconSize; if (highResolution) iconSize = QSize(48, 32); else iconSize = QSize(32, 32); mMainWindow->boardToolBar->setIconSize(iconSize); mMainWindow->webToolBar->setIconSize(iconSize); mMainWindow->documentToolBar->setIconSize(iconSize); foreach(QAction* action, mActionTexts.keys()) { QPair texts = mActionTexts.value(action); if (highResolution) action->setText(texts.first); else { action->setText(texts.second); } action->setToolTip(texts.first); } } QString UBBoardController::truncate(QString text, int maxWidth) { QFontMetricsF fontMetrics(mMainWindow->font()); return fontMetrics.elidedText(text, Qt::ElideRight, maxWidth); } void UBBoardController::stylusToolDoubleClicked(int tool) { if (tool == UBStylusTool::ZoomIn || tool == UBStylusTool::ZoomOut) { zoomRestore(); } else if (tool == UBStylusTool::Hand) { centerRestore(); mActiveScene->setLastCenter(QPointF(0,0)); } } void UBBoardController::addScene() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistViewPositionOnCurrentScene(); persistCurrentScene(false,true); UBDocumentContainer::addPage(mActiveSceneIndex + 1); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); setActiveDocumentScene(mActiveSceneIndex + 1); QApplication::restoreOverrideCursor(); } void UBBoardController::addScene(UBGraphicsScene* scene, bool replaceActiveIfEmpty) { if (scene) { UBGraphicsScene* clone = scene->sceneDeepCopy(); if (scene->document() && (scene->document() != selectedDocument())) { foreach(QUrl relativeFile, scene->relativeDependencies()) { QString source = scene->document()->persistencePath() + "/" + relativeFile.toString(); QString target = selectedDocument()->persistencePath() + "/" + relativeFile.toString(); if(QFileInfo(source).isDir()) UBFileSystemUtils::copyDir(source,target); else{ QFileInfo fi(target); QDir d = fi.dir(); d.mkpath(d.absolutePath()); QFile::copy(source, target); } } } if (replaceActiveIfEmpty && mActiveScene->isEmpty()) { UBPersistenceManager::persistenceManager()->insertDocumentSceneAt(selectedDocument(), clone, mActiveSceneIndex); emit addThumbnailRequired(this, mActiveSceneIndex); setActiveDocumentScene(mActiveSceneIndex); deleteScene(mActiveSceneIndex + 1); } else { persistCurrentScene(false,true); UBPersistenceManager::persistenceManager()->insertDocumentSceneAt(selectedDocument(), clone, mActiveSceneIndex + 1); emit addThumbnailRequired(this, mActiveSceneIndex + 1); setActiveDocumentScene(mActiveSceneIndex + 1); } selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); } } void UBBoardController::addScene(UBDocumentProxy* proxy, int sceneIndex, bool replaceActiveIfEmpty) { UBGraphicsScene* scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(proxy, sceneIndex); if (scene) { addScene(scene, replaceActiveIfEmpty); } } void UBBoardController::duplicateScene(int nIndex) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistCurrentScene(false,true); QList scIndexes; scIndexes << nIndex; duplicatePages(scIndexes); insertThumbPage(nIndex); emit documentThumbnailsUpdated(this); emit addThumbnailRequired(this, nIndex + 1); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); setActiveDocumentScene(nIndex + 1); QApplication::restoreOverrideCursor(); } void UBBoardController::duplicateScene() { if (UBApplication::applicationController->displayMode() != UBApplicationController::Board) return; duplicateScene(mActiveSceneIndex); } UBGraphicsItem *UBBoardController::duplicateItem(UBItem *item) { if (!item) return NULL; UBGraphicsItem *retItem = NULL; mLastCreatedItem = NULL; QUrl sourceUrl; QByteArray pData; //common parameters for any item QPointF itemPos; QSizeF itemSize; QGraphicsItem *commonItem = dynamic_cast(item); if (commonItem) { qreal shifting = UBSettings::settings()->objectFrameWidth; itemPos = commonItem->pos() + QPointF(shifting,shifting); itemSize = commonItem->boundingRect().size(); commonItem->setSelected(false); } UBMimeType::Enum itemMimeType; QString srcFile = item->sourceUrl().toLocalFile(); if (srcFile.isEmpty()) srcFile = item->sourceUrl().toString(); QString contentTypeHeader; if (!srcFile.isEmpty()) contentTypeHeader = UBFileSystemUtils::mimeTypeFromFileName(srcFile); if(NULL != qgraphicsitem_cast(commonItem)) itemMimeType = UBMimeType::Group; else itemMimeType = UBFileSystemUtils::mimeTypeFromString(contentTypeHeader); switch(static_cast(itemMimeType)) { case UBMimeType::AppleWidget: case UBMimeType::W3CWidget: { UBGraphicsWidgetItem *witem = dynamic_cast(item); if (witem) { sourceUrl = witem->getOwnFolder(); } }break; case UBMimeType::Video: case UBMimeType::Audio: { UBGraphicsMediaItem *mitem = dynamic_cast(item); if (mitem) { sourceUrl = mitem->mediaFileUrl(); downloadURL(sourceUrl, srcFile, itemPos, QSize(itemSize.width(), itemSize.height()), false, false); return NULL; // async operation } }break; case UBMimeType::VectorImage: { UBGraphicsSvgItem *viitem = dynamic_cast(item); if (viitem) { pData = viitem->fileData(); sourceUrl = item->sourceUrl(); } }break; case UBMimeType::RasterImage: { UBGraphicsPixmapItem *pixitem = dynamic_cast(item); if (pixitem) { QBuffer buffer(&pData); buffer.open(QIODevice::WriteOnly); QString format = UBFileSystemUtils::extension(item->sourceUrl().toString(QUrl::DecodeReserved)); pixitem->pixmap().save(&buffer, format.toLatin1()); } }break; case UBMimeType::Group: { UBGraphicsGroupContainerItem* groupItem = dynamic_cast(item); UBGraphicsGroupContainerItem* duplicatedGroup = NULL; QList duplicatedItems; QList children = groupItem->childItems(); mActiveScene->setURStackEnable(false); foreach(QGraphicsItem* pIt, children){ UBItem* pItem = dynamic_cast(pIt); if(pItem){ QGraphicsItem * itemToGroup = dynamic_cast(duplicateItem(pItem)); if (itemToGroup) duplicatedItems.append(itemToGroup); } } duplicatedGroup = mActiveScene->createGroup(duplicatedItems); duplicatedGroup->setTransform(groupItem->transform()); groupItem->setSelected(false); retItem = dynamic_cast(duplicatedGroup); QGraphicsItem * itemToAdd = dynamic_cast(retItem); if (itemToAdd) { mActiveScene->addItem(itemToAdd); itemToAdd->setSelected(true); } mActiveScene->setURStackEnable(true); }break; case UBMimeType::UNKNOWN: { QGraphicsItem *gitem = dynamic_cast(item->deepCopy()); if (gitem) { mActiveScene->addItem(gitem); gitem->setPos(itemPos); mLastCreatedItem = gitem; gitem->setSelected(true); } retItem = dynamic_cast(gitem); }break; } if (retItem) { QGraphicsItem *graphicsRetItem = dynamic_cast(retItem); if (mActiveScene->isURStackIsEnabled()) { //should be deleted after scene own undo stack implemented UBGraphicsItemUndoCommand* uc = new UBGraphicsItemUndoCommand(mActiveScene, 0, graphicsRetItem); UBApplication::undoStack->push(uc); } return retItem; } UBItem *createdItem = downloadFinished(true, sourceUrl, srcFile, contentTypeHeader, pData, itemPos, QSize(itemSize.width(), itemSize.height()), false); if (createdItem) { createdItem->setSourceUrl(item->sourceUrl()); item->copyItemParameters(createdItem); QGraphicsItem *createdGitem = dynamic_cast(createdItem); if (createdGitem) createdGitem->setPos(itemPos); mLastCreatedItem = dynamic_cast(createdItem); mLastCreatedItem->setSelected(true); retItem = dynamic_cast(createdItem); } return retItem; } void UBBoardController::deleteScene(int nIndex) { if (selectedDocument()->pageCount()>=2) { mDeletingSceneIndex = nIndex; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistCurrentScene(); showMessage(tr("Deleting page %1").arg(nIndex+1), true); QList scIndexes; scIndexes << nIndex; deletePages(scIndexes); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); if (nIndex >= pageCount()) nIndex = pageCount()-1; setActiveDocumentScene(nIndex); showMessage(tr("Page %1 deleted").arg(nIndex+1)); QApplication::restoreOverrideCursor(); mDeletingSceneIndex = -1; } } void UBBoardController::clearScene() { if (mActiveScene) { freezeW3CWidgets(true); mActiveScene->clearContent(UBGraphicsScene::clearItemsAndAnnotations); mActiveScene->setLastCenter(QPointF(0,0)); mControlView->centerOn(mActiveScene->lastCenter()); updateActionStates(); } } void UBBoardController::clearSceneItems() { if (mActiveScene) { freezeW3CWidgets(true); mActiveScene->clearContent(UBGraphicsScene::clearItems); updateActionStates(); } } void UBBoardController::clearSceneAnnotation() { if (mActiveScene) { mActiveScene->clearContent(UBGraphicsScene::clearAnnotations); updateActionStates(); } } void UBBoardController::clearSceneBackground() { if (mActiveScene) { mActiveScene->clearContent(UBGraphicsScene::clearBackground); updateActionStates(); } } void UBBoardController::showDocumentsDialog() { if (selectedDocument()) persistCurrentScene(); UBApplication::mainWindow->actionLibrary->setChecked(false); } void UBBoardController::libraryDialogClosed(int ret) { Q_UNUSED(ret); mMainWindow->actionLibrary->setChecked(false); } void UBBoardController::blackout() { UBApplication::applicationController->blackout(); } void UBBoardController::showKeyboard(bool show) { if(show) UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); if(UBSettings::settings()->useSystemOnScreenKeyboard->get().toBool()) UBPlatformUtils::showOSK(show); else mPaletteManager->showVirtualKeyboard(show); } void UBBoardController::zoomIn(QPointF scenePoint) { if (mControlView->transform().m11() > UB_MAX_ZOOM) { qApp->beep(); return; } zoom(mZoomFactor, scenePoint); } void UBBoardController::zoomOut(QPointF scenePoint) { if ((mControlView->horizontalScrollBar()->maximum() == 0) && (mControlView->verticalScrollBar()->maximum() == 0)) { // Do not zoom out if we reached the maximum qApp->beep(); return; } qreal newZoomFactor = 1 / mZoomFactor; zoom(newZoomFactor, scenePoint); } void UBBoardController::zoomRestore() { QTransform tr; tr.scale(mSystemScaleFactor, mSystemScaleFactor); mControlView->setTransform(tr); centerRestore(); foreach(QGraphicsItem *gi, mActiveScene->selectedItems ()) { //force item to redraw the frame (for the anti scale calculation) gi->setSelected(false); gi->setSelected(true); } emit zoomChanged(1.0); } void UBBoardController::centerRestore() { centerOn(QPointF(0,0)); } void UBBoardController::centerOn(QPointF scenePoint) { mControlView->centerOn(scenePoint); UBApplication::applicationController->adjustDisplayView(); } void UBBoardController::zoom(const qreal ratio, QPointF scenePoint) { QPointF viewCenter = mControlView->mapToScene(QRect(0, 0, mControlView->width(), mControlView->height()).center()); QPointF offset = scenePoint - viewCenter; QPointF scalledOffset = offset / ratio; qreal currentZoom = ratio * mControlView->viewportTransform().m11() / mSystemScaleFactor; qreal usedRatio = ratio; if (currentZoom > UB_MAX_ZOOM) { currentZoom = UB_MAX_ZOOM; usedRatio = currentZoom * mSystemScaleFactor / mControlView->viewportTransform().m11(); } mControlView->scale(usedRatio, usedRatio); QPointF newCenter = scenePoint - scalledOffset; mControlView->centerOn(newCenter); emit zoomChanged(currentZoom); UBApplication::applicationController->adjustDisplayView(); emit controlViewportChanged(); mActiveScene->setBackgroundZoomFactor(mControlView->transform().m11()); } void UBBoardController::handScroll(qreal dx, qreal dy) { qreal antiScaleRatio = 1/(mSystemScaleFactor * currentZoom()); mControlView->translate(dx*antiScaleRatio, dy*antiScaleRatio); UBApplication::applicationController->adjustDisplayView(); emit controlViewportChanged(); } void UBBoardController::persistViewPositionOnCurrentScene() { QRect rect = mControlView->rect(); QPoint center(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); QPointF viewRelativeCenter = mControlView->mapToScene(center); mActiveScene->setLastCenter(viewRelativeCenter); } void UBBoardController::previousScene() { if (mActiveSceneIndex > 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistViewPositionOnCurrentScene(); persistCurrentScene(); setActiveDocumentScene(mActiveSceneIndex - 1); mControlView->centerOn(mActiveScene->lastCenter()); QApplication::restoreOverrideCursor(); } updateActionStates(); } void UBBoardController::nextScene() { if (mActiveSceneIndex < selectedDocument()->pageCount() - 1) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistViewPositionOnCurrentScene(); persistCurrentScene(); setActiveDocumentScene(mActiveSceneIndex + 1); mControlView->centerOn(mActiveScene->lastCenter()); QApplication::restoreOverrideCursor(); } updateActionStates(); } void UBBoardController::firstScene() { if (mActiveSceneIndex > 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistViewPositionOnCurrentScene(); persistCurrentScene(); setActiveDocumentScene(0); mControlView->centerOn(mActiveScene->lastCenter()); QApplication::restoreOverrideCursor(); } updateActionStates(); } void UBBoardController::lastScene() { if (mActiveSceneIndex < selectedDocument()->pageCount() - 1) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistViewPositionOnCurrentScene(); persistCurrentScene(); setActiveDocumentScene(selectedDocument()->pageCount() - 1); mControlView->centerOn(mActiveScene->lastCenter()); QApplication::restoreOverrideCursor(); } updateActionStates(); } void UBBoardController::downloadURL(const QUrl& url, QString contentSourceUrl, const QPointF& pPos, const QSize& pSize, bool isBackground, bool internalData) { qDebug() << "something has been dropped on the board! Url is: " << url.toString(); QString sUrl = url.toString(); QGraphicsItem *oldBackgroundObject = NULL; if (isBackground) oldBackgroundObject = mActiveScene->backgroundObject(); if(sUrl.startsWith("openboardtool://")) { downloadFinished(true, url, QUrl(), "application/openboard-tool", QByteArray(), pPos, pSize, isBackground); } else if (sUrl.startsWith("file://") || sUrl.startsWith("/")) { QUrl formedUrl = sUrl.startsWith("file://") ? url : QUrl::fromLocalFile(sUrl); QString fileName = formedUrl.toLocalFile(); QString contentType = UBFileSystemUtils::mimeTypeFromFileName(fileName); bool shouldLoadFileData = contentType.startsWith("image") || contentType.startsWith("application/widget") || contentType.startsWith("application/vnd.apple-widget"); if (shouldLoadFileData) { QFile file(fileName); file.open(QIODevice::ReadOnly); downloadFinished(true, formedUrl, QUrl(), contentType, file.readAll(), pPos, pSize, isBackground, internalData); file.close(); } else { // media items should be copyed in separate thread sDownloadFileDesc desc; desc.modal = false; desc.srcUrl = sUrl; desc.originalSrcUrl = contentSourceUrl; desc.currentSize = 0; desc.name = QFileInfo(url.toString()).fileName(); desc.totalSize = 0; // The total size will be retrieved during the download desc.pos = pPos; desc.size = pSize; desc.isBackground = isBackground; UBDownloadManager::downloadManager()->addFileToDownload(desc); } } else { QString urlString = url.toString(); int parametersStringPosition = urlString.indexOf("?"); if(parametersStringPosition != -1) urlString = urlString.left(parametersStringPosition); // When we fall there, it means that we are dropping something from the web to the board sDownloadFileDesc desc; desc.modal = true; desc.srcUrl = urlString; desc.currentSize = 0; desc.name = QFileInfo(urlString).fileName(); desc.totalSize = 0; // The total size will be retrieved during the download desc.pos = pPos; desc.size = pSize; desc.isBackground = isBackground; UBDownloadManager::downloadManager()->addFileToDownload(desc); } if (isBackground && oldBackgroundObject != mActiveScene->backgroundObject()) { if (mActiveScene->isURStackIsEnabled()) { //should be deleted after scene own undo stack implemented UBGraphicsItemUndoCommand* uc = new UBGraphicsItemUndoCommand(mActiveScene, oldBackgroundObject, mActiveScene->backgroundObject()); UBApplication::undoStack->push(uc); } } } UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl contentUrl, QString pContentTypeHeader, QByteArray pData, QPointF pPos, QSize pSize, bool isBackground, bool internalData) { QString mimeType = pContentTypeHeader; // In some cases "image/jpeg;charset=" is retourned by the drag-n-drop. That is // why we will check if an ; exists and take the first part (the standard allows this kind of mimetype) if(mimeType.isEmpty()) mimeType = UBFileSystemUtils::mimeTypeFromFileName(sourceUrl.toString()); int position=mimeType.indexOf(";"); if(position != -1) mimeType=mimeType.left(position); UBMimeType::Enum itemMimeType = UBFileSystemUtils::mimeTypeFromString(mimeType); if (!pSuccess) { showMessage(tr("Downloading content %1 failed").arg(sourceUrl.toString())); return NULL; } mActiveScene->deselectAllItems(); if (!sourceUrl.toString().startsWith("file://") && !sourceUrl.toString().startsWith("openboardtool://")) showMessage(tr("Download finished")); if (UBMimeType::RasterImage == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as raster image"; QPixmap pix; if(pData.length() == 0){ pix.load(sourceUrl.toLocalFile()); } else{ QImage img; img.loadFromData(pData); pix = QPixmap::fromImage(img); } UBGraphicsPixmapItem* pixItem = mActiveScene->addPixmap(pix, NULL, pPos, 1.); pixItem->setSourceUrl(sourceUrl); if (isBackground) { mActiveScene->setAsBackgroundObject(pixItem, true); } else { mActiveScene->scaleToFitDocumentSize(pixItem, true, UBSettings::objectInControlViewMargin); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } return pixItem; } else if (UBMimeType::VectorImage == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as vecto image"; UBGraphicsSvgItem* svgItem = mActiveScene->addSvg(sourceUrl, pPos, pData); svgItem->setSourceUrl(sourceUrl); if (isBackground) { mActiveScene->setAsBackgroundObject(svgItem); } else { mActiveScene->scaleToFitDocumentSize(svgItem, true, UBSettings::objectInControlViewMargin); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } return svgItem; } else if (UBMimeType::AppleWidget == itemMimeType) //mime type invented by us :-( { qDebug() << "accepting mime type" << mimeType << "as Apple widget"; QUrl widgetUrl = sourceUrl; if (pData.length() > 0) { widgetUrl = expandWidgetToTempDir(pData, "wdgt"); } UBGraphicsWidgetItem* appleWidgetItem = mActiveScene->addAppleWidget(widgetUrl, pPos); appleWidgetItem->setSourceUrl(sourceUrl); if (isBackground) { mActiveScene->setAsBackgroundObject(appleWidgetItem); } else { UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } return appleWidgetItem; } else if (UBMimeType::W3CWidget == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as W3C widget"; QUrl widgetUrl = sourceUrl; if (pData.length() > 0) { widgetUrl = expandWidgetToTempDir(pData); } UBGraphicsWidgetItem *w3cWidgetItem = addW3cWidget(widgetUrl, pPos); if (isBackground) { mActiveScene->setAsBackgroundObject(w3cWidgetItem); } else { UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } return w3cWidgetItem; } else if (UBMimeType::Video == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as video"; UBGraphicsMediaItem *mediaVideoItem = 0; QUuid uuid = QUuid::createUuid(); if (pData.length() > 0) { QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), UBPersistenceManager::videoDirectory, uuid, destFile, &pData); if (!b) { showMessage(tr("Add file operation failed: file copying error")); return NULL; } QUrl url = QUrl::fromLocalFile(destFile); mediaVideoItem = mActiveScene->addMedia(url, false, pPos); } else { qDebug() << sourceUrl.toString(); mediaVideoItem = addVideo(sourceUrl, false, pPos, true); } if(mediaVideoItem){ if (contentUrl.isEmpty()) mediaVideoItem->setSourceUrl(sourceUrl); else mediaVideoItem->setSourceUrl(contentUrl); mediaVideoItem->setUuid(uuid); connect(this, SIGNAL(activeSceneChanged()), mediaVideoItem, SLOT(activeSceneChanged())); } UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); return mediaVideoItem; } else if (UBMimeType::Audio == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as audio"; UBGraphicsMediaItem *audioMediaItem = 0; QUuid uuid = QUuid::createUuid(); if (pData.length() > 0) { QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), UBPersistenceManager::audioDirectory, uuid, destFile, &pData); if (!b) { showMessage(tr("Add file operation failed: file copying error")); return NULL; } QUrl url = QUrl::fromLocalFile(destFile); audioMediaItem = mActiveScene->addMedia(url, false, pPos); } else { audioMediaItem = addAudio(sourceUrl, false, pPos, true); } if(audioMediaItem){ if (contentUrl.isEmpty()) audioMediaItem->setSourceUrl(sourceUrl); else audioMediaItem->setSourceUrl(contentUrl); audioMediaItem->setUuid(uuid); connect(this, SIGNAL(activeSceneChanged()), audioMediaItem, SLOT(activeSceneChanged())); } UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); return audioMediaItem; } else if (UBMimeType::Flash == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as flash"; QString sUrl = sourceUrl.toString(); if (sUrl.startsWith("file://") || sUrl.startsWith("/")) { sUrl = sourceUrl.toLocalFile(); } QTemporaryFile* eduMediaFile = 0; if (sUrl.toLower().contains("edumedia-sciences.com")) { eduMediaFile = new QTemporaryFile("XXXXXX.swf"); if (eduMediaFile->open()) { eduMediaFile->write(pData); QFileInfo fi(*eduMediaFile); sUrl = fi.absoluteFilePath(); } } QSize size; if (pSize.height() > 0 && pSize.width() > 0) size = pSize; else size = mActiveScene->nominalSize() * .8; Q_UNUSED(internalData) QString widgetUrl = UBGraphicsW3CWidgetItem::createNPAPIWrapper(sUrl, mimeType, size); UBFileSystemUtils::deleteFile(sourceUrl.toLocalFile()); emit npapiWidgetCreated(widgetUrl); if (widgetUrl.length() > 0) { UBGraphicsWidgetItem *widgetItem = mActiveScene->addW3CWidget(QUrl::fromLocalFile(widgetUrl), pPos); widgetItem->setUuid(QUuid::createUuid()); widgetItem->setSourceUrl(QUrl::fromLocalFile(widgetUrl)); qDebug() << widgetItem->getOwnFolder(); qDebug() << widgetItem->getSnapshotPath(); QString ownFolder = selectedDocument()->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + widgetItem->uuid().toString() + ".wgt"; widgetItem->setOwnFolder(ownFolder); QString adaptedUUid = widgetItem->uuid().toString().replace("{","").replace("}",""); ownFolder = ownFolder.replace(widgetItem->uuid().toString() + ".wgt", adaptedUUid + ".png"); widgetItem->setSnapshotPath(ownFolder); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); return widgetItem; } if (eduMediaFile) delete eduMediaFile; } else if (UBMimeType::PDF == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as PDF"; qDebug() << "pdf data length: " << pData.size(); qDebug() << "sourceurl : " + sourceUrl.toString(); int result = 0; if(!sourceUrl.isEmpty()){ QStringList fileNames; fileNames << sourceUrl.toLocalFile(); result = UBDocumentManager::documentManager()->addFilesToDocument(selectedDocument(), fileNames); } else if(pData.size()){ QTemporaryFile pdfFile("XXXXXX.pdf"); if (pdfFile.open()) { pdfFile.write(pData); QStringList fileNames; fileNames << pdfFile.fileName(); result = UBDocumentManager::documentManager()->addFilesToDocument(selectedDocument(), fileNames); pdfFile.close(); } } if (result){ selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); } } else if (UBMimeType::OpenboardTool == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "OpenBoard Tool"; if (sourceUrl.toString() == UBToolsManager::manager()->compass.id) { mActiveScene->addCompass(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->ruler.id) { mActiveScene->addRuler(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->protractor.id) { mActiveScene->addProtractor(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->triangle.id) { mActiveScene->addTriangle(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->cache.id) { mActiveScene->addCache(); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->magnifier.id) { UBMagnifierParams params; params.x = controlContainer()->geometry().width() / 2; params.y = controlContainer()->geometry().height() / 2; params.zoom = 2; params.sizePercentFromScene = 20; mActiveScene->addMagnifier(params); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else if (sourceUrl.toString() == UBToolsManager::manager()->mask.id) { mActiveScene->addMask(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } else { showMessage(tr("Unknown tool type %1").arg(sourceUrl.toString())); } } else if (sourceUrl.toString().contains("edumedia-sciences.com")) { qDebug() << "accepting url " << sourceUrl.toString() << "as eduMedia content"; QTemporaryFile eduMediaZipFile("XXXXXX.edumedia"); if (eduMediaZipFile.open()) { eduMediaZipFile.write(pData); eduMediaZipFile.close(); QString tempDir = UBFileSystemUtils::createTempDir("uniboard-edumedia"); UBFileSystemUtils::expandZipToDir(eduMediaZipFile, tempDir); QDir appDir(tempDir); foreach(QString subDirName, appDir.entryList(QDir::AllDirs)) { QDir subDir(tempDir + "/" + subDirName + "/contents"); foreach(QString fileName, subDir.entryList(QDir::Files)) { if (fileName.toLower().endsWith(".swf")) { QString swfFile = tempDir + "/" + subDirName + "/contents/" + fileName; QSize size; if (pSize.height() > 0 && pSize.width() > 0) size = pSize; else size = mActiveScene->nominalSize() * .8; QString widgetUrl = UBGraphicsW3CWidgetItem::createNPAPIWrapper(swfFile, "application/x-shockwave-flash", size); if (widgetUrl.length() > 0) { UBGraphicsWidgetItem *widgetItem = mActiveScene->addW3CWidget(QUrl::fromLocalFile(widgetUrl), pPos); widgetItem->setSourceUrl(sourceUrl); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); return widgetItem; } } } } } } else { showMessage(tr("Unknown content type %1").arg(pContentTypeHeader)); qWarning() << "ignoring mime type" << pContentTypeHeader ; } return NULL; } void UBBoardController::setActiveDocumentScene(int pSceneIndex) { setActiveDocumentScene(selectedDocument(), pSceneIndex); } void UBBoardController::setActiveDocumentScene(UBDocumentProxy* pDocumentProxy, const int pSceneIndex, bool forceReload, bool onImport) { saveViewState(); bool documentChange = selectedDocument() != pDocumentProxy; int index = pSceneIndex; int sceneCount = pDocumentProxy->pageCount(); if (index >= sceneCount && sceneCount > 0) index = sceneCount - 1; UBGraphicsScene* targetScene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pDocumentProxy, index); bool sceneChange = targetScene != mActiveScene; if (targetScene) { if (mActiveScene && !onImport) { persistCurrentScene(); freezeW3CWidgets(true); ClearUndoStack(); }else { UBApplication::undoStack->clear(); } mActiveScene = targetScene; mActiveSceneIndex = index; setDocument(pDocumentProxy, forceReload); updateSystemScaleFactor(); mControlView->setScene(mActiveScene); disconnect(mControlView, SIGNAL(mouseReleased()), mActiveScene, SLOT(updateSelectionFrame())); connect(mControlView, SIGNAL(mouseReleased()), mActiveScene, SLOT(updateSelectionFrame())); mDisplayView->setScene(mActiveScene); mActiveScene->setBackgroundZoomFactor(mControlView->transform().m11()); pDocumentProxy->setDefaultDocumentSize(mActiveScene->nominalSize()); updatePageSizeState(); adjustDisplayViews(); UBSettings::settings()->setDarkBackground(mActiveScene->isDarkBackground()); UBSettings::settings()->setPageBackground(mActiveScene->pageBackground()); freezeW3CWidgets(false); } selectionChanged(); updateBackgroundActionsState(mActiveScene->isDarkBackground(), mActiveScene->pageBackground()); if(documentChange) { UBGraphicsTextItem::lastUsedTextColor = QColor(); } if (sceneChange) { emit activeSceneChanged(); } } void UBBoardController::moveSceneToIndex(int source, int target) { if (selectedDocument()) { persistCurrentScene(false,true); UBDocumentContainer::movePageToIndex(source, target); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); UBPersistenceManager::persistenceManager()->persistDocumentMetadata(selectedDocument()); mMovingSceneIndex = source; mActiveSceneIndex = target; setActiveDocumentScene(target); mMovingSceneIndex = -1; emit activeSceneChanged(); emit updateThumbnailsRequired(); } } void UBBoardController::findUniquesItems(const QUndoCommand *parent, QSet &itms) { if (parent->childCount()) { for (int i = 0; i < parent->childCount(); i++) { findUniquesItems(parent->child(i), itms); } } // Undo command transaction macros. Process separatedly if (parent->text() == UBSettings::undoCommandTransactionName) { return; } const UBUndoCommand *undoCmd = static_cast(parent); if(undoCmd->getType() != UBUndoType::undotype_GRAPHICITEM) return; const UBGraphicsItemUndoCommand *cmd = dynamic_cast(parent); // go through all added and removed objects, for create list of unique objects // grouped items will be deleted by groups, so we don't need do delete that items. QSetIterator itAdded(cmd->GetAddedList()); while (itAdded.hasNext()) { QGraphicsItem* item = itAdded.next(); if( !itms.contains(item) && !(item->parentItem() && UBGraphicsGroupContainerItem::Type == item->parentItem()->type())) itms.insert(item); } QSetIterator itRemoved(cmd->GetRemovedList()); while (itRemoved.hasNext()) { QGraphicsItem* item = itRemoved.next(); if( !itms.contains(item) && !(item->parentItem() && UBGraphicsGroupContainerItem::Type == item->parentItem()->type())) itms.insert(item); } } void UBBoardController::ClearUndoStack() { QSet uniqueItems; // go through all stack command for (int i = 0; i < UBApplication::undoStack->count(); i++) { findUniquesItems(UBApplication::undoStack->command(i), uniqueItems); } // Get items from clipboard in order not to delete an item that was cut // (using source URL of graphics items as a surrogate for equality testing) // This ensures that we can cut and paste a media item, widget, etc. from one page to the next. QClipboard *clipboard = QApplication::clipboard(); const QMimeData* data = clipboard->mimeData(); QList sourceURLs; if (data && data->hasFormat(UBApplication::mimeTypeUniboardPageItem)) { const UBMimeDataGraphicsItem* mimeDataGI = qobject_cast (data); if (mimeDataGI) { foreach (UBItem* sourceItem, mimeDataGI->items()) { sourceURLs << sourceItem->sourceUrl(); } } } // go through all unique items, and check, if they are on scene, or not. // if not on scene, than item can be deleted QSetIterator itUniq(uniqueItems); while (itUniq.hasNext()) { QGraphicsItem* item = itUniq.next(); UBGraphicsScene *scene = NULL; if (item->scene()) { scene = dynamic_cast(item->scene()); } bool inClipboard = false; UBItem* ubi = dynamic_cast(item); if (ubi && sourceURLs.contains(ubi->sourceUrl())) inClipboard = true; if(!scene && !inClipboard) { if (!mActiveScene->deleteItem(item)){ delete item; item = 0; } } } // clear stack, and command list UBApplication::undoStack->clear(); } void UBBoardController::adjustDisplayViews() { if (UBApplication::applicationController) { UBApplication::applicationController->adjustDisplayView(); UBApplication::applicationController->adjustPreviousViews(mActiveSceneIndex, selectedDocument()); } } int UBBoardController::autosaveTimeoutFromSettings() { int value = UBSettings::settings()->autoSaveInterval->get().toInt(); int minute = 60 * 1000; return value * minute; } void UBBoardController::changeBackground(bool isDark, UBPageBackground pageBackground) { bool currentIsDark = mActiveScene->isDarkBackground(); UBPageBackground currentBackgroundType = mActiveScene->pageBackground(); if ((isDark != currentIsDark) || (currentBackgroundType != pageBackground)) { UBSettings::settings()->setDarkBackground(isDark); UBSettings::settings()->setPageBackground(pageBackground); mActiveScene->setBackground(isDark, pageBackground); emit backgroundChanged(); } } void UBBoardController::boardViewResized(QResizeEvent* event) { Q_UNUSED(event); int innerMargin = UBSettings::boardMargin; int userHeight = mControlContainer->height() - (2 * innerMargin); mMessageWindow->move(innerMargin, innerMargin + userHeight - mMessageWindow->height()); mMessageWindow->adjustSizeAndPosition(); UBApplication::applicationController->initViewState( mControlView->horizontalScrollBar()->value(), mControlView->verticalScrollBar()->value()); updateSystemScaleFactor(); mControlView->centerOn(0,0); if (mDisplayView) { UBApplication::applicationController->adjustDisplayView(); mDisplayView->centerOn(0,0); } mPaletteManager->containerResized(); UBApplication::boardController->controlView()->scene()->moveMagnifier(); } void UBBoardController::documentWillBeDeleted(UBDocumentProxy* pProxy) { if (selectedDocument() == pProxy) { if (!mIsClosing) setActiveDocumentScene(UBPersistenceManager::persistenceManager()->createDocument()); } } void UBBoardController::showMessage(const QString& message, bool showSpinningWheel) { mMessageWindow->showMessage(message, showSpinningWheel); } void UBBoardController::hideMessage() { mMessageWindow->hideMessage(); } void UBBoardController::setDisabled(bool disable) { mMainWindow->boardToolBar->setDisabled(disable); mControlView->setDisabled(disable); } void UBBoardController::selectionChanged() { updateActionStates(); emit pageSelectionChanged(activeSceneIndex()); emit updateThumbnailsRequired(); } void UBBoardController::undoRedoStateChange(bool canUndo) { Q_UNUSED(canUndo); mMainWindow->actionUndo->setEnabled(UBApplication::undoStack->canUndo()); mMainWindow->actionRedo->setEnabled(UBApplication::undoStack->canRedo()); updateActionStates(); } void UBBoardController::updateActionStates() { mMainWindow->actionBack->setEnabled(selectedDocument() && (mActiveSceneIndex > 0)); mMainWindow->actionForward->setEnabled(selectedDocument() && (mActiveSceneIndex < selectedDocument()->pageCount() - 1)); mMainWindow->actionErase->setEnabled(mActiveScene && !mActiveScene->isEmpty()); } UBGraphicsScene* UBBoardController::activeScene() const { return mActiveScene; } int UBBoardController::activeSceneIndex() const { return mActiveSceneIndex; } void UBBoardController::documentSceneChanged(UBDocumentProxy* pDocumentProxy, int pIndex) { Q_UNUSED(pIndex); if(selectedDocument() == pDocumentProxy) { setActiveDocumentScene(mActiveSceneIndex); updatePage(pIndex); } } void UBBoardController::autosaveTimeout() { if (UBApplication::applicationController->displayMode() != UBApplicationController::Board) { //perform autosave only in board mode return; } saveData(sf_showProgress); UBSettings::settings()->save(); } void UBBoardController::appMainModeChanged(UBApplicationController::MainMode md) { int autoSaveInterval = autosaveTimeoutFromSettings(); if (!autoSaveInterval) { return; } if (!mAutosaveTimer) { mAutosaveTimer = new QTimer(this); connect(mAutosaveTimer, SIGNAL(timeout()), this, SLOT(autosaveTimeout())); } if (md == UBApplicationController::Board) { mAutosaveTimer->start(autoSaveInterval); } else if (mAutosaveTimer->isActive()) { mAutosaveTimer->stop(); } } void UBBoardController::closing() { mIsClosing = true; lastWindowClosed(); ClearUndoStack(); showKeyboard(false); } void UBBoardController::lastWindowClosed() { if (!mCleanupDone) { if (selectedDocument()->pageCount() == 1 && (!mActiveScene || mActiveScene->isEmpty())) { UBPersistenceManager::persistenceManager()->deleteDocument(selectedDocument()); } else { persistCurrentScene(); } UBPersistenceManager::persistenceManager()->purgeEmptyDocuments(); mCleanupDone = true; } } void UBBoardController::setColorIndex(int pColorIndex) { UBDrawingController::drawingController()->setColorIndex(pColorIndex); if (UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Marker && UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Line && UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Text && UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Selector) { UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Pen); } if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Pen || UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Line || UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Text || UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Selector) { mPenColorOnDarkBackground = UBSettings::settings()->penColors(true).at(pColorIndex); mPenColorOnLightBackground = UBSettings::settings()->penColors(false).at(pColorIndex); if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Selector) { // If we are in mode board, then do that if(UBApplication::applicationController->displayMode() == UBApplicationController::Board) { UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Pen); mMainWindow->actionPen->setChecked(true); } } emit penColorChanged(); } else if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Marker) { mMarkerColorOnDarkBackground = UBSettings::settings()->markerColors(true).at(pColorIndex); mMarkerColorOnLightBackground = UBSettings::settings()->markerColors(false).at(pColorIndex); } } void UBBoardController::colorPaletteChanged() { mPenColorOnDarkBackground = UBSettings::settings()->penColor(true); mPenColorOnLightBackground = UBSettings::settings()->penColor(false); mMarkerColorOnDarkBackground = UBSettings::settings()->markerColor(true); mMarkerColorOnLightBackground = UBSettings::settings()->markerColor(false); } qreal UBBoardController::currentZoom() { if (mControlView) return mControlView->viewportTransform().m11() / mSystemScaleFactor; else return 1.0; } void UBBoardController::removeTool(UBToolWidget* toolWidget) { toolWidget->hide(); delete toolWidget; } void UBBoardController::hide() { UBApplication::mainWindow->actionLibrary->setChecked(false); } void UBBoardController::show() { UBApplication::mainWindow->actionLibrary->setChecked(false); } void UBBoardController::persistCurrentScene(bool isAnAutomaticBackup, bool forceImmediateSave) { if(UBPersistenceManager::persistenceManager() && selectedDocument() && mActiveScene && mActiveSceneIndex != mDeletingSceneIndex && (mActiveSceneIndex >= 0) && mActiveSceneIndex != mMovingSceneIndex && (mActiveScene->isModified())) { UBPersistenceManager::persistenceManager()->persistDocumentScene(selectedDocument(), mActiveScene, mActiveSceneIndex); updatePage(mActiveSceneIndex); } } void UBBoardController::updateSystemScaleFactor() { qreal newScaleFactor = 1.0; if (mActiveScene) { QSize pageNominalSize = mActiveScene->nominalSize(); //we're going to keep scale factor untouched if the size is custom QMap sizesMap = UBSettings::settings()->documentSizes; // if(pageNominalSize == sizesMap.value(DocumentSizeRatio::Ratio16_9) || pageNominalSize == sizesMap.value(DocumentSizeRatio::Ratio4_3)) { QSize controlSize = controlViewport(); qreal hFactor = ((qreal)controlSize.width()) / ((qreal)pageNominalSize.width()); qreal vFactor = ((qreal)controlSize.height()) / ((qreal)pageNominalSize.height()); newScaleFactor = qMin(hFactor, vFactor); } } if (mSystemScaleFactor != newScaleFactor) mSystemScaleFactor = newScaleFactor; UBGraphicsScene::SceneViewState viewState = mActiveScene->viewState(); QTransform scalingTransform; qreal scaleFactor = viewState.zoomFactor * mSystemScaleFactor; scalingTransform.scale(scaleFactor, scaleFactor); mControlView->setTransform(scalingTransform); mControlView->horizontalScrollBar()->setValue(viewState.horizontalPosition); mControlView->verticalScrollBar()->setValue(viewState.verticalPostition); mActiveScene->setBackgroundZoomFactor(mControlView->transform().m11());} void UBBoardController::setWidePageSize(bool checked) { Q_UNUSED(checked); QSize newSize = UBSettings::settings()->documentSizes.value(DocumentSizeRatio::Ratio16_9); if (mActiveScene->nominalSize() != newSize) { UBPageSizeUndoCommand* uc = new UBPageSizeUndoCommand(mActiveScene, mActiveScene->nominalSize(), newSize); UBApplication::undoStack->push(uc); setPageSize(newSize); } } void UBBoardController::setRegularPageSize(bool checked) { Q_UNUSED(checked); QSize newSize = UBSettings::settings()->documentSizes.value(DocumentSizeRatio::Ratio4_3); if (mActiveScene->nominalSize() != newSize) { UBPageSizeUndoCommand* uc = new UBPageSizeUndoCommand(mActiveScene, mActiveScene->nominalSize(), newSize); UBApplication::undoStack->push(uc); setPageSize(newSize); } } void UBBoardController::setPageSize(QSize newSize) { if (mActiveScene->nominalSize() != newSize) { mActiveScene->setNominalSize(newSize); saveViewState(); updateSystemScaleFactor(); updatePageSizeState(); adjustDisplayViews(); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); UBSettings::settings()->pageSize->set(newSize); } } void UBBoardController::notifyCache(bool visible) { if(visible) emit cacheEnabled(); mCacheWidgetIsEnabled = visible; } void UBBoardController::updatePageSizeState() { if (mActiveScene->nominalSize() == UBSettings::settings()->documentSizes.value(DocumentSizeRatio::Ratio16_9)) { mMainWindow->actionWidePageSize->setChecked(true); } else if(mActiveScene->nominalSize() == UBSettings::settings()->documentSizes.value(DocumentSizeRatio::Ratio4_3)) { mMainWindow->actionRegularPageSize->setChecked(true); } else { mMainWindow->actionCustomPageSize->setChecked(true); } } void UBBoardController::saveViewState() { if (mActiveScene) { mActiveScene->setViewState(UBGraphicsScene::SceneViewState(currentZoom(), mControlView->horizontalScrollBar()->value(), mControlView->verticalScrollBar()->value(), mActiveScene->lastCenter())); } } void UBBoardController::stylusToolChanged(int tool) { if (UBPlatformUtils::hasVirtualKeyboard() && mPaletteManager->mKeyboardPalette) { UBStylusTool::Enum eTool = (UBStylusTool::Enum)tool; if(eTool != UBStylusTool::Selector && eTool != UBStylusTool::Text) { if(mPaletteManager->mKeyboardPalette->m_isVisible) UBApplication::mainWindow->actionVirtualKeyboard->activate(QAction::Trigger); } } } QUrl UBBoardController::expandWidgetToTempDir(const QByteArray& pZipedData, const QString& ext) { QUrl widgetUrl; QTemporaryFile tmp; if (tmp.open()) { tmp.write(pZipedData); tmp.flush(); tmp.close(); QString tmpDir = UBFileSystemUtils::createTempDir() + "." + ext; if (UBFileSystemUtils::expandZipToDir(tmp, tmpDir)) { widgetUrl = QUrl::fromLocalFile(tmpDir); } } return widgetUrl; } void UBBoardController::grabScene(const QRectF& pSceneRect) { if (mActiveScene) { QImage image(pSceneRect.width(), pSceneRect.height(), QImage::Format_ARGB32); image.fill(Qt::transparent); QRectF targetRect(0, 0, pSceneRect.width(), pSceneRect.height()); QPainter painter(&image); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setRenderHint(QPainter::Antialiasing); mActiveScene->setRenderingContext(UBGraphicsScene::NonScreen); mActiveScene->setRenderingQuality(UBItem::RenderingQualityHigh); mActiveScene->render(&painter, targetRect, pSceneRect); mActiveScene->setRenderingContext(UBGraphicsScene::Screen); // mActiveScene->setRenderingQuality(UBItem::RenderingQualityNormal); mActiveScene->setRenderingQuality(UBItem::RenderingQualityHigh); mPaletteManager->addItem(QPixmap::fromImage(image)); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); } } UBGraphicsMediaItem* UBBoardController::addVideo(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos, bool bUseSource) { QUuid uuid = QUuid::createUuid(); QUrl concreteUrl = pSourceUrl; // media file is not in document folder yet if (!bUseSource) { QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), pSourceUrl.toLocalFile(), UBPersistenceManager::videoDirectory, uuid, destFile); if (!b) { showMessage(tr("Add file operation failed: file copying error")); return NULL; } concreteUrl = QUrl::fromLocalFile(destFile); }// else we just use source Url. UBGraphicsMediaItem* vi = mActiveScene->addMedia(concreteUrl, startPlay, pos); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); if (vi) { vi->setUuid(uuid); vi->setSourceUrl(pSourceUrl); } return vi; } UBGraphicsMediaItem* UBBoardController::addAudio(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos, bool bUseSource) { QUuid uuid = QUuid::createUuid(); QUrl concreteUrl = pSourceUrl; // media file is not in document folder yet if (!bUseSource) { QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), pSourceUrl.toLocalFile(), UBPersistenceManager::audioDirectory, uuid, destFile); if (!b) { showMessage(tr("Add file operation failed: file copying error")); return NULL; } concreteUrl = QUrl::fromLocalFile(destFile); }// else we just use source Url. UBGraphicsMediaItem* ai = mActiveScene->addMedia(concreteUrl, startPlay, pos); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); if (ai){ ai->setUuid(uuid); ai->setSourceUrl(pSourceUrl); } return ai; } UBGraphicsWidgetItem *UBBoardController::addW3cWidget(const QUrl &pUrl, const QPointF &pos) { UBGraphicsWidgetItem* w3cWidgetItem = 0; QUuid uuid = QUuid::createUuid(); QString destPath; if (!UBPersistenceManager::persistenceManager()->addGraphicsWidgetToDocument(selectedDocument(), pUrl.toLocalFile(), uuid, destPath)) return NULL; QUrl newUrl = QUrl::fromLocalFile(destPath); w3cWidgetItem = mActiveScene->addW3CWidget(newUrl, pos); if (w3cWidgetItem) { w3cWidgetItem->setUuid(uuid); w3cWidgetItem->setOwnFolder(newUrl); w3cWidgetItem->setSourceUrl(pUrl); QString struuid = UBStringUtils::toCanonicalUuid(uuid); QString snapshotPath = selectedDocument()->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + struuid + ".png"; w3cWidgetItem->setSnapshotPath(QUrl::fromLocalFile(snapshotPath)); UBGraphicsWidgetItem *tmpItem = dynamic_cast(w3cWidgetItem); if (tmpItem && tmpItem->scene()) tmpItem->takeSnapshot().save(snapshotPath, "PNG"); } return w3cWidgetItem; } void UBBoardController::cut() { //---------------------------------------------------------// QList selectedItems; foreach(QGraphicsItem* gi, mActiveScene->selectedItems()) selectedItems << gi; //---------------------------------------------------------// QList selected; foreach(QGraphicsItem* gi, selectedItems) { gi->setSelected(false); UBItem* ubItem = dynamic_cast(gi); UBGraphicsItem *ubGi = dynamic_cast(gi); if (ubItem && ubGi && !mActiveScene->tools().contains(gi)) { selected << ubItem->deepCopy(); ubGi->remove(); } } //---------------------------------------------------------// if (selected.size() > 0) { QClipboard *clipboard = QApplication::clipboard(); UBMimeDataGraphicsItem* mimeGi = new UBMimeDataGraphicsItem(selected); mimeGi->setData(UBApplication::mimeTypeUniboardPageItem, QByteArray()); clipboard->setMimeData(mimeGi); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); } //---------------------------------------------------------// } void UBBoardController::copy() { QList selected; foreach(QGraphicsItem* gi, mActiveScene->selectedItems()) { UBItem* ubItem = dynamic_cast(gi); if (ubItem && !mActiveScene->tools().contains(gi)) selected << ubItem; } if (selected.size() > 0) { QClipboard *clipboard = QApplication::clipboard(); UBMimeDataGraphicsItem* mimeGi = new UBMimeDataGraphicsItem(selected); mimeGi->setData(UBApplication::mimeTypeUniboardPageItem, QByteArray()); clipboard->setMimeData(mimeGi); } } void UBBoardController::paste() { QClipboard *clipboard = QApplication::clipboard(); qreal xPosition = ((qreal)qrand()/(qreal)RAND_MAX) * 400; qreal yPosition = ((qreal)qrand()/(qreal)RAND_MAX) * 200; QPointF pos(xPosition -200 , yPosition - 100); processMimeData(clipboard->mimeData(), pos); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); } bool zLevelLessThan( UBItem* s1, UBItem* s2) { qreal s1Zvalue = dynamic_cast(s1)->data(UBGraphicsItemData::ItemOwnZValue).toReal(); qreal s2Zvalue = dynamic_cast(s2)->data(UBGraphicsItemData::ItemOwnZValue).toReal(); return s1Zvalue < s2Zvalue; } void UBBoardController::processMimeData(const QMimeData* pMimeData, const QPointF& pPos) { if (pMimeData->hasFormat(UBApplication::mimeTypeUniboardPage)) { const UBMimeData* mimeData = qobject_cast (pMimeData); if (mimeData) { int previousActiveSceneIndex = activeSceneIndex(); int previousPageCount = selectedDocument()->pageCount(); foreach (UBMimeDataItem sourceItem, mimeData->items()) addScene(sourceItem.documentProxy(), sourceItem.sceneIndex(), true); if (selectedDocument()->pageCount() < previousPageCount + mimeData->items().count()) setActiveDocumentScene(previousActiveSceneIndex); else setActiveDocumentScene(previousActiveSceneIndex + 1); return; } } if (pMimeData->hasFormat(UBApplication::mimeTypeUniboardPageItem)) { const UBMimeDataGraphicsItem* mimeData = qobject_cast (pMimeData); if (mimeData) { QList items = mimeData->items(); qStableSort(items.begin(),items.end(),zLevelLessThan); foreach(UBItem* item, items) { QGraphicsItem* pItem = dynamic_cast(item); if(NULL != pItem){ duplicateItem(item); } } return; } } if(pMimeData->hasHtml()) { QString qsHtml = pMimeData->html(); QString url = UBApplication::urlFromHtml(qsHtml); if("" != url) { downloadURL(url, QString(), pPos); return; } } if (pMimeData->hasUrls()) { QList urls = pMimeData->urls(); int index = 0; const UBFeaturesMimeData *internalMimeData = qobject_cast(pMimeData); bool internalData = false; if (internalMimeData) { internalData = true; } foreach(const QUrl url, urls){ QPointF pos(pPos + QPointF(index * 15, index * 15)); downloadURL(url, QString(), pos, QSize(), false, internalData); index++; } return; } if (pMimeData->hasImage()) { QImage img = qvariant_cast (pMimeData->imageData()); QPixmap pix = QPixmap::fromImage(img); // validate that the image is really an image, webkit does not fill properly the image mime data if (pix.width() != 0 && pix.height() != 0) { mActiveScene->addPixmap(pix, NULL, pPos, 1.); return; } } if (pMimeData->hasText()) { if("" != pMimeData->text()){ // Sometimes, it is possible to have an URL as text. we check here if it is the case QString qsTmp = pMimeData->text().remove(QRegExp("[\\0]")); if(qsTmp.startsWith("http")) downloadURL(QUrl(qsTmp), QString(), pPos); else{ if(mActiveScene->selectedItems().count() && mActiveScene->selectedItems().at(0)->type() == UBGraphicsItemType::TextItemType) dynamic_cast(mActiveScene->selectedItems().at(0))->setHtml(pMimeData->text()); else mActiveScene->addTextHtml("", pPos)->setHtml(pMimeData->text()); } } else{ #ifdef Q_OS_OSX // With Safari, in 95% of the drops, the mime datas are hidden in Apple Web Archive pasteboard type. // This is due to the way Safari is working so we have to dig into the pasteboard in order to retrieve // the data. QString qsUrl = UBPlatformUtils::urlFromClipboard(); if("" != qsUrl){ // We finally got the url of the dropped ressource! Let's import it! downloadURL(qsUrl, qsUrl, pPos); return; } #endif } } } void UBBoardController::togglePodcast(bool checked) { if (UBPodcastController::instance()) UBPodcastController::instance()->toggleRecordingPalette(checked); } void UBBoardController::moveGraphicsWidgetToControlView(UBGraphicsWidgetItem* graphicsWidget) { mActiveScene->setURStackEnable(false); UBGraphicsItem *toolW3C = duplicateItem(dynamic_cast(graphicsWidget)); UBGraphicsWidgetItem *copyedGraphicsWidget = NULL; if (UBGraphicsWidgetItem::Type == toolW3C->type()) copyedGraphicsWidget = static_cast(toolW3C); UBToolWidget *toolWidget = new UBToolWidget(copyedGraphicsWidget, mControlView); graphicsWidget->remove(false); mActiveScene->addItemToDeletion(graphicsWidget); mActiveScene->setURStackEnable(true); QPoint controlViewPos = mControlView->mapFromScene(graphicsWidget->sceneBoundingRect().center()); toolWidget->centerOn(mControlView->mapTo(mControlContainer, controlViewPos)); toolWidget->show(); } void UBBoardController::moveToolWidgetToScene(UBToolWidget* toolWidget) { UBGraphicsWidgetItem *widgetToScene = toolWidget->toolWidget(); widgetToScene->resetTransform(); QPoint mainWindowCenter = toolWidget->mapTo(mMainWindow, QPoint(toolWidget->width(), toolWidget->height()) / 2); QPoint controlViewCenter = mControlView->mapFrom(mMainWindow, mainWindowCenter); QPointF scenePos = mControlView->mapToScene(controlViewCenter); mActiveScene->addGraphicsWidget(widgetToScene, scenePos); toolWidget->remove(); } void UBBoardController::updateBackgroundActionsState(bool isDark, UBPageBackground pageBackground) { switch (pageBackground) { case UBPageBackground::crossed: if (isDark) mMainWindow->actionCrossedDarkBackground->setChecked(true); else mMainWindow->actionCrossedLightBackground->setChecked(true); break; case UBPageBackground::ruled : if (isDark) mMainWindow->actionRuledDarkBackground->setChecked(true); else mMainWindow->actionRuledLightBackground->setChecked(true); break; default: if (isDark) mMainWindow->actionPlainDarkBackground->setChecked(true); else mMainWindow->actionPlainLightBackground->setChecked(true); break; } } void UBBoardController::addItem() { QString defaultPath = UBSettings::settings()->lastImportToLibraryPath->get().toString(); QString extensions; foreach(QString ext, UBSettings::imageFileExtensions) { extensions += " *."; extensions += ext; } QString filename = QFileDialog::getOpenFileName(mControlContainer, tr("Add Item"), defaultPath, tr("All Supported (%1)").arg(extensions), NULL, QFileDialog::DontUseNativeDialog); if (filename.length() > 0) { mPaletteManager->addItem(QUrl::fromLocalFile(filename)); QFileInfo source(filename); UBSettings::settings()->lastImportToLibraryPath->set(QVariant(source.absolutePath())); } } void UBBoardController::importPage() { int pageCount = selectedDocument()->pageCount(); if (UBApplication::documentController->addFileToDocument(selectedDocument())) { setActiveDocumentScene(selectedDocument(), pageCount, true); } } void UBBoardController::notifyPageChanged() { emit activeSceneChanged(); } void UBBoardController::onDownloadModalFinished() { } void UBBoardController::displayMetaData(QMap metadatas) { emit displayMetadata(metadatas); } void UBBoardController::freezeW3CWidgets(bool freeze) { if (mActiveSceneIndex >= 0) { QList list = UBApplication::boardController->activeScene()->getFastAccessItems(); foreach(QGraphicsItem *item, list) { freezeW3CWidget(item, freeze); } } } void UBBoardController::freezeW3CWidget(QGraphicsItem *item, bool freeze) { if(item->type() == UBGraphicsW3CWidgetItem::Type) { UBGraphicsW3CWidgetItem* item_casted = dynamic_cast(item); if (0 == item_casted) return; if (freeze) { item_casted->load(QUrl(UBGraphicsW3CWidgetItem::freezedWidgetFilePath())); } else item_casted->loadMainHtml(); } }