Ran qt3to4
[basket4.git] / src / tools.cpp
blob0eed15d18e177b231d6b136b9b9ddccee349a411
1 /***************************************************************************
2 * Copyright (C) 2003 by S�astien Laot *
3 * slaout@linux62.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <kdebug.h>
22 #include <qstring.h>
23 #include <qpixmap.h>
24 #include <qimage.h>
25 #include <q3stylesheet.h>
26 #include <qregexp.h>
27 #include <q3valuestack.h>
28 #include <qfileinfo.h>
29 #include <qdir.h>
30 #include <qmime.h>
31 #include <qfont.h>
32 #include <qfontinfo.h>
33 #include <qobject.h>
34 //Added by qt3to4:
35 #include <Q3CString>
36 #include <Q3MemArray>
38 #include "tools.h"
40 Q3MemArray<QTime> StopWatch::starts;
41 Q3MemArray<double> StopWatch::totals;
42 Q3MemArray<uint> StopWatch::counts;
44 void StopWatch::start(uint id)
46 if (id >= starts.size()) {
47 totals.resize(id + 1);
48 counts.resize(id + 1);
49 for (uint i = starts.size(); i <= id; i++) {
50 totals[i] = 0;
51 counts[i] = 0;
53 starts.resize(id + 1);
55 starts[id] = QTime::currentTime();
58 void StopWatch::check(uint id)
60 if (id >= starts.size())
61 return;
62 double time = starts[id].msecsTo(QTime::currentTime()) / 1000.0;
63 totals[id] += time;
64 counts[id]++;
65 kdDebug() << k_funcinfo << "Timer_" << id << ": " << time << " s [" << counts[id] << " times, total: " << totals[id] << " s, average: " << totals[id] / counts[id] << " s]" << endl;
68 QString Tools::textToHTML(const QString &text)
70 if (text.isEmpty())
71 return "<p></p>";
72 if (/*text.isEmpty() ||*/ text == " " || text == "&nbsp;")
73 return "<p>&nbsp;</p>";
75 // convertFromPlainText() replace "\n\n" by "</p>\n<p>": we don't want that
76 QString htmlString = Q3StyleSheet::convertFromPlainText(text, Q3StyleSheetItem::WhiteSpaceNormal);
77 return htmlString.replace("</p>\n", "<br>\n<br>\n").replace("\n<p>", "\n"); // Don't replace first and last tags
80 QString Tools::textToHTMLWithoutP(const QString &text)
82 // textToHTML(text) return "<p>HTMLizedText</p>". We remove the strating "<p>" and ending </p>"
83 QString HTMLizedText = textToHTML(text);
84 return HTMLizedText.mid(3, HTMLizedText.length() - 3 - 4);
87 QString Tools::htmlToParagraph(const QString &html)
89 QString result = html;
90 bool startedBySpan = false;
92 // Remove the <html> start tag, all the <head> and the <body> start
93 // Because <body> can contain style="..." parameter, we transform it to <span>
94 int pos = result.find("<body");
95 if (pos != -1) {
96 result = "<span" + result.mid(pos + 5);
97 startedBySpan = true;
100 // Remove the ending "</p>\n</body></html>", each tag can be separated by space characters (%s)
101 // "</p>" can be omitted (eg. if the HTML doesn't contain paragraph but tables), as well as "</body>" (optinal)
102 pos = result.find(QRegExp("(?:(?:</p>[\\s\\n\\r\\t]*)*</body>[\\s\\n\\r\\t]*)*</html>", false)); // Case unsensitive
103 if (pos != -1)
104 result = result.left(pos);
106 if (startedBySpan)
107 result += "</span>";
109 return result.replace("</p>", "<br><br>").replace("<p>", "");
112 // The following is adapted from KStringHanlder::tagURLs
113 // The adaptation lies in the change to urlEx
114 // Thanks to Richard Heck
115 QString Tools::tagURLs(const QString &text)
117 QRegExp urlEx("(www\\.(?!\\.)|([a-zA-z]+)://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%\\$]+[\\d\\w/]");
119 QString richText(text);
120 int urlPos = 0;
121 int urlLen;
122 while ((urlPos = urlEx.search(richText, urlPos)) >= 0) {
123 urlLen = urlEx.matchedLength();
124 QString href = richText.mid(urlPos, urlLen);
125 // Qt doesn't support (?<=pattern) so we do it here
126 if ((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()) {
127 urlPos++;
128 continue;
130 QString anchor = "<a href=\"" + href + "\">" + href + "</a>";
131 richText.replace(urlPos, urlLen, anchor);
132 urlPos += anchor.length();
134 return richText;
137 QString Tools::htmlToText(const QString &html)
139 QString text = htmlToParagraph(html);
140 text.remove("\n");
141 text.replace("</h1>", "\n");
142 text.replace("</h2>", "\n");
143 text.replace("</h3>", "\n");
144 text.replace("</h4>", "\n");
145 text.replace("</h5>", "\n");
146 text.replace("</h6>", "\n");
147 text.replace("</li>", "\n");
148 text.replace("</dt>", "\n");
149 text.replace("</dd>", "\n");
150 text.replace("<dd>", " ");
151 text.replace("</div>","\n");
152 text.replace("</blockquote>","\n");
153 text.replace("</caption>","\n");
154 text.replace("</tr>", "\n");
155 text.replace("</th>", " ");
156 text.replace("</td>", " ");
157 text.replace("<br>", "\n");
158 text.replace("<br />","\n");
159 // FIXME: Format <table> tags better, if possible
160 // TODO: Replace &eacute; and co. by theire equivalent!
162 // To manage tags:
163 int pos = 0;
164 int pos2;
165 QString tag, tag3;
166 // To manage lists:
167 int deep = 0; // The deep of the current line in imbriqued lists
168 Q3ValueStack<bool> ul; // true if current list is a <ul> one, false if it's an <ol> one
169 Q3ValueStack<int> lines; // The line number if it is an <ol> list
170 // We're removing every other tags, or replace them in the case of li:
171 while ( (pos = text.find("<"), pos) != -1 ) {
172 // What is the current tag?
173 tag = text.mid(pos + 1, 2);
174 tag3 = text.mid(pos + 1, 3);
175 // Lists work:
176 if (tag == "ul") {
177 deep++;
178 ul.push(true);
179 lines.push(-1);
180 } else if (tag == "ol") {
181 deep++;
182 ul.push(false);
183 lines.push(0);
184 } else if (tag3 == "/ul" || tag3 == "/ol") {
185 deep--;
186 ul.pop();
187 lines.pop();
189 // Where the tag closes?
190 pos2 = text.find(">");
191 if (pos2 != -1) {
192 // Remove the tag:
193 text.remove(pos, pos2 - pos + 1);
194 // And replace li with "* ", "x. "... without forbidding to indent that:
195 if (tag == "li") {
196 // How many spaces before the line (indentation):
197 QString spaces = "";
198 for (int i = 1; i < deep; i++)
199 spaces += " ";
200 // The bullet or number of the line:
201 QString bullet = "* ";
202 if (ul.top() == false) {
203 lines.push(lines.pop() + 1);
204 bullet = QString::number(lines.top()) + ". ";
206 // Insertion:
207 text.insert(pos, spaces + bullet);
209 if ( (tag3 == "/ul" || tag3 == "/ol") && deep == 0 )
210 text.insert(pos, "\n"); // Empty line before and after a set of lists
212 ++pos;
215 text.replace("&gt;", ">");
216 text.replace("&lt;", "<");
217 text.replace("&quot;", "\"");
218 text.replace("&nbsp;", " ");
219 text.replace("&amp;", "&"); // CONVERT IN LAST!!
221 return text;
224 QString Tools::cssFontDefinition(const QFont &font, bool onlyFontFamily)
226 // The font definition:
227 QString definition = QString(font.italic() ? "italic " : "") +
228 QString(font.bold() ? "bold " : "") +
229 QString::number(QFontInfo(font).pixelSize()) + "px ";
231 // Then, try to match the font name with a standard CSS font family:
232 QString genericFont = "";
233 if (definition.contains("serif", false) || definition.contains("roman", false))
234 genericFont = "serif";
235 // No "else if" because "sans serif" must be counted as "sans". So, the order between "serif" and "sans" is important
236 if (definition.contains("sans", false) || definition.contains("arial", false) || definition.contains("helvetica", false))
237 genericFont = "sans-serif";
238 if (definition.contains("mono", false) || definition.contains("courier", false) ||
239 definition.contains("typewriter", false) || definition.contains("console", false) ||
240 definition.contains("terminal", false) || definition.contains("news", false))
241 genericFont = "monospace";
243 // Eventually add the generic font family to the definition:
244 QString fontDefinition = "\"" + font.family() + "\"";
245 if (!genericFont.isEmpty())
246 fontDefinition += ", " + genericFont;
248 if (onlyFontFamily)
249 return fontDefinition;
251 return definition + fontDefinition;
254 QString Tools::stripEndWhiteSpaces(const QString &string)
256 uint length = string.length();
257 uint i;
258 for (i = length; i > 0; --i)
259 if (!string[i-1].isSpace())
260 break;
261 if (i == 0)
262 return "";
263 else
264 return string.left(i);
269 bool Tools::isWebColor(const QColor &color)
271 int r = color.red(); // The 216 web colors are those colors whose RGB (Red, Green, Blue)
272 int g = color.green(); // values are all in the set (0, 51, 102, 153, 204, 255).
273 int b = color.blue();
275 return ( ( r == 0 || r == 51 || r == 102 ||
276 r == 153 || r == 204 || r == 255 ) &&
277 ( g == 0 || g == 51 || g == 102 ||
278 g == 153 || g == 204 || g == 255 ) &&
279 ( b == 0 || b == 51 || b == 102 ||
280 b == 153 || b == 204 || b == 255 ) );
283 QColor Tools::mixColor(const QColor &color1, const QColor &color2)
285 QColor mixedColor;
286 mixedColor.setRgb( (color1.red() + color2.red()) / 2,
287 (color1.green() + color2.green()) / 2,
288 (color1.blue() + color2.blue()) / 2 );
289 return mixedColor;
292 bool Tools::tooDark(const QColor &color)
294 int dontCare, value;
295 color.getHsv(/*hue:*/dontCare, /*saturation:*/dontCare, value);
296 return value < 175;
300 // TODO: Use it for all indentPixmap()
301 QPixmap Tools::normalizePixmap(const QPixmap &pixmap, int width, int height)
303 if (height <= 0)
304 height = width;
306 if (pixmap.isNull() || (pixmap.width() == width && pixmap.height() == height))
307 return pixmap;
309 return pixmap;
312 QPixmap Tools::indentPixmap(const QPixmap &source, int depth, int deltaX)
314 // Verify if it is possible:
315 if (depth <= 0 || source.isNull())
316 return source;
318 // Compute the number of pixels to indent:
319 if (deltaX <= 0)
320 deltaX = 2 * source.width() / 3;
321 int indent = depth * deltaX;
323 // Create the images:
324 QImage resultImage(indent + source.width(), source.height(), 32);
325 QImage sourceImage = source.convertToImage();
326 resultImage.setAlphaBuffer(true);
328 // Clear the indent part (the left part) by making it fully transparent:
329 uint *p;
330 for (int row = 0; row < resultImage.height(); ++row) {
331 for (int column = 0; column < resultImage.width(); ++column) {
332 p = (uint *)resultImage.scanLine(row) + column;
333 *p = 0; // qRgba(0, 0, 0, 0)
337 // Copy the source image byte per byte to the right part:
338 uint *q;
339 for (int row = 0; row < sourceImage.height(); ++row) {
340 for (int column = 0; column < sourceImage.width(); ++column) {
341 p = (uint *)resultImage.scanLine(row) + indent + column;
342 q = (uint *)sourceImage.scanLine(row) + column;
343 *p = *q;
347 // And return the result:
348 QPixmap result;
349 result.convertFromImage(resultImage);
350 return result;
353 #include <iostream>
355 void Tools::deleteRecursively(const QString &folderOrFile)
357 if (folderOrFile.isEmpty())
358 return;
360 QFileInfo fileInfo(folderOrFile);
361 if (fileInfo.isDir()) {
362 // Delete the child files:
363 QDir dir(folderOrFile, QString::null, QDir::Name | QDir::IgnoreCase, QDir::All | QDir::Hidden);
364 QStringList list = dir.entryList();
365 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
366 if ( *it != "." && *it != ".." )
367 deleteRecursively(folderOrFile + "/" + *it);
368 // And then delete the folder:
369 dir.rmdir(folderOrFile);
370 } else
371 // Delete the file:
372 QFile::remove(folderOrFile);
375 QString Tools::fileNameForNewFile(const QString &wantedName, const QString &destFolder)
377 QString fileName = wantedName;
378 QString fullName = destFolder + fileName;
379 QString extension = "";
380 int number = 2;
381 QDir dir;
383 // First check if the file do not exists yet (simplier and more often case)
384 dir = QDir(fullName);
385 if ( ! dir.exists(fullName) )
386 return fileName;
388 // Find the file extension, if it exists : Split fileName in fileName and extension
389 // Example : fileName == "note5-3.txt" => fileName = "note5-3" and extension = ".txt"
390 int extIndex = fileName.findRev('.');
391 if (extIndex != -1 && extIndex != int(fileName.length()-1)) { // Extension found and fileName do not ends with '.' !
392 extension = fileName.mid(extIndex);
393 fileName.truncate(extIndex);
394 } // else fileName = fileName and extension = ""
396 // Find the file number, if it exists : Split fileName in fileName and number
397 // Example : fileName == "note5-3" => fileName = "note5" and number = 3
398 int extNumber = fileName.findRev('-');
399 if (extNumber != -1 && extNumber != int(fileName.length()-1)) { // Number found and fileName do not ends with '-' !
400 bool isANumber;
401 int theNumber = fileName.mid(extNumber + 1).toInt(&isANumber);
402 if (isANumber) {
403 number = theNumber;
404 fileName.truncate(extNumber);
405 } // else :
406 } // else fileName = fileName and number = 2 (because if the file already exists, the genereated name is at last the 2nd)
408 QString finalName;
409 for (/*int number = 2*/; ; ++number) { // TODO: FIXME: If overflow ???
410 finalName = fileName + "-" + QString::number(number) + extension;
411 fullName = destFolder + finalName;
412 dir = QDir(fullName);
413 if ( ! dir.exists(fullName) )
414 break;
417 return finalName;
421 // TODO: Move it from NoteFactory
422 /*QString NoteFactory::iconForURL(const KURL &url)
424 QString icon = KMimeType::iconForURL(url.url());
425 if ( url.protocol() == "mailto" )
426 icon = "message";
427 return icon;
430 bool Tools::isAFileCut(QMimeSource *source)
432 if (source->provides("application/x-kde-cutselection")) {
433 QByteArray array = source->encodedData("application/x-kde-cutselection");
434 return !array.isEmpty() && Q3CString(array.data(), array.size() + 1).at(0) == '1';
435 } else
436 return false;
439 void Tools::printChildren(QObject* parent)
441 const QObjectList* objs = parent->children();
442 QObjectListIt it(*objs);
443 QObject *obj;
445 while((obj = it.current())!= 0){
446 ++it;
447 kdDebug() << k_funcinfo << obj->className() << ": " << obj->name() << endl;