Commit af199594 authored by dt's avatar dt

Adds dynamic ui completion. Wohoo :)

This means, creating a new project, we immediately have completion for
the ui file. Also adding stuff to the ui file now changes the codemodel
immediately.

Yet todo, are tests under windows and suppressing a warning if the form
contains a toplevel spacer.
parent 9c9b38e9
......@@ -24,5 +24,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
<dependency name="CppTools" version="1.1.80"/>
<dependency name="CppEditor" version="1.1.80"/>
<dependency name="Help" version="1.1.80"/>
<dependency name="Designer" version="1.1.80"/>
</dependencyList>
</plugin>
......@@ -34,6 +34,7 @@
#include "qt4nodes.h"
#include "qt4project.h"
#include "qt4projectmanager.h"
#include "qtuicodemodelsupport.h"
#include <projectexplorer/nodesvisitor.h>
#include <projectexplorer/filewatcher.h>
......@@ -540,13 +541,22 @@ Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project,
Qt4ProFileNode::~Qt4ProFileNode()
{
CppTools::CppModelManagerInterface *modelManager
= ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
end = m_uiCodeModelSupport.constEnd();
for (it = m_uiCodeModelSupport.constBegin(); it != end; ++it) {
modelManager->removeEditorSupport(it.value());
delete it.value();
}
}
void Qt4ProFileNode::buildStateChanged(ProjectExplorer::Project *project)
{
if (project == m_project && !ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(m_project))
updateUiFiles();
if (project == m_project && !ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(m_project)) {
QStringList filesToUpdate = updateUiFiles();
updateCodeModelSupportFromBuild(filesToUpdate);
}
}
bool Qt4ProFileNode::hasTargets() const
......@@ -717,6 +727,7 @@ void Qt4ProFileNode::update()
emit qt4Watcher->variablesChanged(this, m_varValues, newVarValues);
}
createUiCodeModelSupport();
updateUiFiles();
foreach (NodesWatcher *watcher, watchers())
......@@ -746,17 +757,16 @@ namespace {
}
// This function is triggered after a build, and updates the state ui files
// That is it adds files that didn't exist yet to the project tree, and calls
// updateSourceFiles() for files that changed
// It does so by storing a modification time for each ui file we know about.
// TODO this function should also be called if the build directory is changed
void Qt4ProFileNode::updateUiFiles()
QStringList Qt4ProFileNode::updateUiFiles()
{
qDebug()<<"Qt4ProFileNode::updateUiFiles()";
// Only those two project types can have ui files for us
if (m_projectType != ApplicationTemplate
&& m_projectType != LibraryTemplate)
return;
return QStringList();
// Find all ui files
FindUiFileNodesVisitor uiFilesVisitor;
......@@ -841,7 +851,8 @@ void Qt4ProFileNode::updateUiFiles()
m_uitimestamps.insert(file->path(), QFileInfo(file->path()).lastModified());
toUpdate << file->path();
// Also adding files depending on that.
// Also adding files depending on that
// We only need to do that for files that were newly created
QString fileName = QFileInfo(file->path()).fileName();
foreach (CPlusPlus::Document::Ptr doc, modelManager->snapshot()) {
if (doc->includedFiles().contains(fileName)) {
......@@ -852,7 +863,7 @@ void Qt4ProFileNode::updateUiFiles()
}
addFileNodes(toAdd, this);
}
m_project->addUiFilesToCodeModel(toUpdate);
return toUpdate;
}
ProFileReader *Qt4PriFileNode::createProFileReader() const
......@@ -1012,6 +1023,83 @@ void Qt4ProFileNode::invalidate()
emit qt4Watcher->projectTypeChanged(this, oldType, InvalidProject);
}
void Qt4ProFileNode::updateCodeModelSupportFromBuild(const QStringList &files)
{
qDebug()<<"Qt4ProFileNode::updateCodeModelSupportFromBuild"<<files;
foreach (const QString &file, files) {
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
end = m_uiCodeModelSupport.constEnd();
for (it = m_uiCodeModelSupport.constBegin(); it != end; ++it) {
if (it.value()->fileName() == file)
it.value()->updateFromBuild();
}
}
}
void Qt4ProFileNode::updateCodeModelSupportFromEditor(const QString &uiFileName, Designer::Internal::FormWindowEditor *fw)
{
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it;
it = m_uiCodeModelSupport.constFind(uiFileName);
if (it != m_uiCodeModelSupport.constEnd()) {
it.value()->updateFromEditor(fw);
}
foreach (ProjectExplorer::ProjectNode *pro, subProjectNodes())
if (Qt4ProFileNode *qt4proFileNode = qobject_cast<Qt4ProFileNode *>(pro))
qt4proFileNode->updateCodeModelSupportFromEditor(uiFileName, fw);
}
void Qt4ProFileNode::createUiCodeModelSupport()
{
qDebug()<<"creatUiCodeModelSupport()";
CppTools::CppModelManagerInterface *modelManager
= ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
// First move all to
QMap<QString, Qt4UiCodeModelSupport *> oldCodeModelSupport;
oldCodeModelSupport = m_uiCodeModelSupport;
m_uiCodeModelSupport.clear();
// Only those two project types can have ui files for us
if (m_projectType == ApplicationTemplate || m_projectType == LibraryTemplate) {
// Find all ui files
FindUiFileNodesVisitor uiFilesVisitor;
this->accept(&uiFilesVisitor);
const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
// Find the UiDir, there can only ever be one
QString uiDir = buildDir();
QStringList tmp = m_varValues[UiDirVar];
if (tmp.size() != 0)
uiDir = tmp.first();
foreach (FileNode *uiFile, uiFiles) {
const QString uiHeaderFilePath
= QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName());
qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path());
if (it != oldCodeModelSupport.end()) {
qDebug()<<"updated old codemodelsupport";
Qt4UiCodeModelSupport *cms = it.value();
cms->setFileName(uiHeaderFilePath);
m_uiCodeModelSupport.insert(it.key(), cms);
oldCodeModelSupport.erase(it);
} else {
qDebug()<<"adding new codemodelsupport";
Qt4UiCodeModelSupport *cms = new Qt4UiCodeModelSupport(modelManager, m_project, uiFile->path(), uiHeaderFilePath);
m_uiCodeModelSupport.insert(uiFile->path(), cms);
modelManager->addEditorSupport(cms);
}
}
}
// Remove old
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
end = oldCodeModelSupport.constEnd();
for (it = oldCodeModelSupport.constBegin(); it!=end; ++it) {
modelManager->removeEditorSupport(it.value());
delete it.value();
}
}
Qt4NodesWatcher::Qt4NodesWatcher(QObject *parent)
: NodesWatcher(parent)
......
......@@ -52,6 +52,12 @@ namespace ProjectExplorer {
class FileWatcher;
}
namespace Designer {
namespace Internal {
class FormWindowEditor;
}
}
namespace Qt4ProjectManager {
// Import base classes into namespace
......@@ -76,6 +82,7 @@ namespace Internal {
using ProjectExplorer::FileType;
class ProFileReader;
class Qt4UiCodeModelSupport;
// Type of projects
enum Qt4ProjectType {
......@@ -127,7 +134,6 @@ public:
//internal
ProFileReader *createProFileReader() const;
protected:
void clear();
static QStringList varNames(FileType type);
......@@ -165,6 +171,8 @@ private:
// watching changes to the .pro and .pri files on disk
ProjectExplorer::FileWatcher *m_fileWatcher;
QMap<QString, Qt4UiCodeModelSupport *> m_uiCodeModelSupport;
// managed by Qt4ProFileNode
friend class Qt4ProFileNode;
};
......@@ -186,6 +194,8 @@ public:
QStringList variableValue(const Qt4Variable var) const;
void updateCodeModelSupportFromBuild(const QStringList &files);
void updateCodeModelSupportFromEditor(const QString &uiFileName, Designer::Internal::FormWindowEditor *fw);
public slots:
void scheduleUpdate();
void update();
......@@ -193,7 +203,8 @@ private slots:
void buildStateChanged(ProjectExplorer::Project*);
private:
void updateUiFiles();
void createUiCodeModelSupport();
QStringList updateUiFiles();
Qt4ProFileNode *createSubProFileNode(const QString &path);
QStringList uiDirPaths(ProFileReader *reader) const;
......
......@@ -245,10 +245,6 @@ Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
m_updateCodeModelTimer.setSingleShot(true);
m_updateCodeModelTimer.setInterval(20);
connect(&m_updateCodeModelTimer, SIGNAL(timeout()), this, SLOT(updateCodeModel()));
m_addUiFilesTimer.setSingleShot(true);
m_addUiFilesTimer.setInterval(20);
connect(&m_addUiFilesTimer, SIGNAL(timeout()), this, SLOT(addUiFiles()));
}
Qt4Project::~Qt4Project()
......@@ -376,27 +372,6 @@ namespace {
};
}
void Qt4Project::addUiFilesToCodeModel(const QStringList &files)
{
// if we already have a full updateCodeModel() scheduled
// then we don't need to this seperately
// since that one will add also all the ui files
if (m_updateCodeModelTimer.isActive())
return;
m_addUiFilesTimer.start();
m_uiFilesToAdd << files;
}
void Qt4Project::addUiFiles()
{
if (m_updateCodeModelTimer.isActive())
return;
CppTools::CppModelManagerInterface *modelManager =
ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
modelManager->updateSourceFiles(m_uiFilesToAdd);
m_uiFilesToAdd.clear();
}
void Qt4Project::scheduleUpdateCodeModel(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
{
m_updateCodeModelTimer.start();
......
......@@ -184,9 +184,6 @@ public:
void notifyChanged(const QString &name);
// called by qt4ProjectNode to add ui_*.h files to the codemodel
void addUiFilesToCodeModel(const QStringList &files);
QString makeCommand(const QString &buildConfiguration) const;
// Is called by qmakestep qt4configurationwidget if the settings change
......@@ -253,8 +250,6 @@ private:
Internal::Qt4ProjectFiles *m_projectFiles;
QTimer m_updateCodeModelTimer;
QTimer m_addUiFilesTimer;
QStringList m_uiFilesToAdd;
QList<Qt4ProjectManager::Internal::Qt4ProFileNode *> m_proFilesForCodeModelUpdate;
QMap<QString, Internal::CodeModelInfo> m_codeModelInfo;
......
......@@ -47,6 +47,7 @@
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/listutils.h>
#include <designer/formwindoweditor.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
......@@ -81,7 +82,9 @@ Qt4Manager::Qt4Manager(Qt4ProjectManagerPlugin *plugin)
m_plugin(plugin),
m_projectExplorer(0),
m_contextProject(0),
m_languageID(0)
m_languageID(0),
m_lastEditor(0),
m_dirty(false)
{
m_languageID = Core::UniqueIDManager::instance()->
uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
......@@ -110,6 +113,64 @@ void Qt4Manager::notifyChanged(const QString &name)
void Qt4Manager::init()
{
m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
this, SLOT(editorAboutToClose(Core::IEditor*)));
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
this, SLOT(editorChanged(Core::IEditor*)));
foreach(Core::IEditor *editor, Core::EditorManager::instance()->openedEditors())
editorOpened(editor);
}
void Qt4Manager::editorChanged(Core::IEditor *editor)
{
// Handle old editor
Designer::Internal::FormWindowEditor *lastEditor = qobject_cast<Designer::Internal::FormWindowEditor *>(m_lastEditor);
if (lastEditor) {
disconnect(lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
if (m_dirty) {
foreach(Qt4Project *project, m_projects)
project->rootProjectNode()->updateCodeModelSupportFromEditor(lastEditor->file()->fileName(), lastEditor);
m_dirty = false;
}
}
m_lastEditor = editor;
// Handle new editor
if (Designer::Internal::FormWindowEditor *fw = qobject_cast<Designer::Internal::FormWindowEditor *>(editor))
connect(fw, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
}
void Qt4Manager::editorAboutToClose(Core::IEditor *editor)
{
if (m_lastEditor == editor) {
// Oh no our editor is going to be closed
// get the content first
Designer::Internal::FormWindowEditor *lastEditor = qobject_cast<Designer::Internal::FormWindowEditor *>(m_lastEditor);
if (lastEditor) {
disconnect(lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
if (m_dirty) {
foreach(Qt4Project *project, m_projects)
project->rootProjectNode()->updateCodeModelSupportFromEditor(lastEditor->file()->fileName(), lastEditor);
m_dirty = false;
}
}
m_lastEditor = 0;
}
}
void Qt4Manager::uiEditorContentsChanged()
{
// cast sender, get filename
if (m_dirty)
return;
Designer::Internal::FormWindowEditor *fw = qobject_cast<Designer::Internal::FormWindowEditor *>(sender());
if (!fw)
return;
m_dirty = true;
}
int Qt4Manager::projectContext() const
......
......@@ -36,6 +36,10 @@
#include <QtCore/QModelIndex>
namespace Core {
class IEditor;
}
namespace ExtensionSystem {
class PluginManager;
}
......@@ -92,6 +96,12 @@ public slots:
void runQMake();
void runQMakeContextMenu();
private slots:
void editorOpened(Core::IEditor *editor);
void editorAboutToClose(Core::IEditor *editor);
void uiEditorContentsChanged();
void editorChanged(Core::IEditor*);
private:
QList<Qt4Project *> m_projects;
void runQMake(ProjectExplorer::Project *p);
......@@ -104,7 +114,8 @@ private:
ProjectExplorer::Project *m_contextProject;
int m_languageID;
Core::IEditor *m_lastEditor;
bool m_dirty;
};
} // namespace Qt4ProjectManager
......
......@@ -34,9 +34,10 @@ HEADERS = qt4projectmanagerplugin.h \
speinfo.h \
qt4projectconfigwidget.h \
qt4buildenvironmentwidget.h \
projectloadwizard.h\
qtversionmanager.h\
qtoptionspage.h
projectloadwizard.h \
qtversionmanager.h \
qtoptionspage.h \
qtuicodemodelsupport.h
SOURCES = qt4projectmanagerplugin.cpp \
qt4projectmanager.cpp \
qt4project.cpp \
......@@ -66,9 +67,10 @@ SOURCES = qt4projectmanagerplugin.cpp \
speinfo.cpp \
qt4projectconfigwidget.cpp \
qt4buildenvironmentwidget.cpp \
projectloadwizard.cpp\
qtversionmanager.cpp\
qtoptionspage.cpp
projectloadwizard.cpp \
qtversionmanager.cpp \
qtoptionspage.cpp \
qtuicodemodelsupport.cpp
FORMS = envvariablespage.ui \
enveditdialog.ui \
proeditorcontainer.ui \
......@@ -77,11 +79,10 @@ FORMS = envvariablespage.ui \
qt4projectconfigwidget.ui \
embeddedpropertiespage.ui \
qt4buildenvironmentwidget.ui \
qtversionmanager.ui\
qtversionmanager.ui \
showbuildlog.ui
RESOURCES = qt4projectmanager.qrc \
wizards/wizards.qrc
include(../../shared/proparser/proparser.pri)
DEFINES += QT_NO_CAST_TO_ASCII
OTHER_FILES += Qt4ProjectManager.pluginspec
......@@ -2,3 +2,4 @@ include(../../plugins/projectexplorer/projectexplorer.pri)
include(../../plugins/cpptools/cpptools.pri)
include(../../plugins/cppeditor/cppeditor.pri)
include(../../plugins/help/help.pri)
include(../../plugins/designer/designer.pri)
......@@ -384,6 +384,7 @@ void QtVersion::setPath(const QString &path)
m_versionInfoUpToDate = false;
m_mkspecUpToDate = false;
m_qmakeCommand = QString::null;
m_uicCommand = QString::null;
// TODO do i need to optimize this?
m_hasDebuggingHelper = !debuggingHelperLibrary().isEmpty();
}
......@@ -753,6 +754,29 @@ QString QtVersion::qmakeCommand() const
return QString::null;
}
QString QtVersion::uicCommand() const
{
if (!isValid())
return QString::null;
if (!m_uicCommand.isNull())
return m_uicCommand;
QString qtdirbin = versionInfo().value("QT_INSTALL_BINS") + "/";
QStringList possibleCommands;
#ifdef Q_OS_WIN
possibleCommands<< "uic.exe";
#else
possibleCommands << "uic-qt4" << "uic4" << "uic" ;
#endif
foreach (const QString &possibleCommand, possibleCommands) {
const QString &fullPath = qtdirbin + possibleCommand;
if (QFileInfo(fullPath).exists()) {
m_uicCommand = QDir::cleanPath(fullPath);
return m_uicCommand;
}
}
return QString::null;
}
ProjectExplorer::ToolChain::ToolChainType QtVersion::toolchainType() const
{
if (!isValid())
......
......@@ -64,6 +64,7 @@ public:
QString mkspec() const;
QString mkspecPath() const;
QString qmakeCommand() const;
QString uicCommand() const;
QString qtVersionString() const;
// Returns the PREFIX, BINPREFIX, DOCPREFIX and similar information
QHash<QString,QString> versionInfo() const;
......@@ -109,7 +110,6 @@ private:
mutable QString m_mkspec; // updated lazily
mutable QString m_mkspecFullPath;
QString m_mingwDirectory;
QString m_prependPath;
QString m_msvcVersion;
mutable QHash<QString,QString> m_versionInfo; // updated lazily
int m_id;
......@@ -118,6 +118,7 @@ private:
mutable bool m_defaultConfigIsDebug;
mutable bool m_defaultConfigIsDebugAndRelease;
mutable QString m_qmakeCommand;
mutable QString m_uicCommand;
// This is updated on first call to qmakeCommand
// That function is called from updateVersionInfo()
mutable QString m_qtVersionString;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment