diff options
Diffstat (limited to 'parts/astyle/astyle_part.cpp')
-rw-r--r-- | parts/astyle/astyle_part.cpp | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/parts/astyle/astyle_part.cpp b/parts/astyle/astyle_part.cpp new file mode 100644 index 00000000..526af170 --- /dev/null +++ b/parts/astyle/astyle_part.cpp @@ -0,0 +1,541 @@ +#include "astyle_part.h" + +#include <qwhatsthis.h> +#include <qvbox.h> +#include <qtextstream.h> +#include <qpopupmenu.h> +#include <kdeversion.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kdevgenericfactory.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kparts/part.h> +#include <kparts/partmanager.h> +#include <ktexteditor/editinterface.h> +#include <ktexteditor/document.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/selectioninterface.h> +#include <kprogress.h> +#include <kdevcore.h> +#include <kdevapi.h> +#include <kdevpartcontroller.h> +#include <kdevplugininfo.h> +#include <configwidgetproxy.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <qlineedit.h> +#include <qregexp.h> + +#include "astyle_widget.h" +#include "astyle_adaptor.h" + +static const KDevPluginInfo data("kdevastyle"); + +namespace { + const char* defaultFormatExtensions = "*.cpp *.h *.hpp,*.c *.h,*.cxx *.hxx,*.c++ *.h++,*.cc *.hh,*.C *.H,*.diff ,*.inl,*.java,*.moc,*.patch,*.tlh,*.xpm"; +} + + +typedef KDevGenericFactory<AStylePart> AStyleFactory; +K_EXPORT_COMPONENT_FACTORY( libkdevastyle, AStyleFactory( data ) ) + +AStylePart::AStylePart(QObject *parent, const char *name, const QStringList &) + : KDevSourceFormatter(&data, parent, name ? name : "AStylePart") +{ + setInstance(AStyleFactory::instance()); + + setXMLFile("kdevpart_astyle.rc"); + + formatTextAction = new KAction(i18n("&Reformat Source"), 0, this, SLOT(beautifySource()), actionCollection(), "edit_astyle"); + formatTextAction->setEnabled(false); + formatTextAction->setToolTip(i18n("Reformat source")); + formatTextAction->setWhatsThis(i18n("<b>Reformat source</b><p>Source reformatting functionality using <b>astyle</b> library. " + "Also available in <b>New Class</b> and <b>Subclassing</b> wizards.")); + + formatFileAction = new KAction(i18n("Format files"), 0, this, SLOT(formatFilesSelect()), actionCollection(), "tools_astyle"); + formatFileAction->setEnabled(false); + formatFileAction->setToolTip(i18n("Format files")); + formatFileAction->setWhatsThis(i18n("<b>Fomat files</b><p>Formatting functionality using <b>astyle</b> library. " + "Also available in <b>New Class</b> and <b>Subclassing</b> wizards.")); + formatFileAction->setEnabled ( true ); + + m_configProxy = new ConfigWidgetProxy(core()); + m_configProxy->createGlobalConfigPage(i18n("Formatting"), GLOBALDOC_OPTIONS, info()->icon()); + m_configProxy->createProjectConfigPage(i18n("Formatting"), PROJECTDOC_OPTIONS, info()->icon()); + + + connect(m_configProxy, SIGNAL(insertConfigWidget(const KDialogBase* ,QWidget*,unsigned int)), this, SLOT(insertConfigWidget(const KDialogBase*,QWidget*,unsigned int))); + + connect(partController(), SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(activePartChanged(KParts::Part*))); + + connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), this, SLOT(contextMenu(QPopupMenu *, const Context *)) ); + + loadGlobal(); + //use the globals first, project level will override later.. + m_project=m_global; + m_projectExtensions = m_globalExtensions; + setExtensions(m_globalExtensions.join("\n"),false); + + // maybe there is a file open already + activePartChanged( partController()->activePart() ); + +} + +void AStylePart::loadGlobal() +{ +// kdDebug(9009) << "Load global"<<endl; + KConfig *config = kapp->config(); + config->setGroup("AStyle"); + QString options = config->readEntry("Options","BlockBreak=0,BlockBreakAll=0,BlockIfElse=0,Brackets=Break,BracketsCloseHeaders=0,FStyle=UserDefined,Fill=Tabs,FillCount=4,FillEmptyLines=0,FillForce=0,IndentBlocks=0,IndentBrackets=0,IndentCases=0,IndentClasses=1,IndentLabels=1,IndentNamespaces=1,IndentPreprocessors=0,IndentSwitches=1,KeepBlocks=1,KeepStatements=1,MaxStatement=40,MinConditional=-1,PadOperators=0,PadParenthesesIn=1,PadParenthesesOut=1,PadParenthesesUn=1,"); + m_globalExtensions=QStringList::split(",",config->readEntry("Extensions",defaultFormatExtensions)); + + QStringList pairs = QStringList::split( ",", options); + QStringList::Iterator it; + for ( it = pairs.begin(); it != pairs.end(); ++it ) { + QStringList bits = QStringList::split( "=", (*it) ); + m_global[bits[0]] = bits[1]; + } + + +// for (QMap<QString, QVariant>::iterator iter = m_global.begin();iter != m_global.end();iter++) +// { +// kdDebug(9009) << "load: " <<iter.key() << "="<< iter.data() << endl; +// } +} + +void AStylePart::saveGlobal() +{ + QString options; + for (QMap<QString, QVariant>::iterator iter = m_global.begin();iter != m_global.end();iter++) + { +// kdDebug(9009) <<"saveGlobal" <<iter.key() << "="<< iter.data() << endl; + options += iter.key(); + options += "="; + options += iter.data().toString(); + options += ","; + } +// for (QMap<QString, QVariant>::iterator iter = m_project.begin();iter != m_project.end();iter++) +// { +// kdDebug(9009) << "project before: " <<iter.key() << "="<< iter.data() << endl; +// } + + KConfig *config = kapp->config(); + config->setGroup("AStyle"); + config->writeEntry("Options",options); + config->writeEntry("Extensions",m_globalExtensions.join(",")); + + config->sync(); +// for (QMap<QString, QVariant>::iterator iter = m_global.begin();iter != m_global.end();iter++) +// { +// kdDebug(9009) << "global after: " <<iter.key() << "="<< iter.data() << endl; +// } +// for (QMap<QString, QVariant>::iterator iter = m_project.begin();iter != m_project.end();iter++) +// { +// kdDebug(9009) << "project after: " <<iter.key() << "="<< iter.data() << endl; +// } +} + +AStylePart::~AStylePart() +{ + saveGlobal(); + delete m_configProxy; +} + +void AStylePart::beautifySource() +{ + KTextEditor::EditInterface *iface + = dynamic_cast<KTextEditor::EditInterface*>(partController()->activePart()); + if (!iface) + return; + + bool has_selection = false; + + KTextEditor::SelectionInterface *sel_iface + = dynamic_cast<KTextEditor::SelectionInterface*>(partController()->activePart()); + if (sel_iface && sel_iface->hasSelection()) + has_selection = true; + + //if there is a selection, we only format it. + ASStringIterator is(has_selection ? sel_iface->selection() : iface->text()); + KDevFormatter formatter(m_project); + + formatter.init(&is); + + QString output; + QTextStream os(&output, IO_WriteOnly); + + // put the selection back to the same indent level. + // taking note of the config options. + unsigned int indentCount=0; + QString indentWith(""); + if ( has_selection){ + QString original = sel_iface->selection(); + for (;indentCount<original.length();indentCount++){ + QChar ch = original[indentCount]; + if ( ch.isSpace()){ + if ( ch == QChar('\n') || ch == QChar('\r')){ + indentWith=""; + } + else{ + indentWith+=original[indentCount]; + } + } + else{ + break; + } + } + + int wsCount = m_project["FillCount"].toInt(); + if (m_project["Fill"].toString() == "Tabs") + { + // tabs and wsCount spaces to be a tab + QString replace; + for (int i =0;i<wsCount;i++) + replace+=' '; + + indentWith=indentWith.replace(replace, QChar('\t')); + indentWith=indentWith.remove(' '); + } else + { + if ( m_project["FillForce"].toBool()){ + //convert tabs to spaces + QString replace; + for (int i =0;i<wsCount;i++) + replace+=' '; + + indentWith=indentWith.replace(QChar('\t'),replace); + } + } + } + + while (formatter.hasMoreLines()){ + if ( has_selection ){ + os << indentWith; + } + os << QString::fromUtf8(formatter.nextLine().c_str()) << endl; + } + + uint col = 0; + uint line = 0; + + if(has_selection) //there was a selection, so only change the part of the text related to it + { + //remove the final newline character, unless it should be there + if ( !sel_iface->selection().endsWith( "\n" ) ) + output.setLength(output.length()-1); + + sel_iface->removeSelectedText(); + cursorPos( partController()->activePart(), &col, &line ); + iface->insertText( col, line, output); + + return; + } + + cursorPos( partController()->activePart(), &col, &line ); + + iface->setText( output ); + + setCursorPos( partController()->activePart(), col, line ); +} + +void AStylePart::insertConfigWidget(const KDialogBase *dlg, QWidget *page, unsigned int pageNo) +{ + switch (pageNo) + { + case GLOBALDOC_OPTIONS: + { + AStyleWidget *w = new AStyleWidget(this, true, page, "astyle config widget"); + connect(dlg, SIGNAL(okClicked()), w, SLOT(accept())); + break; + } + case PROJECTDOC_OPTIONS: + { + AStyleWidget *w = new AStyleWidget(this, false, page, "astyle config widget"); + connect(dlg, SIGNAL(okClicked()), w, SLOT(accept())); + break; + } + } +} + +QString AStylePart::getGlobalExtensions(){ + QString values = m_globalExtensions.join("\n"); + return values.stripWhiteSpace(); +} +QString AStylePart::getProjectExtensions(){ + QString values = m_projectExtensions.join("\n"); + return values.stripWhiteSpace(); +} + + +/** + * Extensions from the widget passed in. + * We preserve the order, so common extensions will + * end up at the top + * @param ext + */ +void AStylePart::setExtensions ( QString ext, bool global ) +{ + kdDebug(9009) << "setExtensions " << ext<<endl; + if ( global){ + m_globalExtensions.clear(); + m_globalExtensions=QStringList::split ( QRegExp("\n"), ext ); + } + else{ + m_searchExtensions.clear(); + m_projectExtensions.clear(); + m_projectExtensions = QStringList::split ( QRegExp("\n"), ext ); + QStringList bits = QStringList::split(QRegExp("\\s+"),ext); + for ( QStringList::Iterator iter = bits.begin(); iter != bits.end(); iter++ ) + { + QString ending=*iter; + if ( ending.startsWith ( "*" ) ) + { + if (ending.length() ==1 ){ + // special case.. any file. + m_searchExtensions.insert(ending, ending); + } + else{ + m_searchExtensions.insert( ending.mid( 1 ), ending); + } + } + else + { + m_searchExtensions.insert(ending, ending); + } + } + } +} + +void AStylePart::activePartChanged ( KParts::Part *part ) +{ + bool enabled = false; + + KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*> ( part ); + + if ( rw_part ) + { + KTextEditor::EditInterface *iface = dynamic_cast<KTextEditor::EditInterface*> ( rw_part ); + + if ( iface ) + { + // check for the everything case.. + if ( m_searchExtensions.find ( "*" ) == m_searchExtensions.end() ) + { + QString extension = rw_part->url().path(); + int pos = extension.findRev ( '.' ); + if ( pos >= 0 ) + { + extension = extension.mid ( pos ); + enabled = ( m_searchExtensions.find ( extension ) != m_searchExtensions.end() ); + } + } + else + { + enabled = true; + } + } + } + + formatTextAction->setEnabled ( enabled ); +} + +QString AStylePart::formatSource( const QString text, AStyleWidget * widget, const QMap<QString, QVariant>& options ) +{ + ASStringIterator is(text); + KDevFormatter * formatter = ( widget)? new KDevFormatter( widget ) : new KDevFormatter(options); + + formatter->init(&is); + + QString output; + QTextStream os(&output, IO_WriteOnly); + + while ( formatter->hasMoreLines() ) + os << QString::fromUtf8( formatter->nextLine().c_str() ) << endl; + + delete formatter; + + return output; +} + +void AStylePart::cursorPos( KParts::Part *part, uint * line, uint * col ) +{ + if (!part || !part->inherits("KTextEditor::Document")) return; + + KTextEditor::ViewCursorInterface *iface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); + if (iface) + { + iface->cursorPositionReal( line, col ); + } +} + +void AStylePart::setCursorPos( KParts::Part *part, uint line, uint col ) +{ + if (!part || !part->inherits("KTextEditor::Document")) return; + + KTextEditor::ViewCursorInterface *iface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); + if (iface) + { + iface->setCursorPositionReal( line, col ); + } +} + +QString AStylePart::formatSource( const QString text ) +{ + return formatSource(text, 0, m_project); +} + +QString AStylePart::indentString( ) const +{ + KDevFormatter formatter(m_project); + return formatter.indentString(); +} + +void AStylePart::contextMenu(QPopupMenu *popup, const Context *context) +{ + if (context->hasType( Context::EditorContext )) + { + popup->insertSeparator(); + int id = popup->insertItem( i18n("Format selection"), this, SLOT(beautifySource()) ); + popup->setWhatsThis(id, i18n("<b>Format</b><p>Formats the current selection, if possible")); + } + else if ( context->hasType( Context::FileContext )){ + const FileContext *ctx = static_cast<const FileContext*>(context); + m_urls = ctx->urls(); + + popup->insertSeparator(); + int id = popup->insertItem( i18n("Format files"), this, SLOT(formatFiles()) ); + popup->setWhatsThis(id, i18n("<b>Format files</b><p>Formats selected files if possible")); + + } +} + +void AStylePart::restorePartialProjectSession(const QDomElement * el) +{ + kdDebug(9009) << "Load project" << endl; + QDomElement style = el->namedItem("AStyle").toElement(); + + if (style.attribute("FStyle", "GLOBAL") == "GLOBAL") + { + m_project = m_global; + m_project["FStyle"] = "GLOBAL"; + m_projectExtensions=m_globalExtensions; + } + else + { + for (QMap<QString, QVariant>::iterator iter = m_global.begin();iter != m_global.end();iter++) + { + m_project[iter.key()] = style.attribute(iter.key(),iter.data().toString()); + } + + QDomElement exten = el->namedItem("Extensions").toElement(); + QString ext = exten.attribute("ext").simplifyWhiteSpace(); + if ( ext.isEmpty()){ + ext=defaultFormatExtensions; + } + setExtensions(ext.replace(QChar(','), QChar('\n')),false); + } +} + + +void AStylePart::savePartialProjectSession(QDomElement * el) +{ + QDomDocument domDoc = el->ownerDocument(); + if (domDoc.isNull()) + return; + + QDomElement style = domDoc.createElement("AStyle"); + style.setAttribute("FStyle", m_project["FStyle"].toString()); + if (m_project["FStyle"] != "GLOBAL") + { + for (QMap<QString, QVariant>::iterator iter = m_project.begin();iter != m_project.end();iter++) + { + style.setAttribute(iter.key(),iter.data().toString()); + } + QDomElement exten = domDoc.createElement ( "Extensions" ); + exten.setAttribute ( "ext", m_projectExtensions.join(",").simplifyWhiteSpace() ); + el->appendChild(exten); + } + el->appendChild(style); +} + +void AStylePart::formatFilesSelect(){ + m_urls.clear(); + QStringList filenames = KFileDialog::getOpenFileNames ( QString::null, getProjectExtensions(),0,"Select files to format" ); + + for(QStringList::Iterator it = filenames.begin(); it != filenames.end();it++){ + m_urls << *it; + } + formatFiles(); +} + + +/** + * Format the selected files with the current style. + */ +void AStylePart::formatFiles() +{ + KURL::List::iterator it = m_urls.begin(); + while ( it != m_urls.end() ) + { + kdDebug ( 9009 ) << "Selected " << ( *it ).pathOrURL() << endl; + ++it; + } + + uint processed = 0; + for ( uint fileCount = 0; fileCount < m_urls.size(); fileCount++ ) + { + QString fileName = m_urls[fileCount].pathOrURL(); + + bool found = false; + for ( QMap<QString, QString>::Iterator it = m_searchExtensions.begin(); it != m_searchExtensions.end(); ++it ) + { + QRegExp re ( it.data(), true, true ); + if ( re.search ( fileName ) == 0 && ( uint ) re.matchedLength() == fileName.length() ) + { + found = true; + break; + } + } + + if ( found ) + { + QString backup = fileName + "#"; + QFile fin ( fileName ); + QFile fout ( backup ); + if ( fin.open ( IO_ReadOnly ) ) + { + if ( fout.open ( IO_WriteOnly ) ) + { + QString fileContents ( fin.readAll() ); + fin.close(); + QTextStream outstream ( &fout ); + outstream << formatSource ( fileContents ); + fout.close(); + QDir().rename ( backup, fileName ); + processed++; + } + else + { + KMessageBox::sorry ( 0, i18n ( "Not able to write %1" ).arg ( backup ) ); + } + } + else + { + KMessageBox::sorry ( 0, i18n ( "Not able to read %1" ).arg ( fileName ) ); + } + } + } + if ( processed != 0 ) + { + KMessageBox::information ( 0, i18n ( "Processed %1 files ending with extensions %2" ).arg ( processed ).arg(getProjectExtensions().stripWhiteSpace()) ); + } + m_urls.clear(); + +} + + +#include "astyle_part.moc" |