OSDN Git Service

Merge remote branch 'origin/2.0'
authorcon <qtc-committer@nokia.com>
Thu, 24 Jun 2010 09:40:22 +0000 (11:40 +0200)
committercon <qtc-committer@nokia.com>
Thu, 24 Jun 2010 09:40:22 +0000 (11:40 +0200)
Conflicts:
doc/qtcreator.qdoc
src/plugins/help/helpplugin.cpp
src/plugins/projectexplorer/projectexplorer.cpp
src/plugins/projectexplorer/projectexplorer.h
src/plugins/qt4projectmanager/qt-maemo/maemopackagecontents.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecontents.h
src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp
src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp
src/tools/qml/qmldump/main.cpp

18 files changed:
1  2 
README
doc/qtcreator.qdoc
doc/qtcreator.qdocconf
qtcreator.pri
src/plugins/help/helpplugin.cpp
src/plugins/projectexplorer/projectexplorer.cpp
src/plugins/projectexplorer/projectexplorer.h
src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecontents.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecontents.h
src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationwidget.cpp
src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp
src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h
src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp
src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h
src/plugins/qt4projectmanager/qt-maemo/qemuruntimemanager.cpp
src/plugins/qt4projectmanager/qt-maemo/qemuruntimemanager.h
src/tools/qml/qmldump/main.cpp

diff --cc README
Simple merge
  
      \section2 Children and SubItem Class
  
 -    The attempt to create child items might lead to errors if data is
 -    uninitialized or corrupted. To gracefully recover in such situations,
 -    use \c Children and \c SubItem \e{Context Managers} to create the nested items.
 +    Child items might report errors if data is uninitialized or corrupted
 +    or if the helper code is broken. To gracefully recover from these
 +    errors, use \c Children and \c SubItem \e{Context Managers} to create
 +    nested items.
  
      The \c Children constructor \gui{__init__(self, dumper, numChild = 1,
 -    childType = None, childNumChild = None)} uses one mandatory argument and three
 -    optional arguments.  The mandatory argument refers to the current \c Dumper
 -    object.  The optional arguments can be used to specify the number \c numChild
 -    of children, with type \c childType_ and \c childNumChild_ grandchildren each.
 -    If \c numChild_ is a list of two integers, the first one specifies the actual
 -    number of children and the second the maximum number of children to print.
 +    childType = None, childNumChild = None)} uses one non-optional argument
 +    \c dumper to refer to the current \c Dumper object and three optional
 +    arguments, specifying the number \c numChild of children, with type
 +    \c childType_ and \c childNumChild_ grandchildren each. If \c numChild_
 +    is a list of two integers, the first one specifies the actual number
 +    of children and the second the maximum number of children to print.
  
-     Similarly, using the \SubItem class helps to protect individual items.
+     Similarly, using the \SubItem class helps to protect individual items.
  
      Example:
      \code
Simple merge
diff --cc qtcreator.pri
Simple merge
@@@ -385,14 -384,13 +385,13 @@@ void HelpPlugin::setupUi(
      connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
          SLOT(setSourceFromSearch(QUrl)));
  
-     // TODO: enable and find a proper keysequence as this is ambiguous
-     // shortcut = new QShortcut(m_splitter);
-     // shortcut->setWhatsThis(tr("Activate Search in Help mode"));
-     // cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"),
-     //     modecontext);
-     // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
-     // connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
-     // shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
+      shortcut = new QShortcut(m_splitter);
+      shortcut->setWhatsThis(tr("Activate Search in Help mode"));
+      cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"),
+          modecontext);
+      cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Slash));
+      connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
 -     shortcutMap.insert(SB_SEARCH, cmd);
++     shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
  
      BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
      BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
      connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
          SLOT(setSource(QUrl)));
  
-     // TODO: enable and find a proper keysequence as this is ambiguous
-     // shortcut = new QShortcut(m_splitter);
-     // shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
-     // cmd = am->registerShortcut(shortcut, QLatin1String("Help.BookmarkShortcut"),
-     //     modecontext);
-     // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_B));
-     // connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
-     // shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
+      shortcut = new QShortcut(m_splitter);
+      shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
+      cmd = am->registerShortcut(shortcut, QLatin1String("Help.BookmarkShortcut"),
+          modecontext);
+      cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B));
+      connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
 -     shortcutMap.insert(SB_BOOKMARKS, cmd);
++     shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
  
      QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
      openPagesWidget->setWindowTitle(tr("Open Pages"));
@@@ -1892,18 -1890,16 +1892,20 @@@ void ProjectExplorerPlugin::updateConte
      d->m_addNewFileAction->setEnabled(false);
      d->m_removeFileAction->setEnabled(false);
  
