Skip to content
Snippets Groups Projects
bardescriptordocument.cpp 9.03 KiB
Newer Older
/**************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "bardescriptordocument.h"

#include "qnxconstants.h"
#include "bardescriptoreditor.h"
#include "bardescriptoreditorwidget.h"
#include "bardescriptordocumentnodehandlers.h"

#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/qtcassert.h>

#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QTextCodec>

using namespace Qnx;
using namespace Qnx::Internal;

BarDescriptorDocument::BarDescriptorDocument(BarDescriptorEditorWidget *editorWidget)
    : Core::TextDocument(editorWidget)
    , m_nodeHandlers(QList<BarDescriptorDocumentAbstractNodeHandler *>())
    , m_editorWidget(editorWidget)
{
    // General
    registerNodeHandler(new BarDescriptorDocumentIdNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentVersionNumberNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentBuildIdNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentAuthorNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentAuthorIdNodeHandler(m_editorWidget));

    // Application
    registerNodeHandler(new BarDescriptorDocumentApplicationNameNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentApplicationDescriptionNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentApplicationIconNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentSplashScreenNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentInitialWindowNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentArgNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentActionNodeHandler(m_editorWidget));
    registerNodeHandler(new BarDescriptorDocumentEnvNodeHandler(m_editorWidget));

    // Assets
    registerNodeHandler(new BarDescriptorDocumentAssetNodeHandler(m_editorWidget));

    // blackberry-nativepackager requires the XML file to be in UTF-8 encoding,
    // force if possible
    if (QTextCodec *defaultUTF8 = QTextCodec::codecForName("UTF-8"))
        setCodec(defaultUTF8);
    else
        setCodec(Core::EditorManager::defaultTextCodec());
}

BarDescriptorDocument::~BarDescriptorDocument()
{
    while (!m_nodeHandlers.isEmpty()) {
        BarDescriptorDocumentAbstractNodeHandler *nodeHandler = m_nodeHandlers.takeFirst();
        delete nodeHandler;
    }
}

bool BarDescriptorDocument::open(QString *errorString, const QString &fileName) {
    QString contents;
    if (read(fileName, &contents, errorString) != Utils::TextFileFormat::ReadSuccess)
        return false;

    setFilePath(fileName);
    m_editorWidget->setFilePath(fileName);

    bool result = loadContent(contents);

    if (!result)
        *errorString = tr("%1 does not appear to be a valid application descriptor file").arg(QDir::toNativeSeparators(fileName));

    return result;
}

bool BarDescriptorDocument::save(QString *errorString, const QString &fn, bool autoSave)
{
    QTC_ASSERT(!autoSave, return false);
    QTC_ASSERT(fn.isEmpty(), return false);
    bool result = write(filePath(), xmlSource(), errorString);
    if (!result)
        return false;

    m_editorWidget->setDirty(false);
    emit changed();
    return true;
}

QString BarDescriptorDocument::defaultPath() const
{
    QFileInfo fi(filePath());
    return fi.absolutePath();
}

QString BarDescriptorDocument::suggestedFileName() const
{
    QFileInfo fi(filePath());
    return fi.fileName();
}

QString BarDescriptorDocument::mimeType() const
{
    return QLatin1String(Constants::QNX_BAR_DESCRIPTOR_MIME_TYPE);
}

bool BarDescriptorDocument::shouldAutoSave() const
{
    return false;
}

bool BarDescriptorDocument::isModified() const
{
    return m_editorWidget->isDirty();
}

bool BarDescriptorDocument::isSaveAsAllowed() const
{
    return false;
}

Core::IDocument::ReloadBehavior BarDescriptorDocument::reloadBehavior(Core::IDocument::ChangeTrigger state, Core::IDocument::ChangeType type) const
{
    if (type == TypeRemoved || type == TypePermissions)
        return BehaviorSilent;
    if (type == TypeContents && state == TriggerInternal && !isModified())
        return BehaviorSilent;
    return BehaviorAsk;
}

bool BarDescriptorDocument::reload(QString *errorString, Core::IDocument::ReloadFlag flag, Core::IDocument::ChangeType type)
{
    Q_UNUSED(type);

    if (flag == Core::IDocument::FlagIgnore)
        return true;

    return open(errorString, filePath());
}

QString BarDescriptorDocument::xmlSource() const
{
    BarDescriptorEditor *editor = qobject_cast<BarDescriptorEditor*>(m_editorWidget->editor());
    QTC_ASSERT(editor, return QString());
    if (editor->activePage() == BarDescriptorEditor::Source) {
        return m_editorWidget->xmlSource();
    } else {
        QDomDocument doc;
        doc.appendChild(doc.createProcessingInstruction(QLatin1String("xml"), QLatin1String("version='1.0' encoding='") + QLatin1String(codec()->name()) + QLatin1String("' standalone='no'")));
        // QNX
        QDomElement rootElem = doc.createElement(QLatin1String("qnx"));
        rootElem.setAttribute(QLatin1String("xmlns"), QLatin1String("http://www.qnx.com/schemas/application/1.0"));
        QMap<int, BarDescriptorDocumentAbstractNodeHandler*> nodeHandlerMap;
        foreach (BarDescriptorDocumentAbstractNodeHandler *nodeHandler, m_nodeHandlers)
            nodeHandlerMap.insertMulti(nodeHandler->order(), nodeHandler);
        QList<BarDescriptorDocumentAbstractNodeHandler*> nodeHandlers = nodeHandlerMap.values();
        foreach (BarDescriptorDocumentAbstractNodeHandler *nodeHandler, nodeHandlers)
            rootElem.appendChild(nodeHandler->toNode(doc));
        doc.appendChild(rootElem);

        return doc.toString(4);
    }
}

bool BarDescriptorDocument::loadContent(const QString &xmlSource, QString *errorMessage, int *errorLine)
{
    QDomDocument doc;
    bool result = doc.setContent(xmlSource, errorMessage, errorLine);
    if (!result)
        return false;

    QDomElement docElem = doc.documentElement();
    if (docElem.tagName() != QLatin1String("qnx"))
        return false;

    m_editorWidget->clear();

    removeUnknownNodeHandlers();
    foreach (BarDescriptorDocumentAbstractNodeHandler *nodeHandler, m_nodeHandlers)
        nodeHandler->clear();

    QDomNode node = docElem.firstChildElement();
    while (!node.isNull()) {
        BarDescriptorDocumentAbstractNodeHandler *nodeHandler = nodeHandlerForDomNode(node);
        if (!nodeHandler) {
            nodeHandler = new BarDescriptorDocumentUnknownNodeHandler(m_editorWidget);
            registerNodeHandler(nodeHandler);
        }

        if (!nodeHandler->handle(node))
            return false;

        node = node.nextSibling();
    }

    m_editorWidget->setXmlSource(xmlSource);

    return true;
}

void BarDescriptorDocument::registerNodeHandler(BarDescriptorDocumentAbstractNodeHandler *nodeHandler)
{
    m_nodeHandlers << nodeHandler;
}

BarDescriptorDocumentAbstractNodeHandler *BarDescriptorDocument::nodeHandlerForDomNode(const QDomNode &node)
{
    foreach (BarDescriptorDocumentAbstractNodeHandler *handler, m_nodeHandlers) {
        if (handler->canHandle(node) && !dynamic_cast<BarDescriptorDocumentUnknownNodeHandler*>(handler))
            return handler;
    }

    return 0;
}

void BarDescriptorDocument::removeUnknownNodeHandlers()
{
    for (int i = m_nodeHandlers.size() - 1; i >= 0; --i) {
        BarDescriptorDocumentUnknownNodeHandler *nodeHandler = dynamic_cast<BarDescriptorDocumentUnknownNodeHandler*>(m_nodeHandlers[i]);
        if (nodeHandler) {
            m_nodeHandlers.removeAt(i);
            delete nodeHandler;
        }
    }
}