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 <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <unistd.h>
00025 
00026 #include <kdebug.h>
00027 #include <kstandarddirs.h>
00028 #include <klocale.h>
00029 #include <kmessagebox.h>
00030 #include <kconfig.h>
00031 
00032 #include <qfile.h>
00033 
00034 KateSyntaxDocument::KateSyntaxDocument(bool force)
00035   : QDomDocument()
00036 {
00037   // Let's build the Mode List (katesyntaxhighlightingrc)
00038   setupModeList(force);
00039   myModeList.setAutoDelete( true );
00040 }
00041 
00042 KateSyntaxDocument::~KateSyntaxDocument()
00043 {
00044 }
00045 
00050 bool KateSyntaxDocument::setIdentifier(const QString& identifier)
00051 {
00052   // if the current file is the same as the new one don't do anything.
00053   if(currentFile != identifier)
00054   {
00055     // let's open the new file
00056     QFile f( identifier );
00057 
00058     if ( f.open(IO_ReadOnly) )
00059     {
00060       // Let's parse the contets of the xml file
00061       /* The result of this function should be check for robustness,
00062          a false returned means a parse error */
00063       QString errorMsg;
00064       int line, col;
00065       bool success=setContent(&f,&errorMsg,&line,&col);
00066 
00067       // Ok, now the current file is the pretended one (identifier)
00068       currentFile = identifier;
00069 
00070       // Close the file, is not longer needed
00071       f.close();
00072 
00073       if (!success)
00074       {
00075         KMessageBox::error(0L,i18n("<qt>The error <b>%4</b><br> has been detected in the file %1 at %2/%3</qt>").arg(identifier)
00076             .arg(line).arg(col).arg(i18n("QXml",errorMsg.utf8())));
00077         return false;
00078       }
00079     }
00080     else
00081     {
00082       // Oh o, we couldn't open the file.
00083       KMessageBox::error( 0L, i18n("Unable to open %1").arg(identifier) );
00084       return false;
00085     }
00086   }
00087   return true;
00088 }
00089 
00093 bool KateSyntaxDocument::nextGroup( KateSyntaxContextData* data)
00094 {
00095   if(!data)
00096     return false;
00097 
00098   // No group yet so go to first child
00099   if (data->currentGroup.isNull())
00100   {
00101     // Skip over non-elements. So far non-elements are just comments
00102     QDomNode node = data->parent.firstChild();
00103     while (node.isComment())
00104       node = node.nextSibling();
00105 
00106     data->currentGroup = node.toElement();
00107   }
00108   else
00109   {
00110     // common case, iterate over siblings, skipping comments as we go
00111     QDomNode node = data->currentGroup.nextSibling();
00112     while (node.isComment())
00113       node = node.nextSibling();
00114 
00115     data->currentGroup = node.toElement();
00116   }
00117 
00118   return !data->currentGroup.isNull();
00119 }
00120 
00124 bool KateSyntaxDocument::nextItem( KateSyntaxContextData* data)
00125 {
00126   if(!data)
00127     return false;
00128 
00129   if (data->item.isNull())
00130   {
00131     QDomNode node = data->currentGroup.firstChild();
00132     while (node.isComment())
00133       node = node.nextSibling();
00134 
00135     data->item = node.toElement();
00136   }
00137   else
00138   {
00139     QDomNode node = data->item.nextSibling();
00140     while (node.isComment())
00141       node = node.nextSibling();
00142 
00143     data->item = node.toElement();
00144   }
00145 
00146   return !data->item.isNull();
00147 }
00148 
00152 QString KateSyntaxDocument::groupItemData( const KateSyntaxContextData* data, const QString& name){
00153   if(!data)
00154     return QString::null;
00155 
00156   // If there's no name just return the tag name of data->item
00157   if ( (!data->item.isNull()) && (name.isEmpty()))
00158   {
00159     return data->item.tagName();
00160   }
00161 
00162   // if name is not empty return the value of the attribute name
00163   if (!data->item.isNull())
00164   {
00165     return data->item.attribute(name);
00166   }
00167 
00168   return QString::null;
00169 
00170 }
00171 
00172 QString KateSyntaxDocument::groupData( const KateSyntaxContextData* data,const QString& name)
00173 {
00174   if(!data)
00175     return QString::null;
00176 
00177   if (!data->currentGroup.isNull())
00178   {
00179     return data->currentGroup.attribute(name);
00180   }
00181   else
00182   {
00183     return QString::null;
00184   }
00185 }
00186 
00187 void KateSyntaxDocument::freeGroupInfo( KateSyntaxContextData* data)
00188 {
00189   if (data)
00190     delete data;
00191 }
00192 
00193 KateSyntaxContextData* KateSyntaxDocument::getSubItems(KateSyntaxContextData* data)
00194 {
00195   KateSyntaxContextData *retval = new KateSyntaxContextData;
00196 
00197   if (data != 0)
00198   {
00199     retval->parent = data->currentGroup;
00200     retval->currentGroup = data->item;
00201   }
00202 
00203   return retval;
00204 }
00205 
00206 bool KateSyntaxDocument::getElement (QDomElement &element, const QString &mainGroupName, const QString &config)
00207 {
00208   kdDebug(13010) << "Looking for \"" << mainGroupName << "\" -> \"" << config << "\"." << endl;
00209 
00210   QDomNodeList nodes = documentElement().childNodes();
00211 
00212   // Loop over all these child nodes looking for mainGroupName
00213   for (unsigned int i=0; i<nodes.count(); i++)
00214   {
00215     QDomElement elem = nodes.item(i).toElement();
00216     if (elem.tagName() == mainGroupName)
00217     {
00218       // Found mainGroupName ...
00219       QDomNodeList subNodes = elem.childNodes();
00220 
00221       // ... so now loop looking for config
00222       for (unsigned int j=0; j<subNodes.count(); j++)
00223       {
00224         QDomElement subElem = subNodes.item(j).toElement();
00225         if (subElem.tagName() == config)
00226         {
00227           // Found it!
00228           element = subElem;
00229           return true;
00230         }
00231       }
00232 
00233       kdDebug(13010) << "WARNING: \""<< config <<"\" wasn't found!" << endl;
00234       return false;
00235     }
00236   }
00237 
00238   kdDebug(13010) << "WARNING: \""<< mainGroupName <<"\" wasn't found!" << endl;
00239   return false;
00240 }
00241 
00246 KateSyntaxContextData* KateSyntaxDocument::getConfig(const QString& mainGroupName, const QString &config)
00247 {
00248   QDomElement element;
00249   if (getElement(element, mainGroupName, config))
00250   {
00251     KateSyntaxContextData *data = new KateSyntaxContextData;
00252     data->item = element;
00253     return data;
00254   }
00255   return 0;
00256 }
00257 
00262 KateSyntaxContextData* KateSyntaxDocument::getGroupInfo(const QString& mainGroupName, const QString &group)
00263 {
00264   QDomElement element;
00265   if (getElement(element, mainGroupName, group+"s"))
00266   {
00267     KateSyntaxContextData *data = new KateSyntaxContextData;
00268     data->parent = element;
00269     return data;
00270   }
00271   return 0;
00272 }
00273 
00277 QStringList& KateSyntaxDocument::finddata(const QString& mainGroup, const QString& type, bool clearList)
00278 {
00279   kdDebug(13010)<<"Create a list of keywords \""<<type<<"\" from \""<<mainGroup<<"\"."<<endl;
00280   if (clearList)
00281     m_data.clear();
00282 
00283   for(QDomNode node = documentElement().firstChild(); !node.isNull(); node = node.nextSibling())
00284   {
00285     QDomElement elem = node.toElement();
00286     if (elem.tagName() == mainGroup)
00287     {
00288       kdDebug(13010)<<"\""<<mainGroup<<"\" found."<<endl;
00289       QDomNodeList nodelist1 = elem.elementsByTagName("list");
00290 
00291       for (uint l=0; l<nodelist1.count(); l++)
00292       {
00293         if (nodelist1.item(l).toElement().attribute("name") == type)
00294         {
00295           kdDebug(13010)<<"List with attribute name=\""<<type<<"\" found."<<endl;
00296           QDomNodeList childlist = nodelist1.item(l).toElement().childNodes();
00297 
00298           for (uint i=0; i<childlist.count(); i++)
00299           {
00300             QString element = childlist.item(i).toElement().text().stripWhiteSpace();
00301             if (element.isEmpty())
00302               continue;
00303 #ifndef NDEBUG
00304             if (i<6)
00305             {
00306               kdDebug(13010)<<"\""<<element<<"\" added to the list \""<<type<<"\""<<endl;
00307             }
00308             else if(i==6)
00309             {
00310               kdDebug(13010)<<"... The list continues ..."<<endl;
00311             }
00312 #endif
00313             m_data += element;
00314           }
00315 
00316           break;
00317         }
00318       }
00319       break;
00320     }
00321   }
00322 
00323   return m_data;
00324 }
00325 
00326 // Private
00330 void KateSyntaxDocument::setupModeList (bool force)
00331 {
00332   // If there's something in myModeList the Mode List was already built so, don't do it again
00333   if (!myModeList.isEmpty())
00334     return;
00335 
00336   // We'll store the ModeList in katesyntaxhighlightingrc
00337   KConfig config("katesyntaxhighlightingrc", false, false);
00338 
00339   // figure our if the kate install is too new
00340   config.setGroup ("General");
00341   if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
00342   {
00343     config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
00344     force = true;
00345   }
00346 
00347   // Let's get a list of all the xml files for hl
00348   QStringList list = KGlobal::dirs()->findAllResources("data","katepart/syntax/*.xml",false,true);
00349 
00350   // Let's iterate through the list and build the Mode List
00351   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00352   {
00353     // Each file has a group called:
00354     QString Group="Cache "+ *it;
00355 
00356     // Let's go to this group
00357     config.setGroup(Group);
00358 
00359     // stat the file
00360     struct stat sbuf;
00361     memset (&sbuf, 0, sizeof(sbuf));
00362     stat(QFile::encodeName(*it), &sbuf);
00363 
00364     // If the group exist and we're not forced to read the xml file, let's build myModeList for katesyntax..rc
00365     if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
00366     {
00367       // Let's make a new KateSyntaxModeListItem to instert in myModeList from the information in katesyntax..rc
00368       KateSyntaxModeListItem *mli=new KateSyntaxModeListItem;
00369       mli->name       = config.readEntry("name");
00370       mli->nameTranslated = i18n("Language",mli->name.utf8());
00371       mli->section    = i18n("Language Section",config.readEntry("section").utf8());
00372       mli->mimetype   = config.readEntry("mimetype");
00373       mli->extension  = config.readEntry("extension");
00374       mli->version    = config.readEntry("version");
00375       mli->priority   = config.readEntry("priority");
00376       mli->author    = config.readEntry("author");
00377       mli->license   = config.readEntry("license");
00378       mli->hidden   =  config.readBoolEntry("hidden");
00379       mli->identifier = *it;
00380 
00381       // Apend the item to the list
00382       myModeList.append(mli);
00383     }
00384     else
00385     {
00386       kdDebug (13010) << "UPDATE hl cache for: " << *it << endl;
00387 
00388       // We're forced to read the xml files or the mode doesn't exist in the katesyntax...rc
00389       QFile f(*it);
00390 
00391       if (f.open(IO_ReadOnly))
00392       {
00393         // Ok we opened the file, let's read the contents and close the file
00394         /* the return of setContent should be checked because a false return shows a parsing error */
00395         QString errMsg;
00396         int line, col;
00397 
00398         bool success = setContent(&f,&errMsg,&line,&col);
00399 
00400         f.close();
00401 
00402         if (success)
00403         {
00404           QDomElement root = documentElement();
00405 
00406           if (!root.isNull())
00407           {
00408             // If the 'first' tag is language, go on
00409             if (root.tagName()=="language")
00410             {
00411               // let's make the mode list item.
00412               KateSyntaxModeListItem *mli = new KateSyntaxModeListItem;
00413 
00414               mli->name      = root.attribute("name");
00415               mli->section   = root.attribute("section");
00416               mli->mimetype  = root.attribute("mimetype");
00417               mli->extension = root.attribute("extensions");
00418               mli->version   = root.attribute("version");
00419               mli->priority  = root.attribute("priority");
00420               mli->author    = root.attribute("author");
00421               mli->license   = root.attribute("license");
00422 
00423               QString hidden = root.attribute("hidden");
00424               mli->hidden    = (hidden == "true" || hidden == "TRUE");
00425 
00426               mli->identifier = *it;
00427 
00428               // Now let's write or overwrite (if force==true) the entry in katesyntax...rc
00429               config.setGroup(Group);
00430               config.writeEntry("name",mli->name);
00431               config.writeEntry("section",mli->section);
00432               config.writeEntry("mimetype",mli->mimetype);
00433               config.writeEntry("extension",mli->extension);
00434               config.writeEntry("version",mli->version);
00435               config.writeEntry("priority",mli->priority);
00436               config.writeEntry("author",mli->author);
00437               config.writeEntry("license",mli->license);
00438               config.writeEntry("hidden",mli->hidden);
00439 
00440               // modified time to keep cache in sync
00441               config.writeEntry("lastModified", sbuf.st_mtime);
00442 
00443               // Now that the data is in the config file, translate section
00444               mli->section    = i18n("Language Section",mli->section.utf8());
00445               mli->nameTranslated = i18n("Language",mli->name.utf8());
00446 
00447               // Append the new item to the list.
00448               myModeList.append(mli);
00449             }
00450           }
00451         }
00452         else
00453         {
00454           KateSyntaxModeListItem *emli=new KateSyntaxModeListItem;
00455 
00456           emli->section=i18n("Errors!");
00457           emli->mimetype="invalid_file/invalid_file";
00458           emli->extension="invalid_file.invalid_file";
00459           emli->version="1.";
00460           emli->name=QString ("Error: %1").arg(*it); // internal
00461           emli->nameTranslated=i18n("Error: %1").arg(*it); // translated
00462           emli->identifier=(*it);
00463 
00464           myModeList.append(emli);
00465         }
00466       }
00467     }
00468   }
00469 
00470   // Syncronize with the file katesyntax...rc
00471   config.sync();
00472 }
00473 
00474 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jan 22 16:53:00 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003