-     QList<ProjectNode::ProjectAction> actions =
-             d->m_currentNode->projectNode()->supportedActions(node);
-     if (qobject_cast<FolderNode*>(d->m_currentNode)) {
-         bool addFilesEnabled = actions.contains(ProjectNode::AddFile);
-         d->m_addExistingFilesAction->setEnabled(addFilesEnabled);
-         d->m_addNewFileAction->setEnabled(addFilesEnabled);
-         d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
-     } else if (qobject_cast<FileNode*>(d->m_currentNode)) {
-         bool removeFileEnabled = actions.contains(ProjectNode::RemoveFile);
-         d->m_removeFileAction->setEnabled(removeFileEnabled);
-         d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
+     if (node->projectNode()) {
 -        QList<ProjectNode::ProjectAction> supportedActions = node->projectNode()->supportedActions();
 -        if (qobject_cast<FolderNode*>(node)) {
 -            const bool addFilesEnabled = supportedActions.contains(ProjectNode::AddFile);
++        QList<ProjectNode::ProjectAction> actions =
++                d->m_currentNode->projectNode()->supportedActions(node);
++
++        if (qobject_cast<FolderNode*>(d->m_currentNode)) {
++            bool addFilesEnabled = actions.contains(ProjectNode::AddFile);
+             d->m_addExistingFilesAction->setEnabled(addFilesEnabled);
+             d->m_addNewFileAction->setEnabled(addFilesEnabled);
 -        } else if (qobject_cast<FileNode*>(node)) {
 -            const bool removeFileEnabled = supportedActions.contains(ProjectNode::RemoveFile);
++            d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
++        } else if (qobject_cast<FileNode*>(d->m_currentNode)) {
++            bool removeFileEnabled = actions.contains(ProjectNode::RemoveFile);
+             d->m_removeFileAction->setEnabled(removeFileEnabled);
++            d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
+         }
      }
  }
  
@@@ -71,87 -58,16 +71,87 @@@ MaemoPackageContents::MaemoPackageConte
  {
  }
  
-             m_deployables.prepend(Deployable(m_packageStep->localExecutableFilePath(),
 +MaemoPackageContents::~MaemoPackageContents() {}
 +
 +bool MaemoPackageContents::init()
 +{
 +    return m_proFile ? true : buildModel();
 +}
 +
 +bool MaemoPackageContents::buildModel() const
 +{
 +    m_deployables.clear();
 +    const Qt4ProFileNode * const proFileNode = m_packageStep
 +        ->qt4BuildConfiguration()->qt4Target()->qt4Project()->rootProjectNode();
 +    if (m_proFileName.isEmpty()) {
 +        m_proFileName = proFileNode->path();
 +        m_proDir = QFileInfo(m_proFileName).dir();
 +    }
 +
 +    resetProFileContents();
 +    if (!m_proFile)
 +        return false;
 +
 +    const QStringList elemList = m_proFileReader->values(InstallsVar, m_proFile);
 +    bool targetFound = false;
 +    foreach (const QString &elem, elemList) {
 +        const QStringList paths
 +            = m_proFileReader->values(pathVar(elem), m_proFile);
 +        if (paths.count() != 1) {
 +            qWarning("Error: Variable %s has %d values.",
 +                qPrintable(pathVar(elem)), paths.count());
 +            continue;
 +        }
 +
 +        const QStringList files
 +            = m_proFileReader->values(filesVar(elem), m_proFile);
 +        if (files.isEmpty() && elem != TargetVar) {
 +            qWarning("Error: Variable %s has no RHS.",
 +                qPrintable(filesVar(elem)));
 +            continue;
 +        }
 +
 +        if (elem == TargetVar) {
-                 m_deployables << Deployable(cleanPath(file), paths.first());
++            m_deployables.prepend(MaemoDeployable(m_packageStep->localExecutableFilePath(),
 +                paths.first()));
 +            targetFound = true;
 +        } else {
 +            foreach (const QString &file, files)
-         m_deployables.prepend(Deployable(m_packageStep->localExecutableFilePath(),
++                m_deployables << MaemoDeployable(cleanPath(file), paths.first());
 +        }
 +    }
 +
 +    if (!targetFound) {
 +        const QString remoteDir = proFileNode->projectType() == LibraryTemplate
 +            ? QLatin1String("/usr/local/lib")
 +            : QLatin1String("/usr/local/bin");
- MaemoPackageContents::Deployable MaemoPackageContents::deployableAt(int row) const
++        m_deployables.prepend(MaemoDeployable(m_packageStep->localExecutableFilePath(),
 +            remoteDir));
 +        QString errorString;
 +        if (!readProFileContents(&errorString)) {
 +            qWarning("Error reading .pro file: %s", qPrintable(errorString));
 +            return false;
 +        }
 +        addValueToProFile(pathVar(TargetVar), remoteDir);
 +        addValueToProFile(InstallsVar, TargetVar);
 +        if (!writeProFileContents(&errorString)) {
 +            qWarning("Error writing .pro file: %s", qPrintable(errorString));
 +            return false;
 +        }
 +    }
 +
 +    m_modified = true;
 +    return true;
 +}
 +
+ MaemoDeployable MaemoPackageContents::deployableAt(int row) const
  {
      Q_ASSERT(row >= 0 && row < rowCount());
 -    return row == 0
 -        ? MaemoDeployable(m_packageStep->localExecutableFilePath(),
 -                     remoteExecutableFilePath())
 -        : m_deployables.at(row - 1);
 +    return m_deployables.at(row);
  }
  
- bool MaemoPackageContents::addDeployable(const Deployable &deployable,
 -bool MaemoPackageContents::addDeployable(const MaemoDeployable &deployable)
++bool MaemoPackageContents::addDeployable(const MaemoDeployable &deployable,
 +    QString *error)
  {
      if (m_deployables.contains(deployable) || deployableAt(0) == deployable)
          return false;
      return true;
  }
  
 -void MaemoPackageContents::removeDeployableAt(int row)
 +bool MaemoPackageContents::removeDeployableAt(int row, QString *error)
  {
      Q_ASSERT(row > 0 && row < rowCount());
-     const Deployable &deployable = deployableAt(row);
 +
++    const MaemoDeployable &deployable = deployableAt(row);
 +    const QString elemToRemove = findInstallsElem(deployable);
 +    if (elemToRemove.isEmpty()) {
 +        *error = tr("Inconsistent model: Deployable not found in  .pro file.");
 +        return false;
 +    }
 +
 +    if (!readProFileContents(error))
 +        return false;
 +
 +    const QString filesVarName = filesVar(elemToRemove);
 +    const bool isOnlyElem
 +        = m_proFileReader->values(filesVarName, m_proFile).count() == 1;
 +    bool success
 +        = removeFileFromProFile(filesVarName, deployable.localFilePath);
 +    if (success && isOnlyElem) {
 +        success = removeValueFromProFile(pathVar(elemToRemove),
 +            deployable.remoteDir);
 +        if (success)
 +            success = removeValueFromProFile(InstallsVar, elemToRemove);
 +    }
 +    if (!success) {
 +        *error = tr("Could not remove deployable from .pro file.");
 +        return false;
 +    }
 +
 +    if (!writeProFileContents(error))
 +        return false;
 +
      beginRemoveRows(QModelIndex(), row, row);
      m_deployables.removeAt(row - 1);
      endRemoveRows();
@@@ -254,33 -126,12 +254,33 @@@ bool MaemoPackageContents::setData(cons
          || role != Qt::EditRole)
          return false;
  
 -    const QString &remoteFilePath = value.toString();
 -    if (index.row() == 0)
 -        m_remoteExecutableFilePath = remoteFilePath;
 -    else
 -        m_deployables[index.row() - 1].remoteFilePath = remoteFilePath;
 -    m_modified = true;
 +    QString error;
 +    if (!readProFileContents(&error)) {
 +        qWarning("%s", qPrintable(error));
 +        return false;
 +    }
 +
-     Deployable &deployable = m_deployables[index.row()];
++    MaemoDeployable &deployable = m_deployables[index.row()];
 +    const QString elemToChange = findInstallsElem(deployable);
 +    if (elemToChange.isEmpty()) {
 +        qWarning("Error: Inconsistent model. "
 +            "INSTALLS element not found in .pro file");
 +        return false;
 +    }
 +    const QString pathElem = pathVar(elemToChange);
 +    if (!removeValueFromProFile(pathElem, deployable.remoteDir)) {
 +        qWarning("Error: Could not change remote path in .pro file.");
 +        return false;
 +    }
 +    const QString &newRemoteDir = value.toString();
 +    addValueToProFile(pathElem, newRemoteDir);
 +
 +    if (!writeProFileContents(&error)) {
 +        qWarning("%s", qPrintable(error));
 +        return false;
 +    }
 +
 +    deployable.remoteDir = newRemoteDir;
      emit dataChanged(index, index);
      return true;
  }
@@@ -290,153 -141,45 +290,153 @@@ QVariant MaemoPackageContents::headerDa
  {
      if (orientation == Qt::Vertical || role != Qt::DisplayRole)
          return QVariant();
 -    return section == 0 ? tr("Local File Path") : tr("Remote File Path");
 +    return section == 0 ? tr("Local File Path") : tr("Remote Directory");
 +}
 +
 +QString MaemoPackageContents::remoteExecutableFilePath() const
 +{
 +    if (!m_proFile)
 +        buildModel();
 +    return deployableAt(0).remoteDir + '/' + m_packageStep->executableFileName();
  }
  
 -QVariantMap MaemoPackageContents::toMap() const
 +bool MaemoPackageContents::readProFileContents(QString *error) const
  {
 -    QVariantMap map;
 -    map.insert(MODIFIED_KEY, m_modified);
 -    map.insert(REMOTE_EXE_KEY, m_remoteExecutableFilePath);
 -    QStringList localFiles;
 -    QStringList remoteFiles;
 -    foreach (const MaemoDeployable &p, m_deployables) {
 -        localFiles << p.localFilePath;
 -        remoteFiles << p.remoteFilePath;
 +    if (!m_proFileLines.isEmpty())
 +        return true;
 +
 +    QFile proFileOnDisk(m_proFileName);
 +    if (!proFileOnDisk.open(QIODevice::ReadOnly)) {
 +        *error = tr("Project file '%1' could not be opened for reading.")
 +            .arg(m_proFileName);
 +        return false;
 +    }
 +    const QString proFileContents
 +        = QString::fromLatin1(proFileOnDisk.readAll());
 +    if (proFileOnDisk.error() != QFile::NoError) {
 +        *error = tr("Project file '%1' could not be read.")
 +            .arg(m_proFileName);
 +        return false;
      }
 -    map.insert(LOCAL_FILES_KEY, localFiles);
 -    map.insert(REMOTE_FILES_KEY, remoteFiles);
 -    return map;
 +    m_proFileLines = proFileContents.split('\n');
 +    return true;
  }
  
 -void MaemoPackageContents::fromMap(const QVariantMap &map)
 +bool MaemoPackageContents::writeProFileContents(QString *error) const
  {
 -    m_modified = map.value(MODIFIED_KEY).toBool();
 -    m_remoteExecutableFilePath = map.value(REMOTE_EXE_KEY).toString();
 -    const QStringList localFiles = map.value(LOCAL_FILES_KEY).toStringList();
 -    const QStringList remoteFiles = map.value(REMOTE_FILES_KEY).toStringList();
 -    if (localFiles.count() != remoteFiles.count())
 -        qWarning("%s: serialized data inconsistent", Q_FUNC_INFO);
 -    const int count = qMin(localFiles.count(), remoteFiles.count());
 -    for (int i = 0; i < count; ++i)
 -        m_deployables << MaemoDeployable(localFiles.at(i), remoteFiles.at(i));
 +    QFile proFileOnDisk(m_proFileName);
 +    if (!proFileOnDisk.open(QIODevice::WriteOnly)) {
 +        *error = tr("Project file '%1' could not be opened for writing.")
 +            .arg(m_proFileName);
 +        resetProFileContents();
 +        return false;
 +    }
 +
 +    // TODO: Disconnect and reconnect FS watcher here.
 +    proFileOnDisk.write(m_proFileLines.join("\n").toLatin1());
 +    proFileOnDisk.close();
 +    if (proFileOnDisk.error() != QFile::NoError) {
 +        *error = tr("Project file '%1' could not be written.")
 +            .arg(m_proFileName);
 +        resetProFileContents();
 +        return false;
 +    }
 +    m_modified = true;
 +    return true;
  }
  
 -QString MaemoPackageContents::remoteExecutableFilePath() const
 +QString MaemoPackageContents::cleanPath(const QString &relFileName) const
  {
 -    if (m_remoteExecutableFilePath.isEmpty()) {
 -        m_remoteExecutableFilePath = QLatin1String("/usr/local/bin/")
 -                                     + m_packageStep->executableFileName();
 +    // I'd rather use QDir::cleanPath(), but that doesn't work well
 +    // enough for redundant ".." dirs.
 +    return QFileInfo(m_proFile->directoryName() + '/'
 +        + relFileName).canonicalFilePath();
 +}
 +
- QString MaemoPackageContents::findInstallsElem(const Deployable &deployable) const
++QString MaemoPackageContents::findInstallsElem(const MaemoDeployable &deployable) const
 +{
 +    const QStringList elems = m_proFileReader->values(InstallsVar, m_proFile);
 +    foreach (const QString &elem, elems) {
 +        const QStringList elemPaths
 +            = m_proFileReader->values(pathVar(elem), m_proFile);
 +        if (elemPaths.count() != 1 || elemPaths.first() != deployable.remoteDir)
 +            continue;
 +        if (elem == TargetVar)
 +            return elem;
 +        const QStringList elemFiles
 +            = m_proFileReader->values(filesVar(elem), m_proFile);
 +        foreach (const QString &file, elemFiles) {
 +            if (cleanPath(file) == deployable.localFilePath)
 +                return elem;
 +        }
 +    }
 +    return QString();
 +}
 +
 +void MaemoPackageContents::addFileToProFile(const QString &var,
 +    const QString &absFilePath)
 +{
 +    ProWriter::addFiles(m_proFile, &m_proFileLines, m_proDir,
 +        QStringList(absFilePath), var);
 +    parseProFile(ParseFromLines);
 +}
 +
 +void MaemoPackageContents::addValueToProFile(const QString &var,
 +    const QString &value) const
 +{
 +    ProWriter::addVarValues(m_proFile, &m_proFileLines, m_proDir,
 +        QStringList(value), var);
 +    parseProFile(ParseFromLines);
 +}
 +
 +bool MaemoPackageContents::removeFileFromProFile(const QString &var,
 +    const QString &absFilePath)
 +{
 +    const bool success = ProWriter::removeFiles(m_proFile, &m_proFileLines,
 +        m_proDir, QStringList(absFilePath),
 +        QStringList(var)).isEmpty();
 +    if (success)
 +        parseProFile(ParseFromLines);
 +    else
 +        resetProFileContents();
 +    return success;
 +}
 +
 +bool MaemoPackageContents::removeValueFromProFile(const QString &var,
 +    const QString &value)
 +{
 +    const bool success = ProWriter::removeVarValues(m_proFile,
 +        &m_proFileLines, m_proDir, QStringList(value),
 +        QStringList(var)).isEmpty();
 +    if (success)
 +        parseProFile(ParseFromLines);
 +    else
 +        resetProFileContents();
 +    return success;
 +}
 +
 +void MaemoPackageContents::parseProFile(ParseType type) const
 +{
 +    if (type == ParseFromLines) {
 +        m_proFile = m_proFileReader->parsedProFile(m_proFileName, false,
 +            m_proFileLines.join("\n"));
 +    } else {
 +        m_proFile = 0;
 +        if (ProFile *pro = m_proFileReader->parsedProFile(m_proFileName)) {
 +            if (m_proFileReader->accept(pro))
 +                m_proFile = pro;
 +            pro->deref();
 +        }
      }
 -    return m_remoteExecutableFilePath;
 +}
 +
 +void MaemoPackageContents::resetProFileContents() const
 +{
 +    m_proFileLines.clear();
 +    parseProFile(ParseFromFile);
 +    if (!m_proFile)
 +        qWarning("Fatal: Could not parse .pro file '%s'.",
 +            qPrintable(m_proFileName));
  }
  
  } // namespace Qt4ProjectManager
  #define MAEMOPACKAGECONTENTS_H
  
  #include <QtCore/QAbstractTableModel>
 +#include <QtCore/QDir>
+ #include <QtCore/QHash>
  #include <QtCore/QList>
 +#include <QtCore/QScopedPointer>
  #include <QtCore/QString>
 -#include <QtCore/QVariantMap>
 +#include <QtCore/QStringList>
 +
 +QT_BEGIN_NAMESPACE
 +class ProFile;
 +struct ProFileOption;
 +QT_END_NAMESPACE
  
  namespace Qt4ProjectManager {
  namespace Internal {
 -    MaemoDeployable(const QString &localFilePath, const QString &remoteFilePath)
 -        : localFilePath(localFilePath), remoteFilePath(remoteFilePath) {}
+ struct MaemoDeployable
+ {
 -            && remoteFilePath == other.remoteFilePath;
++    MaemoDeployable(const QString &localFilePath, const QString &remoteDir)
++        : localFilePath(localFilePath), remoteDir(remoteDir) {}
+     bool operator==(const MaemoDeployable &other) const
+     {
+         return localFilePath == other.localFilePath
 -    QString remoteFilePath;
++            && remoteDir == other.remoteDir;
+     }
+     QString localFilePath;
 -    return qHash(qMakePair(d.localFilePath, d.remoteFilePath));
++    QString remoteDir;
+ };
+ inline uint qHash(const MaemoDeployable &d)
+ {
 -
++    return qHash(qMakePair(d.localFilePath, d.remoteDir));
+ }
  class MaemoPackageCreationStep;
 +class ProFileReader;
  
  class MaemoPackageContents : public QAbstractTableModel
  {
      Q_OBJECT
  public:
-     struct Deployable
-     {
-         Deployable(const QString &localFilePath, const QString &remoteDir)
-             : localFilePath(localFilePath), remoteDir(remoteDir) {}
-         bool operator==(const Deployable &other) const
-         {
-             return localFilePath == other.localFilePath
-                     && remoteDir == other.remoteDir;
-         }
-         QString localFilePath;
-         QString remoteDir;
-     };
      MaemoPackageContents(MaemoPackageCreationStep *packageStep);
 +    ~MaemoPackageContents();
  
 -    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
 +    bool init();
  
 -    QVariantMap toMap() const;
 -    void fromMap(const QVariantMap &map);
 +    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
  
-     Deployable deployableAt(int row) const;
-     bool addDeployable(const Deployable &deployable, QString *error);
+     MaemoDeployable deployableAt(int row) const;
 -    bool addDeployable(const MaemoDeployable &deployable);
 -    void removeDeployableAt(int row);
++    bool addDeployable(const MaemoDeployable &deployable, QString *error);
 +    bool removeDeployableAt(int row, QString *error);
      bool isModified() const { return m_modified; }
      void setUnModified() { m_modified = false; }
      QString remoteExecutableFilePath() const;
@@@ -90,31 -89,11 +96,31 @@@ private
      virtual bool setData(const QModelIndex &index, const QVariant &value,
                           int role = Qt::EditRole);
  
 -private:
 +    bool buildModel() const;
 +    void resetProFileContents() const;
 +    bool readProFileContents(QString *error) const;
 +    bool writeProFileContents(QString *error) const;
 +
 +    QString cleanPath(const QString &relFileName) const;
 +
-     QString findInstallsElem(const Deployable &deployable) const;
++    QString findInstallsElem(const MaemoDeployable &deployable) const;
 +    void addFileToProFile(const QString &var, const QString &absFilePath);
 +    void addValueToProFile(const QString &var, const QString &value) const;
 +    bool removeFileFromProFile(const QString &var, const QString &absFilePath);
 +    bool removeValueFromProFile(const QString &var, const QString &value);
 +
 +    enum ParseType { ParseFromFile, ParseFromLines };
 +    void parseProFile(ParseType type) const;
 +
      const MaemoPackageCreationStep * const m_packageStep;
 -    QList<MaemoDeployable> m_deployables;
 -    bool m_modified;
 -    mutable QString m_remoteExecutableFilePath;
 +    QScopedPointer<ProFileOption> m_proFileOption;
 +    QScopedPointer<ProFileReader> m_proFileReader;
-     mutable QList<Deployable> m_deployables;
++    mutable QList<MaemoDeployable> m_deployables;
 +    mutable bool m_modified;
 +    mutable ProFile *m_proFile;
 +    mutable QStringList m_proFileLines; // TODO: FS watcher
 +    mutable QString m_proFileName;
 +    mutable QDir m_proDir;
  };
  
  } // namespace Qt4ProjectManager
@@@ -64,9 -64,7 +64,8 @@@ MaemoPackageCreationWidget::MaemoPackag
        m_ui(new Ui::MaemoPackageCreationWidget)
  {
      m_ui->setupUi(this);
 +    m_ui->packageContentsView->setWordWrap(false);
      m_ui->skipCheckBox->setChecked(!m_step->isPackagingEnabled());
-     m_ui->packageContentsView->setEnabled(m_step->isPackagingEnabled());
      m_ui->packageContentsView->setModel(step->packageContents());
      setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
      connect(step->packageContents(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
@@@ -102,16 -100,14 +101,16 @@@ void MaemoPackageCreationWidget::addFil
      QTC_ASSERT(bc, return);
      const QString title = tr("Choose a local file");
      const QString baseDir = bc->target()->project()->projectDirectory();
 -    const QString localFile = QFileDialog::getOpenFileName(this, title, baseDir);
 +    const QString localFile = QFileDialog::getOpenFileName(this, title, baseDir); // TODO: Support directories?
      if (localFile.isEmpty())
          return;
-     const MaemoPackageContents::Deployable
 -    const MaemoDeployable deployable(QFileInfo(localFile).absoluteFilePath(), "/");
++    const MaemoDeployable
 +        deployable(QDir::toNativeSeparators(QFileInfo(localFile).absoluteFilePath()),
 +        "/");
      MaemoPackageContents * const contents = m_step->packageContents();
 -    if (!contents->addDeployable(deployable)) {
 -        QMessageBox::information(this, tr("File already in package"),
 -                                 tr("You have already added this file."));
 +    QString errorString;
 +    if (!contents->addDeployable(deployable, &errorString)) {
 +        QMessageBox::information(this, tr("Error adding file"), errorString);
      } else {
          const QModelIndex newIndex
              = contents->index(contents->rowCount() - 1, 1);
@@@ -135,14 -130,23 +130,23 @@@ QVariantMap MaemoRunConfiguration::toMa
      return map;
  }
  
- void MaemoRunConfiguration::addDeployTimesToMap(const QString &key,
-     const QMap<QString, QDateTime> &deployTimes, QVariantMap &map) const
+ void MaemoRunConfiguration::addDeployTimesToMap(QVariantMap &map) const
  {
-     QMap<QString, QVariant> variantMap;
-     QMap<QString, QDateTime>::ConstIterator it = deployTimes.begin();
-     for (; it != deployTimes.end(); ++it)
-         variantMap.insert(it.key(), it.value());
-     map.insert(key, variantMap);
+     QVariantList hostList;
+     QVariantList fileList;
+     QVariantList remotePathList;
+     QVariantList timeList;
+     typedef QHash<DeployablePerHost, QDateTime>::ConstIterator DepIt;
+     for (DepIt it = m_lastDeployed.begin(); it != m_lastDeployed.end(); ++it) {
+         hostList << it.key().first.localFilePath;
 -        remotePathList << it.key().first.remoteFilePath;
++        remotePathList << it.key().first.remoteDir;
+         fileList << it.key().second;
+         timeList << it.value();
+     }
+     map.insert(LastDeployedHostsKey, hostList);
+     map.insert(LastDeployedFilesKey, fileList);
+     map.insert(LastDeployedRemotePathsKey, remotePathList);
+     map.insert(LastDeployedTimesKey, timeList);
  }
  
  bool MaemoRunConfiguration::fromMap(const QVariantMap &map)
@@@ -108,14 -108,10 +106,9 @@@ private slots
  
  private:
      void init();
 -    const QString cmd(const QString &cmdName) const;
      const MaemoToolChain *toolchain() const;
-     bool fileNeedsDeployment(const QString &path, const QDateTime &lastDeployed) const;
-     void addDeployTimesToMap(const QString &key,
-                              const QMap<QString, QDateTime> &deployTimes,
-                              QVariantMap &map) const;
-     void getDeployTimesFromMap(const QString &key,
-                                QMap<QString, QDateTime> &deployTimes,
-                                const QVariantMap &map);
+     void addDeployTimesToMap(QVariantMap &map) const;
+     void getDeployTimesFromMap(const QVariantMap &map);
  
      QString m_proFilePath;
      mutable QString m_gdbPath;
@@@ -37,7 -37,6 +37,7 @@@
  #include "maemopackagecreationstep.h"
  #include "maemosshthread.h"
  #include "maemorunconfiguration.h"
++#include "maemopackagecontents.h"
  
  #include <coreplugin/icore.h>
  #include <coreplugin/progressmanager/progressmanager.h>
@@@ -47,8 -44,8 +47,9 @@@
  #include <extensionsystem/pluginmanager.h>
  #include <projectexplorer/toolchain.h>
  #include <utils/qtcassert.h>
 +#include <projectexplorer/projectexplorerconstants.h>
  
+ #include <QtCore/QCryptographicHash>
  #include <QtCore/QDir>
  #include <QtCore/QFileInfo>
  #include <QtCore/QFuture>
@@@ -129,26 -123,55 +130,54 @@@ void AbstractMaemoRunControl::startDepl
      if (m_stoppedByUser) {
          emit finished();
      } else {
+         m_needsInstall = false;
          m_deployables.clear();
-         if (m_runConfig->currentlyNeedsDeployment(m_devConfig.server.host)) {
-             m_deployables.append(Deployable(packageFileName(),
-                 QFileInfo(executableOnHost()).canonicalPath(),
-                 &MaemoRunConfiguration::wasDeployed));
-             m_needsInstall = true;
+         m_remoteLinks.clear();
+         const MaemoPackageCreationStep * const packageStep
+             = m_runConfig->packageStep();
+         if (packageStep->isPackagingEnabled()) {
 -            const MaemoDeployable d(packageFilePath(),
 -                remoteDir() + '/' + packageFileName());
++            const MaemoDeployable d(packageFilePath(), remoteDir());
+             m_needsInstall = addDeployableIfNeeded(d);
          } else {
-             m_needsInstall = false;
-         }        
-         if (forDebugging
-             && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) {
-             const QFileInfo &info(m_runConfig->dumperLib());
-             m_deployables.append(Deployable(info.fileName(), info.canonicalPath(),
-                 &MaemoRunConfiguration::debuggingHelpersDeployed));
+             const MaemoPackageContents * const packageContents
+                 = packageStep->packageContents();
+             for (int i = 0; i < packageContents->rowCount(); ++i) {
+                 const MaemoDeployable &d = packageContents->deployableAt(i);
+                 if (addDeployableIfNeeded(d))
+                     m_needsInstall = true;
+             }
          }
  
 -                const MaemoDeployable d(m_runConfig->dumperLib(),
 -                    remoteDir() + '/' + dumperInfo.fileName());
+         if (forDebugging) {
+             QFileInfo dumperInfo(m_runConfig->dumperLib());
+             if (dumperInfo.exists()) {
++                const MaemoDeployable d(m_runConfig->dumperLib(), remoteDir());
+                 m_needsInstall = addDeployableIfNeeded(d);
+             }
+         }
          deploy();
      }
  }
  
 -            = QFileInfo(deployable.remoteFilePath).fileName();
+ bool AbstractMaemoRunControl::addDeployableIfNeeded(const MaemoDeployable &deployable)
+ {
+     if (m_runConfig->currentlyNeedsDeployment(m_devConfig.server.host,
+         deployable)) {
+         const QString fileName
 -            + QCryptographicHash::hash(deployable.remoteFilePath.toUtf8(),
++            = QFileInfo(deployable.localFilePath).fileName();
++        const QString remoteFilePath = deployable.remoteDir + '/' + fileName;
+         const QString sftpTargetFilePath = remoteDir() + '/' + fileName + '.'
 -        m_remoteLinks.insert(sftpTargetFilePath, deployable.remoteFilePath);
++            + QCryptographicHash::hash(remoteFilePath.toUtf8(),
+                   QCryptographicHash::Md5).toHex();
+         m_deployables.append(MaemoDeployable(deployable.localFilePath,
+             sftpTargetFilePath));
++        m_remoteLinks.insert(sftpTargetFilePath, remoteFilePath); // TODO fix merge mess
+         return true;
+     } else {
+         return false;
+     }
+ }
  void AbstractMaemoRunControl::deploy()
  {
      Core::ICore::instance()->progressManager()
      if (!m_deployables.isEmpty()) {
          QList<Core::SftpTransferInfo> deploySpecs;
          QStringList files;
-         foreach (const Deployable &deployable, m_deployables) {
-             const QString srcFilePath
-                 = deployable.dir % QDir::separator() % deployable.fileName;
-             const QString tgtFilePath
-                 = remoteDir() % QDir::separator() % deployable.fileName;
-             files << srcFilePath;
-             deploySpecs << Core::SftpTransferInfo(srcFilePath,
-                                tgtFilePath.toUtf8(), Core::SftpTransferInfo::Upload);
+         foreach (const MaemoDeployable &deployable, m_deployables) {
+             files << deployable.localFilePath;
++            const QString remoteFilePath = deployable.remoteDir + '/' + QFileInfo(deployable.localFilePath).fileName();
+             deploySpecs << Core::SftpTransferInfo(deployable.localFilePath,
 -                deployable.remoteFilePath.toUtf8(),
++                remoteFilePath.toUtf8(),
+                 Core::SftpTransferInfo::Upload);
          }
          emit appendMessage(this, tr("Files to deploy: %1.").arg(files.join(" ")), false);
          m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig.server, deploySpecs));
  
  void AbstractMaemoRunControl::handleFileCopied()
  {
-     Deployable deployable = m_deployables.takeFirst();
-     (m_runConfig->*deployable.updateTimestamp)(m_devConfig.server.host);
+     const MaemoDeployable &deployable = m_deployables.takeFirst();
+     m_runConfig->setDeployed(m_devConfig.server.host,
+         MaemoDeployable(deployable.localFilePath,
 -        m_remoteLinks.value(deployable.remoteFilePath)));
++        m_remoteLinks.value(deployable.remoteDir))); // TODO fix merge mess
      m_progress.setProgressValue(m_progress.progressValue() + 1);
  }
  
@@@ -243,44 -251,20 +243,44 @@@ int main(int argc, char *argv[]
  {
      QApplication app(argc, argv);
  
 +    if (argc != 1 && argc != 2) {
 +        qWarning() << "Usage: qmldump [path/to/plugin/directory]";
 +        return 1;
 +    }
 +
 +    QString pluginImportName;
 +    QString pluginImportPath;
 +    if (argc == 2) {
 +        QFileInfo pluginPath(argv[1]);
 +        if (pluginPath.exists() && pluginPath.isDir()) {
 +            pluginImportPath = pluginPath.absolutePath();
 +            pluginImportName = pluginPath.fileName();
 +        }
 +    }
 +
      QDeclarativeView view;
      QDeclarativeEngine *engine = view.engine();
-     importCode += "import org.webkit 1.0;\n";
 +    if (!pluginImportPath.isEmpty())
 +        engine->addImportPath(pluginImportPath);
 +
 +    QByteArray importCode;
 +    importCode += "import Qt 4.7;\n";
 +    importCode += "import Qt.labs.particles 4.7;\n";
 +    importCode += "import Qt.labs.gestures 4.7;\n";
 +    importCode += "import Qt.labs.folderlistmodel 4.7;\n";
++    importCode += "import QtWebKit 1.0;\n";
 +    if (!pluginImportName.isEmpty())
 +        importCode += QString("import %0 1.0;\n").arg(pluginImportName).toAscii();
  
      {
 -        QByteArray code;
 -        code += "import Qt 4.7;\n";
 -        code += "import Qt.labs.particles 4.7;\n";
 -        code += "import Qt.labs.gestures 4.7;\n";
 -        code += "import Qt.labs.folderlistmodel 4.7;\n";
 -        code += "import QtWebKit 1.0;\n";
 +        QByteArray code = importCode;
          code += "Item {}";
          QDeclarativeComponent c(engine);
 +
          c.setData(code, QUrl("xxx"));
          c.create();
 +        if (!c.errors().isEmpty())
 +            qDebug() << c.errorString();
      }
  
      cppToQml.insert("QString", "string");