kate Library API Documentation

katesyntaxdocument.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00003    Copyright (C) 2000 Scott Manson <sdmanson@alltel.net>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include "katesyntaxdocument.h"
00021 
00022 #include <kdebug.h>
00023 #include <kstandarddirs.h>
00024 #include <klocale.h>
00025 #include <kmessagebox.h>
00026 #include <kconfig.h>
00027 
00028 #include <qfile.h>
00029 
00033 SyntaxDocument::SyntaxDocument(bool force)
00034   : QDomDocument()
00035 {
00036   // Let's build the Mode List (katesyntaxhighlightingrc)
00037   setupModeList(force);
00038   myModeList.setAutoDelete( true );
00039 }
00040 
00044 SyntaxDocument::~SyntaxDocument()
00045 {
00046 }
00047 
00052 bool SyntaxDocument::setIdentifier(const QString& identifier)
00053 {
00054   // if the current file is the same as the new one don't do anything.
00055   if(currentFile != identifier)
00056   {
00057     // let's open the new file
00058     QFile f( identifier );
00059 
00060     if ( f.open(IO_ReadOnly) )
00061     {
00062       // Let's parse the contets of the xml file
00063       /* The result of this function should be check for robustness,
00064          a false returned means a parse error */
00065       QString errorMsg;
00066       int line, col;
00067       bool success=setContent(&f,&errorMsg,&line,&col);
00068 
00069       // Ok, now the current file is the pretended one (identifier)
00070       currentFile = identifier;
00071 
00072       // Close the file, is not longer needed
00073       f.close();
00074 
00075       if (!success)
00076       {
00077         KMessageBox::error(0L,i18n("<qt>The error <b>%4</b><br> has been detected in the file %1 at %2/%3</qt>").arg(identifier)
00078             .arg(line).arg(col).arg(i18n("QXml",errorMsg.utf8())));
00079         return false;
00080       }
00081     }
00082     else
00083     {
00084       // Oh o, we couldn't open the file.
00085       KMessageBox::error( 0L, i18n("Unable to open %1").arg(identifier) );
00086       return false;
00087     }
00088   }
00089   return true;
00090 }
00091 
00094 SyntaxModeList SyntaxDocument::modeList()
00095 {
00096   return myModeList;
00097 }
00098 
00102 bool SyntaxDocument::nextGroup( syntaxContextData* data)
00103 {
00104   if(!data)
00105     return false;
00106 
00107   // No group yet so go to first child
00108   if (data->currentGroup.isNull())
00109   {
00110     // Skip over non-elements. So far non-elements are just comments
00111     QDomNode node = data->parent.firstChild();
00112     while (node.isComment())
00113       node = node.nextSibling();
00114 
00115     data->currentGroup = node.toElement();
00116   }
00117   else
00118   {
00119     // common case, iterate over siblings, skipping comments as we go
00120     QDomNode node = data->currentGroup.nextSibling();
00121     while (node.isComment())
00122       node = node.nextSibling();
00123 
00124     data->currentGroup = node.toElement();
00125   }
00126 
00127   return !data->currentGroup.isNull();
00128 }
00129 
00133 bool SyntaxDocument::nextItem( syntaxContextData* data)
00134 {
00135   if(!data)
00136     return false;
00137 
00138   if (data->item.isNull())
00139   {
00140     QDomNode node = data->currentGroup.firstChild();
00141     while (node.isComment())
00142       node = node.nextSibling();
00143 
00144     data->item = node.toElement();
00145   }
00146   else
00147   {
00148     QDomNode node = data->item.nextSibling();
00149     while (node.isComment())
00150       node = node.nextSibling();
00151 
00152     data->item = node.toElement();
00153   }
00154 
00155   return !data->item.isNull();
00156 }
00157 
00161 QString SyntaxDocument::groupItemData( const syntaxContextData* data, const QString& name){
00162   if(!data)
00163     return QString::null;
00164 
00165   // If there's no name just return the tag name of data->item
00166   if ( (!data->item.isNull()) && (name.isEmpty()))
00167   {
00168     return data->item.tagName();
00169   }
00170 
00171   // if name is not empty return the value of the attribute name
00172   if (!data->item.isNull())
00173   {
00174     return data->item.attribute(name);
00175   }
00176 
00177   return QString::null;
00178 
00179 }
00180 
00181 QString SyntaxDocument::groupData( const syntaxContextData* data,const QString& name)
00182 {
00183   if(!data)
00184     return QString::null;
00185 
00186   if (!data->currentGroup.isNull())
00187   {
00188     return data->currentGroup.attribute(name);
00189   }
00190   else
00191   {
00192     return QString::null;
00193   }
00194 }
00195 
00196 void SyntaxDocument::freeGroupInfo( syntaxContextData* data)
00197 {
00198   if (data)
00199     delete data;
00200 }
00201 
00202 syntaxContextData* SyntaxDocument::getSubItems(syntaxContextData* data)
00203 {
00204   syntaxContextData *retval = new syntaxContextData;
00205 
00206   if (data != 0)
00207   {
00208     retval->parent = data->currentGroup;
00209     retval->currentGroup = data->item;
00210   }
00211 
00212   return retval;
00213 }
00214 
00215 bool SyntaxDocument::getElement (QDomElement &element, const QString &mainGroupName, const QString &config)
00216 {
00217   kdDebug(13010) << "Looking for \"" << mainGroupName << "\" -> \"" << config << "\"." << endl;
00218 
00219   QDomNodeList nodes = documentElement().childNodes();
00220 
00221   // Loop over all these child nodes looking for mainGroupName
00222   for (unsigned int i=0; i<nodes.count(); i++)
00223   {
00224     QDomElement elem = nodes.item(i).toElement();
00225     if (elem.tagName() == mainGroupName)
00226     {
00227       // Found mainGroupName ...
00228       QDomNodeList subNodes = elem.childNodes();
00229 
00230       // ... so now loop looking for config
00231       for (unsigned int j=0; j<subNodes.count(); j++)
00232       {
00233         QDomElement subElem = subNodes.item(j).toElement();
00234         if (subElem.tagName() == config)
00235         {
00236           // Found it!
00237           element = subElem;
00238           return true;
00239         }
00240       }
00241 
00242       kdDebug(13010) << "WARNING: \""<< config <<"\" wasn't found!" << endl;
00243       return false;
00244     }
00245   }
00246 
00247   kdDebug(13010) << "WARNING: \""<< mainGroupName <<"\" wasn't found!" << endl;
00248   return false;
00249 }
00250 
00255 syntaxContextData* SyntaxDocument::getConfig(const QString& mainGroupName, const QString &config)
00256 {
00257   QDomElement element;
00258   if (getElement(element, mainGroupName, config))
00259   {
00260     syntaxContextData *data = new syntaxContextData;
00261     data->item = element;
00262     return data;
00263   }
00264   return 0;
00265 }
00266 
00271 syntaxContextData* SyntaxDocument::getGroupInfo(const QString& mainGroupName, const QString &group)
00272 {
00273   QDomElement element;
00274   if (getElement(element, mainGroupName, group+"s"))
00275   {
00276     syntaxContextData *data = new syntaxContextData;
00277     data->parent = element;
00278     return data;
00279   }
00280   return 0;
00281 }
00282 
00286 QStringList& SyntaxDocument::finddata(const QString& mainGroup, const QString& type, bool clearList)
00287 {
00288   kdDebug(13010)<<"Create a list of keywords \""<<type<<"\" from \""<<mainGroup<<"\"."<<endl;
00289   if (clearList)
00290     m_data.clear();
00291 
00292   for(QDomNode node = documentElement().firstChild(); !node.isNull(); node = node.nextSibling())
00293   {
00294     QDomElement elem = node.toElement();
00295     if (elem.tagName() == mainGroup)
00296     {
00297       kdDebug(13010)<<"\""<<mainGroup<<"\" found."<<endl;
00298       QDomNodeList nodelist1 = elem.elementsByTagName("list");
00299 
00300       for (uint l=0; l<nodelist1.count(); l++)
00301       {
00302         if (nodelist1.item(l).toElement().attribute("name") == type)
00303         {
00304           kdDebug(13010)<<"List with attribute name=\""<<type<<"\" found."<<endl;
00305           QDomNodeList childlist = nodelist1.item(l).toElement().childNodes();
00306 
00307           for (uint i=0; i<childlist.count(); i++)
00308           {
00309             QString element = childlist.item(i).toElement().text().stripWhiteSpace();
00310             if (element.isEmpty())
00311               continue;
00312 #ifndef NDEBUG
00313             if (i<6)
00314             {
00315               kdDebug(13010)<<"\""<<element<<"\" added to the list \""<<type<<"\""<<endl;
00316             }
00317             else if(i==6)
00318             {
00319               kdDebug(13010)<<"... The list continues ..."<<endl;
00320             }
00321 #endif
00322             m_data += element;
00323           }
00324 
00325           break;
00326         }
00327       }
00328       break;
00329     }
00330   }
00331 
00332   return m_data;
00333 }
00334 
00335 // Private
00339 void SyntaxDocument::setupModeList (bool force)
00340 {
00341   // If there's something in myModeList the Mode List was already built so, don't do it again
00342   if (!myModeList.isEmpty())
00343     return;
00344 
00345   // We'll store the ModeList in katesyntaxhighlightingrc
00346   KConfig config("katesyntaxhighlightingrc", false, false);
00347 
00348   // figure our if the kate install is too new
00349   config.setGroup ("General");
00350   if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
00351   {
00352     config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
00353     force = true;
00354   }
00355 
00356   // Let's get a list of all the xml files for hl
00357   QStringList list = KGlobal::dirs()->findAllResources("data","katepart/syntax/*.xml",false,true);
00358 
00359   // Let's iterate through the list and build the Mode List
00360   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00361   {
00362     // Each file has a group called:
00363     QString Group="Cache "+*it;
00364 
00365     // If the group exist and we're not forced to read the xml file, let's build myModeList for katesyntax..rc
00366     if ((config.hasGroup(Group)) && (!force))
00367     {
00368       // Let's go to this group
00369       config.setGroup(Group);
00370 
00371       // Let's make a new syntaxModeListItem to instert in myModeList from the information in katesyntax..rc
00372       syntaxModeListItem *mli=new syntaxModeListItem;
00373       mli->name       = config.readEntry("name"); // ### TODO: translation (bug #72220)
00374       mli->section    = i18n("Language Section",config.readEntry("section").utf8());
00375       mli->mimetype   = config.readEntry("mimetype");
00376       mli->extension  = config.readEntry("extension");
00377       mli->version    = config.readEntry("version");
00378       mli->priority   = config.readEntry("priority");
00379       mli->identifier = *it;
00380 
00381       // Apend the item to the list
00382       myModeList.append(mli);
00383     }
00384     else
00385     {
00386       // We're forced to read the xml files or the mode doesn't exist in the katesyntax...rc
00387       QFile f(*it);
00388 
00389       if (f.open(IO_ReadOnly))
00390       {
00391         // Ok we opened the file, let's read the contents and close the file
00392         /* the return of setContent should be checked because a false return shows a parsing error */
00393         QString errMsg;
00394         int line, col;
00395 
00396         bool success = setContent(&f,&errMsg,&line,&col);
00397 
00398         f.close();
00399 
00400         if (success)
00401         {
00402           QDomElement root = documentElement();
00403 
00404           if (!root.isNull())
00405           {
00406             // If the 'first' tag is language, go on
00407             if (root.tagName()=="language")
00408             {
00409               // let's make the mode list item.
00410               syntaxModeListItem *mli = new syntaxModeListItem;
00411 
00412               mli->name      = root.attribute("name");
00413               mli->section   = root.attribute("section");
00414               mli->mimetype  = root.attribute("mimetype");
00415               mli->extension = root.attribute("extensions");
00416               mli->version   = root.attribute("version");
00417               mli->priority  = root.attribute("priority");
00418 
00419               mli->identifier = *it;
00420 
00421               // Now let's write or overwrite (if force==true) the entry in katesyntax...rc
00422               config.setGroup(Group);
00423               config.writeEntry("name",mli->name);
00424               if (mli->section.isEmpty()) // ### TODO: can this happen at all?
00425                 config.writeEntry("section","Other");
00426               else
00427                 config.writeEntry("section",mli->section);
00428               config.writeEntry("mimetype",mli->mimetype);
00429               config.writeEntry("extension",mli->extension);
00430               config.writeEntry("version",mli->version);
00431               config.writeEntry("priority",mli->priority);
00432 
00433               // Now that the data is in the config file, translate section
00434               if (mli->section.isEmpty()) // ### TODO: can this happen at all?
00435                 mli->section    = i18n("Language Section",mli->section.utf8());
00436               else
00437                 mli->section    = i18n("Language Section","Other"); // We need the i18n context for when reading again the config
00438 
00439               // Append the new item to the list.
00440               myModeList.append(mli);
00441             }
00442           }
00443         }
00444         else
00445         {
00446           syntaxModeListItem *emli=new syntaxModeListItem;
00447 
00448           emli->section=i18n("Errors!");
00449           emli->mimetype="invalid_file/invalid_file";
00450           emli->extension="invalid_file.invalid_file";
00451           emli->version="1.";
00452           emli->name=i18n("Error: %1").arg(*it);
00453           emli->identifier=(*it);
00454 
00455           myModeList.append(emli);
00456         }
00457       }
00458     }
00459   }
00460   // Syncronize with the file katesyntax...rc
00461   config.sync();
00462 }
00463 
00464 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 12 09:10:45 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003