UBPersistenceManager.cpp 41.9 KB
Newer Older
Claudio Valerio's avatar
Claudio Valerio committed
1
/*
2
 * Copyright (C) 2015-2018 Département de l'Instruction Publique (DIP-SEM)
Craig Watson's avatar
Craig Watson committed
3
 *
4
 * Copyright (C) 2013 Open Education Foundation
Claudio Valerio's avatar
Claudio Valerio committed
5
 *
6 7 8 9 10 11
 * 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
Claudio Valerio's avatar
Claudio Valerio committed
12 13
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License,
14 15 16 17
 * 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).
 *
18
 * OpenBoard is distributed in the hope that it will be useful,
Claudio Valerio's avatar
Claudio Valerio committed
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Claudio Valerio's avatar
Claudio Valerio committed
21
 * GNU General Public License for more details.
Claudio Valerio's avatar
Claudio Valerio committed
22
 *
Claudio Valerio's avatar
Claudio Valerio committed
23
 * You should have received a copy of the GNU General Public License
24
 * along with OpenBoard. If not, see <http://www.gnu.org/licenses/>.
Claudio Valerio's avatar
Claudio Valerio committed
25 26
 */

27

Claudio Valerio's avatar
Claudio Valerio committed
28

Claudio Valerio's avatar
Claudio Valerio committed
29
#include "UBPersistenceManager.h"
30
#include "gui/UBMainWindow.h"
Claudio Valerio's avatar
Claudio Valerio committed
31 32

#include <QtXml>
33 34 35 36
#include <QVariant>
#include <QDomDocument>
#include <QXmlStreamWriter>
#include <QModelIndex>
Claudio Valerio's avatar
Claudio Valerio committed
37 38 39 40 41 42 43

#include "frameworks/UBPlatformUtils.h"
#include "frameworks/UBFileSystemUtils.h"

#include "core/UBApplication.h"
#include "core/UBSettings.h"
#include "core/UBSetting.h"
44
#include "core/UBForeignObjectsHandler.h"
Claudio Valerio's avatar
Claudio Valerio committed
45 46 47 48 49 50 51 52

#include "document/UBDocumentProxy.h"

#include "adaptors/UBExportPDF.h"
#include "adaptors/UBSvgSubsetAdaptor.h"
#include "adaptors/UBThumbnailAdaptor.h"
#include "adaptors/UBMetadataDcSubsetAdaptor.h"

53 54 55 56 57
#include "domain/UBGraphicsMediaItem.h"
#include "domain/UBGraphicsWidgetItem.h"
#include "domain/UBGraphicsPixmapItem.h"
#include "domain/UBGraphicsSvgItem.h"

58
#include "board/UBBoardController.h"
Claudio Valerio's avatar
Claudio Valerio committed
59
#include "board/UBBoardPaletteManager.h"
60

61 62
#include "document/UBDocumentController.h"

63
#include "core/memcheck.h"
Claudio Valerio's avatar
Claudio Valerio committed
64 65 66 67 68 69

const QString UBPersistenceManager::imageDirectory = "images"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::objectDirectory = "objects"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::widgetDirectory = "widgets"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::videoDirectory = "videos"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::audioDirectory = "audios"; // added to
70 71 72 73 74 75 76 77
const QString UBPersistenceManager::fileDirectory = "files"; // Issue 1683 (Evolution) - AOU - 20131206

const QString UBPersistenceManager::myDocumentsName = "MyDocuments";
const QString UBPersistenceManager::modelsName = "Models";
const QString UBPersistenceManager::untitledDocumentsName = "UntitledDocuments";
const QString UBPersistenceManager::fFolders = "folders.xml";
const QString UBPersistenceManager::tFolder = "folder";
const QString UBPersistenceManager::aName = "name";
Claudio Valerio's avatar
Claudio Valerio committed
78 79 80 81 82 83 84 85

UBPersistenceManager * UBPersistenceManager::sSingleton = 0;

UBPersistenceManager::UBPersistenceManager(QObject *pParent)
    : QObject(pParent)
    , mHasPurgedDocuments(false)
{

86 87
    xmlFolderStructureFilename = "model";

Claudio Valerio's avatar
Claudio Valerio committed
88 89 90 91 92
    mDocumentSubDirectories << imageDirectory;
    mDocumentSubDirectories << objectDirectory;
    mDocumentSubDirectories << widgetDirectory;
    mDocumentSubDirectories << videoDirectory;
    mDocumentSubDirectories << audioDirectory;
93
    mDocumentSubDirectories << fileDirectory; // Issue 1683 (Evolution) - AOU - 20131206
Claudio Valerio's avatar
Claudio Valerio committed
94

95 96
    mDocumentRepositoryPath = UBSettings::userDocumentDirectory();
    mFoldersXmlStorageName =  mDocumentRepositoryPath + "/" + fFolders;
97

98 99
    mDocumentTreeStructureModel = new UBDocumentTreeModel(this);
    createDocumentProxiesStructure();
100

101

102
    emit proxyListChanged();
Claudio Valerio's avatar
Claudio Valerio committed
103 104 105 106 107 108 109 110 111 112 113 114
}

UBPersistenceManager* UBPersistenceManager::persistenceManager()
{
    if (!sSingleton)
    {
        sSingleton = new UBPersistenceManager(UBApplication::staticMemoryCleaner);
    }

    return sSingleton;
}

115 116 117 118 119 120 121
void UBPersistenceManager::destroy()
{
    if (sSingleton)
        delete sSingleton;
    sSingleton = NULL;
}

122
UBPersistenceManager::~UBPersistenceManager()
123 124 125
{
}

126
void UBPersistenceManager::createDocumentProxiesStructure(bool interactive)
127
{
128
    mDocumentRepositoryPath = UBSettings::userDocumentDirectory();
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    QDir rootDir(mDocumentRepositoryPath);
    rootDir.mkpath(rootDir.path());

    QFileInfoList contentList = rootDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time | QDir::Reversed);
    createDocumentProxiesStructure(contentList, interactive);

    if (QFileInfo(mFoldersXmlStorageName).exists()) {
        QDomDocument xmlDom;
        QFile inFile(mFoldersXmlStorageName);
        if (inFile.open(QIODevice::ReadOnly)) {
            QString domString(inFile.readAll());

            int errorLine = 0; int errorColumn = 0;
            QString errorStr;

            if (xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn)) {
                loadFolderTreeFromXml("", xmlDom.firstChildElement());
            } else {
                qDebug() << "Error reading content of " << mFoldersXmlStorageName << endl
                         << "Error:" << inFile.errorString()
                         << "Line:" << errorLine
                         << "Column:" << errorColumn;
            }
            inFile.close();
        } else {
            qDebug() << "Error reading" << mFoldersXmlStorageName << endl
                     << "Error:" << inFile.errorString();
        }
    }
