You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdewebdev/quanta/utility/quantacommon.cpp

754 lines
22 KiB

/***************************************************************************
quantacommon.cpp - description
-------------------
begin : Sat Jul 27 2002
copyright : (C) 2002, 2003 by Andras Mantia <amantia@kde.org>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License. *
* *
***************************************************************************/
//system includes
#include <sys/types.h>
#include <unistd.h>
//qt includes
#include <tqstringlist.h>
#include <tqdict.h>
#include <tqdir.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqwidget.h>
//kde includes
#include <kapplication.h>
#include <dcopref.h>
#include <kurl.h>
#include <kdirwatch.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kprotocolinfo.h>
#include <kprogress.h>
#include <ktempdir.h>
#include <ktempfile.h>
//remove the below ones when KTQPasteAction is removed
#include <dcopclient.h>
#include <kdebug.h>
#include <kpopupmenu.h>
#include <ktoolbar.h>
#include <ktoolbarbutton.h>
#include <kstringhandler.h>
#include <tqwhatsthis.h>
#include <tqtimer.h>
#include <tqclipboard.h>
#include <tqdatastream.h>
#include "qextfileinfo.h"
#include "quantacommon.h"
#include "tag.h"
#include "dtds.h"
//#include "resource.h"
TQConfig qConfig; //holds the main configuration settings
TQString tmpDir;
TQRegExp scriptBeginRx;
TQRegExp scriptEndRx;
Node *baseNode;
Parser *parser;
KDirWatch *fileWatcher;
KProgress *progressBar;
TQString toolbarExtension = ".toolbar.tgz";
TQRegExp newLineRx("\\n");
TQStringList charList; //hold the list of the &char; chars. See the data/chars file.
TQMap<int, TQString> replacementMap;
TQPtrList<KTempFile> tempFileList;
TQPtrList<KTempDir> tempDirList;
bool typingInProgress;
QuantaCommon::QuantaCommon(){
}
QuantaCommon::~QuantaCommon(){
}
/** convert tag to upper or lower case */
TQString QuantaCommon::tagCase( const TQString& tag)
{
TQString sTag = tag;
switch (qConfig.tagCase)
{
case 1: sTag = tag.lower();
break;
case 2: sTag = tag.upper();
}
return sTag;
}
/** convert attr of tag to upper or lower case */
TQString QuantaCommon::attrCase( const TQString& attr)
{
TQString sAttr = attr;
switch (qConfig.attrCase)
{
case 1: sAttr = attr.lower();
break;
case 2: sAttr = attr.upper();
}
return sAttr;
}
/** returns the attribute value in quoted form, by taking care of the
quotation setting*/
TQString QuantaCommon::quoteAttributeValue(const TQString& value)
{
TQString quote = qConfig.attrValueQuotation;
return quote + value + quote;
}
/** Set's up the url correctly from urlString. */
void QuantaCommon::setUrl(KURL &url, const TQString& urlString)
{
KURL oldUrl = url;
url = urlString;
if (!KProtocolInfo::isKnownProtocol(url))
{
url = oldUrl;
url.setPath(urlString);
if (url.protocol().isEmpty())
url.setProtocol("file");
}
}
/** No descriptions */
bool QuantaCommon::isSingleTag(const TQString& dtdName, const TQString& tag)
{
bool single = false;
//!doctype is a common tag to all DTDs not listed in the tagsList
if(tag.lower() == "!doctype" || tag.lower() == "?xml")
return true;
const DTDStruct* dtd = DTDs::ref()->tqfind(dtdName);
if (dtd && !tag.isEmpty())
{
TQString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
TQTag* qtag = dtd->tagsList->tqfind(searchForTag);
if (qtag)
single = qtag->isSingle();
}
return single;
}
/** No descriptions */
bool QuantaCommon::isOptionalTag(const TQString& dtdName, const TQString& tag)
{
bool optional = false;
const DTDStruct* dtd = DTDs::ref()->tqfind(dtdName);
if (dtd && !tag.isEmpty())
{
TQString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
TQTag* qtag = dtd->tagsList->tqfind(searchForTag);
if (qtag)
optional = qtag->isOptional();
}
return optional;
}
/** No descriptions */
bool QuantaCommon::isKnownTag(const TQString& dtdName, const TQString& tag)
{
bool known = false;
const DTDStruct* dtd = DTDs::ref()->tqfind(dtdName);
if (dtd && !tag.isEmpty())
{
TQString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
if (dtd->tagsList->tqfind(searchForTag))
known = true;
}
return known;
}
AttributeList* QuantaCommon::tagAttributes(const TQString& dtdName, const TQString& tag)
{
AttributeList* attrs = 0L;
const DTDStruct* dtd = DTDs::ref()->tqfind(dtdName);
if (dtd && !tag.isEmpty())
{
TQString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
TQTag* qtag = dtd->tagsList->tqfind(searchForTag);
if (qtag)
attrs = qtag->attributes();
}
return attrs;
}
/** Returns the TQTag object for the tag "tag" from the DTD named "dtdname". */
TQTag* QuantaCommon::tagFromDTD(const TQString& dtdName, const TQString& tag)
{
const DTDStruct* dtd = DTDs::ref()->tqfind(dtdName);
return tagFromDTD(dtd, tag);
}
/** Returns the TQTag object for the tag "tag" from the DTD. */
TQTag* QuantaCommon::tagFromDTD(const DTDStruct *dtd, const TQString& tag)
{
TQTag *qtag = 0;
if (dtd && !tag.isEmpty())
{
TQString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
qtag = dtd->tagsList->tqfind(searchForTag);
}
return qtag;
}
/** Returns the TQTag object for the node "node" from node's DTD. */
TQTag* QuantaCommon::tagFromDTD(Node *node)
{
if(!node || !node->tag)
return 0L;
return tagFromDTD(node->tag->dtd(), node->tag->name);
}
/** Returns an XML style string containing the GUI for attributes. */
TQString QuantaCommon::xmlFromAttributes(AttributeList* attributes)
{
TQString xmlStr;
TQTextStream stream( &xmlStr, IO_WriteOnly );
stream.setEncoding(TQTextStream::UnicodeUTF8);
if (attributes)
{
int row = 0;
for ( uint i = 0; i< attributes->count();i++)
{
Attribute *attribute = attributes->at(i);
TQString name = attribute->name.left(1).upper()+attribute->name.right(attribute->name.length()-1);
stream << " <attr name=\"" + attribute->name +"\" type=\""+attribute->type+"\"";
if (!attribute->defaultValue.isEmpty())
stream << " defaultValue=\"" + attribute->defaultValue + "\"";
if (!attribute->status.isEmpty())
stream << " status=\"" + attribute->status + "\"";
stream << ">" << endl;
stream << " <text>" << name << "</text>" << endl;
if (attribute->type != "check")
{
stream << " <textlocation col=\"0\" row=\"" << row << "\" />" << endl;
}
stream << " <location col=\"1\" row=\"" << row << "\" />" << endl;
if (attribute->type == "list")
{
stream << " <items>" << endl;
for (uint j = 0; j < attribute->values.count(); j++)
{
stream << " <item>" << attribute->values[j] << "</item>" << endl;
}
stream << " </items>" << endl;
}
stream << " </attr>" << endl << endl ;
row++;
} //for
} //if
return xmlStr;
}
/** Returns 0 if the (line,col) is inside the area specified by the other
arguments, -1 if it is before the area and 1 if it is after. */
int QuantaCommon::isBetween(int line, int col, int bLine, int bCol, int eLine,
int eCol){
int pos = 0;
if (line < bLine || (line == bLine && (col < bCol) )) pos = -1; //it is before
if (line > eLine || (line == eLine && (col > eCol) )) pos = 1; //it is after
return pos;
}
/** Returns a pointer to a KStandardDirs object usable for plugin searchup. type
is the plugin binary type (exe or lib). The returned pointer must be deleted by
the caller!! */
KStandardDirs* QuantaCommon::pluginDirs(const char *type)
{
KStandardDirs *dirs = new KStandardDirs();
dirs->addKDEDefaults();
for (uint i = 0; i < qConfig.pluginSearchPaths.count(); i++)
{
dirs->addResourceDir(type, qConfig.pluginSearchPaths[i]);
}
return dirs;
}
/** Return true, if the url belong to the mimetype group. */
bool QuantaCommon::checkMimeGroup(const KURL& url, const TQString& group)
{
KMimeType::List list = KMimeType::allMimeTypes();
KMimeType::List::iterator it;
bool status = false;
KMimeType::Ptr mime = KMimeType::findByURL(url);
TQString mimetype = mime->name();
mimetype = mimetype.section('/',-1);
for ( it = list.begin(); it != list.end(); ++it )
{
if ( ((*it)->name().tqcontains(group)) && ((*it)->name().tqfind(mimetype) != -1)
) {
status = true;
break;
}
}
if (!status && group == "text")
{
if (url.isLocalFile())
{
KMimeType::Format f = KMimeType::findFormatByFileContent(url.path());
if (f.text && f.compression == KMimeType::Format::NoCompression)
status = true;
} else
{
TQVariant v = mime->property("X-KDE-text");
if (v.isValid())
status = v.toBool();
}
}
if (!status && group == "text" && mimetype == "x-zerosize")
status = true;
return status;
}
/** Return true, if the url has the mimetype type. */
bool QuantaCommon::checkMimeType(const KURL& url, const TQString& type)
{
bool status = false;
TQString mimetype = KMimeType::findByURL(url)->name();
mimetype = mimetype.section('/',-1);
if (mimetype == type) status = true;
return status;
}
/** Return true, if the url has exactly the mimetype type. */
bool QuantaCommon::checkExactMimeType(const KURL& url, const TQString& type)
{
bool status = false;
TQString mimetype = KMimeType::findByURL(url)->name();
if (mimetype == type) status = true;
return status;
}
/** Returns the url without the filename. */
KURL QuantaCommon::convertToPath(const KURL& url)
{
KURL result = url;
result.setFileName("");
result.adjustPath(1);
return result;
}
/** Return a string to be used when an url is saved to the project file.
Returns url.url() if it's an absolute url and
url.path() if the url is relative */
TQString QuantaCommon::qUrl(const KURL &url)
{
TQString result = url.path();
if (url.path().startsWith("/")) result = url.url();
return result;
}
/** No descriptions */
void QuantaCommon::dirCreationError(TQWidget *widget, const KURL& url)
{
KMessageBox::error(widget, i18n("<qt>Cannot create folder<br><b>%1</b>.<br>Check that you have write permission in the tqparent folder or that the connection to<br><b>%2</b><br> is valid.</qt>")
.tqarg(url.prettyURL(0, KURL::StripFileProtocol))
.tqarg(url.protocol()+"://"+url.user()+"@"+url.host()));}
/**
Adds the backslash before the special chars (like ?, *, . ) so the returned
string can be used in regular expressions.*/
TQString QuantaCommon::makeRxCompatible(const TQString& s)
{
const uint max = 7;
const TQRegExp rxs[max]={TQRegExp("\\?"),
TQRegExp("\\*"),
TQRegExp("\\."),
TQRegExp("\\^"),
TQRegExp("\\$"),
TQRegExp("\\{"),
TQRegExp("\\}")
};
const TQString strs[max]={TQString("\\?"),
TQString("\\*"),
TQString("\\."),
TQString("\\^"),
TQString("\\$"),
TQString("\\{"),
TQString("\\}")
};
TQString str = s;
for (uint i = 0; i < max - 1; i++)
{
str.tqreplace(rxs[i], strs[i]);
}
return str;
}
/** Returns the translated a_str in English. A "back-translation" useful e.g in case of CSS elements selected from a listbox. */
TQString QuantaCommon::i18n2normal(const TQString& a_str)
{
//TODO: a TQMap lookup would be faster, but we need a pre-built TQMap<TQString,TQString>
const int keywordNum = 15 *5;
const TQString keywords[keywordNum] =
{"normal", "italic", "oblique", "serif", "sans-serif",
"cursive", "fantasy", "monospace", "small-caps", "lighter",
"bold", "bolder", "xx-small", "x-small", "small",
"medium", "large", "x-large", "xx-large", "smaller",
"larger", "repeat", "repeat-x", "repeat-y", "no-repeat",
"scroll", "fixed", "top", "center", "bottom",
"left", "right", "none", "underline", "overline"
"line-through", "blibk", "justify","baseline", "sub",
"super", "text-top","text-bottom","capitalize","uppercase",
"lowercase","thin", "thick", "[length value]","dotted",
"dashed", "solid", "double", "groove", "ridge",
"inset", "outset", "block", "inline", "list-item",
"none", "pre", "nowrap", "disc", "circle",
"square", "decimal", "lower-roman","upper-roman","lower-alpha",
"upper-alpha","inside","outside", "auto", "both" };
TQString str = a_str;
if (!a_str.isEmpty())
{
for (int i = 0; i < keywordNum; i++)
{
if (!keywords[i].isEmpty() && a_str == i18n(keywords[i].utf8()))
{
str = keywords[i];
break;
}
}
}
return str;
}
static const TQChar space(' ');
void QuantaCommon::removeCommentsAndQuotes(TQString &str, const DTDStruct *dtd)
{
//Replace all the commented strings and the escaped quotation marks (\", \')
// with spaces so they will not mess up our parsing
int pos = 0;
int l;
TQString s;
while (pos != -1)
{
pos = dtd->commentsStartRx.search(str, pos);
if (pos != -1)
{
s = dtd->commentsStartRx.cap();
if (s == "\\\"" || s == "\\'")
{
int i = pos;
int slahNum = 0;
while (i > 0 && str[i] == '\\')
{
slahNum++;
i--;
}
if (slahNum % 2 == 0)
{
pos++;
} else
{
str[pos] = space;
str[pos+1] = space;
pos += 2;
}
} else
{
s = dtd->comments[s];
l = str.tqfind(s, pos);
l = (l == -1) ? str.length() : l;
for (int i = pos; i < l ; i++)
{
str[i] = space;
}
pos = l + s.length();
}
}
}
//Now replace the quoted strings with spaces
TQRegExp strRx("(\"[^\"]*\"|'[^']*')");
pos = 0;
while (pos != -1)
{
pos = strRx.search(str, pos);
if (pos != -1)
{
l = strRx.matchedLength();
for (int i = pos; i < pos + l ; i++)
{
str[i] = space;
}
pos += l;
}
}
}
bool QuantaCommon::insideCommentsOrQuotes(int position, const TQString &string, const DTDStruct *dtd)
{
//Return true if position is inside a commented or quoted string
TQString str = string;
int pos = 0;
int l;
TQString s;
while (pos != -1)
{
pos = dtd->commentsStartRx.search(str, pos);
if (pos == position)
return true;
if (pos != -1)
{
s = dtd->commentsStartRx.cap();
if (s == "\\\"" || s == "\\'")
{
int i = pos;
int slahNum = 0;
while (i > 0 && str[i] == '\\')
{
slahNum++;
i--;
}
if (slahNum % 2 == 0)
{
pos++;
} else
{
str[pos] = space;
str[pos+1] = space;
pos += 2;
}
} else
{
s = dtd->comments[s];
l = str.tqfind(s, pos);
l = (l == -1) ? str.length() : l;
for (int i = pos; i < l ; i++)
{
str[i] = space;
if (i == position)
return true;
}
pos = l + s.length();
}
}
}
//Now replace the quoted strings with spaces
const TQRegExp strRx("(\"[^\"]*\"|'[^']*')");
pos = 0;
while (pos != -1)
{
pos = strRx.search(str, pos);
if (pos != -1)
{
l = strRx.matchedLength();
for (int i = pos; i < pos + l ; i++)
{
str[i] = space;
if (i == position)
return true;
}
pos += l;
}
}
return false;
}
DCOPReply QuantaCommon::callDCOPMethod(const TQString& interface, const TQString& method, const TQString& arguments)
{
TQStringList argumentList = TQStringList::split(",", arguments, true);
TQString app = "quanta";
if (!kapp->inherits("KUniqueApplication"))
{
pid_t pid = ::getpid();
app += TQString("-%1").tqarg(pid);
}
DCOPRef quantaRef(app.utf8(), interface.utf8());
DCOPReply reply;
int argumentCount = argumentList.count();
if (argumentCount == 0)
{
reply = quantaRef.call(method.utf8());
}
else if (argumentCount == 1)
{
reply = quantaRef.call(method.utf8(), argumentList[0]);
}
else if (argumentCount == 2)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1]);
else if (argumentCount == 3)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2]);
else if (argumentCount == 4)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3]);
else if (argumentCount == 5)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4]);
else if (argumentCount == 6)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5]);
else if (argumentCount == 7)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5], argumentList[6]);
else if (argumentCount == 8)
reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5], argumentList[6], argumentList[7]);
return reply;
}
void QuantaCommon::normalizeStructure(TQString f,TQStringList& l)
{
f.remove("\t");
f.remove("\n");
f.remove("\r");
while(f.tqcontains("<"))
{
TQString z(f);
z.truncate(z.tqfind(">")+1);
z.remove(0,z.tqfind("<"));
f.remove(0,f.tqfind(">")+1);
l.append(z);
}
}
bool QuantaCommon::closesTag(Tag *tag1, Tag *tag2)
{
if (tag1->nameSpace.isEmpty())
{
if (!tag2->nameSpace.isEmpty())
return false; //namespace missmatch
TQString tag1Name = tag1->dtd()->caseSensitive ? tag1->name : tag1->name.upper();
TQString tag2Name = tag2->dtd()->caseSensitive ? tag2->name : tag2->name.upper();
if ("/" + tag1Name != tag2Name)
return false; //not the closing tag
} else
{
if (tag2->nameSpace.isEmpty())
return false; //namespace missmatch
TQString tag1Name = tag1->dtd()->caseSensitive ? (tag1->nameSpace + tag1->name) : (tag1->nameSpace.upper() + tag1->name.upper());
TQString tag2Name = tag2->dtd()->caseSensitive ? (tag2->nameSpace + tag2->name) : (tag2->nameSpace.upper() + tag2->name.upper());
if ("/" + tag1Name != tag2Name)
return false; //namespace missmatch or not the closing tag
}
return true;
}
bool QuantaCommon::closesTag(TQString namespaceName, TQString tagName, bool caseSensitive,
TQString namespaceName2, TQString tagName2, bool caseSensitive2)
{
TQString tag1Name, tag2Name;
if(namespaceName.isEmpty())
{
if(!namespaceName.isEmpty())
return false;//namespace missmatch
tag1Name = caseSensitive ? tagName : tagName.upper();
tag2Name = caseSensitive2 ? tagName2 : tagName2.upper();
if("/" + tag1Name != tag2Name)
return false;//not the closing tag
}
else
{
if(namespaceName2.isEmpty())
return false;//namespace missmatch
tag1Name = caseSensitive ? (namespaceName + tagName) : (namespaceName.upper() +
tagName.upper());
tag2Name = caseSensitive2 ? (namespaceName2 + tagName2) : (namespaceName2.upper() +
tagName2.upper());
if("/" + tag1Name != tag2Name)
return false; //namespace missmatch or not the closing tag
}
return true;
}
int QuantaCommon::denyBinaryInsert(TQWidget *window)
{
int result = KMessageBox::questionYesNo(window, i18n("The file type is not recognized. \
Opening binary files may confuse Quanta.\n Are you sure you want to open this file?"),
i18n("Unknown Type"), KStdGuiItem::open(), i18n("Do Not Open"), "Open Everything");
return result;
}
bool QuantaCommon::checkOverwrite(const KURL& url, TQWidget *window)
{
bool result = true;
if (QExtFileInfo::exists(url, false, window))
{
if (KMessageBox::warningContinueCancel(window,
i18n( "<qt>The file <b>%1</b> already exists.<br>Do you want to overwrite it?</qt>" ).tqarg(url.prettyURL(0, KURL::StripFileProtocol)), TQString(), i18n("Overwrite")) == KMessageBox::Cancel)
result = false;
}
return result;
}
TQStringList QuantaCommon::readPathListEntry(KConfig *config, const TQString &pKey)
{
TQStringList list = config->readPathListEntry(pKey);
TQStringList::Iterator end = list.end();
for (TQStringList::Iterator it = list.begin(); it != end; ++it)
{
KURL u = KURL::fromPathOrURL(*it);
if (u.isValid() && u.isLocalFile())
{
u.setPath(QExtFileInfo::canonicalPath(u.path()));
*it = u.url();
}
}
return list;
}
TQString QuantaCommon::readPathEntry(KConfig *config, const TQString &pKey)
{
TQString path = config->readPathEntry(pKey);
KURL u = KURL::fromPathOrURL(path);
if (u.isValid() && u.isLocalFile())
{
u.setPath(QExtFileInfo::canonicalPath(u.path()));
path = u.url();
}
return path;
}
TQString QuantaCommon::encodedChar(uint code)
{
if (replacementMap.tqcontains(code))
return TQString("%1;").tqarg(replacementMap[code]);
else
return TQString("&#%1;").tqarg(code);
}