mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-26 11:52:54 +00:00
241 lines
6.3 KiB
C++
241 lines
6.3 KiB
C++
/*
|
|
Copyright 2008 Hamish Rodda <rodda@kde.org>
|
|
Copyright 2009 Ramon Zarazua <killerfox512 gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "codegenerator.h"
|
|
|
|
#include "documentchangeset.h"
|
|
#include "duchainchangeset.h"
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <interfaces/icore.h>
|
|
#include <interfaces/idocumentcontroller.h>
|
|
|
|
#include <language/duchain/duchainlock.h>
|
|
|
|
#include <qtimer.h>
|
|
#include "applychangeswidget.h"
|
|
|
|
namespace KDevelop
|
|
{
|
|
|
|
class CodeGeneratorPrivate
|
|
{
|
|
public:
|
|
|
|
CodeGeneratorPrivate() : autoGen(false), context(0) {}
|
|
|
|
QMap<IndexedString, DUChainChangeSet *> duchainChanges;
|
|
DocumentChangeSet documentChanges;
|
|
|
|
bool autoGen;
|
|
DUContext * context;
|
|
DocumentRange range;
|
|
QString error;
|
|
};
|
|
|
|
CodeGeneratorBase::CodeGeneratorBase()
|
|
: d(new CodeGeneratorPrivate)
|
|
{
|
|
}
|
|
|
|
CodeGeneratorBase::~CodeGeneratorBase()
|
|
{
|
|
clearChangeSets();
|
|
delete d;
|
|
}
|
|
|
|
void CodeGeneratorBase::autoGenerate ( DUContext* context, const KDevelop::DocumentRange* range )
|
|
{
|
|
d->autoGen = true;
|
|
d->context = context;
|
|
d->range = *range;
|
|
}
|
|
|
|
|
|
void CodeGeneratorBase::addChangeSet(DUChainChangeSet * duchainChange)
|
|
{
|
|
IndexedString file = duchainChange->topDuContext().data()->url() ;
|
|
|
|
QMap<IndexedString, DUChainChangeSet *>::iterator it = d->duchainChanges.find(file);
|
|
|
|
//if we already have an entry for this file, merge it
|
|
if(it !=d->duchainChanges.end())
|
|
{
|
|
**it << *duchainChange;
|
|
delete duchainChange;
|
|
}
|
|
else
|
|
d->duchainChanges.insert(file, duchainChange);
|
|
}
|
|
|
|
void CodeGeneratorBase::addChangeSet(DocumentChangeSet & docChangeSet)
|
|
{
|
|
d->documentChanges << docChangeSet;
|
|
}
|
|
|
|
DocumentChangeSet & CodeGeneratorBase::documentChangeSet()
|
|
{
|
|
return d->documentChanges;
|
|
}
|
|
|
|
const QString & CodeGeneratorBase::errorText() const
|
|
{
|
|
return d->error;
|
|
}
|
|
|
|
bool CodeGeneratorBase::autoGeneration() const
|
|
{
|
|
return d->autoGen;
|
|
}
|
|
|
|
void CodeGeneratorBase::setErrorText(const QString & errorText)
|
|
{
|
|
d->error = errorText;
|
|
}
|
|
|
|
void CodeGeneratorBase::clearChangeSets()
|
|
{
|
|
kDebug() << "Cleaning up all the changesets registered by the generator";
|
|
foreach(DUChainChangeSet * changeSet, d->duchainChanges)
|
|
delete changeSet;
|
|
d->duchainChanges.clear();
|
|
|
|
d->documentChanges = DocumentChangeSet();
|
|
}
|
|
|
|
bool CodeGeneratorBase::execute()
|
|
{
|
|
kDebug() << "Checking Preconditions for the codegenerator";
|
|
|
|
//Shouldn't there be a method in iDocument to get a DocumentRange as well?
|
|
|
|
KUrl document;
|
|
if(!d->autoGen)
|
|
{
|
|
if( !ICore::self()->documentController()->activeDocument() )
|
|
{
|
|
setErrorText( i18n("Could not find an open document" ) );
|
|
return false;
|
|
}
|
|
|
|
document = ICore::self()->documentController()->activeDocument()->url();
|
|
|
|
if(d->range.isEmpty())
|
|
{
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
d->range = DocumentRange(document.url(), ICore::self()->documentController()->activeDocument()->textSelection());
|
|
}
|
|
}
|
|
|
|
if(!d->context)
|
|
{
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
TopDUContext * documentChain = DUChain::self()->chainForDocument(document);
|
|
if(!documentChain)
|
|
{
|
|
setErrorText(QString("Could not find chain for selected document: %1").arg(document.url()));
|
|
return false;
|
|
}
|
|
d->context = documentChain->findContextIncluding(d->range);
|
|
|
|
if(!d->context)
|
|
{
|
|
//Attempt to get the context again
|
|
QList<TopDUContext *> contexts = DUChain::self()->chainsForDocument(document);
|
|
foreach(TopDUContext * top, contexts)
|
|
{
|
|
kDebug() << "Checking top context with range: " << top->range().textRange() << " for a context";
|
|
if((d->context = top->findContextIncluding(d->range)))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!d->context)
|
|
{
|
|
setErrorText(i18n("Error finding context for selection range"));
|
|
return false;
|
|
}
|
|
|
|
if(!checkPreconditions(d->context,d->range))
|
|
{
|
|
setErrorText(i18n("Error checking conditions to generate code: %1",errorText()));
|
|
return false;
|
|
}
|
|
|
|
if(!d->autoGen)
|
|
{
|
|
kDebug() << "Gathering user information for the codegenerator";
|
|
if(!gatherInformation())
|
|
{
|
|
setErrorText(i18n("Error Gathering user information: %1",errorText()));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
kDebug() << "Generating code";
|
|
if(!process())
|
|
{
|
|
setErrorText(i18n("Error generating code: %1",errorText()));
|
|
return false;
|
|
}
|
|
|
|
if(!d->autoGen)
|
|
{
|
|
kDebug() << "Submitting to the user for review";
|
|
return displayChanges();
|
|
}
|
|
|
|
//If it is autogenerated, it shouldn't need to apply changes, instead return them to client that my be another generator
|
|
DocumentChangeSet::ChangeResult result(true);
|
|
if(!d->autoGen && !(result = d->documentChanges.applyAllChanges()))
|
|
{
|
|
setErrorText(result.m_failureReason);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CodeGeneratorBase::displayChanges()
|
|
{
|
|
DocumentChangeSet::ChangeResult result = d->documentChanges.applyAllToTemp();
|
|
if(!result)
|
|
{
|
|
setErrorText(result.m_failureReason);
|
|
return false;
|
|
}
|
|
|
|
ApplyChangesWidget widget;
|
|
//TODO: Find some good information to put
|
|
widget.setInformation("Info?");
|
|
|
|
QMap<IndexedString, IndexedString> temps = d->documentChanges.tempNamesForAll();
|
|
for(QMap<IndexedString, IndexedString>::iterator it = temps.begin();
|
|
it != temps.end(); ++it)
|
|
widget.addDocuments(it.key() , it.value());
|
|
|
|
if(widget.exec())
|
|
return widget.applyAllChanges();
|
|
else
|
|
return false;
|
|
}
|
|
|
|
}
|