159 160
}

161
void UBPersistenceManager::createDocumentProxiesStructure(const QFileInfoList &contentInfo, bool interactive)
Claudio Valerio's avatar
Claudio Valerio committed
162
{
163 164 165
    foreach(QFileInfo path, contentInfo)
    {
        QString fullPath = path.absoluteFilePath();
166

167
        QDir dir(fullPath);
168

169 170 171 172 173
        if (dir.entryList(QDir::Files | QDir::NoDotAndDotDot).size() > 0)
        {
            QMap<QString, QVariant> metadatas = UBMetadataDcSubsetAdaptor::load(fullPath);
            QString docGroupName = metadatas.value(UBSettings::documentGroupName, QString()).toString();
            QString docName = metadatas.value(UBSettings::documentName, QString()).toString();
174

175 176 177 178
            if (docName.isEmpty()) {
                qDebug() << "Group name and document name are empty in UBPersistenceManager::createDocumentProxiesStructure()";
                continue;
            }
179

180 181 182 183
            QModelIndex parentIndex = mDocumentTreeStructureModel->goTo(docGroupName);
            if (!parentIndex.isValid()) {
                return;
            }
184

185 186 187 188
            UBDocumentProxy* docProxy = new UBDocumentProxy(fullPath); // managed in UBDocumentTreeNode
            foreach(QString key, metadatas.keys()) {
                docProxy->setMetaData(key, metadatas.value(key));
            }
189

190 191 192 193 194 195 196 197 198 199 200 201
            docProxy->setPageCount(sceneCount(docProxy));
            bool addDoc = false;
            if (!interactive) {
                addDoc = true;
            } else if (processInteractiveReplacementDialog(docProxy) == QDialog::Accepted) {
                addDoc = true;
            }
            if (addDoc) {
                mDocumentTreeStructureModel->addDocument(docProxy, parentIndex);
            }
        }
    }
Claudio Valerio's avatar
Claudio Valerio committed
202 203
}

204
QDialog::DialogCode UBPersistenceManager::processInteractiveReplacementDialog(UBDocumentProxy *pProxy)
Claudio Valerio's avatar
Claudio Valerio committed
205
{
206 207 208 209 210 211 212 213
    //TODO claudio remove this hack necessary on double click on ubz file
    Qt::CursorShape saveShape;
    if(UBApplication::overrideCursor()){
        saveShape = UBApplication::overrideCursor()->shape();
        UBApplication::overrideCursor()->setShape(Qt::ArrowCursor);
    }
    else
        saveShape = Qt::ArrowCursor;
Claudio Valerio's avatar
Claudio Valerio committed
214

215
    QDialog::DialogCode result = QDialog::Rejected;
Claudio Valerio's avatar
Claudio Valerio committed
216

217 218 219 220 221 222 223 224
    if (UBApplication::documentController
            && UBApplication::documentController->mainWidget()) {
        QString docGroupName = pProxy->metaData(UBSettings::documentGroupName).toString();
        QModelIndex parentIndex = mDocumentTreeStructureModel->goTo(docGroupName);
        if (!parentIndex.isValid()) {
            UBApplication::overrideCursor()->setShape(saveShape);
            return QDialog::Rejected;
        }
225

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
        QStringList docList = mDocumentTreeStructureModel->nodeNameList(parentIndex);
        QString docName = pProxy->metaData(UBSettings::documentName).toString();

        if (docList.contains(docName)) {
            UBDocumentReplaceDialog *replaceDialog = new UBDocumentReplaceDialog(docName
                                                                                 , docList
                                                                                 , /*UBApplication::documentController->mainWidget()*/0
                                                                                 , Qt::Widget);
            if (replaceDialog->exec() == QDialog::Accepted) {
                result = QDialog::Accepted;
                QString resultName = replaceDialog->lineEditText();
                int i = docList.indexOf(resultName);
                if (i != -1) { //replace
                    QModelIndex replaceIndex = mDocumentTreeStructureModel->index(i, 0, parentIndex);
                    UBDocumentProxy *replaceProxy = mDocumentTreeStructureModel->proxyData(replaceIndex);
                    if (replaceProxy) {
                        deleteDocument(replaceProxy);
                    }
                    if (replaceIndex.isValid()) {
                        mDocumentTreeStructureModel->removeRow(i, parentIndex);
                    }
                }
                pProxy->setMetaData(UBSettings::documentName, resultName);
            }
            replaceDialog->setParent(0);
            delete replaceDialog;
        } else {
            result = QDialog::Accepted;
        }
255
    }
256 257 258
    //TODO claudio the if is an hack
    if(UBApplication::overrideCursor())
        UBApplication::overrideCursor()->setShape(saveShape);
259

260 261
    return result;
}
Claudio Valerio's avatar
Claudio Valerio committed
262

263 264 265
QString UBPersistenceManager::adjustDocumentVirtualPath(const QString &str)
{
    QStringList pathList = str.split("/", QString::SkipEmptyParts);
Claudio Valerio's avatar
Claudio Valerio committed
266

267 268 269 270
    if (pathList.isEmpty()) {
        pathList.append(myDocumentsName);
        pathList.append(untitledDocumentsName);
    }
Claudio Valerio's avatar
Claudio Valerio committed
271

272 273 274 275 276
    if (pathList.first() != myDocumentsName
            && pathList.first() != UBSettings::trashedDocumentGroupNamePrefix
            && pathList.first() != modelsName) {
        pathList.prepend(myDocumentsName);
    }
Claudio Valerio's avatar
Claudio Valerio committed
277

278 279
    return pathList.join("/");
}
Claudio Valerio's avatar
Claudio Valerio committed
280

281 282 283 284
void UBPersistenceManager::closing()
{
    QDir rootDir(mDocumentRepositoryPath);
    rootDir.mkpath(rootDir.path());
Claudio Valerio's avatar
Claudio Valerio committed
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299
    QFile outFile(mFoldersXmlStorageName);
    if (outFile.open(QIODevice::WriteOnly)) {
        QXmlStreamWriter writer(&outFile);
        writer.setAutoFormatting(true);
        writer.writeStartDocument();
        writer.writeStartElement("content");
        saveFoldersTreeToXml(writer, QModelIndex());
        writer.writeEndElement();
        writer.writeEndDocument();

        outFile.close();
    } else {
        qDebug() << "failed to open document" <<  mFoldersXmlStorageName << "for writing" << endl
                 << "Error string:" << outFile.errorString();
Claudio Valerio's avatar
Claudio Valerio committed
300 301 302
    }
}

303 304 305 306
bool UBPersistenceManager::isSceneInCached(UBDocumentProxy *proxy, int index) const
{
    return mSceneCache.contains(proxy, index);
}
Claudio Valerio's avatar
Claudio Valerio committed
307 308 309

QStringList UBPersistenceManager::allShapes()
{
310
    QString shapeLibraryPath = UBSettings::settings()->applicationShapeLibraryDirectory();
Claudio Valerio's avatar
Claudio Valerio committed
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

    QDir dir(shapeLibraryPath);

    if (!dir.exists())
        dir.mkpath(shapeLibraryPath);

    QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
    QStringList paths;

    foreach(QString file, files)
    {
        paths.append(shapeLibraryPath + QString("/") + file);
    }

    return paths;
}

QStringList UBPersistenceManager::allGips()
{
330
    QString gipLibraryPath = UBSettings::settings()->userGipLibraryDirectory();
Claudio Valerio's avatar
Claudio Valerio committed
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401

    QDir dir(gipLibraryPath);

    QStringList files = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
    QStringList paths;

    foreach(QString file, files)
    {
        QFileInfo fi(file);

        if (UBSettings::settings()->widgetFileExtensions.contains(fi.suffix()))
            paths.append(dir.path() + QString("/") + file);
    }

    return paths;
}

QStringList UBPersistenceManager::allImages(const QDir& dir)
{
    if (!dir.exists())
        dir.mkpath(dir.path());

    QStringList files = dir.entryList(QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDir::Name);
    QStringList paths;

    foreach(QString file, files)
    {
        paths.append(dir.path() + QString("/") + file);
    }

    return paths;
}


QStringList UBPersistenceManager::allVideos(const QDir& dir)
{
    if (!dir.exists())
        dir.mkpath(dir.path());

    QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
    QStringList paths;

    foreach(QString file, files)
    {
        paths.append(dir.path() + QString("/") + file);
    }

    return paths;
}


QStringList UBPersistenceManager::allWidgets(const QDir& dir)
{
    if (!dir.exists())
        dir.mkpath(dir.path());

    QStringList files = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
    QStringList paths;

    foreach(QString file, files)
    {
        QFileInfo fi(file);

        if (UBSettings::settings()->widgetFileExtensions.contains(fi.suffix()))
            paths.append(dir.path() + QString("/") + file);
    }

    return paths;
}


402 403 404 405 406 407
UBDocumentProxy* UBPersistenceManager::createDocument(const QString& pGroupName
                                                      , const QString& pName
                                                      , bool withEmptyPage
                                                      , QString directory
                                                      , int pageCount
                                                      , bool promptDialogIfExists)
Claudio Valerio's avatar
Claudio Valerio committed
408
{
409 410 411 412 413 414 415 416 417
    UBDocumentProxy *doc;
    if(directory.length() != 0 ){
        doc = new UBDocumentProxy(directory); // deleted in UBPersistenceManager::destructor
        doc->setPageCount(pageCount);
    }
    else{
        checkIfDocumentRepositoryExists();
        doc = new UBDocumentProxy();
    }
Claudio Valerio's avatar
Claudio Valerio committed
418 419 420 421 422 423 424 425 426 427 428 429

    if (pGroupName.length() > 0)
    {
        doc->setMetaData(UBSettings::documentGroupName, pGroupName);
    }

    if (pName.length() > 0)
    {
        doc->setMetaData(UBSettings::documentName, pName);
    }

    doc->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion);
430
    QString currentDate =  UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime());
431 432
    doc->setMetaData(UBSettings::documentUpdatedAt,currentDate);
    doc->setMetaData(UBSettings::documentDate,currentDate);
Claudio Valerio's avatar
Claudio Valerio committed
433

434
    if (withEmptyPage) {
435
        createDocumentSceneAt(doc, 0);
436 437 438 439 440 441 442 443 444
    }
    else{
        this->generatePathIfNeeded(doc);
        QDir dir(doc->persistencePath());
        if (!dir.mkpath(doc->persistencePath()))
        {
            return 0; // if we can't create the path, abort function.
        }
    }
Claudio Valerio's avatar
Claudio Valerio committed
445

446 447 448 449 450 451 452 453 454 455 456 457 458
    bool addDoc = false;
    if (!promptDialogIfExists) {
        addDoc = true;
    } else if (processInteractiveReplacementDialog(doc) == QDialog::Accepted) {
        addDoc = true;
    }
    if (addDoc) {
        mDocumentTreeStructureModel->addDocument(doc);
        emit proxyListChanged();
    } else {
        deleteDocument(doc);
        doc = 0;
    }
Claudio Valerio's avatar
Claudio Valerio committed
459

460 461
    return doc;
}
Claudio Valerio's avatar
Claudio Valerio committed
462

463 464 465 466 467 468 469 470 471 472 473
UBDocumentProxy* UBPersistenceManager::createNewDocument(const QString& pGroupName
                                                      , const QString& pName
                                                      , bool withEmptyPage
                                                      , QString directory
                                                      , int pageCount
                                                      , bool promptDialogIfExists)
{
    UBDocumentProxy *resultDoc = createDocument(pGroupName, pName, withEmptyPage, directory, pageCount, promptDialogIfExists);
    if (resultDoc) {
        mDocumentTreeStructureModel->markDocumentAsNew(resultDoc);
    }
Claudio Valerio's avatar
Claudio Valerio committed
474

475
    return resultDoc;
Claudio Valerio's avatar
Claudio Valerio committed
476 477
}

478 479 480 481 482 483
UBDocumentProxy* UBPersistenceManager::createDocumentFromDir(const QString& pDocumentDirectory
                                                             , const QString& pGroupName
                                                             , const QString& pName
                                                             , bool withEmptyPage
                                                             , bool addTitlePage
                                                             , bool promptDialogIfExists)
Claudio Valerio's avatar
Claudio Valerio committed
484 485 486 487 488
{
    checkIfDocumentRepositoryExists();

    UBDocumentProxy* doc = new UBDocumentProxy(pDocumentDirectory); // deleted in UBPersistenceManager::destructor

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
489 490 491 492 493 494 495 496 497 498
    if (pGroupName.length() > 0)
    {
        doc->setMetaData(UBSettings::documentGroupName, pGroupName);
    }

    if (pName.length() > 0)
    {
        doc->setMetaData(UBSettings::documentName, pName);
    }

499 500 501 502 503 504 505 506 507 508
    QMap<QString, QVariant> metadatas = UBMetadataDcSubsetAdaptor::load(pDocumentDirectory);

    if(withEmptyPage) createDocumentSceneAt(doc, 0);
    if(addTitlePage) persistDocumentScene(doc, mSceneCache.createScene(doc, 0, false), 0);

    foreach(QString key, metadatas.keys())
    {
        doc->setMetaData(key, metadatas.value(key));
    }

Claudio Valerio's avatar
Claudio Valerio committed
509 510 511 512 513 514 515 516
    doc->setUuid(QUuid::createUuid());
    doc->setPageCount(sceneCount(doc));

    for(int i = 0; i < doc->pageCount(); i++)
    {
        UBSvgSubsetAdaptor::setSceneUuid(doc, i, QUuid::createUuid());
    }

517 518 519 520 521 522 523 524
    //work around the
    bool addDoc = false;
    if (!promptDialogIfExists) {
        addDoc = true;
    } else if (processInteractiveReplacementDialog(doc) == QDialog::Accepted) {
        addDoc = true;
    }
    if (addDoc) {
525
        UBMetadataDcSubsetAdaptor::persist(doc);
526 527 528 529 530 531 532
        mDocumentTreeStructureModel->addDocument(doc);
        emit proxyListChanged();
        emit documentCreated(doc);
    } else {
        deleteDocument(doc);
        doc = 0;
    }
Claudio Valerio's avatar
Claudio Valerio committed
533 534 535 536 537 538 539 540 541 542 543

    return doc;
}


void UBPersistenceManager::deleteDocument(UBDocumentProxy* pDocumentProxy)
{
    checkIfDocumentRepositoryExists();

    emit documentWillBeDeleted(pDocumentProxy);

544 545
    if (QFileInfo(pDocumentProxy->persistencePath()).exists())
        UBFileSystemUtils::deleteDir(pDocumentProxy->persistencePath());
Claudio Valerio's avatar
Claudio Valerio committed
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570

    mSceneCache.removeAllScenes(pDocumentProxy);

    pDocumentProxy->deleteLater();
}

UBDocumentProxy* UBPersistenceManager::duplicateDocument(UBDocumentProxy* pDocumentProxy)
{
    checkIfDocumentRepositoryExists();

    UBDocumentProxy *copy = new UBDocumentProxy(); // deleted in UBPersistenceManager::destructor

    generatePathIfNeeded(copy);

    UBFileSystemUtils::copyDir(pDocumentProxy->persistencePath(), copy->persistencePath());

    // regenerate scenes UUIDs
    for(int i = 0; i < pDocumentProxy->pageCount(); i++)
    {
        UBSvgSubsetAdaptor::setSceneUuid(pDocumentProxy, i, QUuid::createUuid());
    }

    foreach(QString key, pDocumentProxy->metaDatas().keys())
    {
        copy->setMetaData(key, pDocumentProxy->metaDatas().value(key));
571
    }    
Claudio Valerio's avatar
Claudio Valerio committed
572 573 574 575 576 577 578 579 580 581

    copy->setMetaData(UBSettings::documentName,
            pDocumentProxy->metaData(UBSettings::documentName).toString() + " " + tr("(copy)"));

    copy->setUuid(QUuid::createUuid());

    persistDocumentMetadata(copy);

    copy->setPageCount(sceneCount(copy));

582
    emit proxyListChanged();
Claudio Valerio's avatar
Claudio Valerio committed
583 584 585 586 587 588 589 590 591 592

    emit documentCreated(copy);

    return copy;

}


void UBPersistenceManager::deleteDocumentScenes(UBDocumentProxy* proxy, const QList<int>& indexes)
{
593
    checkIfDocumentRepositoryExists();
Claudio Valerio's avatar
Claudio Valerio committed
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619

    int pageCount = UBPersistenceManager::persistenceManager()->sceneCount(proxy);

    QList<int> compactedIndexes;

    foreach(int index, indexes)
    {
        if (!compactedIndexes.contains(index))
            compactedIndexes.append(index);
    }

    if (compactedIndexes.size() == pageCount)
    {
        deleteDocument(proxy);
        return;
    }

    if (compactedIndexes.size() == 0)
        return;

    foreach(int index, compactedIndexes)
    {
        emit documentSceneWillBeDeleted(proxy, index);
    }

    QString sourceName = proxy->metaData(UBSettings::documentName).toString();
620
    UBDocumentProxy *trashDocProxy = createDocument(UBSettings::trashedDocumentGroupNamePrefix/* + sourceGroupName*/, sourceName, false);
Claudio Valerio's avatar
Claudio Valerio committed
621 622 623

    foreach(int index, compactedIndexes)
    {
624
        UBGraphicsScene *scene = loadDocumentScene(proxy, index);
Claudio Valerio's avatar
Claudio Valerio committed
625 626
        if (scene)
        {
627
            //scene is about to move into new document
Claudio Valerio's avatar
Claudio Valerio committed
628 629 630 631 632 633 634 635 636
            foreach (QUrl relativeFile, scene->relativeDependencies())
            {
                QString source = scene->document()->persistencePath() + "/" + relativeFile.toString();
                QString target = trashDocProxy->persistencePath() + "/" + relativeFile.toString();

                QFileInfo fi(target);
                QDir d = fi.dir();

                d.mkpath(d.absolutePath());
637
                QFile::copy(source, target);
Claudio Valerio's avatar
Claudio Valerio committed
638 639
            }

640
            insertDocumentSceneAt(trashDocProxy, scene, trashDocProxy->pageCount());
Claudio Valerio's avatar
Claudio Valerio committed
641 642 643 644 645 646 647 648 649 650
        }
    }

    for (int i = 1; i < pageCount; i++)
    {
        renamePage(trashDocProxy, i , i - 1);
    }

    foreach(int index, compactedIndexes)
    {
651
        QString svgFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", index);
Claudio Valerio's avatar
Claudio Valerio committed
652 653 654

        QFile::remove(svgFileName);

655
        QString thumbFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", index);
Claudio Valerio's avatar
Claudio Valerio committed
656 657 658

        QFile::remove(thumbFileName);

659
        mSceneCache.removeScene(proxy, index);
Claudio Valerio's avatar
Claudio Valerio committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701

        proxy->decPageCount();

    }

    qSort(compactedIndexes);

    int offset = 1;

    for (int i = compactedIndexes.at(0) + 1; i < pageCount; i++)
    {
        if(compactedIndexes.contains(i))
        {
            offset++;
        }
        else
        {
            renamePage(proxy, i , i - offset);

            mSceneCache.moveScene(proxy, i, i - offset);

        }
    }
}


