File indexing completed on 2024-06-09 13:46:35

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by David Saxton                                    *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "pinmapping.h"
0012 #include "canvasmanipulator.h"
0013 #include "cnitemgroup.h"
0014 #include "eckeypad.h"
0015 #include "ecsevensegment.h"
0016 #include "libraryitem.h"
0017 #include "microinfo.h"
0018 #include "micropackage.h"
0019 #include "node.h"
0020 #include "viewcontainer.h"
0021 
0022 #include <KLocalizedString>
0023 #include <KStandardShortcut>
0024 
0025 #include <QAction>
0026 #include <QApplication>
0027 #include <QDialogButtonBox>
0028 #include <QFrame>
0029 #include <QPushButton>
0030 #include <QVBoxLayout>
0031 
0032 #include <ktechlab_debug.h>
0033 
0034 // BEGIN class PinMapping
0035 PinMapping::PinMapping(Type type)
0036 {
0037     m_type = type;
0038 }
0039 
0040 PinMapping::PinMapping()
0041 {
0042     m_type = Invalid;
0043 }
0044 
0045 PinMapping::~PinMapping()
0046 {
0047 }
0048 // END class PinMapping
0049 
0050 // BEGIN class PinMapEditor
0051 PinMapEditor::PinMapEditor(PinMapping *pinMapping, MicroInfo *picInfo, QWidget *parent)
0052     : QDialog(parent)
0053 {
0054     setModal(true);
0055     setWindowTitle(i18n("Pin Map Editor"));
0056 
0057     QVBoxLayout *mainLayout = new QVBoxLayout;
0058     setLayout(mainLayout);
0059 
0060     m_pPinMapping = pinMapping;
0061 
0062     m_pPinMapDocument = new PinMapDocument();
0063 
0064     {
0065         QAction *actionDelSel = new QAction(this);
0066         actionDelSel->setShortcut(Qt::Key_Delete);
0067         connect(actionDelSel, &QAction::triggered, m_pPinMapDocument, &PinMapDocument::deleteSelection);
0068         addAction(actionDelSel);
0069     }
0070     {
0071         QAction *actionSelAll = new QAction(this);
0072         actionSelAll->setShortcut(KStandardShortcut::selectAll().first());
0073         connect(actionSelAll, &QAction::triggered, m_pPinMapDocument, &PinMapDocument::selectAll);
0074         addAction(actionSelAll);
0075     }
0076     {
0077         QAction *actionUndo = new QAction(this);
0078         actionUndo->setShortcut(KStandardShortcut::undo().first());
0079         connect(actionUndo, &QAction::triggered, m_pPinMapDocument, &PinMapDocument::undo);
0080         addAction(actionUndo);
0081     }
0082     {
0083         QAction *actionRedo = new QAction(this);
0084         actionRedo->setShortcut(KStandardShortcut::redo().first());
0085         connect(actionRedo, &QAction::triggered, m_pPinMapDocument, &PinMapDocument::redo);
0086         addAction(actionRedo);
0087     }
0088 
0089     QFrame *f = new QFrame(this);
0090     f->setMinimumWidth(480);
0091     f->setMinimumHeight(480);
0092 
0093     f->setFrameShape(QFrame::Box);
0094     f->setFrameShadow(QFrame::Plain);
0095     QVBoxLayout *fLayout = new QVBoxLayout; // ( f, 1, 0, "fLayout" ); // 2018.08.18 - use non-deprected constructor
0096     fLayout->setContentsMargins(1, 1, 1, 1);
0097     fLayout->setSpacing(0);
0098     fLayout->setObjectName("fLayout");
0099 
0100     ViewContainer *vc = new ViewContainer(nullptr, f);
0101     fLayout->addWidget(vc);
0102 
0103     m_pPinMapView = static_cast<PinMapView *>(m_pPinMapDocument->createView(vc, 0));
0104 
0105     // qApp->processEvents(); // 2015.07.07 - do not process events, if it is not urgently needed; might generate crashes?
0106 
0107     m_pPinMapDocument->init(*m_pPinMapping, picInfo);
0108 
0109     mainLayout->addWidget(f);
0110 
0111     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply);
0112     mainLayout->addWidget(buttonBox);
0113     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0114     okButton->setDefault(true);
0115     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0116     connect(buttonBox, &QDialogButtonBox::accepted, this, &PinMapEditor::slotOk);
0117     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0118     connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &PinMapEditor::slotApply);
0119 }
0120 
0121 void PinMapEditor::slotApply()
0122 {
0123     savePinMapping();
0124 }
0125 
0126 void PinMapEditor::slotOk()
0127 {
0128     savePinMapping();
0129     accept();
0130 }
0131 
0132 void PinMapEditor::savePinMapping()
0133 {
0134     *m_pPinMapping = m_pPinMapDocument->pinMapping();
0135 }
0136 // END class PinMapEditor
0137 
0138 // BEGIN class PinMapDocument
0139 PinMapDocument::PinMapDocument()
0140     : CircuitICNDocument(nullptr)
0141 {
0142     m_pPicComponent = nullptr;
0143     m_pKeypad = nullptr;
0144     m_pSevenSegment = nullptr;
0145     m_type = dt_pinMapEditor;
0146 
0147     m_cmManager->addManipulatorInfo(CMSelect::manipulatorInfo());
0148 }
0149 
0150 PinMapDocument::~PinMapDocument()
0151 {
0152 }
0153 
0154 void PinMapDocument::init(const PinMapping &pinMapping, MicroInfo *microInfo)
0155 {
0156     m_pinMappingType = pinMapping.type();
0157 
0158     m_pPicComponent = static_cast<PIC_IC *>(addItem("PIC_IC", QPoint(336, 224), true));
0159     m_pPicComponent->initPackage(microInfo);
0160 
0161     const QStringList pins = pinMapping.pins();
0162     const QStringList::const_iterator end = pins.end();
0163 
0164     int keypadCols = -1; // -1 means no keypad
0165 
0166     switch (m_pinMappingType) {
0167     case PinMapping::SevenSegment: {
0168         m_pSevenSegment = static_cast<ECSevenSegment *>(addItem("ec/seven_segment", QPoint(144, 232), true));
0169 
0170         char ssPin = 'a';
0171         for (QStringList::const_iterator it = pins.begin(); it != end; ++it) {
0172             ICNDocument::createConnector(m_pSevenSegment->childNode(QChar(ssPin)), m_pPicComponent->childNode(*it));
0173             ssPin++;
0174         }
0175 
0176         break;
0177     }
0178 
0179     case PinMapping::Keypad_4x3:
0180         m_pKeypad = static_cast<ECKeyPad *>(addItem("ec/keypad", QPoint(144, 232), true));
0181         m_pKeypad->property("numCols")->setValue(3);
0182         keypadCols = 3;
0183         break;
0184 
0185     case PinMapping::Keypad_4x4:
0186         m_pKeypad = static_cast<ECKeyPad *>(addItem("ec/keypad", QPoint(144, 232), true));
0187         m_pKeypad->property("numCols")->setValue(4);
0188         keypadCols = 4;
0189         break;
0190 
0191     case PinMapping::Invalid:
0192         qCDebug(KTL_LOG) << "m_pinMappingType == Invalid";
0193         break;
0194     }
0195 
0196     if (keypadCols != -1) {
0197         QStringList::const_iterator it = pins.begin();
0198         for (unsigned row = 0; (row < 4) && (it != end); ++row, ++it)
0199             ICNDocument::createConnector(m_pKeypad->childNode(QString("row_%1").arg(row)), m_pPicComponent->childNode(*it));
0200 
0201         for (int col = 0; (col < keypadCols) && (it != end); ++col, ++it)
0202             ICNDocument::createConnector(m_pKeypad->childNode(QString("col_%1").arg(col)), m_pPicComponent->childNode(*it));
0203     }
0204 
0205     clearHistory(); // Don't allow undoing of initial creation of stuff
0206 }
0207 
0208 bool PinMapDocument::isValidItem(Item *item)
0209 {
0210     return isValidItem(item->type());
0211 }
0212 
0213 bool PinMapDocument::isValidItem(const QString &id)
0214 {
0215     if (!m_pPicComponent && id == "PIC_IC")
0216         return true;
0217 
0218     switch (m_pinMappingType) {
0219     case PinMapping::SevenSegment:
0220         return (!m_pSevenSegment && id == "ec/seven_segment");
0221 
0222     case PinMapping::Keypad_4x3:
0223         return (!m_pKeypad && id == "ec/keypad");
0224 
0225     case PinMapping::Keypad_4x4:
0226         return (!m_pKeypad && id == "ec/keypad");
0227 
0228     case PinMapping::Invalid:
0229         return false;
0230     }
0231 
0232     return false;
0233 }
0234 
0235 void PinMapDocument::deleteSelection()
0236 {
0237     m_selectList->removeQCanvasItem(m_pPicComponent);
0238     m_selectList->removeQCanvasItem(m_pSevenSegment);
0239     m_selectList->removeQCanvasItem(m_pKeypad);
0240 
0241     ICNDocument::deleteSelection();
0242 }
0243 
0244 PinMapping PinMapDocument::pinMapping() const
0245 {
0246     const NodeInfoMap picNodeInfoMap = m_pPicComponent->nodeMap();
0247     const NodeInfoMap::const_iterator picNodeInfoMapEnd = picNodeInfoMap.end();
0248 
0249     QStringList picPinIDs;
0250     QStringList attachedIDs;
0251     Component *attached = nullptr;
0252 
0253     switch (m_pinMappingType) {
0254     case PinMapping::SevenSegment:
0255         for (unsigned i = 0; i < 7; ++i)
0256             attachedIDs << QChar('a' + i);
0257         attached = m_pSevenSegment;
0258         break;
0259 
0260     case PinMapping::Keypad_4x3:
0261         for (unsigned i = 0; i < 4; ++i)
0262             attachedIDs << QString::fromLatin1("row_%1").arg(i);
0263         for (unsigned i = 0; i < 3; ++i)
0264             attachedIDs << QString::fromLatin1("col_%1").arg(i);
0265         attached = m_pKeypad;
0266         break;
0267 
0268     case PinMapping::Keypad_4x4:
0269         for (unsigned i = 0; i < 4; ++i)
0270             attachedIDs << QString::fromLatin1("row_%1").arg(i);
0271         for (unsigned i = 0; i < 4; ++i)
0272             attachedIDs << QString::fromLatin1("col_%1").arg(i);
0273         attached = m_pKeypad;
0274         break;
0275 
0276     case PinMapping::Invalid:
0277         break;
0278     }
0279 
0280     if (!attached)
0281         return PinMapping();
0282 
0283     QStringList::iterator end = attachedIDs.end();
0284     for (QStringList::iterator attachedIt = attachedIDs.begin(); attachedIt != end; ++attachedIt) {
0285         Node *node = attached->childNode(*attachedIt);
0286         QString pinID;
0287 
0288         for (NodeInfoMap::const_iterator it = picNodeInfoMap.begin(); it != picNodeInfoMapEnd; ++it) {
0289             if (it.value().node->isConnected(node)) {
0290                 pinID = it.key();
0291                 break;
0292             }
0293         }
0294 
0295         picPinIDs << pinID;
0296     }
0297 
0298     PinMapping pinMapping(m_pinMappingType);
0299     pinMapping.setPins(picPinIDs);
0300 
0301     return pinMapping;
0302 }
0303 // END class PinMapDocument
0304 
0305 // BEGIN class PinMapView
0306 PinMapView::PinMapView(PinMapDocument *pinMapDocument, ViewContainer *viewContainer, uint viewAreaId)
0307     : ICNView(pinMapDocument, viewContainer, viewAreaId)
0308 {
0309 }
0310 
0311 PinMapView::~PinMapView()
0312 {
0313 }
0314 // END class PinMapView
0315 
0316 // BEGIN class PIC_IC
0317 Item *PIC_IC::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0318 {
0319     return new PIC_IC(static_cast<ICNDocument *>(itemDocument), newItem, id);
0320 }
0321 
0322 LibraryItem *PIC_IC::libraryItem()
0323 {
0324     return new LibraryItem(QStringList(QString::fromLatin1("PIC_IC")), nullptr, nullptr, LibraryItem::lit_other, PIC_IC::construct);
0325 }
0326 
0327 PIC_IC::PIC_IC(ICNDocument *icnDocument, bool newItem, const char *id)
0328     : Component(icnDocument, newItem, id ? id : "PIC_IC")
0329 {
0330 }
0331 
0332 PIC_IC::~PIC_IC()
0333 {
0334 }
0335 
0336 void PIC_IC::initPackage(MicroInfo *microInfo)
0337 {
0338     // The code in this function is a stripped down version of that in PICComponent::initPackage
0339 
0340     if (!microInfo)
0341         return;
0342 
0343     MicroPackage *microPackage = microInfo->package();
0344     if (!microPackage)
0345         return;
0346 
0347     // BEGIN Get pin IDs
0348     QStringList allPinIDs = microPackage->pinIDs();
0349     QStringList ioPinIDs = microPackage->pinIDs(PicPin::type_bidir | PicPin::type_input | PicPin::type_open);
0350 
0351     // Now, we make the unwanted pin ids blank, so a pin is not created for them
0352     const QStringList::iterator allPinIDsEnd = allPinIDs.end();
0353     for (QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it) {
0354         if (!ioPinIDs.contains(*it))
0355             *it = "";
0356     }
0357     // END Get pin IDs
0358 
0359     // BEGIN Remove old stuff
0360     // Remove old text
0361     TextMap textMapCopy = m_textMap;
0362     const TextMap::iterator textMapEnd = textMapCopy.end();
0363     for (TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it)
0364         removeDisplayText(it.key());
0365 
0366     // Remove old nodes
0367     NodeInfoMap nodeMapCopy = m_nodeMap;
0368     const NodeInfoMap::iterator nodeMapEnd = nodeMapCopy.end();
0369     for (NodeInfoMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it) {
0370         if (!ioPinIDs.contains(it.key()))
0371             removeNode(it.key());
0372     }
0373     // END Remove old stuff
0374 
0375     // BEGIN Create new stuff
0376     initDIPSymbol(allPinIDs, 80);
0377     initDIP(allPinIDs);
0378     // END Create new stuff
0379 
0380     addDisplayText("picid", QRect(offsetX(), offsetY() - 16, width(), 16), microInfo->id());
0381 }
0382 // END class PIC_IC
0383 
0384 #include "moc_pinmapping.cpp"