Ejemplo n.º 1
0
bool SES_DrawWire::addNextNetPoint(Schematic&   schematic,
                                   const Point& pos) noexcept {
  Q_ASSERT(mSubState == SubState_PositioningNetPoint);

  // abort if p2 == p0 (no line drawn)
  if (pos == mFixedStartAnchor->getPosition()) {
    abortPositioning(true);
    return false;
  } else {
    bool finishCommand = false;

    try {
      // create a new undo command group to make all changes atomic
      QScopedPointer<UndoCommandGroup> cmdGroup(
          new UndoCommandGroup("Add schematic netline"));

      // remove p1 if p1 == p0 || p1 == p2
      if ((mPositioningNetPoint1->getPosition() ==
           mFixedStartAnchor->getPosition()) ||
          (mPositioningNetPoint1->getPosition() ==
           mPositioningNetPoint2->getPosition())) {
        QScopedPointer<CmdSchematicNetSegmentRemoveElements> cmdRemove(
            new CmdSchematicNetSegmentRemoveElements(
                mPositioningNetPoint1->getNetSegment()));
        cmdRemove->removeNetPoint(*mPositioningNetPoint1);
        cmdRemove->removeNetLine(*mPositioningNetLine1);
        cmdRemove->removeNetLine(*mPositioningNetLine2);
        QScopedPointer<CmdSchematicNetSegmentAddElements> cmdAdd(
            new CmdSchematicNetSegmentAddElements(
                mPositioningNetPoint1->getNetSegment()));
        mPositioningNetLine2 =
            cmdAdd->addNetLine(*mFixedStartAnchor, *mPositioningNetPoint2);
        mUndoStack.appendToCmdGroup(cmdAdd.take());
        mUndoStack.appendToCmdGroup(cmdRemove.take());
      }

      // find anchor under cursor
      SI_NetLineAnchor* otherAnchor     = nullptr;
      SI_NetSegment*    otherNetSegment = nullptr;
      QString           otherForcedNetName;
      if (SI_NetPoint* netpoint =
              findNetPoint(schematic, pos, mPositioningNetPoint2)) {
        otherAnchor     = netpoint;
        otherNetSegment = &netpoint->getNetSegment();
      } else if (SI_SymbolPin* pin = findSymbolPin(schematic, pos)) {
        otherAnchor     = pin;
        otherNetSegment = pin->getNetSegmentOfLines();
        // connect pin if needed
        if (!otherNetSegment) {
          Q_ASSERT(pin->getComponentSignalInstance());
          mUndoStack.appendToCmdGroup(new CmdCompSigInstSetNetSignal(
              *pin->getComponentSignalInstance(),
              &mPositioningNetPoint2->getNetSignalOfNetSegment()));
          otherForcedNetName =
              pin->getComponentSignalInstance()->getForcedNetSignalName();
        }
      } else if (SI_NetLine* netline =
                     findNetLine(schematic, pos, mPositioningNetLine2)) {
        // split netline
        otherNetSegment = &netline->getNetSegment();
        QScopedPointer<CmdSchematicNetSegmentAddElements> cmdAdd(
            new CmdSchematicNetSegmentAddElements(*otherNetSegment));
        otherAnchor = cmdAdd->addNetPoint(pos);
        cmdAdd->addNetLine(*otherAnchor, netline->getStartPoint());
        cmdAdd->addNetLine(*otherAnchor, netline->getEndPoint());
        mUndoStack.appendToCmdGroup(cmdAdd.take());  // can throw
        QScopedPointer<CmdSchematicNetSegmentRemoveElements> cmdRemove(
            new CmdSchematicNetSegmentRemoveElements(*otherNetSegment));
        cmdRemove->removeNetLine(*netline);
        mUndoStack.appendToCmdGroup(cmdRemove.take());  // can throw
      }

      // if anchor found under the cursor, replace "mPositioningNetPoint2" with
      // it
      if (otherAnchor) {
        if ((!otherNetSegment) ||
            (otherNetSegment == &mPositioningNetPoint2->getNetSegment())) {
          QScopedPointer<CmdSchematicNetSegmentAddElements> cmdAdd(
              new CmdSchematicNetSegmentAddElements(
                  mPositioningNetPoint2->getNetSegment()));
          cmdAdd->addNetLine(*otherAnchor,
                             mPositioningNetLine2->getStartPoint());
          mUndoStack.appendToCmdGroup(cmdAdd.take());  // can throw
          QScopedPointer<CmdSchematicNetSegmentRemoveElements> cmdRemove(
              new CmdSchematicNetSegmentRemoveElements(
                  mPositioningNetPoint2->getNetSegment()));
          cmdRemove->removeNetPoint(*mPositioningNetPoint2);
          cmdRemove->removeNetLine(*mPositioningNetLine2);
          mUndoStack.appendToCmdGroup(cmdRemove.take());  // can throw
        } else {
          // change net signal if needed
          NetSignal* thisSignal =
              &mPositioningNetPoint2->getNetSignalOfNetSegment();
          NetSignal* otherSignal = &otherNetSegment->getNetSignal();
          if (thisSignal != otherSignal) {
            NetSignal*     resultingNetSignal       = nullptr;
            SI_NetSegment* netSegmentToChangeSignal = nullptr;
            if (otherNetSegment->getForcedNetNames().count() > 0) {
              resultingNetSignal = &otherNetSegment->getNetSignal();
              netSegmentToChangeSignal =
                  &mPositioningNetPoint2->getNetSegment();
            } else if (mPositioningNetPoint2->getNetSegment()
                           .getForcedNetNames()
                           .count() > 0) {
              resultingNetSignal =
                  &mPositioningNetPoint2->getNetSignalOfNetSegment();
              netSegmentToChangeSignal = otherNetSegment;
            } else if (otherSignal->hasAutoName() &&
                       (!thisSignal->hasAutoName())) {
              resultingNetSignal =
                  &mPositioningNetPoint2->getNetSignalOfNetSegment();
              netSegmentToChangeSignal = otherNetSegment;
            } else {
              resultingNetSignal = &otherNetSegment->getNetSignal();
              netSegmentToChangeSignal =
                  &mPositioningNetPoint2->getNetSegment();
            }
            mUndoStack.appendToCmdGroup(
                new CmdChangeNetSignalOfSchematicNetSegment(
                    *netSegmentToChangeSignal, *resultingNetSignal));
          }
          // combine both net segments
          mUndoStack.appendToCmdGroup(new CmdCombineSchematicNetSegments(
              mPositioningNetPoint2->getNetSegment(), *mPositioningNetPoint2,
              *otherNetSegment, *otherAnchor));
        }
        if (!otherForcedNetName.isEmpty()) {
          // change net name if connected to a pin with forced net name
          try {
            CircuitIdentifier name =
                CircuitIdentifier(otherForcedNetName);  // can throw
            NetSignal* signal =
                schematic.getProject().getCircuit().getNetSignalByName(*name);
            if (signal) {
              mUndoStack.appendToCmdGroup(
                  new CmdChangeNetSignalOfSchematicNetSegment(
                      mPositioningNetPoint2->getNetSegment(), *signal));
            } else {
              QScopedPointer<CmdNetSignalEdit> cmd(new CmdNetSignalEdit(
                  schematic.getProject().getCircuit(),
                  mPositioningNetPoint2->getNetSignalOfNetSegment()));
              cmd->setName(name, false);
              mUndoStack.appendToCmdGroup(cmd.take());
            }
          } catch (const Exception& e) {
            QMessageBox::warning(
                &mEditor, tr("Invalid net name"),
                QString(
                    tr("Could not apply the forced net name because '%1' is "
                       "not a valid net name."))
                    .arg(otherForcedNetName));
          }
        }
        finishCommand = true;
      } else {
        finishCommand = false;
      }
    } catch (const UserCanceled& e) {
      return false;
    } catch (const Exception& e) {
      QMessageBox::critical(&mEditor, tr("Error"), e.getMsg());
      return false;
    }

    try {
      // finish the current command
      mUndoStack.commitCmdGroup();
      mSubState = SubState_Idle;

      // abort or start a new command
      if (finishCommand) {
        mUndoStack.beginCmdGroup(QString());  // this is ugly!
        abortPositioning(true);
        return false;
      } else {
        return startPositioning(schematic, pos, mPositioningNetPoint2);
      }
    } catch (const Exception& e) {
      QMessageBox::critical(&mEditor, tr("Error"), e.getMsg());
      if (mSubState != SubState_Idle) {
        abortPositioning(false);
      }
      return false;
    }
  }
}