void UBPersistenceManager::duplicateDocumentScene(UBDocumentProxy* proxy, int index)
{
    checkIfDocumentRepositoryExists();

    int pageCount = UBPersistenceManager::persistenceManager()->sceneCount(proxy);

    for (int i = pageCount; i > index + 1; i--)
    {
        renamePage(proxy, i - 1 , i);

        mSceneCache.moveScene(proxy, i - 1, i);

    }

    copyPage(proxy, index , index + 1);

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
    //TODO: write a proper way to handle object on disk
    UBGraphicsScene *scene = loadDocumentScene(proxy, index + 1);

    foreach(QGraphicsItem* item, scene->items())
    {
        UBGraphicsMediaItem *mediaItem = qgraphicsitem_cast<UBGraphicsMediaItem*> (item);

        if (mediaItem){
            QString source = mediaItem->mediaFileUrl().toLocalFile();
            QString destination = source;
            QUuid newUuid = QUuid::createUuid();
            QString fileName = QFileInfo(source).completeBaseName();
            destination = destination.replace(fileName,newUuid.toString());
            QFile::copy(source,destination);
            mediaItem->setMediaFileUrl(QUrl::fromLocalFile(destination));
            continue;
        }

        UBGraphicsWidgetItem* widget = qgraphicsitem_cast<UBGraphicsWidgetItem*>(item);
        if(widget){
            QUuid newUUid = QUuid::createUuid();
            QString newUUidString = newUUid.toString().remove("{").remove("}");
            QString actualUuidString = widget->uuid().toString().remove("{").remove("}");

            QString widgetSourcePath = proxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/{" + actualUuidString + "}.wgt";
            QString screenshotSourcePath = proxy->persistencePath() + "/" +  UBPersistenceManager::widgetDirectory + "/" + actualUuidString + ".png";

            QString widgetDestinationPath = widgetSourcePath;
            widgetDestinationPath = widgetDestinationPath.replace(actualUuidString,newUUidString);
            QString screenshotDestinationPath = screenshotSourcePath;
            screenshotDestinationPath = screenshotDestinationPath.replace(actualUuidString,newUUidString);

            UBFileSystemUtils::copyDir(widgetSourcePath,widgetDestinationPath);
            QFile::copy(screenshotSourcePath,screenshotDestinationPath);

            widget->setUuid(newUUid);

            widget->widgetUrl(QUrl::fromLocalFile(widgetDestinationPath));

            continue;
        }

        UBGraphicsPixmapItem* pixmapItem = qgraphicsitem_cast<UBGraphicsPixmapItem*>(item);
        if(pixmapItem){
            QString source = proxy->persistencePath() + "/" +  UBPersistenceManager::imageDirectory + "/" + pixmapItem->uuid().toString() + ".png";
            QString destination = source;
            QUuid newUuid = QUuid::createUuid();
            QString fileName = QFileInfo(source).completeBaseName();
            destination = destination.replace(fileName,newUuid.toString());
            QFile::copy(source,destination);
            pixmapItem->setUuid(newUuid);
            continue;
        }

        UBGraphicsSvgItem* svgItem = qgraphicsitem_cast<UBGraphicsSvgItem*>(item);
        if(svgItem){
            QString source = proxy->persistencePath() + "/" +  UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg";
            QString destination = source;
            QUuid newUuid = QUuid::createUuid();
            QString fileName = QFileInfo(source).completeBaseName();
            destination = destination.replace(fileName,newUuid.toString());
            QFile::copy(source,destination);
            svgItem->setUuid(newUuid);
            continue;
        }

    }
    scene->setModified(true);

    persistDocumentScene(proxy,scene, index + 1);

773
    proxy->incPageCount();
774

775 776
    emit documentSceneCreated(proxy, index + 1);
}
777

