/*
* Copyright (C) 2015-2018 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.path();
QString destination = selectedDocument()->persistencePath() + "/" + relativeFile.path();
UBFileSystemUtils::copy(source, destination, true);
}
}
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::setActiveSceneIndex(int i)
{
mActiveSceneIndex = i;
}
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();
}
}