summaryrefslogtreecommitdiffstats
path: root/parts/astyle/astyle_part.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parts/astyle/astyle_part.cpp')
-rw-r--r--parts/astyle/astyle_part.cpp541
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"