778 779 780 781 782 783
void UBPersistenceManager::copyDocumentScene(UBDocumentProxy *from, int fromIndex, UBDocumentProxy *to, int toIndex)
{
    if (from == to && toIndex <= fromIndex) {
        qDebug() << "operation is not supported" << Q_FUNC_INFO;
        return;
    }
784

785
    checkIfDocumentRepositoryExists();
786

787 788 789 790
    for (int i = to->pageCount(); i > toIndex; i--) {
        renamePage(to, i - 1, i);
        mSceneCache.moveScene(to, i - 1, i);
    }
791

792 793 794
    UBForeighnObjectsHandler hl;
    hl.copyPage(QUrl::fromLocalFile(from->persistencePath()), fromIndex,
                QUrl::fromLocalFile(to->persistencePath()), toIndex);
795

796
    to->incPageCount();
797

798 799
    QString thumbTmp(from->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", fromIndex));
    QString thumbTo(to->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", toIndex));
800

801 802
    QFile::remove(thumbTo);
    QFile::copy(thumbTmp, thumbTo);
803

804 805 806 807 808 809
    Q_ASSERT(QFileInfo(thumbTmp).exists());
    Q_ASSERT(QFileInfo(thumbTo).exists());
    const QPixmap *pix = new QPixmap(thumbTmp);
    UBDocumentController *ctrl = UBApplication::documentController;
    ctrl->addPixmapAt(pix, toIndex);
    ctrl->TreeViewSelectionChanged(ctrl->firstSelectedTreeIndex(), QModelIndex());
Claudio Valerio's avatar
Claudio Valerio committed
810

811
//    emit documentSceneCreated(to, toIndex + 1);
Claudio Valerio's avatar
Claudio Valerio committed
812 813 814
}


Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
815
UBGraphicsScene* UBPersistenceManager::createDocumentSceneAt(UBDocumentProxy* proxy, int index, bool useUndoRedoStack)
Claudio Valerio's avatar
Claudio Valerio committed
816 817 818 819 820 821 822 823
{
    int count = sceneCount(proxy);

    for(int i = count - 1; i >= index; i--)
        renamePage(proxy, i , i + 1);

    mSceneCache.shiftUpScenes(proxy, index, count -1);

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
824
    UBGraphicsScene *newScene = mSceneCache.createScene(proxy, index, useUndoRedoStack);
Claudio Valerio's avatar
Claudio Valerio committed
825

826 827 828 829 830
    newScene->setBackground(UBSettings::settings()->isDarkBackground(),
            UBSettings::settings()->UBSettings::pageBackground());

    newScene->setBackgroundGridSize(UBSettings::settings()->crossSize);

Claudio Valerio's avatar
Claudio Valerio committed
831 832 833 834 835 836 837 838 839 840
    persistDocumentScene(proxy, newScene, index);

    proxy->incPageCount();

    emit documentSceneCreated(proxy, index);

    return newScene;
}


841
void UBPersistenceManager::insertDocumentSceneAt(UBDocumentProxy* proxy, UBGraphicsScene* scene, int index, bool persist)
Claudio Valerio's avatar
Claudio Valerio committed
842 843 844 845 846 847 848 849 850 851 852 853 854 855
{
    scene->setDocument(proxy);

    int count = sceneCount(proxy);

    for(int i = count - 1; i >= index; i--)
    {
        renamePage(proxy, i , i + 1);
    }

    mSceneCache.shiftUpScenes(proxy, index, count -1);

    mSceneCache.insert(proxy, index, scene);

856 857 858
    if (persist) {
        persistDocumentScene(proxy, scene, index);
    }
Claudio Valerio's avatar
Claudio Valerio committed
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873

    proxy->incPageCount();

    emit documentSceneCreated(proxy, index);

}


void UBPersistenceManager::moveSceneToIndex(UBDocumentProxy* proxy, int source, int target)
{
    checkIfDocumentRepositoryExists();

    if (source == target)
        return;

874 875
    QFile svgTmp(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", source));
    svgTmp.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.tmp", target));
Claudio Valerio's avatar
Claudio Valerio committed
876

877 878
    QFile thumbTmp(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", source));
    thumbTmp.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.tmp", target));
Claudio Valerio's avatar
Claudio Valerio committed
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

    if (source < target)
    {
        for (int i = source + 1; i <= target; i++)
        {
            renamePage(proxy, i , i - 1);
        }
    }
    else
    {
        for (int i = source - 1; i >= target; i--)
        {
            renamePage(proxy, i , i + 1);
        }
    }

895 896
    QFile svg(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.tmp", target));
    svg.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", target));
Claudio Valerio's avatar
Claudio Valerio committed
897

898 899
    QFile thumb(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.tmp", target));
    thumb.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", target));
Claudio Valerio's avatar
Claudio Valerio committed
900 901 902 903 904

    mSceneCache.moveScene(proxy, source, target);
}


905
UBGraphicsScene* UBPersistenceManager::loadDocumentScene(UBDocumentProxy* proxy, int sceneIndex)
Claudio Valerio's avatar
Claudio Valerio committed
906 907
{
    if (mSceneCache.contains(proxy, sceneIndex))
908
        return mSceneCache.value(proxy, sceneIndex);
909
    else {
910 911 912 913 914
        UBGraphicsScene* scene = UBSvgSubsetAdaptor::loadScene(proxy, sceneIndex);
        if(!scene){
            createDocumentSceneAt(proxy,0);
            scene = UBSvgSubsetAdaptor::loadScene(proxy, 0);
        }
Claudio Valerio's avatar
Claudio Valerio committed
915 916 917

        if (scene)
            mSceneCache.insert(proxy, sceneIndex, scene);
918

919
        return scene;
920
    }
921
}
922

923 924 925
void UBPersistenceManager::reassignDocProxy(UBDocumentProxy *newDocument, UBDocumentProxy *oldDocument)
{
    return mSceneCache.reassignDocProxy(newDocument, oldDocument);
Claudio Valerio's avatar
Claudio Valerio committed
926 927
}

928
void UBPersistenceManager::persistDocumentScene(UBDocumentProxy* pDocumentProxy, UBGraphicsScene* pScene, const int pSceneIndex)
Claudio Valerio's avatar
Claudio Valerio committed
929 930 931
{
    checkIfDocumentRepositoryExists();

932
    pScene->deselectAllItems();
Claudio Valerio's avatar
Claudio Valerio committed
933 934 935 936 937 938

    generatePathIfNeeded(pDocumentProxy);

    QDir dir(pDocumentProxy->persistencePath());
    dir.mkpath(pDocumentProxy->persistencePath());

939 940
    if (pDocumentProxy->isModified())
        UBMetadataDcSubsetAdaptor::persist(pDocumentProxy);
941

Claudio Valerio's avatar
Claudio Valerio committed
942
    if (pScene->isModified())
Claudio Valerio's avatar
Claudio Valerio committed
943
    {
944
        UBSvgSubsetAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex);
945

946
        UBThumbnailAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex);
947

948
        pScene->setModified(false);
Claudio Valerio's avatar
Claudio Valerio committed
949
    }
950 951

    mSceneCache.insert(pDocumentProxy, pSceneIndex, pScene);
Claudio Valerio's avatar
Claudio Valerio committed
952 953 954
}


955
UBDocumentProxy* UBPersistenceManager::persistDocumentMetadata(UBDocumentProxy* pDocumentProxy)
Claudio Valerio's avatar
Claudio Valerio committed
956
{
957
    UBMetadataDcSubsetAdaptor::persist(pDocumentProxy);
Claudio Valerio's avatar
Claudio Valerio committed
958

959 960 961
    emit documentMetadataChanged(pDocumentProxy);

    return pDocumentProxy;
Claudio Valerio's avatar
Claudio Valerio committed
962 963 964 965 966
}


void UBPersistenceManager::renamePage(UBDocumentProxy* pDocumentProxy, const int sourceIndex, const int targetIndex)
{
967 968
    QFile svg(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", sourceIndex));
    svg.rename(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg",  targetIndex));
Claudio Valerio's avatar
Claudio Valerio committed
969

970 971
    QFile thumb(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex));
    thumb.rename(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex));
Claudio Valerio's avatar
Claudio Valerio committed
972 973 974 975 976
}


void UBPersistenceManager::copyPage(UBDocumentProxy* pDocumentProxy, const int sourceIndex, const int targetIndex)
{
977 978
    QFile svg(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg",sourceIndex));
    svg.copy(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex));
Claudio Valerio's avatar
Claudio Valerio committed
979 980 981

    UBSvgSubsetAdaptor::setSceneUuid(pDocumentProxy, targetIndex, QUuid::createUuid());

982 983
    QFile thumb(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex));
    thumb.copy(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex));
Claudio Valerio's avatar
Claudio Valerio committed
984 985 986 987 988
}


int UBPersistenceManager::sceneCount(const UBDocumentProxy* proxy)
{
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
989
    const QString pPath = proxy->persistencePath();
990

Claudio Valerio's avatar
Claudio Valerio committed
991 992
    int pageIndex = 0;
    bool moreToProcess = true;
993
    bool addedMissingZeroPage = false;
Claudio Valerio's avatar
Claudio Valerio committed
994 995 996

    while (moreToProcess)
    {
997
        QString fileName = pPath + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex);
Claudio Valerio's avatar
Claudio Valerio committed
998 999 1000 1001

        QFile file(fileName);

        if (file.exists())
1002
        {
Claudio Valerio's avatar
Claudio Valerio committed
1003
            pageIndex++;
1004
        }
Claudio Valerio's avatar
Claudio Valerio committed
1005
        else
1006
        {
Claudio Valerio's avatar
Claudio Valerio committed
1007
            moreToProcess = false;
1008 1009 1010 1011 1012 1013 1014
        }
    }

    if(pageIndex == 1 && addedMissingZeroPage){
        // increment is done only to check if there are other pages than the missing zero page
        // This situation means -> no pages on the document
        return 0;
Claudio Valerio's avatar
Claudio Valerio committed
1015 1016 1017 1018 1019
    }

    return pageIndex;
}

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1020
QStringList UBPersistenceManager::getSceneFileNames(const QString& folder)
Claudio Valerio's avatar
Claudio Valerio committed
1021
{
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1022 1023 1024
    QDir dir(folder, "page???.svg", QDir::Name, QDir::Files);
    return dir.entryList();
}
Claudio Valerio's avatar
Claudio Valerio committed
1025

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1026 1027
QString UBPersistenceManager::generateUniqueDocumentPath(const QString& baseFolder)
{
Claudio Valerio's avatar
Claudio Valerio committed
1028 1029 1030
    QDateTime now = QDateTime::currentDateTime();
    QString dirName = now.toString("yyyy-MM-dd hh-mm-ss.zzz");

1031
    return baseFolder + QString("/OpenBoard Document %1").arg(dirName);
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1032 1033 1034 1035 1036
}

QString UBPersistenceManager::generateUniqueDocumentPath()
{
    return generateUniqueDocumentPath(UBSettings::userDocumentDirectory());
Claudio Valerio's avatar
Claudio Valerio committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
}


void UBPersistenceManager::generatePathIfNeeded(UBDocumentProxy* pDocumentProxy)
{
    if (pDocumentProxy->persistencePath().length() == 0)
    {
        pDocumentProxy->setPersistencePath(generateUniqueDocumentPath());
    }
}


Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1049
bool UBPersistenceManager::addDirectoryContentToDocument(const QString& documentRootFolder, UBDocumentProxy* pDocument)
Claudio Valerio's avatar
Claudio Valerio committed
1050
{
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1051 1052 1053
    QStringList sourceScenes = getSceneFileNames(documentRootFolder);
    if (sourceScenes.empty())
        return false;
Claudio Valerio's avatar
Claudio Valerio committed
1054 1055 1056

    int targetPageCount = pDocument->pageCount();

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1057
    for(int sourceIndex = 0 ; sourceIndex < sourceScenes.size(); sourceIndex++)
Claudio Valerio's avatar
Claudio Valerio committed
1058 1059 1060
    {
        int targetIndex = targetPageCount + sourceIndex;

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1061 1062 1063
        QFile svg(documentRootFolder + "/" + sourceScenes[sourceIndex]);
        if (!svg.copy(pDocument->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex)))
            return false;
Claudio Valerio's avatar
Claudio Valerio committed
1064 1065 1066

        UBSvgSubsetAdaptor::setSceneUuid(pDocument, targetIndex, QUuid::createUuid());

1067
        QFile thumb(documentRootFolder + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex));
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1068
        // We can ignore error in this case, thumbnail will be genarated
1069
        thumb.copy(pDocument->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex));
