• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katesyntaxdocument.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "katesyntaxdocument.h"
00021 
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <unistd.h>
00025 #include <time.h>
00026 #include <sys/time.h>
00027 
00028 #include <kdebug.h>
00029 #include <kstandarddirs.h>
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <kconfiggroup.h>
00033 #include <kde_file.h>
00034 
00035 #include <QtGui/QApplication>
00036 #include <QtCore/QFile>
00037 
00038 // use this to turn on over verbose debug output...
00039 #undef KSD_OVER_VERBOSE
00040 
00041 KateSyntaxDocument::KateSyntaxDocument(KConfig *config, bool force)
00042   : QDomDocument()
00043   , m_config (config)
00044 {
00045   // Let's build the Mode List (katesyntaxhighlightingrc)
00046   setupModeList(force);
00047 }
00048 
00049 KateSyntaxDocument::~KateSyntaxDocument()
00050 {
00051   for (int i=0; i < myModeList.size(); i++)
00052     delete myModeList[i];
00053 }
00054 
00059 bool KateSyntaxDocument::setIdentifier(const QString& identifier)
00060 {
00061   // if the current file is the same as the new one don't do anything.
00062   if(currentFile != identifier)
00063   {
00064     // let's open the new file
00065     QFile f( identifier );
00066 
00067     if ( f.open(QIODevice::ReadOnly) )
00068     {
00069       // Let's parse the contets of the xml file
00070       /* The result of this function should be check for robustness,
00071          a false returned means a parse error */
00072       QString errorMsg;
00073       int line, col;
00074       bool success=setContent(&f,&errorMsg,&line,&col);
00075 
00076       // Ok, now the current file is the pretended one (identifier)
00077       currentFile = identifier;
00078 
00079       // Close the file, is not longer needed
00080       f.close();
00081 
00082       if (!success)
00083       {
00084         KMessageBox::error(QApplication::activeWindow(),i18n("<qt>The error <b>%4</b><br /> has been detected in the file %1 at %2/%3</qt>", identifier,
00085              line, col, i18nc("QXml",errorMsg.toUtf8())));
00086         return false;
00087       }
00088     }
00089     else
00090     {
00091       // Oh o, we couldn't open the file.
00092       KMessageBox::error(QApplication::activeWindow(), i18n("Unable to open %1", identifier) );
00093       return false;
00094     }
00095   }
00096   return true;
00097 }
00098 
00102 bool KateSyntaxDocument::nextGroup( KateSyntaxContextData* 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 KateSyntaxDocument::nextItem( KateSyntaxContextData* 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 KateSyntaxDocument::groupItemData( const KateSyntaxContextData* data, const QString& name){
00162   if(!data)
00163     return QString();
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();
00178 
00179 }
00180 
00181 QString KateSyntaxDocument::groupData( const KateSyntaxContextData* data,const QString& name)
00182 {
00183   if(!data)
00184     return QString();
00185 
00186   if (!data->currentGroup.isNull())
00187   {
00188     return data->currentGroup.attribute(name);
00189   }
00190   else
00191   {
00192     return QString();
00193   }
00194 }
00195 
00196 void KateSyntaxDocument::freeGroupInfo( KateSyntaxContextData* data)
00197 {
00198   if (data)
00199     delete data;
00200 }
00201 
00202 KateSyntaxContextData* KateSyntaxDocument::getSubItems(KateSyntaxContextData* data)
00203 {
00204   KateSyntaxContextData *retval = new KateSyntaxContextData;
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 KateSyntaxDocument::getElement (QDomElement &element, const QString &mainGroupName, const QString &config)
00216 {
00217 #ifdef KSD_OVER_VERBOSE
00218   kDebug(13010) << "Looking for \"" << mainGroupName << "\" -> \"" << config << "\".";
00219 #endif
00220 
00221   QDomNodeList nodes = documentElement().childNodes();
00222 
00223   // Loop over all these child nodes looking for mainGroupName
00224   for (int i=0; i<nodes.count(); i++)
00225   {
00226     QDomElement elem = nodes.item(i).toElement();
00227     if (elem.tagName() == mainGroupName)
00228     {
00229       // Found mainGroupName ...
00230       QDomNodeList subNodes = elem.childNodes();
00231 
00232       // ... so now loop looking for config
00233       for (int j=0; j<subNodes.count(); j++)
00234       {
00235         QDomElement subElem = subNodes.item(j).toElement();
00236         if (subElem.tagName() == config)
00237         {
00238           // Found it!
00239           element = subElem;
00240           return true;
00241         }
00242       }
00243 
00244 #ifdef KSD_OVER_VERBOSE
00245       kDebug(13010) << "WARNING: \""<< config <<"\" wasn't found!";
00246 #endif
00247 
00248       return false;
00249     }
00250   }
00251 
00252 #ifdef KSD_OVER_VERBOSE
00253   kDebug(13010) << "WARNING: \""<< mainGroupName <<"\" wasn't found!";
00254 #endif
00255 
00256   return false;
00257 }
00258 
00263 KateSyntaxContextData* KateSyntaxDocument::getConfig(const QString& mainGroupName, const QString &config)
00264 {
00265   QDomElement element;
00266   if (getElement(element, mainGroupName, config))
00267   {
00268     KateSyntaxContextData *data = new KateSyntaxContextData;
00269     data->item = element;
00270     return data;
00271   }
00272   return 0;
00273 }
00274 
00279 KateSyntaxContextData* KateSyntaxDocument::getGroupInfo(const QString& mainGroupName, const QString &group)
00280 {
00281   QDomElement element;
00282   if (getElement(element, mainGroupName, group+'s'))
00283   {
00284     KateSyntaxContextData *data = new KateSyntaxContextData;
00285     data->parent = element;
00286     return data;
00287   }
00288   return 0;
00289 }
00290 
00294 QStringList& KateSyntaxDocument::finddata(const QString& mainGroup, const QString& type, bool clearList)
00295 {
00296 #ifdef KSD_OVER_VERBOSE
00297   kDebug(13010)<<"Create a list of keywords \""<<type<<"\" from \""<<mainGroup<<"\".";
00298 #endif
00299 
00300   if (clearList)
00301     m_data.clear();
00302 
00303   for(QDomNode node = documentElement().firstChild(); !node.isNull(); node = node.nextSibling())
00304   {
00305     QDomElement elem = node.toElement();
00306     if (elem.tagName() == mainGroup)
00307     {
00308 #ifdef KSD_OVER_VERBOSE
00309       kDebug(13010)<<"\""<<mainGroup<<"\" found.";
00310 #endif
00311 
00312       QDomNodeList nodelist1 = elem.elementsByTagName("list");
00313 
00314       for (int l=0; l<nodelist1.count(); l++)
00315       {
00316         if (nodelist1.item(l).toElement().attribute("name") == type)
00317         {
00318 #ifdef KSD_OVER_VERBOSE
00319           kDebug(13010)<<"List with attribute name=\""<<type<<"\" found.";
00320 #endif
00321           
00322           QDomNodeList childlist = nodelist1.item(l).toElement().childNodes();
00323 
00324           for (int i=0; i<childlist.count(); i++)
00325           {
00326             QString element = childlist.item(i).toElement().text().trimmed();
00327             if (element.isEmpty())
00328               continue;
00329 
00330 #ifdef KSD_OVER_VERBOSE
00331             if (i<6)
00332             {
00333               kDebug(13010)<<"\""<<element<<"\" added to the list \""<<type<<"\"";
00334             }
00335             else if(i==6)
00336             {
00337               kDebug(13010)<<"... The list continues ...";
00338             }
00339 #endif
00340 
00341             m_data += element;
00342           }
00343 
00344           break;
00345         }
00346       }
00347       break;
00348     }
00349   }
00350 
00351   return m_data;
00352 }
00353 
00354 // Private
00358 void KateSyntaxDocument::setupModeList (bool force)
00359 {
00360   // If there's something in myModeList the Mode List was already built so, don't do it again
00361   if (!myModeList.isEmpty())
00362     return;
00363 
00364   // We'll store the ModeList in katesyntaxhighlightingrc
00365   KConfigGroup generalConfig(m_config, "General");
00366 
00367   // figure our if the kate install is too new
00368   if (generalConfig.readEntry ("Version",0) > generalConfig.readEntry ("CachedVersion",0))
00369   {
00370     generalConfig.writeEntry ("CachedVersion", generalConfig.readEntry ("Version",0));
00371     force = true;
00372   }
00373 
00374   // Let's get a list of all the xml files for hl
00375   const QStringList list = KGlobal::dirs()->findAllResources("data","katepart/syntax/*.xml",
00376                                                        KStandardDirs::NoDuplicates);
00377 
00378   // Let's iterate through the list and build the Mode List
00379   for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
00380   {
00381     // Each file has a group called:
00382     QString Group="Cache "+ *it;
00383 
00384     // Let's go to this group
00385     KConfigGroup config(m_config, Group);
00386 
00387     // stat the file
00388     KDE_struct_stat sbuf;
00389     memset (&sbuf, 0, sizeof(sbuf));
00390     KDE::stat(*it, &sbuf);
00391 
00392     // If the group exist and we're not forced to read the xml file, let's build myModeList for katesyntax..rc
00393     if (!force && config.exists() && (sbuf.st_mtime == config.readEntry("lastModified",0)))
00394     {
00395       // Let's make a new KateSyntaxModeListItem to instert in myModeList from the information in katesyntax..rc
00396       KateSyntaxModeListItem *mli=new KateSyntaxModeListItem;
00397       mli->name       = config.readEntry("name");
00398       mli->nameTranslated = i18nc("Language",mli->name.toUtf8());
00399       mli->section    = i18nc("Language Section",config.readEntry("section").toUtf8());
00400       mli->mimetype   = config.readEntry("mimetype");
00401       mli->extension  = config.readEntry("extension");
00402       mli->version    = config.readEntry("version");
00403       mli->priority   = config.readEntry("priority");
00404       mli->style      = config.readEntry("style");
00405       mli->author    = config.readEntry("author");
00406       mli->license   = config.readEntry("license");
00407       mli->indenter = config.readEntry("indenter");
00408       mli->hidden   =  config.readEntry("hidden", false);
00409       mli->identifier = *it;
00410 
00411       // Apend the item to the list
00412       myModeList.append(mli);
00413     }
00414     else
00415     {
00416 #ifdef KSD_OVER_VERBOSE
00417       kDebug (13010) << "UPDATE hl cache for: " << *it;
00418 #endif
00419 
00420       // We're forced to read the xml files or the mode doesn't exist in the katesyntax...rc
00421       QFile f(*it);
00422 
00423       if (f.open(QIODevice::ReadOnly))
00424       {
00425         // Ok we opened the file, let's read the contents and close the file
00426         /* the return of setContent should be checked because a false return shows a parsing error */
00427         QString errMsg;
00428         int line, col;
00429 
00430         bool success = setContent(&f,&errMsg,&line,&col);
00431 
00432         f.close();
00433 
00434         if (success)
00435         {
00436           QDomElement root = documentElement();
00437 
00438           if (!root.isNull())
00439           {
00440             // If the 'first' tag is language, go on
00441             if (root.tagName()=="language")
00442             {
00443               // let's make the mode list item.
00444               KateSyntaxModeListItem *mli = new KateSyntaxModeListItem;
00445 
00446               mli->name      = root.attribute("name");
00447               mli->section   = root.attribute("section");
00448               mli->mimetype  = root.attribute("mimetype");
00449               mli->extension = root.attribute("extensions");
00450               mli->version   = root.attribute("version");
00451               mli->priority  = root.attribute("priority");
00452               mli->style     = root.attribute("style");
00453               mli->author    = root.attribute("author");
00454               mli->license   = root.attribute("license");
00455               mli->indenter   = root.attribute("indenter");
00456 
00457               QString hidden = root.attribute("hidden");
00458               mli->hidden    = (hidden == "true" || hidden == "TRUE");
00459 
00460               mli->identifier = *it;
00461 
00462               // Now let's write or overwrite (if force==true) the entry in katesyntax...rc
00463               config = KConfigGroup(m_config, Group);
00464               config.writeEntry("name",mli->name);
00465               config.writeEntry("section",mli->section);
00466               config.writeEntry("mimetype",mli->mimetype);
00467               config.writeEntry("extension",mli->extension);
00468               config.writeEntry("version",mli->version);
00469               config.writeEntry("priority",mli->priority);
00470               config.writeEntry("style",mli->style);
00471               config.writeEntry("author",mli->author);
00472               config.writeEntry("license",mli->license);
00473               config.writeEntry("indenter",mli->indenter);
00474               config.writeEntry("hidden",mli->hidden);
00475 
00476               // modified time to keep cache in sync
00477               config.writeEntry("lastModified", int(sbuf.st_mtime));
00478 
00479               // Now that the data is in the config file, translate section
00480               mli->section    = i18nc("Language Section",mli->section.toUtf8());
00481               mli->nameTranslated = i18nc("Language",mli->name.toUtf8());
00482 
00483               // Append the new item to the list.
00484               myModeList.append(mli);
00485             }
00486           }
00487         }
00488         else
00489         {
00490           KateSyntaxModeListItem *emli=new KateSyntaxModeListItem;
00491 
00492           emli->section=i18n("Errors!");
00493           emli->mimetype="invalid_file/invalid_file";
00494           emli->extension="invalid_file.invalid_file";
00495           emli->version="1.";
00496           emli->name=QString ("Error: %1").arg(*it); // internal
00497           emli->nameTranslated=i18n("Error: %1", *it); // translated
00498           emli->identifier=(*it);
00499 
00500           myModeList.append(emli);
00501         }
00502       }
00503     }
00504   }
00505 
00506   // Synchronize with the file katesyntax...rc
00507   generalConfig.sync();
00508 }
00509 
00510 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal