File indexing completed on 2024-12-08 11:07:14
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2006 David Saxton <david@bluehaze.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 ***************************************************************************/ 0009 0010 #include "config.h" 0011 0012 #include "canvasitemparts.h" 0013 #include "cnitem.h" 0014 #include "component.h" 0015 #include "ecnode.h" 0016 #include "ecsubcircuit.h" 0017 #include "electronics/circuitdocument.h" 0018 #include "itemlibrary.h" 0019 #include "libraryitem.h" 0020 #include "node.h" 0021 #include "pinmapping.h" 0022 #include "port.h" 0023 #include "subcircuits.h" 0024 0025 #include <KConfigGroup> 0026 #include <KLocalizedString> 0027 #include <KMessageBox> 0028 #include <KSharedConfig> 0029 0030 #include <QApplication> 0031 #include <QBitmap> 0032 #include <QDir> 0033 #include <QFile> 0034 #include <QImage> 0035 #include <QLocale> 0036 #include <QPainter> 0037 #include <QPixmap> 0038 #include <QPushButton> 0039 #include <QRegExp> 0040 #include <QStandardPaths> 0041 #include <QTimer> 0042 0043 #include <cassert> 0044 0045 // BEGIN Item includes 0046 #ifdef MECHANICS 0047 #include "chassiscircular2.h" 0048 #endif 0049 0050 #include "dpimage.h" 0051 #include "dpline.h" 0052 #include "dptext.h" 0053 #include "solidshape.h" 0054 0055 #include "callsub.h" 0056 #include "count.h" 0057 #include "delay.h" 0058 #include "embed.h" 0059 #include "end.h" 0060 #include "forloop.h" 0061 #include "inputbutton.h" 0062 #include "interrupt.h" 0063 #include "keypad.h" 0064 #include "pulse.h" 0065 #include "readport.h" 0066 #include "repeat.h" 0067 #include "setpin.h" 0068 #include "sevenseg.h" 0069 #include "start.h" 0070 #include "sub.h" 0071 #include "testpin.h" 0072 #include "unary.h" 0073 #include "varassignment.h" 0074 #include "varcomparison.h" 0075 #include "while.h" 0076 #include "writeport.h" 0077 0078 #include "addac.h" 0079 #include "bidirled.h" 0080 #include "binarycounter.h" 0081 #include "bussplitter.h" 0082 #include "demultiplexer.h" 0083 #include "dependentsource.h" 0084 #include "discretelogic.h" 0085 #include "externalconnection.h" 0086 #include "flipflop.h" 0087 #include "fulladder.h" 0088 #include "inductor.h" 0089 #include "magnitudecomparator.h" 0090 #include "matrixdisplay.h" 0091 #include "matrixdisplaydriver.h" 0092 #include "meter.h" 0093 #include "multiinputgate.h" 0094 #include "multiplexer.h" 0095 #include "parallelportcomponent.h" 0096 #include "piccomponent.h" 0097 #include "probe.h" 0098 #include "pushswitch.h" 0099 #include "ram.h" 0100 #include "resistordip.h" 0101 #include "rotoswitch.h" 0102 #include "serialportcomponent.h" 0103 #include "toggleswitch.h" 0104 0105 #include "capacitor.h" 0106 #include "ec555.h" 0107 #include "ecbcdto7segment.h" 0108 #include "ecbjt.h" 0109 #include "ecclockinput.h" 0110 #include "eccurrentsignal.h" 0111 #include "eccurrentsource.h" 0112 #include "ecdiode.h" 0113 #include "ecfixedvoltage.h" 0114 #include "ecground.h" 0115 #include "ecjfet.h" 0116 #include "eckeypad.h" 0117 #include "ecmosfet.h" 0118 #include "ecopamp.h" 0119 #include "ecpotentiometer.h" 0120 #include "ecsevensegment.h" 0121 #include "ecsignallamp.h" 0122 #include "ecvoltagesignal.h" 0123 #include "ecvoltagesource.h" 0124 #include "led.h" 0125 #include "ledbargraphdisplay.h" 0126 #include "resistor.h" 0127 #include "variablecapacitor.h" 0128 #include "variableresistor.h" 0129 0130 // END Item includes 0131 0132 #include <ktechlab_debug.h> 0133 0134 KLocalizedString ItemLibrary::m_emptyItemDescription = ki18n("This help item does not yet exist for the %1 language. Help out with KTechlab by creating one via the \"Edit\" button."); 0135 0136 ItemLibrary::ItemLibrary() 0137 { 0138 addFlowParts(); 0139 addComponents(); 0140 addMechanics(); 0141 addDrawParts(); 0142 0143 loadItemDescriptions(); 0144 } 0145 0146 ItemLibrary::~ItemLibrary() 0147 { 0148 // qCDebug(KTL_LOG) << "m_itemDescriptions[\"en_US\"].size()="<<m_itemDescriptions["en_US"].size(); 0149 0150 qDeleteAll(m_items); 0151 m_items.clear(); 0152 } 0153 0154 void ItemLibrary::addFlowParts() 0155 { 0156 // Container loops 0157 addLibraryItem(Repeat::libraryItem()); 0158 addLibraryItem(While::libraryItem()); 0159 addLibraryItem(ForLoop::libraryItem()); 0160 0161 // Variable operations 0162 addLibraryItem(Unary::libraryItem()); 0163 addLibraryItem(VarAssignment::libraryItem()); 0164 addLibraryItem(VarComparison::libraryItem()); 0165 0166 // I/O 0167 addLibraryItem(SetPin::libraryItem()); 0168 addLibraryItem(TestPin::libraryItem()); 0169 addLibraryItem(WritePort::libraryItem()); 0170 addLibraryItem(ReadPort::libraryItem()); 0171 0172 // Functions 0173 addLibraryItem(SevenSeg::libraryItem()); 0174 // addLibraryItem( Pulse::libraryItem() ); 0175 addLibraryItem(Keypad::libraryItem()); 0176 // addLibraryItem( Count::libraryItem() ); 0177 // addLibraryItem( InputButton::libraryItem() ); 0178 addLibraryItem(Delay::libraryItem()); 0179 0180 // Common 0181 addLibraryItem(Embed::libraryItem()); 0182 addLibraryItem(CallSub::libraryItem()); 0183 // addLibraryItem( Interrupt::libraryItem() ); 0184 addLibraryItem(Sub::libraryItem()); 0185 addLibraryItem(End::libraryItem()); 0186 addLibraryItem(Start::libraryItem()); 0187 } 0188 0189 void ItemLibrary::addComponents() 0190 { 0191 // Integrated Circuits 0192 addLibraryItem(ECBCDTo7Segment::libraryItem()); 0193 addLibraryItem(MatrixDisplayDriver::libraryItem()); 0194 addLibraryItem(BinaryCounter::libraryItem()); 0195 addLibraryItem(DAC::libraryItem()); 0196 addLibraryItem(ADC::libraryItem()); 0197 addLibraryItem(ECOpAmp::libraryItem()); 0198 addLibraryItem(MagnitudeComparator::libraryItem()); 0199 addLibraryItem(Demultiplexer::libraryItem()); 0200 addLibraryItem(Multiplexer::libraryItem()); 0201 addLibraryItem(FullAdder::libraryItem()); 0202 addLibraryItem(RAM::libraryItem()); 0203 addLibraryItem(EC555::libraryItem()); 0204 addLibraryItem(ECDFlipFlop::libraryItem()); 0205 addLibraryItem(ECSRFlipFlop::libraryItem()); 0206 addLibraryItem(ECJKFlipFlop::libraryItem()); 0207 #ifndef NO_GPSIM 0208 addLibraryItem(PICComponent::libraryItem()); 0209 #endif 0210 0211 // Connections 0212 if (ParallelPort::isAvailable()) 0213 addLibraryItem(ParallelPortComponent::libraryItem()); 0214 if (SerialPort::isAvailable()) 0215 addLibraryItem(SerialPortComponent::libraryItem()); 0216 addLibraryItem(ExternalConnection::libraryItem()); 0217 addLibraryItem(BusSplitter::libraryItem()); 0218 0219 // Logic 0220 addLibraryItem(ECXnor::libraryItem()); 0221 addLibraryItem(ECXor::libraryItem()); 0222 addLibraryItem(ECNor::libraryItem()); 0223 addLibraryItem(ECOr::libraryItem()); 0224 addLibraryItem(ECNand::libraryItem()); 0225 addLibraryItem(ECAnd::libraryItem()); 0226 addLibraryItem(Inverter::libraryItem()); 0227 addLibraryItem(Buffer::libraryItem()); 0228 addLibraryItem(ECClockInput::libraryItem()); 0229 addLibraryItem(ECLogicOutput::libraryItem()); 0230 addLibraryItem(ECLogicInput::libraryItem()); 0231 0232 // Outputs 0233 // addLibraryItem( FrequencyMeter::libraryItem() ); 0234 addLibraryItem(CurrentProbe::libraryItem()); 0235 addLibraryItem(VoltageProbe::libraryItem()); 0236 addLibraryItem(LogicProbe::libraryItem()); 0237 addLibraryItem(ECAmmeter::libraryItem()); 0238 addLibraryItem(ECVoltMeter::libraryItem()); 0239 addLibraryItem(LEDBarGraphDisplay::libraryItem()); 0240 addLibraryItem(MatrixDisplay::libraryItem()); 0241 addLibraryItem(ECSevenSegment::libraryItem()); 0242 addLibraryItem(BiDirLED::libraryItem()); 0243 addLibraryItem(ECSignalLamp::libraryItem()); 0244 addLibraryItem(LED::libraryItem()); 0245 0246 // Switches 0247 addLibraryItem(ECRotoSwitch::libraryItem()); 0248 addLibraryItem(ECDPDT::libraryItem()); 0249 addLibraryItem(ECSPDT::libraryItem()); 0250 addLibraryItem(ECDPST::libraryItem()); 0251 addLibraryItem(ECSPST::libraryItem()); 0252 addLibraryItem(ECKeyPad::libraryItem()); 0253 addLibraryItem(ECPTBSwitch::libraryItem()); 0254 addLibraryItem(ECPTMSwitch::libraryItem()); 0255 0256 // Nonlinear 0257 // addLibraryItem( ECMOSFET::libraryItemPDM() ); 0258 // addLibraryItem( ECMOSFET::libraryItemNDM() ); 0259 addLibraryItem(ECMOSFET::libraryItemPEM()); 0260 addLibraryItem(ECMOSFET::libraryItemNEM()); 0261 addLibraryItem(ECJFET::libraryItemPJFET()); 0262 addLibraryItem(ECJFET::libraryItemNJFET()); 0263 addLibraryItem(ECBJT::libraryItemPNP()); 0264 addLibraryItem(ECBJT::libraryItemNPN()); 0265 addLibraryItem(ECDiode::libraryItem()); 0266 0267 // Discrete 0268 // addLibraryItem( VoltageRegulator::libraryItem() ); 0269 addLibraryItem(VariableResistor::libraryItem()); 0270 addLibraryItem(VariableCapacitor::libraryItem()); 0271 addLibraryItem(ECPotentiometer::libraryItem()); 0272 addLibraryItem(ResistorDIP::libraryItem()); 0273 addLibraryItem(Inductor::libraryItem()); 0274 addLibraryItem(Capacitor::libraryItem()); 0275 addLibraryItem(Resistor::libraryItem()); 0276 0277 // Dependent Sources 0278 addLibraryItem(ECVCVS::libraryItem()); 0279 addLibraryItem(ECVCCS::libraryItem()); 0280 addLibraryItem(ECCCVS::libraryItem()); 0281 addLibraryItem(ECCCCS::libraryItem()); 0282 0283 // Independent Sources 0284 addLibraryItem(ECCurrentSignal::libraryItem()); 0285 addLibraryItem(ECVoltageSignal::libraryItem()); 0286 addLibraryItem(ECCurrentSource::libraryItem()); 0287 addLibraryItem(ECGround::libraryItem()); 0288 addLibraryItem(ECFixedVoltage::libraryItem()); 0289 addLibraryItem(ECCell::libraryItem()); 0290 0291 // Other 0292 addLibraryItem(ECSubcircuit::libraryItem()); 0293 addLibraryItem(PIC_IC::libraryItem()); 0294 } 0295 0296 void ItemLibrary::addDrawParts() 0297 { 0298 addLibraryItem(DPImage::libraryItem()); 0299 addLibraryItem(DPText::libraryItem()); 0300 addLibraryItem(DPLine::libraryItem()); 0301 addLibraryItem(DPArrow::libraryItem()); 0302 addLibraryItem(DPRectangle::libraryItem()); 0303 addLibraryItem(DPEllipse::libraryItem()); 0304 } 0305 0306 void ItemLibrary::addMechanics() 0307 { 0308 #ifdef MECHANICS 0309 addLibraryItem(ChassisCircular2::libraryItem()); 0310 #endif 0311 } 0312 0313 void ItemLibrary::addLibraryItem(LibraryItem *item) 0314 { 0315 m_items.prepend(item); 0316 } 0317 0318 LibraryItem *ItemLibrary::libraryItem(QString type) const 0319 { 0320 if (type.startsWith(QString::fromLatin1("/"))) { 0321 // Possibly change e.g. "/ec/capacitor" to "ec/capacitor" 0322 type.remove(0, 1); 0323 } 0324 0325 LibraryItemList::const_iterator end = m_items.end(); 0326 LibraryItemList::const_iterator it = m_items.begin(); 0327 for (; it != end; ++it) { 0328 if ((*it)->allIDs().contains(type)) 0329 return *it; 0330 } 0331 return nullptr; 0332 } 0333 0334 Item *ItemLibrary::createItem(const QString &id, ItemDocument *itemDocument, bool newItem, const char *newId, bool finishCreation) 0335 { 0336 Item *item = nullptr; 0337 if (id.startsWith(QString::fromLatin1("sc/"))) { 0338 // Is a subcircuit... 0339 0340 CircuitDocument *circuitDocument = dynamic_cast<CircuitDocument *>(itemDocument); 0341 if (!circuitDocument) { 0342 qCWarning(KTL_LOG) << "Cannot create subcircuit without a circuit document"; 0343 return nullptr; 0344 } 0345 0346 QString temp = id; 0347 int numId = temp.remove(QString::fromLatin1("sc/")).toInt(); 0348 0349 item = subcircuits()->createSubcircuit(numId, circuitDocument, newItem, newId); 0350 } else { 0351 LibraryItem *li = libraryItem(id); 0352 0353 if (!li) 0354 qCWarning(KTL_LOG) << "Could not find the item constructor for id " << id; 0355 else { 0356 item = li->createItemFnPtr()(itemDocument, newItem, newId); 0357 item->m_type = li->activeID(); 0358 } 0359 } 0360 0361 if (finishCreation && item) 0362 item->finishedCreation(); 0363 0364 return item; 0365 } 0366 0367 QImage ItemLibrary::componentImage(Component *component, const uint maxSize) 0368 { 0369 // Default orientation for painting 0370 const int angleDegrees = component->angleDegrees(); 0371 const bool flipped = component->flipped(); 0372 component->setAngleDegrees(0); 0373 component->setFlipped(false); 0374 0375 QRect bound = component->boundingRect().normalized(); 0376 bound.setLeft(bound.left() - 8); 0377 bound.setRight(bound.right() + 8); 0378 bound.setTop(bound.top() - 8); 0379 bound.setBottom(bound.bottom() + 8); 0380 0381 // We want a nice square bounding rect 0382 const int dy = bound.width() - bound.height(); 0383 if (dy > 0) { 0384 bound.setTop(bound.top() - (dy / 2)); 0385 bound.setBottom(bound.bottom() + (dy / 2)); 0386 } else if (dy < 0) { 0387 bound.setLeft(bound.left() + (dy / 2)); 0388 bound.setRight(bound.right() - (dy / 2)); 0389 } 0390 0391 const bool cache = ((bound.width() * bound.height()) > int(maxSize)); 0392 QString type; 0393 if (cache && m_imageMap.contains(component->type())) 0394 return m_imageMap[component->type()]; 0395 0396 // Create pixmap big enough to contain CNItem and surrounding nodes 0397 // and copy the button grab to it 0398 0399 QPixmap pm(bound.size()); 0400 0401 QBitmap mask(bound.size()); 0402 mask.fill(Qt::color0); 0403 0404 // QPainter maskPainter(&mask); // 2016.05.03 - initialize painter explicitly 0405 QPainter maskPainter; 0406 { 0407 const bool isSuccess = maskPainter.begin(&mask); 0408 if (!isSuccess) { 0409 qCWarning(KTL_LOG) << " painter not active at line " << __LINE__; 0410 } 0411 } 0412 maskPainter.translate(-bound.x(), -bound.y()); 0413 maskPainter.setPen(Qt::color1); 0414 maskPainter.setBrush(Qt::color1); 0415 0416 // BEGIN painting on the pixmap 0417 { 0418 // QPainter p(&pm); // 2016.05.03 - initialize painter explicitly 0419 QPainter p; 0420 const bool isBeginSuccess = p.begin(&pm); 0421 if (!isBeginSuccess) { 0422 qCWarning(KTL_LOG) << " painter not active at line " << __LINE__; 0423 } 0424 p.translate(-bound.x(), -bound.y()); 0425 p.setPen(component->pen()); 0426 p.setBrush(component->brush()); 0427 0428 // BEGIN Draw the component 0429 const bool sel = component->isSelected(); 0430 0431 if (sel) { 0432 // We block the signals as we end up in an infinite loop with component emitting a selected signal 0433 component->blockSignals(true); 0434 component->setSelected(false); 0435 component->blockSignals(false); 0436 } 0437 0438 component->drawShape(p); 0439 component->drawShape(maskPainter); 0440 0441 if (sel) { 0442 component->blockSignals(true); 0443 component->setSelected(sel); 0444 component->blockSignals(false); 0445 } 0446 // END Draw the component 0447 0448 maskPainter.setPen(Qt::color1); 0449 maskPainter.setBrush(Qt::color1); 0450 0451 QTransform transMatrix; // Matrix to apply to the image 0452 0453 NodeInfoMap nodes = component->nodeMap(); 0454 const NodeInfoMap::iterator nodesEnd = nodes.end(); 0455 for (NodeInfoMap::iterator it = nodes.begin(); it != nodesEnd; ++it) { 0456 Node *node = it.value().node; 0457 const bool sel = node->isSelected(); 0458 if (sel) 0459 node->setSelected(false); 0460 if (ECNode *ecnode = dynamic_cast<ECNode *>(node)) { 0461 bool showVB = ecnode->showVoltageBars(); 0462 bool showVC = ecnode->showVoltageColor(); 0463 0464 ecnode->setShowVoltageBars(false); 0465 ecnode->setShowVoltageColor(false); 0466 0467 ecnode->drawShape(p); 0468 ecnode->drawShape(maskPainter); 0469 0470 ecnode->setShowVoltageBars(showVB); 0471 ecnode->setShowVoltageColor(showVC); 0472 } else { 0473 node->drawShape(p); 0474 node->drawShape(maskPainter); 0475 } 0476 0477 if (sel) 0478 node->setSelected(sel); 0479 } 0480 0481 p.setPen(Qt::black); 0482 TextMap text = component->textMap(); 0483 const TextMap::iterator textEnd = text.end(); 0484 for (TextMap::iterator it = text.begin(); it != textEnd; ++it) { 0485 it.value()->drawShape(p); 0486 it.value()->drawShape(maskPainter); 0487 } 0488 0489 // maskPainter.setPen( Qt::color1 ); 0490 // maskPainter.setBrush( Qt::color1 ); 0491 component->drawWidgets(p); 0492 // component->drawWidgets(maskPainter); 0493 } 0494 // END painting on the pixmap 0495 0496 pm.setMask(mask); // pm needs not to have active painters on it 0497 0498 // Now, rotate the image so that it's the right way up, and scale it to size 0499 QImage im = pm.toImage(); 0500 // im = im.smoothScale( 50, 50, Qt::ScaleMin ); //2018.12.01 0501 im = im.scaled(QSize(50, 50), Qt::KeepAspectRatio, Qt::SmoothTransformation); 0502 0503 if (cache) 0504 m_imageMap[component->type()] = im; 0505 0506 // Restore original orientation 0507 component->setAngleDegrees(angleDegrees); 0508 component->setFlipped(flipped); 0509 0510 return im; 0511 } 0512 0513 bool ItemLibrary::saveDescriptions(const QString &languageCode) 0514 { 0515 QString url = itemDescriptionsFile(languageCode); 0516 0517 QFile file(url); 0518 if (!file.open(QIODevice::WriteOnly)) { 0519 KMessageBox::error(nullptr, i18n("Could not open item descriptions file \"%1\" for writing.", url)); 0520 return false; 0521 } 0522 0523 QTextStream stream(&file); 0524 0525 const QStringMap itemDescriptions = m_itemDescriptions[languageCode]; 0526 for (auto descIt = itemDescriptions.begin(), end = itemDescriptions.end(); descIt != end; ++descIt) { 0527 stream << QString::fromLatin1("<!-- item: %1 -->\n").arg(descIt.key()); 0528 stream << descIt.value() << Qt::endl; 0529 } 0530 0531 file.close(); 0532 0533 return true; 0534 } 0535 0536 bool ItemLibrary::haveDescription(QString type, const QString &languageCode) const 0537 { 0538 if (type.startsWith(QString::fromLatin1("/"))) { 0539 // Possibly change e.g. "/ec/capacitor" to "ec/capacitor" 0540 type.remove(0, 1); 0541 } 0542 0543 if (!m_itemDescriptions[languageCode].contains(type)) { 0544 return libraryItem(type); 0545 } 0546 0547 return !m_itemDescriptions[languageCode][type].isEmpty(); 0548 } 0549 0550 QString ItemLibrary::description(QString type, const QString &languageCode) const 0551 { 0552 if (type.startsWith(QString::fromLatin1("/"))) { 0553 // Possibly change e.g. "/ec/capacitor" to "ec/capacitor" 0554 type.remove(0, 1); 0555 } 0556 0557 QString current = m_itemDescriptions[languageCode][type]; 0558 0559 if (current.isEmpty()) { 0560 // Try english-language description 0561 current = m_itemDescriptions[QString::fromLatin1("en_US")][type]; 0562 if (current.isEmpty()) 0563 return emptyItemDescription(languageCode); 0564 } 0565 0566 return current; 0567 } 0568 0569 QString ItemLibrary::emptyItemDescription(const QString &languageCode) const 0570 { 0571 // return m_emptyItemDescription.arg( KGlobal::locale()->twoAlphaToLanguageName( language ) ); 0572 return m_emptyItemDescription.subs(QLocale(languageCode).nativeLanguageName()).toString(); 0573 } 0574 0575 bool ItemLibrary::setDescription(QString type, const QString &description, const QString &languageCode) 0576 { 0577 if (type.startsWith(QString::fromLatin1("/"))) { 0578 // Possibly change e.g. "/ec/capacitor" to "ec/capacitor" 0579 type.remove(0, 1); 0580 } 0581 0582 m_itemDescriptions[languageCode][type] = description; 0583 return saveDescriptions(languageCode); 0584 } 0585 0586 void ItemLibrary::setItemDescriptionsDirectory(QString dir) 0587 { 0588 if (!dir.isEmpty() && !dir.endsWith(QString::fromLatin1("/"))) 0589 dir += QString::fromLatin1("/"); 0590 0591 KSharedConfigPtr conf = KSharedConfig::openConfig(); 0592 // QString prevGroup = conf->group(); 0593 0594 KConfigGroup grGen = conf->group("General"); 0595 grGen.writePathEntry("ItemDescriptionsDirectory", dir); 0596 // conf->setGroup( prevGroup ); 0597 } 0598 0599 QString ItemLibrary::itemDescriptionsDirectory() const 0600 { 0601 KSharedConfigPtr conf = KSharedConfig::openConfig(); 0602 // QString prevGroup = conf->group(); 0603 0604 KConfigGroup grGen = conf->group("General"); 0605 QString dir = grGen.readPathEntry("ItemDescriptionsDirectory", QStandardPaths::locate(QStandardPaths::AppDataLocation, "contexthelp/", QStandardPaths::LocateDirectory)); 0606 // conf->setGroup( prevGroup ); 0607 0608 if (!dir.isEmpty() && !dir.endsWith(QString::fromLatin1("/"))) 0609 dir += QString::fromLatin1("/"); 0610 0611 return dir; 0612 } 0613 0614 QString ItemLibrary::itemDescriptionsFile(const QString &languageCode) const 0615 { 0616 QString dir(itemDescriptionsDirectory()); 0617 if (dir.isEmpty()) 0618 return QString(); 0619 0620 const QString url = dir + QLatin1String("help-") + languageCode; 0621 0622 return url; 0623 } 0624 0625 void ItemLibrary::loadItemDescriptions() 0626 { 0627 // Create an entry for the default language (American English) 0628 // and the current language 0629 // KLocale * locale = KLocale::global(); 0630 // m_itemDescriptions[ locale->defaultLanguage() ]; 0631 // m_itemDescriptions[ locale->language() ]; 0632 0633 m_itemDescriptions[QLocale().name()]; 0634 0635 const QStringList languages = descriptionLanguages(); 0636 QStringList::const_iterator end = languages.end(); 0637 for (QStringList::const_iterator it = languages.begin(); it != end; ++it) { 0638 QString url = itemDescriptionsFile(*it); 0639 0640 QFile file(url); 0641 if (!file.open(QIODevice::ReadOnly)) { 0642 qCWarning(KTL_LOG) << "Could not open file \"" << url << "\""; 0643 continue; 0644 } 0645 0646 QTextStream stream(&file); 0647 0648 QString type; 0649 QString description; 0650 while (!stream.atEnd()) { 0651 QString line = stream.readLine(); 0652 if (line.startsWith(QString::fromLatin1("<!-- item: "))) { 0653 // Save the previous description 0654 if (!type.isEmpty()) 0655 m_itemDescriptions[*it][type] = description.trimmed(); 0656 0657 line.remove(QString::fromLatin1("<!-- item: ")); 0658 line.remove(QString::fromLatin1(" -->")); 0659 0660 type = line.trimmed(); 0661 if (type.startsWith(QString::fromLatin1("/"))) { 0662 // Possibly change e.g. "/ec/capacitor" to "ec/capacitor" 0663 type.remove(0, 1); 0664 } 0665 0666 description = QString(); 0667 } else 0668 description += line + '\n'; 0669 } 0670 0671 // Save the previous description 0672 if (!type.isEmpty()) 0673 m_itemDescriptions[*it][type] = description.trimmed(); 0674 0675 file.close(); 0676 } 0677 } 0678 0679 #include "moc_itemlibrary.cpp"