Claudio Valerio's avatar
Claudio Valerio committed
1070 1071 1072 1073 1074
    }

    foreach(QString dir, mDocumentSubDirectories)
    {
        qDebug() << "copying " << documentRootFolder << "/" << dir << " to " << pDocument->persistencePath() << "/" + dir;
Claudio Valerio's avatar
Claudio Valerio committed
1075

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
1076 1077 1078 1079
        QDir srcDir(documentRootFolder + "/" + dir);
        if (srcDir.exists())
            if (!UBFileSystemUtils::copyDir(documentRootFolder + "/" + dir, pDocument->persistencePath() + "/" + dir))
                return false;
Claudio Valerio's avatar
Claudio Valerio committed
1080 1081 1082 1083
    }

    pDocument->setPageCount(sceneCount(pDocument));

1084 1085
    //issue NC - NNE - 20131213 : At this point, all is well done.
    return true;
Claudio Valerio's avatar
Claudio Valerio committed
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
}


bool UBPersistenceManager::isEmpty(UBDocumentProxy* pDocumentProxy)
{
    if(!pDocumentProxy)
        return true;

    if (pDocumentProxy->pageCount() > 1)
        return false;

1097
    UBGraphicsScene *theSoleScene = UBSvgSubsetAdaptor::loadScene(pDocumentProxy, 0);
Claudio Valerio's avatar
Claudio Valerio committed
1098 1099 1100 1101 1102 1103

    bool empty = false;

    if (theSoleScene)
    {
        empty = theSoleScene->isEmpty();
1104
        delete theSoleScene;
Claudio Valerio's avatar
Claudio Valerio committed
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
    }
    else
    {
        empty = true;
    }

    return empty;
}


void UBPersistenceManager::purgeEmptyDocuments()
{
1117
    QList<UBDocumentProxy*> toBeDeleted;
Claudio Valerio's avatar
Claudio Valerio committed
1118

1119 1120 1121
    foreach(UBDocumentProxy* docProxy, mDocumentTreeStructureModel->newDocuments())
    {
        if (isEmpty(docProxy))
Claudio Valerio's avatar
Claudio Valerio committed
1122
        {
1123
            toBeDeleted << docProxy;
Claudio Valerio's avatar
Claudio Valerio committed
1124
        }
1125
    }
Claudio Valerio's avatar
Claudio Valerio committed
1126

1127 1128 1129
    foreach(UBDocumentProxy* docProxy, toBeDeleted)
    {
        deleteDocument(docProxy);
Claudio Valerio's avatar
Claudio Valerio committed
1130 1131 1132
    }
}

Claudio Valerio's avatar
Claudio Valerio committed
1133 1134
bool UBPersistenceManager::addFileToDocument(UBDocumentProxy* pDocumentProxy,
                                                     QString path,
1135 1136 1137 1138
                                                     const QString& subdir,
                                                     QUuid objectUuid,
                                                     QString& destinationPath,
                                                     QByteArray* data)
