1 /***************************************************************************
2 * Copyright (C) 2005 by Sébastien Laoût *
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 ***************************************************************************/
20
21 #include "tag.h"
22
23 #include <KIconLoader>
24 #include <KActionCollection>
25 #include <KLocalizedString>
26
27 #include <QtCore/QDir>
28 #include <QtCore/QList>
29 #include <QtCore/QTextStream>
30 #include <QtGui/QFont>
31 #include <QtXml/QDomDocument>
32 #include <QLocale>
33
34 #include "xmlwork.h"
35 #include "global.h"
36 #include "debugwindow.h"
37 #include "bnpview.h"
38 #include "tools.h"
39 #include "basketscene.h"
40 #include "gitwrapper.h"
41
42
43 /** class State: */
44
State(const QString & id,Tag * tag)45 State::State(const QString &id, Tag *tag)
46 : m_id(id), m_name(), m_emblem(), m_bold(false), m_italic(false), m_underline(false),
47 m_strikeOut(false), m_textColor(), m_fontName(), m_fontSize(-1), m_backgroundColor(),
48 m_textEquivalent(), m_onAllTextLines(false), m_allowCrossReferences(true), m_parentTag(tag)
49 {
50 }
51
~State()52 State::~State()
53 {
54 }
55
nextState(bool cycle)56 State* State::nextState(bool cycle /*= true*/)
57 {
58 if (!parentTag())
59 return 0;
60
61 List states = parentTag()->states();
62 // The tag contains only one state:
63 if (states.count() == 1)
64 return 0;
65 // Find the next state:
66 for (List::iterator it = states.begin(); it != states.end(); ++it)
67 // Found the current state in the list:
68 if (*it == this) {
69 // Find the next state:
70 State *next = *(++it);
71 if (it == states.end())
72 return (cycle ? states.first() : 0);
73 return next;
74 }
75 // Should not happens:
76 Q_ASSERT(false);
77 return 0;
78 }
79
fullName()80 QString State::fullName()
81 {
82 if (!parentTag() || parentTag()->states().count() == 1)
83 return (name().isEmpty() && parentTag() ? parentTag()->name() : name());
84 return QString(i18n("%1: %2", parentTag()->name(), name()));
85 }
86
font(QFont base)87 QFont State::font(QFont base)
88 {
89 if (bold())
90 base.setBold(true);
91 if (italic())
92 base.setItalic(true);
93 if (underline())
94 base.setUnderline(true);
95 if (strikeOut())
96 base.setStrikeOut(true);
97 if (!fontName().isEmpty())
98 base.setFamily(fontName());
99 if (fontSize() > 0)
100 base.setPointSize(fontSize());
101 return base;
102 }
103
toCSS(const QString & gradientFolderPath,const QString & gradientFolderName,const QFont & baseFont)104 QString State::toCSS(const QString &gradientFolderPath, const QString &gradientFolderName, const QFont &baseFont)
105 {
106 QString css;
107 if (bold())
108 css += " font-weight: bold;";
109 if (italic())
110 css += " font-style: italic;";
111 if (underline() && strikeOut())
112 css += " text-decoration: underline line-through;";
113 else if (underline())
114 css += " text-decoration: underline;";
115 else if (strikeOut())
116 css += " text-decoration: line-through;";
117 if (textColor().isValid())
118 css += " color: " + textColor().name() + ";";
119 if (!fontName().isEmpty()) {
120 QString fontFamily = Tools::cssFontDefinition(fontName(), /*onlyFontFamily=*/true);
121 css += " font-family: " + fontFamily + ";";
122 }
123 if (fontSize() > 0)
124 css += " font-size: " + QString::number(fontSize()) + "px;";
125 if (backgroundColor().isValid()) {
126 // Get the colors of the gradient and the border:
127 QColor topBgColor;
128 QColor bottomBgColor;
129 Note::getGradientColors(backgroundColor(), &topBgColor, &bottomBgColor);
130 // Produce the CSS code:
131 QString gradientFileName = BasketScene::saveGradientBackground(backgroundColor(), font(baseFont), gradientFolderPath);
132 css += " background: " + bottomBgColor.name() + " url('" + gradientFolderName + gradientFileName + "') repeat-x;";
133 css += " border-top: solid " + topBgColor.name() + " 1px;";
134 css += " border-bottom: solid " + Tools::mixColor(topBgColor, bottomBgColor).name() + " 1px;";
135 }
136
137 if (css.isEmpty())
138 return "";
139 else
140 return " .tag_" + id() + " {" + css + " }\n";
141 }
142
merge(const List & states,State * result,int * emblemsCount,bool * haveInvisibleTags,const QColor & backgroundColor)143 void State::merge(const List &states, State *result, int *emblemsCount, bool *haveInvisibleTags, const QColor &backgroundColor)
144 {
145 *result = State(); // Reset to default values.
146 *emblemsCount = 0;
147 *haveInvisibleTags = false;
148
149 for (List::const_iterator it = states.begin(); it != states.end(); ++it) {
150 State *state = *it;
151 bool isVisible = false;
152 // For each propertie, if that properties have a value (is not default) is the current state of the list,
153 // and if it haven't been set to the result state by a previous state, then it's visible and we assign the propertie to the result state.
154 if (!state->emblem().isEmpty()) {
155 ++*emblemsCount;
156 isVisible = true;
157 }
158 if (state->bold() && !result->bold()) {
159 result->setBold(true);
160 isVisible = true;
161 }
162 if (state->italic() && !result->italic()) {
163 result->setItalic(true);
164 isVisible = true;
165 }
166 if (state->underline() && !result->underline()) {
167 result->setUnderline(true);
168 isVisible = true;
169 }
170 if (state->strikeOut() && !result->strikeOut()) {
171 result->setStrikeOut(true);
172 isVisible = true;
173 }
174 if (state->textColor().isValid() && !result->textColor().isValid()) {
175 result->setTextColor(state->textColor());
176 isVisible = true;
177 }
178 if (!state->fontName().isEmpty() && result->fontName().isEmpty()) {
179 result->setFontName(state->fontName());
180 isVisible = true;
181 }
182 if (state->fontSize() > 0 && result->fontSize() <= 0) {
183 result->setFontSize(state->fontSize());
184 isVisible = true;
185 }
186 if (state->backgroundColor().isValid() && !result->backgroundColor().isValid() && state->backgroundColor() != backgroundColor) { // vv
187 result->setBackgroundColor(state->backgroundColor()); // This is particular: if the note background color is the same as the basket one, don't use that.
188 isVisible = true;
189 }
190 // If it's not visible, well, at least one tag is not visible: the note will display "..." at the tags arrow place to show that:
191 if (!isVisible)
192 *haveInvisibleTags = true;
193 }
194 }
195
copyTo(State * other)196 void State::copyTo(State *other)
197 {
198 other->m_id = m_id;
199 other->m_name = m_name;
200 other->m_emblem = m_emblem;
201 other->m_bold = m_bold;
202 other->m_italic = m_italic;
203 other->m_underline = m_underline;
204 other->m_strikeOut = m_strikeOut;
205 other->m_textColor = m_textColor;
206 other->m_fontName = m_fontName;
207 other->m_fontSize = m_fontSize;
208 other->m_backgroundColor = m_backgroundColor;
209 other->m_textEquivalent = m_textEquivalent;
210 other->m_onAllTextLines = m_onAllTextLines; // TODO
211 other->m_allowCrossReferences = m_allowCrossReferences;
212 //TODO: other->m_parentTag;
213 }
214
215 /** class Tag: */
216
217 Tag::List Tag::all = Tag::List();
218
219 long Tag::nextStateUid = 1;
220
getNextStateUid()221 long Tag::getNextStateUid()
222 {
223 return nextStateUid++; // Return the next Uid and THEN increment the Uid
224 }
225
Tag()226 Tag::Tag()
227 {
228 static int tagNumber = 0;
229 ++tagNumber;
230 QString sAction = "tag_shortcut_number_" + QString::number(tagNumber);
231
232 KActionCollection *ac = Global::bnpView->actionCollection();
233 m_action = ac->addAction(sAction, Global::bnpView,
234 SLOT(activatedTagShortcut()));
235 m_action->setText("FAKE TEXT");
236 m_action->setIcon(QIcon::fromTheme("FAKE ICON"));
237
238 ac->setShortcutsConfigurable(m_action, false); // We do it in the tag properties dialog
239
240 m_inheritedBySiblings = false;
241 }
242
~Tag()243 Tag::~Tag()
244 {
245 delete m_action;
246 }
247
setName(const QString & name)248 void Tag::setName(const QString &name)
249 {
250 m_name = name;
251 m_action->setText("TAG SHORTCUT: " + name); // TODO: i18n (for debug purpose only by now).
252 }
253
stateForId(const QString & id)254 State* Tag::stateForId(const QString &id)
255 {
256 for (List::iterator it = all.begin(); it != all.end(); ++it)
257 for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2)
258 if ((*it2)->id() == id)
259 return *it2;
260 return 0;
261 }
262
tagForKAction(QAction * action)263 Tag* Tag::tagForKAction(QAction *action)
264 {
265 for (List::iterator it = all.begin(); it != all.end(); ++it)
266 if ((*it)->m_action == action)
267 return *it;
268 return 0;
269 }
270
loadTags(const QString & path)271 QMap<QString, QString> Tag::loadTags(const QString &path/* = QString()*//*, bool merge = false*/)
272 {
273 QMap<QString, QString> mergedStates;
274
275 bool merge = !path.isEmpty();
276 QString fullPath = (merge ? path : Global::savesFolder() + "tags.xml");
277 QString doctype = "basketTags";
278
279 QDir dir;
280 if (!dir.exists(fullPath)) {
281 if (merge)
282 return mergedStates;
283 DEBUG_WIN << "Tags file does not exist: Creating it...";
284 createDefaultTagsSet(fullPath);
285 }
286
287 QScopedPointer<QDomDocument> document(XMLWork::openFile(doctype, fullPath));
288 if (!document) {
289 DEBUG_WIN << "<font color=red>FAILED to read the tags file</font>";
290 return mergedStates;
291 }
292
293 QDomElement docElem = document->documentElement();
294 if (!merge)
295 nextStateUid = docElem.attribute("nextStateUid", QString::number(nextStateUid)).toLong();
296
297 QDomNode node = docElem.firstChild();
298 while (!node.isNull()) {
299 QDomElement element = node.toElement();
300 if ((!element.isNull()) && element.tagName() == "tag") {
301 Tag *tag = new Tag();
302 // Load properties:
303 QString name = XMLWork::getElementText(element, "name");
304 QString shortcut = XMLWork::getElementText(element, "shortcut");
305 QString inherited = XMLWork::getElementText(element, "inherited", "false");
306 tag->setName(name);
307 tag->setShortcut(QKeySequence(shortcut));
308 tag->setInheritedBySiblings(XMLWork::trueOrFalse(inherited));
309 // Load states:
310 QDomNode subNode = element.firstChild();
311 while (!subNode.isNull()) {
312 QDomElement subElement = subNode.toElement();
313 if ((!subElement.isNull()) && subElement.tagName() == "state") {
314 State *state = new State(subElement.attribute("id"), tag);
315 state->setName(XMLWork::getElementText(subElement, "name"));
316 state->setEmblem(XMLWork::getElementText(subElement, "emblem"));
317 QDomElement textElement = XMLWork::getElement(subElement, "text");
318 state->setBold(XMLWork::trueOrFalse(textElement.attribute("bold", "false")));
319 state->setItalic(XMLWork::trueOrFalse(textElement.attribute("italic", "false")));
320 state->setUnderline(XMLWork::trueOrFalse(textElement.attribute("underline", "false")));
321 state->setStrikeOut(XMLWork::trueOrFalse(textElement.attribute("strikeOut", "false")));
322 QString textColor = textElement.attribute("color", "");
323 state->setTextColor(textColor.isEmpty() ? QColor() : QColor(textColor));
324 QDomElement fontElement = XMLWork::getElement(subElement, "font");
325 state->setFontName(fontElement.attribute("name", ""));
326 QString fontSize = fontElement.attribute("size", "");
327 state->setFontSize(fontSize.isEmpty() ? -1 : fontSize.toInt());
328 QString backgroundColor = XMLWork::getElementText(subElement, "backgroundColor", "");
329 state->setBackgroundColor(backgroundColor.isEmpty() ? QColor() : QColor(backgroundColor));
330 QDomElement textEquivalentElement = XMLWork::getElement(subElement, "textEquivalent");
331 state->setTextEquivalent(textEquivalentElement.attribute("string", ""));
332 state->setOnAllTextLines(XMLWork::trueOrFalse(textEquivalentElement.attribute("onAllTextLines", "false")));
333 QString allowXRef = XMLWork::getElementText(subElement, "allowCrossReferences", "true");
334 state->setAllowCrossReferences(XMLWork::trueOrFalse(allowXRef));
335 tag->appendState(state);
336 }
337 subNode = subNode.nextSibling();
338 }
339 // If the Tag is Valid:
340 if (tag->countStates() > 0) {
341 // Rename Things if Needed:
342 State *firstState = tag->states().first();
343 if (tag->countStates() == 1 && firstState->name().isEmpty())
344 firstState->setName(tag->name());
345 if (tag->name().isEmpty())
346 tag->setName(firstState->name());
347 // Add or Merge the Tag:
348 if (!merge) {
349 all.append(tag);
350 } else {
351 Tag *similarTag = tagSimilarTo(tag);
352 // Tag does not exists, add it:
353 if (similarTag == 0) {
354 // We are merging the new states, so we should choose new and unique (on that computer) ids for those states:
355 for (State::List::iterator it = tag->states().begin(); it != tag->states().end(); ++it) {
356 State *state = *it;
357 QString uid = state->id();
358 QString newUid = "tag_state_" + QString::number(getNextStateUid());
359 state->setId(newUid);
360 mergedStates[uid] = newUid;
361 }
362 // TODO: if shortcut is already assigned to a previous note, do not import it, keep the user settings!
363 all.append(tag);
364 // Tag already exists, rename to theire ids:
365 } else {
366 State::List::iterator it2 = similarTag->states().begin();
367 for (State::List::iterator it = tag->states().begin(); it != tag->states().end(); ++it, ++it2) {
368 State *state = *it;
369 State *similarState = *it2;
370 QString uid = state->id();
371 QString newUid = similarState->id();
372 if (uid != newUid)
373 mergedStates[uid] = newUid;
374 }
375 delete tag; // Already exists, not to be merged. Delete the shortcut and all.
376 }
377 }
378 }
379 }
380 node = node.nextSibling();
381 }
382
383 return mergedStates;
384 }
385
tagSimilarTo(Tag * tagToTest)386 Tag* Tag::tagSimilarTo(Tag *tagToTest)
387 {
388 // Tags are considered similar if they have the same name, the same number of states, in the same order, and the same look.
389 // Keyboard shortcut, text equivalent and onEveryLines are user settings, and thus not considered during the comparison.
390 // Default tags (To Do, Important, Idea...) do not take into account the name of the tag and states during the comparison.
391 // Default tags are equal only if they have the same number of states, in the same order, and the same look.
392 // This is because default tag names are translated differently in every countries, but they are essentialy the same!
393 // User tags begins with "tag_state_" followed by a number. Default tags are the other ones.
394
395 // Browse all tags:
396 for (List::iterator it = all.begin(); it != all.end(); ++it) {
397 Tag *tag = *it;
398 bool same = true;
399 bool sameName;
400 bool defaultTag = true;
401 // We test only name and look. Shorcut and whenever it is inherited by sibling new notes are user settings only!
402 sameName = tag->name() == tagToTest->name();
403 if (tag->countStates() != tagToTest->countStates())
404 continue; // Tag is different!
405 // We found a tag with same name, check if every states/look are same too:
406 State::List::iterator itTest = tagToTest->states().begin();
407 for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2, ++itTest) {
408 State *state = *it2;
409 State *stateToTest = *itTest;
410 if (state->id().startsWith(QLatin1String("tag_state_")) || stateToTest->id().startsWith(QLatin1String("tag_state_"))) {
411 defaultTag = false;
412 }
413 if (state->name() != stateToTest->name()) {
414 sameName = false;
415 }
416 if (state->emblem() != stateToTest->emblem()) {
417 same = false; break;
418 }
419 if (state->bold() != stateToTest->bold()) {
420 same = false; break;
421 }
422 if (state->italic() != stateToTest->italic()) {
423 same = false; break;
424 }
425 if (state->underline() != stateToTest->underline()) {
426 same = false; break;
427 }
428 if (state->strikeOut() != stateToTest->strikeOut()) {
429 same = false; break;
430 }
431 if (state->textColor() != stateToTest->textColor()) {
432 same = false; break;
433 }
434 if (state->fontName() != stateToTest->fontName()) {
435 same = false; break;
436 }
437 if (state->fontSize() != stateToTest->fontSize()) {
438 same = false; break;
439 }
440 if (state->backgroundColor() != stateToTest->backgroundColor()) {
441 same = false; break;
442 }
443 // Text equivalent (as well as onAllTextLines) is also a user setting!
444 }
445 // We found an existing tag that is "exactly" the same:
446 if (same && (sameName || defaultTag))
447 return tag;
448 }
449
450 // Not found:
451 return 0;
452 }
453
saveTags()454 void Tag::saveTags()
455 {
456 DEBUG_WIN << "Saving tags...";
457 saveTagsTo(all, Global::savesFolder() + "tags.xml");
458
459 GitWrapper::commitTagsXml();
460 }
461
saveTagsTo(QList<Tag * > & list,const QString & fullPath)462 void Tag::saveTagsTo(QList<Tag*> &list, const QString &fullPath)
463 {
464 // Create Document:
465 QDomDocument document(/*doctype=*/"basketTags");
466 QDomElement root = document.createElement("basketTags");
467 root.setAttribute("nextStateUid", static_cast<long long int>(nextStateUid));
468 document.appendChild(root);
469
470 // Save all tags:
471 for (List::iterator it = list.begin(); it != list.end(); ++it) {
472 Tag *tag = *it;
473 // Create tag node:
474 QDomElement tagNode = document.createElement("tag");
475 root.appendChild(tagNode);
476 // Save tag properties:
477 XMLWork::addElement(document, tagNode, "name", tag->name());
478 XMLWork::addElement(document, tagNode, "shortcut", tag->shortcut().toString());
479 XMLWork::addElement(document, tagNode, "inherited", XMLWork::trueOrFalse(tag->inheritedBySiblings()));
480 // Save all states:
481 for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2) {
482 State *state = *it2;
483 // Create state node:
484 QDomElement stateNode = document.createElement("state");
485 tagNode.appendChild(stateNode);
486 // Save state properties:
487 stateNode.setAttribute("id", state->id());
488 XMLWork::addElement(document, stateNode, "name", state->name());
489 XMLWork::addElement(document, stateNode, "emblem", state->emblem());
490 QDomElement textNode = document.createElement("text");
491 stateNode.appendChild(textNode);
492 QString textColor = (state->textColor().isValid() ? state->textColor().name() : "");
493 textNode.setAttribute("bold", XMLWork::trueOrFalse(state->bold()));
494 textNode.setAttribute("italic", XMLWork::trueOrFalse(state->italic()));
495 textNode.setAttribute("underline", XMLWork::trueOrFalse(state->underline()));
496 textNode.setAttribute("strikeOut", XMLWork::trueOrFalse(state->strikeOut()));
497 textNode.setAttribute("color", textColor);
498 QDomElement fontNode = document.createElement("font");
499 stateNode.appendChild(fontNode);
500 fontNode.setAttribute("name", state->fontName());
501 fontNode.setAttribute("size", state->fontSize());
502 QString backgroundColor = (state->backgroundColor().isValid() ? state->backgroundColor().name() : "");
503 XMLWork::addElement(document, stateNode, "backgroundColor", backgroundColor);
504 QDomElement textEquivalentNode = document.createElement("textEquivalent");
505 stateNode.appendChild(textEquivalentNode);
506 textEquivalentNode.setAttribute("string", state->textEquivalent());
507 textEquivalentNode.setAttribute("onAllTextLines", XMLWork::trueOrFalse(state->onAllTextLines()));
508 XMLWork::addElement(document, stateNode, "allowCrossReferences", XMLWork::trueOrFalse(state->allowCrossReferences()));
509 }
510 }
511
512 // Write to Disk:
513 if (!BasketScene::safelySaveToFile(fullPath, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString()))
514 DEBUG_WIN << "<font color=red>FAILED to save tags</font>!";
515 }
516
copyTo(Tag * other)517 void Tag::copyTo(Tag *other)
518 {
519 other->m_name = m_name;
520 other->m_action->setShortcut(m_action->shortcut());
521 other->m_inheritedBySiblings = m_inheritedBySiblings;
522 }
523
createDefaultTagsSet(const QString & fullPath)524 void Tag::createDefaultTagsSet(const QString &fullPath)
525 {
526 QString xml = QString(
527 "<!DOCTYPE basketTags>\n"
528 "<basketTags>\n"
529 " <tag>\n"
530 " <name>%1</name>\n" // "To Do"
531 " <shortcut>Ctrl+1</shortcut>\n"
532 " <inherited>true</inherited>\n"
533 " <state id=\"todo_unchecked\">\n"
534 " <name>%2</name>\n" // "Unchecked"
535 " <emblem>tag_checkbox</emblem>\n"
536 " <text bold=\"false\" italic=\"false\" underline=\"false\" strikeOut=\"false\" color=\"\" />\n"
537 " <font name=\"\" size=\"\" />\n"
538 " <backgroundColor></backgroundColor>\n"
539 " <textEquivalent string=\"[ ]\" onAllTextLines=\"false\" />\n"
540 " </state>\n"
541 " <state id=\"todo_done\">\n"
542 " <name>%3</name>\n" // "Done"
543 " <emblem>tag_checkbox_checked</emblem>\n"
544 " <text bold=\"false\" italic=\"false\" underline=\"false\" strikeOut=\"true\" color=\"\" />\n"
545 " <font name=\"\" size=\"\" />\n"
546 " <backgroundColor></backgroundColor>\n"
547 " <textEquivalent string=\"[x]\" onAllTextLines=\"false\" />\n"
548 " </state>\n"
549 " </tag>\n"
550 "\n"
551 " <tag>\n"
552 " <name>%4</name>\n" // "Progress"
553 " <shortcut>Ctrl+2</shortcut>\n"
554 " <inherited>true</inherited>\n"
555 " <state id=\"progress_000\">\n"
556 " <name>%5</name>\n" // "0 %"
557 " <emblem>tag_progress_000</emblem>\n"
558 " <textEquivalent string=\"[ ]\" />\n"
559 " </state>\n"
560 " <state id=\"progress_025\">\n"
561 " <name>%6</name>\n" // "25 %"
562 " <emblem>tag_progress_025</emblem>\n"
563 " <textEquivalent string=\"[= ]\" />\n"
564 " </state>\n"
565 " <state id=\"progress_050\">\n"
566 " <name>%7</name>\n" // "50 %"
567 " <emblem>tag_progress_050</emblem>\n"
568 " <textEquivalent string=\"[== ]\" />\n"
569 " </state>\n"
570 " <state id=\"progress_075\">\n"
571 " <name>%8</name>\n" // "75 %"
572 " <emblem>tag_progress_075</emblem>\n"
573 " <textEquivalent string=\"[=== ]\" />\n"
574 " </state>\n"
575 " <state id=\"progress_100\">\n"
576 " <name>%9</name>\n" // "100 %"
577 " <emblem>tag_progress_100</emblem>\n"
578 " <textEquivalent string=\"[====]\" />\n"
579 " </state>\n"
580 " </tag>\n"
581 "\n")
582 .arg(i18n("To Do"), i18n("Unchecked"), i18n("Done")) // %1 %2 %3
583 .arg(i18n("Progress"), i18n("0 %"), i18n("25 %")) // %4 %5 %6
584 .arg(i18n("50 %"), i18n("75 %"), i18n("100 %")) // %7 %8 %9
585 + QString(
586 " <tag>\n"
587 " <name>%1</name>\n" // "Priority"
588 " <shortcut>Ctrl+3</shortcut>\n"
589 " <inherited>true</inherited>\n"
590 " <state id=\"priority_low\">\n"
591 " <name>%2</name>\n" // "Low"
592 " <emblem>tag_priority_low</emblem>\n"
593 " <textEquivalent string=\"{1}\" />\n"
594 " </state>\n"
595 " <state id=\"priority_medium\">\n"
596 " <name>%3</name>\n" // "Medium
597 " <emblem>tag_priority_medium</emblem>\n"
598 " <textEquivalent string=\"{2}\" />\n"
599 " </state>\n"
600 " <state id=\"priority_high\">\n"
601 " <name>%4</name>\n" // "High"
602 " <emblem>tag_priority_high</emblem>\n"
603 " <textEquivalent string=\"{3}\" />\n"
604 " </state>\n"
605 " </tag>\n"
606 "\n"
607 " <tag>\n"
608 " <name>%5</name>\n" // "Preference"
609 " <shortcut>Ctrl+4</shortcut>\n"
610 " <inherited>true</inherited>\n"
611 " <state id=\"preference_bad\">\n"
612 " <name>%6</name>\n" // "Bad"
613 " <emblem>tag_preference_bad</emblem>\n"
614 " <textEquivalent string=\"(* )\" />\n"
615 " </state>\n"
616 " <state id=\"preference_good\">\n"
617 " <name>%7</name>\n" // "Good"
618 " <emblem>tag_preference_good</emblem>\n"
619 " <textEquivalent string=\"(** )\" />\n"
620 " </state>\n"
621 " <state id=\"preference_excellent\">\n"
622 " <name>%8</name>\n" // "Excellent"
623 " <emblem>tag_preference_excellent</emblem>\n"
624 " <textEquivalent string=\"(***)\" />\n"
625 " </state>\n"
626 " </tag>\n"
627 "\n"
628 " <tag>\n"
629 " <name>%9</name>\n" // "Highlight"
630 " <shortcut>Ctrl+5</shortcut>\n"
631 " <state id=\"highlight\">\n"
632 " <backgroundColor>#ffffcc</backgroundColor>\n"
633 " <textEquivalent string=\"=>\" />\n"
634 " </state>\n"
635 " </tag>\n"
636 "\n")
637 .arg(i18n("Priority"), i18n("Low"), i18n("Medium")) // %1 %2 %3
638 .arg(i18n("High"), i18n("Preference"), i18n("Bad")) // %4 %5 %6
639 .arg(i18n("Good"), i18n("Excellent"), i18n("Highlight")) // %7 %8 %9
640 + QString(
641 " <tag>\n"
642 " <name>%1</name>\n" // "Important"
643 " <shortcut>Ctrl+6</shortcut>\n"
644 " <state id=\"important\">\n"
645 " <emblem>tag_important</emblem>\n"
646 " <backgroundColor>#ffcccc</backgroundColor>\n"
647 " <textEquivalent string=\"!!\" />\n"
648 " </state>\n"
649 " </tag>\n"
650 "\n"
651 " <tag>\n"
652 " <name>%2</name>\n" // "Very Important"
653 " <shortcut>Ctrl+7</shortcut>\n"
654 " <state id=\"very_important\">\n"
655 " <emblem>tag_important</emblem>\n"
656 " <text color=\"#ffffff\" />\n"
657 " <backgroundColor>#ff0000</backgroundColor>\n"
658 " <textEquivalent string=\"/!\\\" />\n"
659 " </state>\n"
660 " </tag>\n"
661 "\n"
662 " <tag>\n"
663 " <name>%3</name>\n" // "Information"
664 " <shortcut>Ctrl+8</shortcut>\n"
665 " <state id=\"information\">\n"
666 " <emblem>dialog-information</emblem>\n"
667 " <textEquivalent string=\"(i)\" />\n"
668 " </state>\n"
669 " </tag>\n"
670 "\n"
671 " <tag>\n"
672 " <name>%4</name>\n" // "Idea"
673 " <shortcut>Ctrl+9</shortcut>\n"
674 " <state id=\"idea\">\n"
675 " <emblem>ktip</emblem>\n"
676 " <textEquivalent string=\"%5\" />\n" // I.
677 " </state>\n"
678 " </tag>""\n"
679 "\n"
680 " <tag>\n"
681 " <name>%6</name>\n" // "Title"
682 " <shortcut>Ctrl+0</shortcut>\n"
683 " <state id=\"title\">\n"
684 " <text bold=\"true\" />\n"
685 " <textEquivalent string=\"##\" />\n"
686 " </state>\n"
687 " </tag>\n"
688 "\n"
689 " <tag>\n"
690 " <name>%7</name>\n" // "Code"
691 " <state id=\"code\">\n"
692 " <font name=\"monospace\" />\n"
693 " <textEquivalent string=\"|\" onAllTextLines=\"true\" />\n"
694 " <allowCrossReferences>false</allowCrossReferences>\n"
695 " </state>\n"
696 " </tag>\n"
697 "\n"
698 " <tag>\n"
699 " <state id=\"work\">\n"
700 " <name>%8</name>\n" // "Work"
701 " <text color=\"#ff8000\" />\n"
702 " <textEquivalent string=\"%9\" />\n" // W.
703 " </state>\n"
704 " </tag>""\n"
705 "\n")
706 .arg(i18n("Important"), i18n("Very Important"), i18n("Information")) // %1 %2 %3
707 .arg(i18n("Idea"), i18nc("The initial of 'Idea'", "I."), i18n("Title")) // %4 %5 %6
708 .arg(i18n("Code"), i18n("Work"), i18nc("The initial of 'Work'", "W.")) // %7 %8 %9
709 + QString(
710 " <tag>\n"
711 " <state id=\"personal\">\n"
712 " <name>%1</name>\n" // "Personal"
713 " <text color=\"#008000\" />\n"
714 " <textEquivalent string=\"%2\" />\n" // P.
715 " </state>\n"
716 " </tag>\n"
717 "\n"
718 " <tag>\n"
719 " <state id=\"funny\">\n"
720 " <name>%3</name>\n" // "Funny"
721 " <emblem>tag_fun</emblem>\n"
722 " </state>\n"
723 " </tag>\n"
724 "</basketTags>\n"
725 "")
726 .arg(i18n("Personal"), i18nc("The initial of 'Personal'", "P."), i18n("Funny")); // %1 %2 %3
727
728 // Write to Disk:
729 QFile file(fullPath);
730 if (file.open(QIODevice::WriteOnly)) {
731 QTextStream stream(&file);
732 stream.setCodec("UTF-8");
733 stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
734 stream << xml;
735 file.close();
736 } else
737 DEBUG_WIN << "<font color=red>FAILED to create the tags file</font>!";
738 }
739
740 // StateAction
StateAction(State * state,const QKeySequence & shortcut,QWidget * parent,bool withTagName)741 StateAction::StateAction(State *state, const QKeySequence &shortcut, QWidget* parent, bool withTagName)
742 : KToggleAction(parent)
743 , m_state(state)
744 {
745 setText(m_state->name());
746
747 if (withTagName && m_state->parentTag())
748 setText(m_state->parentTag()->name());
749
750 setIcon(KIconLoader::global()->loadIcon(m_state->emblem(),
751 KIconLoader::Small,
752 16,
753 KIconLoader::DefaultState,
754 QStringList(),
755 /*path_store=*/0L,
756 /*canReturnNull=*/true
757 )
758 );
759
760 setShortcut(shortcut);
761 }
762
~StateAction()763 StateAction::~StateAction()
764 {
765 // pass
766 }
767