File indexing completed on 2024-05-19 13:33:06

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"