Claudio Valerio's avatar
Claudio Valerio committed
1139
{
Claudio Valerio's avatar
Claudio Valerio committed
1140
    Q_ASSERT(path.length());
Claudio Valerio's avatar
Claudio Valerio committed
1141 1142 1143
    QFileInfo fi(path);

    if (!pDocumentProxy || objectUuid.isNull())
1144 1145 1146
        return false;
    if (data == NULL && !fi.exists())
        return false;
Claudio Valerio's avatar
Claudio Valerio committed
1147

1148 1149
    qDebug() << fi.suffix();

1150
    QString fileName = subdir + "/" + objectUuid.toString() + "." + fi.suffix();
1151

1152
    destinationPath = pDocumentProxy->persistencePath() + "/" + fileName;
Claudio Valerio's avatar
Claudio Valerio committed
1153

1154
    if (!QFile::exists(destinationPath))
Claudio Valerio's avatar
Claudio Valerio committed
1155 1156
    {
        QDir dir;
1157
        dir.mkdir(pDocumentProxy->persistencePath() + "/" + subdir);
1158 1159
        if (!QFile::exists(pDocumentProxy->persistencePath() + "/" + subdir))
            return false;
Claudio Valerio's avatar
Claudio Valerio committed
1160

1161
        if (data == NULL)
Claudio Valerio's avatar
Claudio Valerio committed
1162
        {
1163 1164
            QFile source(path);
            return source.copy(destinationPath);
Claudio Valerio's avatar
Claudio Valerio committed
1165
        }
1166
        else
Claudio Valerio's avatar
Claudio Valerio committed
1167
        {
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
            QFile newFile(destinationPath);

            if (newFile.open(QIODevice::WriteOnly))
            {
                qint64 n = newFile.write(*data);
                newFile.flush();
                newFile.close();
                return n == data->size();
            }
            else
            {
                return false;
            }
Claudio Valerio's avatar
Claudio Valerio committed
1181 1182
        }
    }
1183
    else
Claudio Valerio's avatar
Claudio Valerio committed
1184
    {
Claudio Valerio's avatar
Claudio Valerio committed
1185
        return false;
Claudio Valerio's avatar
Claudio Valerio committed
1186 1187
    }
}
1188

1189
bool UBPersistenceManager::addGraphicsWidgetToDocument(UBDocumentProxy *pDocumentProxy,
Claudio Valerio's avatar
Claudio Valerio committed
1190
                                                       QString path,
1191 1192
                                                       QUuid objectUuid,
                                                       QString& destinationPath)
1193 1194 1195 1196
{
    QFileInfo fi(path);

    if (!fi.exists() || !pDocumentProxy || objectUuid.isNull())
1197
        return false;
1198 1199 1200

    QString widgetRootDir = path;
    QString extension = QFileInfo(widgetRootDir).suffix();
Claudio Valerio's avatar
Claudio Valerio committed
1201

1202
    destinationPath = pDocumentProxy->persistencePath() + "/" + widgetDirectory +  "/" + objectUuid.toString() + "." + extension;
1203

1204
    if (!QFile::exists(destinationPath)) {
1205
        QDir dir;
1206 1207 1208
        if (!dir.mkpath(destinationPath))
            return false;
        return UBFileSystemUtils::copyDir(widgetRootDir, destinationPath);
1209
    }
1210 1211
    else
        return false;
1212
}
Claudio Valerio's avatar
Claudio Valerio committed
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232


void UBPersistenceManager::documentRepositoryChanged(const QString& path)
{
    Q_UNUSED(path);
    checkIfDocumentRepositoryExists();
}


void UBPersistenceManager::checkIfDocumentRepositoryExists()
{
    QDir rp(mDocumentRepositoryPath);

    if (!rp.exists())
    {
        // we have lost the document repository ..

        QString humanPath = QDir::cleanPath(mDocumentRepositoryPath);
        humanPath = QDir::toNativeSeparators(humanPath);

1233
        UBApplication::mainWindow->warning(tr("Document Repository Loss"),tr("OpenBoard has lost access to the document repository '%1'. Unfortunately the application must shut down to avoid data corruption. Latest changes may be lost as well.").arg(humanPath));
Claudio Valerio's avatar
Claudio Valerio committed
1234 1235 1236 1237

        UBApplication::quit();
    }
}
1238

1239
void UBPersistenceManager::saveFoldersTreeToXml(QXmlStreamWriter &writer, const QModelIndex &parentIndex)
1240
{
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
    for (int i = 0; i < mDocumentTreeStructureModel->rowCount(parentIndex); i++)
    {
        QModelIndex currentIndex = mDocumentTreeStructureModel->index(i, 0, parentIndex);
        if (mDocumentTreeStructureModel->isCatalog(currentIndex))
        {
            writer.writeStartElement(tFolder);
            writer.writeAttribute(aName, mDocumentTreeStructureModel->nodeFromIndex(currentIndex)->nodeName());
            saveFoldersTreeToXml(writer, currentIndex);
            writer.writeEndElement();
        }
    }
}
1253

1254 1255
void UBPersistenceManager::loadFolderTreeFromXml(const QString &path, const QDomElement &element)
{
1256

1257 1258 1259 1260 1261 1262 1263
    QDomElement iterElement = element.firstChildElement();
    while(!iterElement.isNull())
    {
        QString leafPath;
        if (tFolder == iterElement.tagName())
        {
            leafPath = iterElement.attribute(aName);
1264

1265 1266 1267 1268 1269 1270
            if (!leafPath.isEmpty())
            {
                mDocumentTreeStructureModel->goTo(path + "/" + leafPath);
                if (!iterElement.firstChildElement().isNull())
                    loadFolderTreeFromXml(path + "/" +  leafPath, iterElement);
            }
1271
        }
1272
        iterElement = iterElement.nextSiblingElement();
1273 1274
    }
}
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317

bool UBPersistenceManager::mayHaveVideo(UBDocumentProxy* pDocumentProxy)
{
    QDir videoDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::videoDirectory);

    return videoDir.exists() && videoDir.entryInfoList().length() > 0;
}

bool UBPersistenceManager::mayHaveAudio(UBDocumentProxy* pDocumentProxy)
{
    QDir audioDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::audioDirectory);

    return audioDir.exists() && audioDir.entryInfoList().length() > 0;
}

bool UBPersistenceManager::mayHavePDF(UBDocumentProxy* pDocumentProxy)
{
    QDir objectDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::objectDirectory);

    QStringList filters;
    filters << "*.pdf";

    return objectDir.exists() && objectDir.entryInfoList(filters).length() > 0;
}


bool UBPersistenceManager::mayHaveSVGImages(UBDocumentProxy* pDocumentProxy)
{
    QDir imageDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory);

    QStringList filters;
    filters << "*.svg";

    return imageDir.exists() && imageDir.entryInfoList(filters).length() > 0;
}


bool UBPersistenceManager::mayHaveWidget(UBDocumentProxy* pDocumentProxy)
{
    QDir widgetDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory);

    return widgetDir.exists() && widgetDir.entryInfoList(QDir::Dirs).length() > 0;
}