Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/schematic_element.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                             schematic_element.cpp
00003                            -----------------------
00004     begin                : Sat Mar 3 2006
00005     copyright            : (C) 2006 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 #include <stdlib.h>
00018 #include <limits.h>
00019 
00020 #include "schematic.h"
00021 #include <Q3PtrList>
00022 #include <QDebug>
00023 
00024 
00025 /* *******************************************************************
00026    *****                                                         *****
00027    *****              Actions handling the nodes                 *****
00028    *****                                                         *****
00029    ******************************************************************* */
00030 
00031 // Inserts a port into the schematic and connects it to another node if
00032 // the coordinates are identical. The node is returned.
00033 Node* Schematic::insertNode(int x, int y, Element *e)
00034 {
00035     Node *pn;
00036     // check if new node lies upon existing node
00037     for(pn = Nodes->first(); pn != 0; pn = Nodes->next())  // check every node
00038         if(pn->cx == x) if(pn->cy == y)
00039             {
00040                 pn->Connections.append(e);
00041                 break;
00042             }
00043 
00044     if(pn == 0)   // create new node, if no existing one lies at this position
00045     {
00046         pn = new Node(x, y);
00047         Nodes->append(pn);
00048         pn->Connections.append(e);  // connect schematic node to component node
00049     }
00050     else return pn;   // return, if node is not new
00051 
00052     // check if the new node lies upon an existing wire
00053     for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next())
00054     {
00055         if(pw->x1 == x)
00056         {
00057             if(pw->y1 > y) continue;
00058             if(pw->y2 < y) continue;
00059         }
00060         else if(pw->y1 == y)
00061         {
00062             if(pw->x1 > x) continue;
00063             if(pw->x2 < x) continue;
00064         }
00065         else continue;
00066 
00067         // split the wire into two wires
00068         splitWire(pw, pn);
00069         return pn;
00070     }
00071 
00072     return pn;
00073 }
00074 
00075 // ---------------------------------------------------
00076 Node* Schematic::selectedNode(int x, int y)
00077 {
00078     for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) // test nodes
00079         if(pn->getSelected(x, y))
00080             return pn;
00081 
00082     return 0;
00083 }
00084 
00085 
00086 /* *******************************************************************
00087    *****                                                         *****
00088    *****              Actions handling the wires                 *****
00089    *****                                                         *****
00090    ******************************************************************* */
00091 
00092 // Inserts a port into the schematic and connects it to another node if the
00093 // coordinates are identical. If 0 is returned, no new wire is inserted.
00094 // If 2 is returned, the wire line ended.
00095 int Schematic::insertWireNode1(Wire *w)
00096 {
00097     Node *pn;
00098     // check if new node lies upon an existing node
00099     for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node
00100         if(pn->cx == w->x1) if(pn->cy == w->y1) break;
00101 
00102     if(pn != 0)
00103     {
00104         pn->Connections.append(w);
00105         w->Port1 = pn;
00106         return 2;   // node is not new
00107     }
00108 
00109 
00110 
00111     // check if the new node lies upon an existing wire
00112     for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next())
00113     {
00114         if(ptr2->x1 == w->x1)
00115         {
00116             if(ptr2->y1 > w->y1) continue;
00117             if(ptr2->y2 < w->y1) continue;
00118 
00119             if(ptr2->isHorizontal() == w->isHorizontal())   // ptr2-wire is vertical
00120             {
00121                 if(ptr2->y2 >= w->y2)
00122                 {
00123                     delete w;    // new wire lies within an existing wire
00124                     return 0;
00125                 }
00126                 else
00127                 {
00128                     // one part of the wire lies within an existing wire
00129                     // the other part not
00130                     if(ptr2->Port2->Connections.count() == 1)
00131                     {
00132                         w->y1 = ptr2->y1;
00133                         w->Port1 = ptr2->Port1;
00134                         if(ptr2->Label)
00135                         {
00136                             w->Label = ptr2->Label;
00137                             w->Label->pOwner = w;
00138                         }
00139                         ptr2->Port1->Connections.removeRef(ptr2);  // two -> one wire
00140                         ptr2->Port1->Connections.append(w);
00141                         Nodes->removeRef(ptr2->Port2);
00142                         Wires->removeRef(ptr2);
00143                         return 2;
00144                     }
00145                     else
00146                     {
00147                         w->y1 = ptr2->y2;
00148                         w->Port1 = ptr2->Port2;
00149                         ptr2->Port2->Connections.append(w);   // shorten new wire
00150                         return 2;
00151                     }
00152                 }
00153             }
00154         }
00155         else if(ptr2->y1 == w->y1)
00156         {
00157             if(ptr2->x1 > w->x1) continue;
00158             if(ptr2->x2 < w->x1) continue;
00159 
00160             if(ptr2->isHorizontal() == w->isHorizontal())   // ptr2-wire is horizontal
00161             {
00162                 if(ptr2->x2 >= w->x2)
00163                 {
00164                     delete w;   // new wire lies within an existing wire
00165                     return 0;
00166                 }
00167                 else
00168                 {
00169                     // one part of the wire lies within an existing wire
00170                     // the other part not
00171                     if(ptr2->Port2->Connections.count() == 1)
00172                     {
00173                         w->x1 = ptr2->x1;
00174                         w->Port1 = ptr2->Port1;
00175                         if(ptr2->Label)
00176                         {
00177                             w->Label = ptr2->Label;
00178                             w->Label->pOwner = w;
00179                         }
00180                         ptr2->Port1->Connections.removeRef(ptr2); // two -> one wire
00181                         ptr2->Port1->Connections.append(w);
00182                         Nodes->removeRef(ptr2->Port2);
00183                         Wires->removeRef(ptr2);
00184                         return 2;
00185                     }
00186                     else
00187                     {
00188                         w->x1 = ptr2->x2;
00189                         w->Port1 = ptr2->Port2;
00190                         ptr2->Port2->Connections.append(w);   // shorten new wire
00191                         return 2;
00192                     }
00193                 }
00194             }
00195         }
00196         else continue;
00197 
00198         pn = new Node(w->x1, w->y1);   // create new node
00199         Nodes->append(pn);
00200         pn->Connections.append(w);  // connect schematic node to the new wire
00201         w->Port1 = pn;
00202 
00203         // split the wire into two wires
00204         splitWire(ptr2, pn);
00205         return 2;
00206     }
00207 
00208     pn = new Node(w->x1, w->y1);   // create new node
00209     Nodes->append(pn);
00210     pn->Connections.append(w);  // connect schematic node to the new wire
00211     w->Port1 = pn;
00212     return 1;
00213 }
00214 
00215 // ---------------------------------------------------
00216 // if possible, connect two horizontal wires to one
00217 bool Schematic::connectHWires1(Wire *w)
00218 {
00219     Wire *pw;
00220     Node *n = w->Port1;
00221 
00222     pw = (Wire*)n->Connections.last();  // last connection is the new wire itself
00223     for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev())
00224     {
00225         if(pw->Type != isWire) continue;
00226         if(!pw->isHorizontal()) continue;
00227         if(pw->x1 < w->x1)
00228         {
00229             if(n->Connections.count() != 2) continue;
00230             if(pw->Label)
00231             {
00232                 w->Label = pw->Label;
00233                 w->Label->pOwner = w;
00234             }
00235             else if(n->Label)
00236             {
00237                 w->Label = n->Label;
00238                 w->Label->pOwner = w;
00239                 w->Label->Type = isHWireLabel;
00240             }
00241             w->x1 = pw->x1;
00242             w->Port1 = pw->Port1;      // new wire lengthens an existing one
00243             Nodes->removeRef(n);
00244             w->Port1->Connections.removeRef(pw);
00245             w->Port1->Connections.append(w);
00246             Wires->removeRef(pw);
00247             return true;
00248         }
00249         if(pw->x2 >= w->x2)    // new wire lies within an existing one ?
00250         {
00251             w->Port1->Connections.removeRef(w); // second node not yet made
00252             delete w;
00253             return false;
00254         }
00255         if(pw->Port2->Connections.count() < 2)
00256         {
00257             // existing wire lies within the new one
00258             if(pw->Label)
00259             {
00260                 w->Label = pw->Label;
00261                 w->Label->pOwner = w;
00262             }
00263             pw->Port1->Connections.removeRef(pw);
00264             Nodes->removeRef(pw->Port2);
00265             Wires->removeRef(pw);
00266             return true;
00267         }
00268         w->x1 = pw->x2;    // shorten new wire according to an existing one
00269         w->Port1->Connections.removeRef(w);
00270         w->Port1 = pw->Port2;
00271         w->Port1->Connections.append(w);
00272         return true;
00273     }
00274 
00275     return true;
00276 }
00277 
00278 // ---------------------------------------------------
00279 // if possible, connect two vertical wires to one
00280 bool Schematic::connectVWires1(Wire *w)
00281 {
00282     Wire *pw;
00283     Node *n = w->Port1;
00284 
00285     pw = (Wire*)n->Connections.last();  // last connection is the new wire itself
00286     for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev())
00287     {
00288         if(pw->Type != isWire) continue;
00289         if(pw->isHorizontal()) continue;
00290         if(pw->y1 < w->y1)
00291         {
00292             if(n->Connections.count() != 2) continue;
00293             if(pw->Label)
00294             {
00295                 w->Label = pw->Label;
00296                 w->Label->pOwner = w;
00297             }
00298             else if(n->Label)
00299             {
00300                 w->Label = n->Label;
00301                 w->Label->pOwner = w;
00302                 w->Label->Type = isVWireLabel;
00303             }
00304             w->y1 = pw->y1;
00305             w->Port1 = pw->Port1;         // new wire lengthens an existing one
00306             Nodes->removeRef(n);
00307             w->Port1->Connections.removeRef(pw);
00308             w->Port1->Connections.append(w);
00309             Wires->removeRef(pw);
00310             return true;
00311         }
00312         if(pw->y2 >= w->y2)    // new wire lies complete within an existing one ?
00313         {
00314             w->Port1->Connections.removeRef(w); // second node not yet made
00315             delete w;
00316             return false;
00317         }
00318         if(pw->Port2->Connections.count() < 2)
00319         {
00320             // existing wire lies within the new one
00321             if(pw->Label)
00322             {
00323                 w->Label = pw->Label;
00324                 w->Label->pOwner = w;
00325             }
00326             pw->Port1->Connections.removeRef(pw);
00327             Nodes->removeRef(pw->Port2);
00328             Wires->removeRef(pw);
00329             return true;
00330         }
00331         w->y1 = pw->y2;    // shorten new wire according to an existing one
00332         w->Port1->Connections.removeRef(w);
00333         w->Port1 = pw->Port2;
00334         w->Port1->Connections.append(w);
00335         return true;
00336     }
00337 
00338     return true;
00339 }
00340 
00341 // ---------------------------------------------------
00342 // Inserts a port into the schematic and connects it to another node if the
00343 // coordinates are identical. If 0 is returned, no new wire is inserted.
00344 // If 2 is returned, the wire line ended.
00345 int Schematic::insertWireNode2(Wire *w)
00346 {
00347     Node *pn;
00348     // check if new node lies upon an existing node
00349     for(pn = Nodes->first(); pn != 0; pn = Nodes->next())  // check every node
00350         if(pn->cx == w->x2) if(pn->cy == w->y2) break;
00351 
00352     if(pn != 0)
00353     {
00354         pn->Connections.append(w);
00355         w->Port2 = pn;
00356         return 2;   // node is not new
00357     }
00358 
00359 
00360 
00361     // check if the new node lies upon an existing wire
00362     for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next())
00363     {
00364         if(ptr2->x1 == w->x2)
00365         {
00366             if(ptr2->y1 > w->y2) continue;
00367             if(ptr2->y2 < w->y2) continue;
00368 
00369             // (if new wire lies within an existing wire, was already check before)
00370             if(ptr2->isHorizontal() == w->isHorizontal())   // ptr2-wire is vertical
00371             {
00372                 // one part of the wire lies within an existing wire
00373                 // the other part not
00374                 if(ptr2->Port1->Connections.count() == 1)
00375                 {
00376                     if(ptr2->Label)
00377                     {
00378                         w->Label = ptr2->Label;
00379                         w->Label->pOwner = w;
00380                     }
00381                     w->y2 = ptr2->y2;
00382                     w->Port2 = ptr2->Port2;
00383                     ptr2->Port2->Connections.removeRef(ptr2);  // two -> one wire
00384                     ptr2->Port2->Connections.append(w);
00385                     Nodes->removeRef(ptr2->Port1);
00386                     Wires->removeRef(ptr2);
00387                     return 2;
00388                 }
00389                 else
00390                 {
00391                     w->y2 = ptr2->y1;
00392                     w->Port2 = ptr2->Port1;
00393                     ptr2->Port1->Connections.append(w);   // shorten new wire
00394                     return 2;
00395                 }
00396             }
00397         }
00398         else if(ptr2->y1 == w->y2)
00399         {
00400             if(ptr2->x1 > w->x2) continue;
00401             if(ptr2->x2 < w->x2) continue;
00402 
00403             // (if new wire lies within an existing wire, was already check before)
00404             if(ptr2->isHorizontal() == w->isHorizontal())   // ptr2-wire is horizontal
00405             {
00406                 // one part of the wire lies within an existing wire
00407                 // the other part not
00408                 if(ptr2->Port1->Connections.count() == 1)
00409                 {
00410                     if(ptr2->Label)
00411                     {
00412                         w->Label = ptr2->Label;
00413                         w->Label->pOwner = w;
00414                     }
00415                     w->x2 = ptr2->x2;
00416                     w->Port2 = ptr2->Port2;
00417                     ptr2->Port2->Connections.removeRef(ptr2);  // two -> one wire
00418                     ptr2->Port2->Connections.append(w);
00419                     Nodes->removeRef(ptr2->Port1);
00420                     Wires->removeRef(ptr2);
00421                     return 2;
00422                 }
00423                 else
00424                 {
00425                     w->x2 = ptr2->x1;
00426                     w->Port2 = ptr2->Port1;
00427                     ptr2->Port1->Connections.append(w);   // shorten new wire
00428                     return 2;
00429                 }
00430             }
00431         }
00432         else continue;
00433 
00434         pn = new Node(w->x2, w->y2);   // create new node
00435         Nodes->append(pn);
00436         pn->Connections.append(w);  // connect schematic node to the new wire
00437         w->Port2 = pn;
00438 
00439         // split the wire into two wires
00440         splitWire(ptr2, pn);
00441         return 2;
00442     }
00443 
00444     pn = new Node(w->x2, w->y2);   // create new node
00445     Nodes->append(pn);
00446     pn->Connections.append(w);  // connect schematic node to the new wire
00447     w->Port2 = pn;
00448     return 1;
00449 }
00450 
00451 // ---------------------------------------------------
00452 // if possible, connect two horizontal wires to one
00453 bool Schematic::connectHWires2(Wire *w)
00454 {
00455     Wire *pw;
00456     Node *n = w->Port2;
00457 
00458     pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
00459     for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev())
00460     {
00461         if(pw->Type != isWire) continue;
00462         if(!pw->isHorizontal()) continue;
00463         if(pw->x2 > w->x2)
00464         {
00465             if(n->Connections.count() != 2) continue;
00466             if(pw->Label)
00467             {
00468                 w->Label = pw->Label;
00469                 w->Label->pOwner = w;
00470             }
00471             w->x2 = pw->x2;
00472             w->Port2 = pw->Port2;      // new wire lengthens an existing one
00473             Nodes->removeRef(n);
00474             w->Port2->Connections.removeRef(pw);
00475             w->Port2->Connections.append(w);
00476             Wires->removeRef(pw);
00477             return true;
00478         }
00479         // (if new wire lies complete within an existing one, was already
00480         // checked before)
00481 
00482         if(pw->Port1->Connections.count() < 2)
00483         {
00484             // existing wire lies within the new one
00485             if(pw->Label)
00486             {
00487                 w->Label = pw->Label;
00488                 w->Label->pOwner = w;
00489             }
00490             pw->Port2->Connections.removeRef(pw);
00491             Nodes->removeRef(pw->Port1);
00492             Wires->removeRef(pw);
00493             return true;
00494         }
00495         w->x2 = pw->x1;    // shorten new wire according to an existing one
00496         w->Port2->Connections.removeRef(w);
00497         w->Port2 = pw->Port1;
00498         w->Port2->Connections.append(w);
00499         return true;
00500     }
00501 
00502     return true;
00503 }
00504 
00505 // ---------------------------------------------------
00506 // if possible, connect two vertical wires to one
00507 bool Schematic::connectVWires2(Wire *w)
00508 {
00509     Wire *pw;
00510     Node *n = w->Port2;
00511 
00512     pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
00513     for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev())
00514     {
00515         if(pw->Type != isWire) continue;
00516         if(pw->isHorizontal()) continue;
00517         if(pw->y2 > w->y2)
00518         {
00519             if(n->Connections.count() != 2) continue;
00520             if(pw->Label)
00521             {
00522                 w->Label = pw->Label;
00523                 w->Label->pOwner = w;
00524             }
00525             w->y2 = pw->y2;
00526             w->Port2 = pw->Port2;     // new wire lengthens an existing one
00527             Nodes->removeRef(n);
00528             w->Port2->Connections.removeRef(pw);
00529             w->Port2->Connections.append(w);
00530             Wires->removeRef(pw);
00531             return true;
00532         }
00533         // (if new wire lies complete within an existing one, was already
00534         // checked before)
00535 
00536         if(pw->Port1->Connections.count() < 2)
00537         {
00538             // existing wire lies within the new one
00539             if(pw->Label)
00540             {
00541                 w->Label = pw->Label;
00542                 w->Label->pOwner = w;
00543             }
00544             pw->Port2->Connections.removeRef(pw);
00545             Nodes->removeRef(pw->Port1);
00546             Wires->removeRef(pw);
00547             return true;
00548         }
00549         w->y2 = pw->y1;    // shorten new wire according to an existing one
00550         w->Port2->Connections.removeRef(w);
00551         w->Port2 = pw->Port1;
00552         w->Port2->Connections.append(w);
00553         return true;
00554     }
00555 
00556     return true;
00557 }
00558 
00559 // ---------------------------------------------------
00560 // Inserts a vertical or horizontal wire into the schematic and connects
00561 // the ports that hit together. Returns whether the beginning and ending
00562 // (the ports of the wire) are connected or not.
00563 int Schematic::insertWire(Wire *w)
00564 {
00565     int  tmp, con = 0;
00566     bool ok;
00567 
00568     // change coordinates if necessary (port 1 coordinates must be less
00569     // port 2 coordinates)
00570     if(w->x1 > w->x2)
00571     {
00572         tmp = w->x1;
00573         w->x1 = w->x2;
00574         w->x2 = tmp;
00575     }
00576     else if(w->y1 > w->y2)
00577     {
00578         tmp = w->y1;
00579         w->y1 = w->y2;
00580         w->y2 = tmp;
00581     }
00582     else con = 0x100;
00583 
00584 
00585 
00586     tmp = insertWireNode1(w);
00587     if(tmp == 0) return 3;  // no new wire and no open connection
00588     if(tmp > 1) con |= 2;   // insert node and remember if it remains open
00589 
00590     if(w->isHorizontal()) ok = connectHWires1(w);
00591     else ok = connectVWires1(w);
00592     if(!ok) return 3;
00593 
00594 
00595 
00596 
00597     tmp = insertWireNode2(w);
00598     if(tmp == 0) return 3;  // no new wire and no open connection
00599     if(tmp > 1) con |= 1;   // insert node and remember if it remains open
00600 
00601     if(w->isHorizontal()) ok = connectHWires2(w);
00602     else ok = connectVWires2(w);
00603     if(!ok) return 3;
00604 
00605 
00606 
00607     // change node 1 and 2
00608     if(con > 255) con = ((con >> 1) & 1) | ((con << 1) & 2);
00609 
00610     Wires->append(w);    // add wire to the schematic
00611 
00612 
00613 
00614 
00615     int  n1, n2;
00616     Wire *pw, *nw;
00617     Node *pn, *pn2;
00618     Element *pe;
00619     // ................................................................
00620     // Check if the new line covers existing nodes.
00621     // In order to also check new appearing wires -> use "for"-loop
00622     for(pw = Wires->current(); pw != 0; pw = Wires->next())
00623         for(pn = Nodes->first(); pn != 0; )    // check every node
00624         {
00625             if(pn->cx == pw->x1)
00626             {
00627                 if(pn->cy <= pw->y1)
00628                 {
00629                     pn = Nodes->next();
00630                     continue;
00631                 }
00632                 if(pn->cy >= pw->y2)
00633                 {
00634                     pn = Nodes->next();
00635                     continue;
00636                 }
00637             }
00638             else if(pn->cy == pw->y1)
00639             {
00640                 if(pn->cx <= pw->x1)
00641                 {
00642                     pn = Nodes->next();
00643                     continue;
00644                 }
00645                 if(pn->cx >= pw->x2)
00646                 {
00647                     pn = Nodes->next();
00648                     continue;
00649                 }
00650             }
00651             else
00652             {
00653                 pn = Nodes->next();
00654                 continue;
00655             }
00656 
00657             n1 = 2;
00658             n2 = 3;
00659             pn2 = pn;
00660             // check all connections of the current node
00661             for(pe=pn->Connections.first(); pe!=0; pe=pn->Connections.next())
00662             {
00663                 if(pe->Type != isWire) continue;
00664                 nw = (Wire*)pe;
00665                 // wire lies within the new ?
00666                 if(pw->isHorizontal() != nw->isHorizontal()) continue;
00667 
00668                 pn  = nw->Port1;
00669                 pn2 = nw->Port2;
00670                 n1  = pn->Connections.count();
00671                 n2  = pn2->Connections.count();
00672                 if(n1 == 1)
00673                 {
00674                     Nodes->removeRef(pn);     // delete node 1 if open
00675                     pn2->Connections.removeRef(nw);   // remove connection
00676                     pn = pn2;
00677                 }
00678 
00679                 if(n2 == 1)
00680                 {
00681                     pn->Connections.removeRef(nw);   // remove connection
00682                     Nodes->removeRef(pn2);     // delete node 2 if open
00683                     pn2 = pn;
00684                 }
00685 
00686                 if(pn == pn2)
00687                 {
00688                     if(nw->Label)
00689                     {
00690                         pw->Label = nw->Label;
00691                         pw->Label->pOwner = pw;
00692                     }
00693                     Wires->removeRef(nw);    // delete wire
00694                     Wires->findRef(pw);      // set back to current wire
00695                 }
00696                 break;
00697             }
00698             if(n1 == 1) if(n2 == 1) continue;
00699 
00700             // split wire into two wires
00701             if((pw->x1 != pn->cx) || (pw->y1 != pn->cy))
00702             {
00703                 nw = new Wire(pw->x1, pw->y1, pn->cx, pn->cy, pw->Port1, pn);
00704                 pn->Connections.append(nw);
00705                 Wires->append(nw);
00706                 Wires->findRef(pw);
00707                 pw->Port1->Connections.append(nw);
00708             }
00709             pw->Port1->Connections.removeRef(pw);
00710             pw->x1 = pn2->cx;
00711             pw->y1 = pn2->cy;
00712             pw->Port1 = pn2;
00713             pn2->Connections.append(pw);
00714 
00715             pn = Nodes->next();
00716         }
00717 
00718     if (Wires->containsRef (w))  // if two wire lines with different labels ...
00719         oneLabel(w->Port1);       // ... are connected, delete one label
00720     return con | 0x0200;   // sent also end flag
00721 }
00722 
00723 // ---------------------------------------------------
00724 // Follows a wire line and selects it.
00725 void Schematic::selectWireLine(Element *pe, Node *pn, bool ctrl)
00726 {
00727     Node *pn_1st = pn;
00728     while(pn->Connections.count() == 2)
00729     {
00730         if(pn->Connections.first() == pe)  pe = pn->Connections.last();
00731         else  pe = pn->Connections.first();
00732 
00733         if(pe->Type != isWire) break;
00734         if(ctrl) pe->isSelected ^= ctrl;
00735         else pe->isSelected = true;
00736 
00737         if(((Wire*)pe)->Port1 == pn)  pn = ((Wire*)pe)->Port2;
00738         else  pn = ((Wire*)pe)->Port1;
00739         if(pn == pn_1st) break;  // avoid endless loop in wire loops
00740     }
00741 }
00742 
00743 // ---------------------------------------------------
00744 Wire* Schematic::selectedWire(int x, int y)
00745 {
00746     for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next())
00747         if(pw->getSelected(x, y))
00748             return pw;
00749 
00750     return 0;
00751 }
00752 
00753 // ---------------------------------------------------
00754 // Splits the wire "*pw" into two pieces by the node "*pn".
00755 Wire* Schematic::splitWire(Wire *pw, Node *pn)
00756 {
00757     Wire *newWire = new Wire(pn->cx, pn->cy, pw->x2, pw->y2, pn, pw->Port2);
00758     newWire->isSelected = pw->isSelected;
00759 
00760     pw->x2 = pn->cx;
00761     pw->y2 = pn->cy;
00762     pw->Port2 = pn;
00763 
00764     newWire->Port2->Connections.prepend(newWire);
00765     pn->Connections.prepend(pw);
00766     pn->Connections.prepend(newWire);
00767     newWire->Port2->Connections.removeRef(pw);
00768     Wires->append(newWire);
00769 
00770     if(pw->Label)
00771         if((pw->Label->cx > pn->cx) || (pw->Label->cy > pn->cy))
00772         {
00773             newWire->Label = pw->Label;   // label goes to the new wire
00774             pw->Label = 0;
00775             newWire->Label->pOwner = newWire;
00776         }
00777 
00778     return newWire;
00779 }
00780 
00781 // ---------------------------------------------------
00782 // If possible, make one wire out of two wires.
00783 bool Schematic::oneTwoWires(Node *n)
00784 {
00785     Wire *e3;
00786     Wire *e1 = (Wire*)n->Connections.getFirst();  // two wires -> one wire
00787     Wire *e2 = (Wire*)n->Connections.getLast();
00788 
00789     if(e1->Type == isWire) if(e2->Type == isWire)
00790             if(e1->isHorizontal() == e2->isHorizontal())
00791             {
00792                 if(e1->x1 == e2->x2) if(e1->y1 == e2->y2)
00793                     {
00794                         e3 = e1;
00795                         e1 = e2;
00796                         e2 = e3;    // e1 must have lesser coordinates
00797                     }
00798                 if(e2->Label)     // take over the node name label ?
00799                 {
00800                     e1->Label = e2->Label;
00801                     e1->Label->pOwner = e1;
00802                 }
00803                 else if(n->Label)
00804                 {
00805                     e1->Label = n->Label;
00806                     e1->Label->pOwner = e1;
00807                     if(e1->isHorizontal())
00808                         e1->Label->Type = isHWireLabel;
00809                     else
00810                         e1->Label->Type = isVWireLabel;
00811                 }
00812 
00813                 e1->x2 = e2->x2;
00814                 e1->y2 = e2->y2;
00815                 e1->Port2 = e2->Port2;
00816                 Nodes->removeRef(n);    // delete node (is auto delete)
00817                 e1->Port2->Connections.removeRef(e2);
00818                 e1->Port2->Connections.append(e1);
00819                 Wires->removeRef(e2);
00820                 return true;
00821             }
00822     return false;
00823 }
00824 
00825 // ---------------------------------------------------
00826 // Deletes the wire 'w'.
00827 void Schematic::deleteWire(Wire *w)
00828 {
00829     if(w->Port1->Connections.count() == 1)
00830     {
00831         if(w->Port1->Label) delete w->Port1->Label;
00832         Nodes->removeRef(w->Port1);     // delete node 1 if open
00833     }
00834     else
00835     {
00836         w->Port1->Connections.removeRef(w);   // remove connection
00837         if(w->Port1->Connections.count() == 2)
00838             oneTwoWires(w->Port1);  // two wires -> one wire
00839     }
00840 
00841     if(w->Port2->Connections.count() == 1)
00842     {
00843         if(w->Port2->Label) delete w->Port2->Label;
00844         Nodes->removeRef(w->Port2);     // delete node 2 if open
00845     }
00846     else
00847     {
00848         w->Port2->Connections.removeRef(w);   // remove connection
00849         if(w->Port2->Connections.count() == 2)
00850             oneTwoWires(w->Port2);  // two wires -> one wire
00851     }
00852 
00853     if(w->Label)
00854     {
00855         delete w->Label;
00856         w->Label = 0;
00857     }
00858     Wires->removeRef(w);
00859 }
00860 
00861 // ---------------------------------------------------
00862 int Schematic::copyWires(int& x1, int& y1, int& x2, int& y2,
00863                          QList<Element *> *ElementCache)
00864 {
00865     int count=0;
00866     Node *pn;
00867     Wire *pw;
00868     WireLabel *pl;
00869     for(pw = Wires->first(); pw != 0; )  // find bounds of all selected wires
00870         if(pw->isSelected)
00871         {
00872             if(pw->x1 < x1) x1 = pw->x1;
00873             if(pw->x2 > x2) x2 = pw->x2;
00874             if(pw->y1 < y1) y1 = pw->y1;
00875             if(pw->y2 > y2) y2 = pw->y2;
00876 
00877             count++;
00878             ElementCache->append(pw);
00879 
00880             // rescue non-selected node labels
00881             pn = pw->Port1;
00882             if(pn->Label)
00883                 if(pn->Connections.count() < 2)
00884                 {
00885                     ElementCache->append(pn->Label);
00886 
00887                     // Don't set pn->Label->pOwner=0 , so text position stays unchanged.
00888                     // But remember its wire.
00889                     pn->Label->pOwner = (Node*)pw;
00890                     pn->Label = 0;
00891                 }
00892             pn = pw->Port2;
00893             if(pn->Label)
00894                 if(pn->Connections.count() < 2)
00895                 {
00896                     ElementCache->append(pn->Label);
00897 
00898                     // Don't set pn->Label->pOwner=0 , so text position stays unchanged.
00899                     // But remember its wire.
00900                     pn->Label->pOwner = (Node*)pw;
00901                     pn->Label = 0;
00902                 }
00903 
00904             pl = pw->Label;
00905             pw->Label = 0;
00906             deleteWire(pw);
00907             pw->Label = pl;    // restore wire label
00908             pw = Wires->current();
00909         }
00910         else pw = Wires->next();
00911 
00912     return count;
00913 }
00914 
00915 
00916 /* *******************************************************************
00917    *****                                                         *****
00918    *****                  Actions with markers                   *****
00919    *****                                                         *****
00920    ******************************************************************* */
00921 
00922 Marker* Schematic::setMarker(int x, int y)
00923 {
00924   // only diagrams ...
00925   for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev()){
00926     if(Marker* m=pd->setMarker(x,y)){
00927       setChanged(true, true);
00928       return m;
00929     }
00930   }
00931   return NULL;
00932 }
00933 
00934 // ---------------------------------------------------
00935 // Moves the marker pointer left/right on the graph.
00936 void Schematic::markerLeftRight(bool left, Q3PtrList<Element> *Elements)
00937 {
00938     bool acted = false;
00939     for(auto i : *Elements) {
00940         Marker* pm = prechecked_cast<Marker*>(i);
00941         assert(pm);
00942         if(pm->moveLeftRight(left))
00943             acted = true;
00944     }
00945 
00946     if(acted)  setChanged(true, true, 'm');
00947 }
00948 
00949 // ---------------------------------------------------
00950 // Moves the marker pointer up/down on the more-dimensional graph.
00951 void Schematic::markerUpDown(bool up, Q3PtrList<Element> *Elements)
00952 {
00953     Marker *pm;
00954     bool acted = false;
00955     for(pm = (Marker*)Elements->first(); pm!=0; pm = (Marker*)Elements->next())
00956     {
00957         if(pm->moveUpDown(up))
00958             acted = true;
00959     }
00960 
00961     if(acted)  setChanged(true, true, 'm');
00962 }
00963 
00964 
00965 /* *******************************************************************
00966    *****                                                         *****
00967    *****               Actions with all elements                 *****
00968    *****                                                         *****
00969    ******************************************************************* */
00970 
00971 /* Selects the element that contains the coordinates x/y.
00972    Returns the pointer to the element.
00973 
00974    If 'flag' is true, the element can be deselected. If
00975    'flag' is false the element cannot be deselected. The
00976    purpose of this is to prevent deselection in cases such
00977    as right-clicking on a selected element to get a context
00978    menu.
00979 */
00980 Element* Schematic::selectElement(float fX, float fY, bool flag, int *index)
00981 {
00982     int n, x = int(fX), y = int(fY);
00983     Element *pe_1st = 0;
00984     Element *pe_sel = 0;
00985     WireLabel *pl = 0;
00986     float Corr = textCorr(); // for selecting text
00987 
00988     // test all nodes and their labels
00989     for(Node *pn = Nodes->last(); pn != 0; pn = Nodes->prev())
00990     {
00991         if(!flag)
00992         {
00993             // The element cannot be deselected
00994             if(index)
00995             {
00996                 // 'index' is only true if called from MouseActions::MPressSelect()
00997                 if(pn->getSelected(x, y))
00998                 {
00999                     // Return the node pointer, as the selection cannot change
01000                     return pn;
01001                 }
01002             }
01003         }
01004 
01005         pl = pn->Label; // Get any wire label associated with the Node
01006         if(pl)
01007         {
01008             if(pl->getSelected(x, y))
01009             {
01010                 if(flag)
01011                 {
01012                     // The element can be deselected, so toggle its isSelected member
01013                     // TODO: I don't see a need for the xor here, a simple ! on the current value
01014                     // would be clearer and have the same effect?
01015                     pl->isSelected ^= flag;
01016                     return pl;
01017                 }
01018                 if(pe_sel)
01019                 {
01020                     // There is another currently
01021                     pe_sel->isSelected = false;
01022                     return pl;
01023                 }
01024                 if(pe_1st == 0)
01025                 {
01026                     // give access to elements lying beneath by storing this label.
01027                     // If no label pointer (or other element) has previously been
01028                     // stored, the current label pointer is stored here.
01029                     // pe_1st is returned if no other selected element
01030                     pe_1st = pl;
01031                 }
01032                 if(pl->isSelected)
01033                 {
01034                     // if current label is already selected, store a pointer to it.
01035                     // This can be used to cycle through
01036                     pe_sel = pl;
01037                 }
01038             }
01039         }
01040     }
01041 
01042     // test all wires and wire labels
01043     for(Wire *pw = Wires->last(); pw != 0; pw = Wires->prev())
01044     {
01045         if(pw->getSelected(x, y))
01046         {
01047             if(flag)
01048             {
01049                 // The element can be deselected
01050                 pw->isSelected ^= flag;
01051                 return pw;
01052             }
01053             if(pe_sel)
01054             {
01055                 pe_sel->isSelected = false;
01056                 return pw;
01057             }
01058             if(pe_1st == 0)
01059             {
01060                 pe_1st = pw;   // give access to elements lying beneath
01061             }
01062             if(pw->isSelected)
01063             {
01064                 pe_sel = pw;
01065             }
01066         }
01067         pl = pw->Label; // test any label associated with the wire
01068         if(pl)
01069         {
01070             if(pl->getSelected(x, y))
01071             {
01072                 if(flag)
01073                 {
01074                     // The element can be deselected
01075                     pl->isSelected ^= flag;
01076                     return pl;
01077                 }
01078                 if(pe_sel)
01079                 {
01080                     pe_sel->isSelected = false;
01081                     return pl;
01082                 }
01083                 if(pe_1st == 0)
01084                 {
01085                     // give access to elements lying beneath
01086                     pe_1st = pl;
01087                 }
01088                 if(pl->isSelected)
01089                 {
01090                     pe_sel = pl;
01091                 }
01092             }
01093         }
01094     }
01095 
01096     // test all components
01097     for(Component *pc = Components->last(); pc != 0; pc = Components->prev())
01098     {
01099         if(pc->getSelected(x, y))
01100         {
01101             if(flag)
01102             {
01103                 // The element can be deselected
01104                 pc->isSelected ^= flag;
01105                 return pc;
01106             }
01107             if(pe_sel)
01108             {
01109                 pe_sel->isSelected = false;
01110                 return pc;
01111             }
01112             if(pe_1st == 0)
01113             {
01114                 pe_1st = pc;
01115             }  // give access to elements lying beneath
01116             if(pc->isSelected)
01117             {
01118                 pe_sel = pc;
01119             }
01120         }
01121         else
01122         {
01123             n = pc->getTextSelected(x, y, Corr);
01124             if(n >= 0)     // was property text clicked ?
01125             {
01126                 pc->Type = isComponentText;
01127                 if(index)  *index = n;
01128                 return pc;
01129             }
01130         }
01131     }
01132 
01133     Corr = 5.0 / Scale;  // size of line select and area for resizing
01134     // test all diagrams
01135     for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev())
01136     {
01137 
01138         foreach(Graph *pg, pd->Graphs)
01139         {
01140             // test markers of graphs
01141             foreach(Marker *pm, pg->Markers)
01142             {
01143                 if(pm->getSelected(x-pd->cx, y-pd->cy))
01144                 {
01145                     if(flag)
01146                     {
01147                         // The element can be deselected
01148                         pm->isSelected ^= flag;
01149                         return pm;
01150                     }
01151                     if(pe_sel)
01152                     {
01153                         pe_sel->isSelected = false;
01154                         return pm;
01155                     }
01156                     if(pe_1st == 0)
01157                     {
01158                         pe_1st = pm;   // give access to elements beneath
01159                     }
01160                     if(pm->isSelected)
01161                     {
01162                         pe_sel = pm;
01163                     }
01164                 }
01165             }
01166         }
01167 
01168         // resize area clicked ?
01169         if(pd->isSelected)
01170         {
01171             if(pd->resizeTouched(fX, fY, Corr))
01172             {
01173                 if(pe_1st == 0)
01174                 {
01175                     pd->Type = isDiagramResize;
01176                     return pd;
01177                 }
01178             }
01179         }
01180 
01181         if(pd->getSelected(x, y))
01182         {
01183             if(pd->Name[0] == 'T')     // tabular, timing diagram or truth table ?
01184             {
01185                 if(pd->Name[1] == 'i')
01186                 {
01187                     if(y > pd->cy)
01188                     {
01189                         if(x < pd->cx+pd->xAxis.numGraphs) continue;
01190                         pd->Type = isDiagramHScroll;
01191                         return pd;
01192                     }
01193                 }
01194                 else
01195                 {
01196                     if(x < pd->cx)        // clicked on scroll bar ?
01197                     {
01198                         pd->Type = isDiagramVScroll;
01199                         return pd;
01200                     }
01201                 }
01202             }
01203 
01204             // test graphs of diagram
01205             foreach(Graph *pg, pd->Graphs)
01206             {
01207                 if(pg->getSelected(x-pd->cx, pd->cy-y) >= 0)
01208                 {
01209                     if(flag)
01210                     {
01211                         // The element can be deselected
01212                         pg->isSelected ^= flag;
01213                         return pg;
01214                     }
01215                     if(pe_sel)
01216                     {
01217                         pe_sel->isSelected = false;
01218                         return pg;
01219                     }
01220                     if(pe_1st == 0)
01221                     {
01222                         pe_1st = pg;   // access to elements lying beneath
01223                     }
01224                     if(pg->isSelected)
01225                     {
01226                         pe_sel = pg;
01227                     }
01228                 }
01229             }
01230 
01231             if(flag)
01232             {
01233                 // The element can be deselected
01234                 pd->isSelected ^= flag;
01235                 return pd;
01236             }
01237             if(pe_sel)
01238             {
01239                 pe_sel->isSelected = false;
01240                 return pd;
01241             }
01242             if(pe_1st == 0)
01243             {
01244                 pe_1st = pd;    // give access to elements lying beneath
01245             }
01246             if(pd->isSelected)
01247             {
01248                 pe_sel = pd;
01249             }
01250         }
01251     }
01252 
01253     // test all paintings
01254     for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev())
01255     {
01256         if(pp->isSelected)
01257         {
01258             if(pp->resizeTouched(fX, fY, Corr))
01259             {
01260                 if(pe_1st == 0)
01261                 {
01262                     pp->Type = isPaintingResize;
01263                     return pp;
01264                 }
01265             }
01266         }
01267 
01268         if(pp->getSelected(fX, fY, Corr))
01269         {
01270             if(flag)
01271             {
01272                 // The element can be deselected
01273                 pp->isSelected ^= flag;
01274                 return pp;
01275             }
01276             if(pe_sel)
01277             {
01278                 pe_sel->isSelected = false;
01279                 return pp;
01280             }
01281             if(pe_1st == 0)
01282             {
01283                 pe_1st = pp;    // give access to elements lying beneath
01284             }
01285             if(pp->isSelected)
01286             {
01287                 pe_sel = pp;
01288             }
01289         }
01290     }
01291 
01292     return pe_1st;
01293 }
01294 
01295 void Schematic::highlightWireLabels ()
01296 {
01297     WireLabel *pltestinner = 0;
01298     WireLabel *pltestouter = 0;
01299 
01300     // First set highlighting for all wire labels to false
01301     for(Wire *pwouter = Wires->last(); pwouter != 0; pwouter = Wires->prev())
01302     {
01303         pltestouter = pwouter->Label; // test any label associated with the wire
01304         if (pltestouter)
01305         {
01306             pltestouter->setHighlighted (false);
01307         }
01308     }
01309 
01310     // Then test every wire's label to see if we need to highlight it
01311     // and matching labels
01312     for(Wire *pwouter = Wires->last(); pwouter != 0; pwouter = Wires->prev())
01313     {
01314         // get any label associated with the wire
01315         pltestouter = pwouter->Label;
01316         if (pltestouter)
01317         {
01318             if (pltestouter->isSelected)
01319             {
01320                 // Search for matching labels
01321                 for(Wire *pwinner = Wires->last(); pwinner != 0; pwinner = Wires->prev())
01322                 {
01323                     pltestinner = pwinner->Label; // test any label associated with the wire
01324                     if (pltestinner)
01325                     {
01326                         // Highlight the label if it has the same name as the selected label
01327                         if (strcmp(pltestouter->Name, pltestinner->Name) == 0)
01328                         {
01329                             pltestinner->setHighlighted (true);
01330                         }
01331                     }
01332                 }
01333             }
01334         }
01335     }
01336 }
01337 
01338 // ---------------------------------------------------
01339 // Deselects all elements except 'e'.
01340 void Schematic::deselectElements(Element *e)
01341 {
01342     // test all components
01343     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
01344         if(e != pc)  pc->isSelected = false;
01345 
01346     // test all wires
01347     for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next())
01348     {
01349         if(e != pw)  pw->isSelected = false;
01350         if(pw->Label) if(pw->Label != e)  pw->Label->isSelected = false;
01351     }
01352 
01353     // test all node labels
01354     for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
01355         if(pn->Label) if(pn->Label != e)  pn->Label->isSelected = false;
01356 
01357     // test all diagrams
01358     for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
01359     {
01360         if(e != pd)  pd->isSelected = false;
01361 
01362         // test graphs of diagram
01363         foreach(Graph *pg, pd->Graphs)
01364         {
01365             if(e != pg) pg->isSelected = false;
01366 
01367             // test markers of graph
01368             foreach(Marker *pm, pg->Markers)
01369                 if(e != pm) pm->isSelected = false;
01370         }
01371 
01372     }
01373 
01374     // test all paintings
01375     for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next())
01376         if(e != pp)  pp->isSelected = false;
01377 }
01378 
01379 // ---------------------------------------------------
01380 // Selects elements that lie within the rectangle x1/y1, x2/y2.
01381 int Schematic::selectElements(int x1, int y1, int x2, int y2, bool flag)
01382 {
01383     int  z=0;   // counts selected elements
01384     int  cx1, cy1, cx2, cy2;
01385 
01386     // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2
01387     cx1 = (x1 < x2) ? x1 : x2;
01388     cx2 = (x1 > x2) ? x1 : x2;
01389     cy1 = (y1 < y2) ? y1 : y2;
01390     cy2 = (y1 > y2) ? y1 : y2;
01391     x1 = cx1;
01392     x2 = cx2;
01393     y1 = cy1;
01394     y2 = cy2;
01395 
01396     // test all components
01397     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
01398     {
01399         pc->Bounding(cx1, cy1, cx2, cy2);
01400         if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2)
01401                     {
01402                         pc->isSelected = true;
01403                         z++;
01404                         continue;
01405                     }
01406         if(pc->isSelected &= flag) z++;
01407     }
01408 
01409 
01410     Wire *pw;
01411     for(pw = Wires->first(); pw != 0; pw = Wires->next())   // test all wires
01412     {
01413         if(pw->x1 >= x1) if(pw->x2 <= x2) if(pw->y1 >= y1) if(pw->y2 <= y2)
01414                     {
01415                         pw->isSelected = true;
01416                         z++;
01417                         continue;
01418                     }
01419         if(pw->isSelected &= flag) z++;
01420     }
01421 
01422 
01423     // test all wire labels *********************************
01424     WireLabel *pl=0;
01425     for(pw = Wires->first(); pw != 0; pw = Wires->next())
01426     {
01427         if(pw->Label)
01428         {
01429             pl = pw->Label;
01430             if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2)
01431                     if(pl->y1 >= y1) if((pl->y1+pl->y2) <= y2)
01432                         {
01433                             pl->isSelected = true;
01434                             z++;
01435                             continue;
01436                         }
01437             if(pl->isSelected &= flag) z++;
01438         }
01439     }
01440 
01441 
01442     // test all node labels *************************************
01443     for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
01444     {
01445         pl = pn->Label;
01446         if(pl)
01447         {
01448             if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2)
01449                     if((pl->y1-pl->y2) >= y1) if(pl->y1 <= y2)
01450                         {
01451                             pl->isSelected = true;
01452                             z++;
01453                             continue;
01454                         }
01455             if(pl->isSelected &= flag) z++;
01456         }
01457     }
01458 
01459 
01460     // test all diagrams *******************************************
01461     for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
01462     {
01463         // test graphs of diagram
01464         foreach(Graph *pg, pd->Graphs)
01465         {
01466             if(pg->isSelected &= flag) z++;
01467 
01468             // test markers of graph
01469             foreach(Marker *pm, pg->Markers)
01470             {
01471                 pm->Bounding(cx1, cy1, cx2, cy2);
01472                 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2)
01473                             {
01474                                 pm->isSelected = true;
01475                                 z++;
01476                                 continue;
01477                             }
01478                 if(pm->isSelected &= flag) z++;
01479             }
01480         }
01481 
01482         // test diagram itself
01483         pd->Bounding(cx1, cy1, cx2, cy2);
01484         if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2)
01485                     {
01486                         pd->isSelected = true;
01487                         z++;
01488                         continue;
01489                     }
01490         if(pd->isSelected &= flag) z++;
01491     }
01492 
01493     // test all paintings *******************************************
01494     for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next())
01495     {
01496         pp->Bounding(cx1, cy1, cx2, cy2);
01497         if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2)
01498                     {
01499                         pp->isSelected = true;
01500                         z++;
01501                         continue;
01502                     }
01503         if(pp->isSelected &= flag) z++;
01504     }
01505 
01506     return z;
01507 }
01508 
01509 // ---------------------------------------------------
01510 // Selects all markers.
01511 void Schematic::selectMarkers()
01512 {
01513     for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
01514         foreach(Graph *pg, pd->Graphs)
01515             foreach(Marker *pm, pg->Markers)
01516                 pm->isSelected = true;
01517 }
01518 
01519 // ---------------------------------------------------
01520 // For moving elements: If the moving element is connected to a not
01521 // moving element, insert two wires. If the connected element is already
01522 // a wire, use this wire. Otherwise create new wire.
01523 void Schematic::newMovingWires(Q3PtrList<Element> *p, Node *pn, int pos)
01524 {
01525     Element *pe;
01526 
01527     if(pn->State & 8)  // Were new wires already inserted ?
01528         return;
01529     pn->State |= 8;
01530 
01531     for (;;)
01532     {
01533         if(pn->State & 16)  // node was already worked on
01534             break;
01535 
01536         pe = pn->Connections.getFirst();
01537         if(pe == 0)  return;
01538 
01539         if(pn->Connections.count() > 1)
01540             break;
01541         if(pe->Type != isWire)  // is it connected to exactly one wire ?
01542             break;
01543 
01544         // .................................................
01545         long  mask = 1, invMask = 3;
01546         Wire *pw2=0, *pw = (Wire*)pe;
01547 
01548         Node *pn2 = pw->Port1;
01549         if(pn2 == pn) pn2 = pw->Port2;
01550 
01551         if(pn2->Connections.count() == 2) // two existing wires connected ?
01552             if((pn2->State & (8+4)) == 0)
01553             {
01554                 Element *pe2 = pn2->Connections.getFirst();
01555                 if(pe2 == pe) pe2 = pn2->Connections.getLast();
01556                 // connected wire connected to exactly one wire ?
01557                 if(pe2->Type == isWire)
01558                     pw2  = (Wire*)pe2;
01559             }
01560 
01561         // .................................................
01562         // reuse one wire
01563         p->insert(pos, pw);
01564         pw->Port1->Connections.removeRef(pw);   // remove connection 1
01565         pw->Port1->State |= 16+4;
01566         pw->Port2->Connections.removeRef(pw);   // remove connection 2
01567         pw->Port2->State |= 16+4;
01568         Wires->take(Wires->findRef(pw));
01569 
01570         if(pw->isHorizontal()) mask = 2;
01571 
01572         if(pw2 == 0)    // place new wire between component and old wire
01573         {
01574             pn = pn2;
01575             mask ^= 3;
01576             invMask = 0;
01577         }
01578 
01579         if(pw->Port1 != pn)
01580         {
01581             pw->Port1->State |= mask;
01582             pw->Port1 = (Node*)mask;
01583             pw->Port2->State |= invMask;
01584             pw->Port2 = (Node*)invMask;  // move port 2 completely
01585         }
01586         else
01587         {
01588             pw->Port1->State |= invMask;
01589             pw->Port1 = (Node*)invMask;
01590             pw->Port2->State |= mask;
01591             pw->Port2 = (Node*)mask;
01592         }
01593 
01594         invMask ^= 3;
01595         // .................................................
01596         // create new wire ?
01597         if(pw2 == 0)
01598         {
01599             if(pw->Port1 != (Node*)mask)
01600                 p->insert(pos,
01601                           new Wire(pw->x2, pw->y2, pw->x2, pw->y2, (Node*)mask, (Node*)invMask));
01602             else
01603                 p->insert(pos,
01604                           new Wire(pw->x1, pw->y1, pw->x1, pw->y1, (Node*)mask, (Node*)invMask));
01605             return;
01606         }
01607 
01608 
01609         // .................................................
01610         // reuse a second wire
01611         p->insert(pos, pw2);
01612         pw2->Port1->Connections.removeRef(pw2);   // remove connection 1
01613         pw2->Port1->State |= 16+4;
01614         pw2->Port2->Connections.removeRef(pw2);   // remove connection 2
01615         pw2->Port2->State |= 16+4;
01616         Wires->take(Wires->findRef(pw2));
01617 
01618         if(pw2->Port1 != pn2)
01619         {
01620             pw2->Port1 = (Node*)0;
01621             pw2->Port2->State |= mask;
01622             pw2->Port2 = (Node*)mask;
01623         }
01624         else
01625         {
01626             pw2->Port1->State |= mask;
01627             pw2->Port1 = (Node*)mask;
01628             pw2->Port2 = (Node*)0;
01629         }
01630         return;
01631     }
01632 
01633     // only x2 moving
01634     p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)0, (Node*)1));
01635     // x1, x2, y2 moving
01636     p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)1, (Node*)3));
01637 }
01638 
01639 // ---------------------------------------------------
01640 // For moving of elements: Copies all selected elements into the
01641 // list 'p' and deletes them from the document.
01642 // BUG: does not (only) copy, as the name suggests.
01643 //      cannot be used to make copies.
01644 // returns the number of "copied" _Markers_ only
01645 int Schematic::copySelectedElements(Q3PtrList<Element> *p)
01646 {
01647     int i, count = 0;
01648     Component *pc;
01649     Wire      *pw;
01650     Diagram   *pd;
01651     Element   *pe;
01652     Node      *pn;
01653 
01654 
01655     // test all components *********************************
01656     // Insert components before wires in order to prevent short-cut removal.
01657     for(pc = Components->first(); pc != 0; )
01658         if(pc->isSelected)
01659         {
01660             p->append(pc);
01661             count++;
01662 
01663             // delete all port connections
01664             foreach(Port *pp, pc->Ports)
01665             {
01666                 pp->Connection->Connections.removeRef((Element*)pc);
01667                 pp->Connection->State = 4;
01668             }
01669 
01670             Components->take();   // take component out of the document
01671             pc = Components->current();
01672         }
01673         else pc = Components->next();
01674 
01675     // test all wires and wire labels ***********************
01676     for(pw = Wires->first(); pw != 0; )
01677     {
01678         if(pw->Label) if(pw->Label->isSelected)
01679                 p->append(pw->Label);
01680 
01681         if(pw->isSelected)
01682         {
01683             p->append(pw);
01684 
01685             pw->Port1->Connections.removeRef(pw);   // remove connection 1
01686             pw->Port1->State = 4;
01687             pw->Port2->Connections.removeRef(pw);   // remove connection 2
01688             pw->Port2->State = 4;
01689             Wires->take();
01690             pw = Wires->current();
01691         }
01692         else pw = Wires->next();
01693     }
01694 
01695     // ..............................................
01696     // Inserts wires, if a connection to a not moving element is found.
01697     // The order of the "for"-loops is important to guarantee a stable
01698     // operation: components, new wires, old wires
01699     pc = (Component*)p->first();
01700     for(i=0; i<count; i++)
01701     {
01702         foreach(Port *pp, pc->Ports)
01703             newMovingWires(p, pp->Connection, count);
01704 
01705         p->findRef(pc);   // back to the real current pointer
01706         pc = (Component*)p->next();
01707     }
01708 
01709     for(pe = (Element*)pc; pe != 0; pe = p->next())  // new wires
01710         if(pe->isSelected)
01711             break;
01712 
01713     for(pw = (Wire*)pe; pw != 0; pw = (Wire*)p->next())
01714         if(pw->Type == isWire)    // not working on labels
01715         {
01716             newMovingWires(p, pw->Port1, count);
01717             newMovingWires(p, pw->Port2, count);
01718             p->findRef(pw);   // back to the real current pointer
01719         }
01720 
01721 
01722     // ..............................................
01723     // delete the unused nodes
01724     for(pn = Nodes->first(); pn!=0; )
01725     {
01726         if(pn->State & 8)
01727             if(pn->Connections.count() == 2)
01728                 if(oneTwoWires(pn))    // if possible, connect two wires to one
01729                 {
01730                     pn = Nodes->current();
01731                     continue;
01732                 }
01733 
01734         if(pn->Connections.count() == 0)
01735         {
01736             if(pn->Label)
01737             {
01738                 pn->Label->Type = isMovingLabel;
01739                 if(pn->State & 1)
01740                 {
01741                     if(!(pn->State & 2)) pn->Label->Type = isHMovingLabel;
01742                 }
01743                 else if(pn->State & 2) pn->Label->Type = isVMovingLabel;
01744                 p->append(pn->Label);    // do not forget the node labels
01745             }
01746             Nodes->remove();
01747             pn = Nodes->current();
01748             continue;
01749         }
01750 
01751         pn->State = 0;
01752         pn = Nodes->next();
01753     }
01754 
01755     // test all node labels
01756     // do this last to avoid double copying
01757     for(pn = Nodes->first(); pn != 0; pn = Nodes->next())
01758         if(pn->Label) if(pn->Label->isSelected)
01759                 p->append(pn->Label);
01760 
01761 
01762     // test all paintings **********************************
01763     for(Painting *ppa = Paintings->first(); ppa != 0; )
01764         if(ppa->isSelected)
01765         {
01766             p->append(ppa);
01767             Paintings->take();
01768             ppa = Paintings->current();
01769         }
01770         else ppa = Paintings->next();
01771 
01772     count = 0;  // count markers now
01773     // test all diagrams **********************************
01774     for(pd = Diagrams->first(); pd != 0; )
01775         if(pd->isSelected)
01776         {
01777             p->append(pd);
01778             Diagrams->take();
01779             pd = Diagrams->current();
01780         }
01781         else
01782         {
01783             foreach(Graph *pg, pd->Graphs)
01784             {
01785                 QMutableListIterator<Marker *> im(pg->Markers);
01786                 Marker *pm;
01787                 while (im.hasNext())
01788                 {
01789                     pm = im.next();
01790                     if(pm->isSelected)
01791                     {
01792                         count++;
01793                         p->append(pm);
01794                     }
01795                 }
01796             }
01797 
01798             pd = Diagrams->next();
01799         }
01800 
01801     return count;
01802 }
01803 
01804 // ---------------------------------------------------
01805 bool Schematic::copyComps2WiresPaints(int& x1, int& y1, int& x2, int& y2,
01806                                       QList<Element *> *ElementCache)
01807 {
01808     x1=INT_MAX;
01809     y1=INT_MAX;
01810     x2=INT_MIN;
01811     y2=INT_MIN;
01812     copyLabels(x1, y1, x2, y2, ElementCache);   // must be first of all !
01813     copyComponents2(x1, y1, x2, y2, ElementCache);
01814     copyWires(x1, y1, x2, y2, ElementCache);
01815     copyPaintings(x1, y1, x2, y2, ElementCache);
01816 
01817     if(y1 == INT_MAX) return false;  // no element selected
01818     return true;
01819 }
01820 
01821 // ---------------------------------------------------
01822 // Used in "aligning()", "distributeHorizontal()", "distributeVertical()".
01823 int Schematic::copyElements(int& x1, int& y1, int& x2, int& y2,
01824                             QList<Element *> *ElementCache)
01825 {
01826     int bx1, by1, bx2, by2;
01827     Wires->setAutoDelete(false);
01828     Components->setAutoDelete(false);
01829 
01830     x1=INT_MAX;
01831     y1=INT_MAX;
01832     x2=INT_MIN;
01833     y2=INT_MIN;
01834     // take components and wires out of list, check their boundings
01835     int number = copyComponents(x1, y1, x2, y2, ElementCache);
01836     number += copyWires(x1, y1, x2, y2, ElementCache);
01837 
01838     Wires->setAutoDelete(true);
01839     Components->setAutoDelete(true);
01840 
01841     // find upper most selected diagram
01842     for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev())
01843         if(pd->isSelected)
01844         {
01845             pd->Bounding(bx1, by1, bx2, by2);
01846             if(bx1 < x1) x1 = bx1;
01847             if(bx2 > x2) x2 = bx2;
01848             if(by1 < y1) y1 = by1;
01849             if(by2 > y2) y2 = by2;
01850             ElementCache->append(pd);
01851             number++;
01852         }
01853     // find upper most selected painting
01854     for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev())
01855         if(pp->isSelected)
01856         {
01857             pp->Bounding(bx1, by1, bx2, by2);
01858             if(bx1 < x1) x1 = bx1;
01859             if(bx2 > x2) x2 = bx2;
01860             if(by1 < y1) y1 = by1;
01861             if(by2 > y2) y2 = by2;
01862             ElementCache->append(pp);
01863             number++;
01864         }
01865 
01866     return number;
01867 }
01868 
01869 // ---------------------------------------------------
01870 // Deletes all selected elements.
01871 bool Schematic::deleteElements()
01872 {
01873     bool sel = false;
01874 
01875     Component *pc = Components->first();
01876     while(pc != 0)      // all selected component
01877         if(pc->isSelected)
01878         {
01879             deleteComp(pc);
01880             pc = Components->current();
01881             sel = true;
01882         }
01883         else pc = Components->next();
01884 
01885     Wire *pw = Wires->first();
01886     while(pw != 0)        // all selected wires and their labels
01887     {
01888         if(pw->Label)
01889             if(pw->Label->isSelected)
01890             {
01891                 delete pw->Label;
01892                 pw->Label = 0;
01893                 sel = true;
01894             }
01895 
01896         if(pw->isSelected)
01897         {
01898             deleteWire(pw);
01899             pw = Wires->current();
01900             sel = true;
01901         }
01902         else pw = Wires->next();
01903     }
01904 
01905     // all selected labels on nodes ***************************
01906     for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
01907         if(pn->Label)
01908             if(pn->Label->isSelected)
01909             {
01910                 delete pn->Label;
01911                 pn->Label = 0;
01912                 sel = true;
01913             }
01914 
01915     Diagram *pd = Diagrams->first();
01916     while(pd != 0)      // test all diagrams
01917         if(pd->isSelected)
01918         {
01919             Diagrams->remove();
01920             pd = Diagrams->current();
01921             sel = true;
01922         }
01923         else
01924         {
01925             bool wasGraphDeleted = false;
01926             // all graphs of diagram
01927 
01928             QMutableListIterator<Graph *> ig(pd->Graphs);
01929             Graph *pg;
01930 
01931             while (ig.hasNext())
01932             {
01933                 pg = ig.next();
01934                 // all markers of diagram
01935                 QMutableListIterator<Marker *> im(pg->Markers);
01936                 Marker *pm;
01937                 while (im.hasNext())
01938                 {
01939                     pm = im.next();
01940                     if(pm->isSelected)
01941                     {
01942                         im.remove();
01943                         sel = true;
01944                     }
01945                 }
01946 
01947                 if(pg->isSelected)
01948                 {
01949                     ig.remove();
01950                     sel = wasGraphDeleted = true;
01951                 }
01952             }
01953             if(wasGraphDeleted)
01954                 pd->recalcGraphData();  // update diagram (resize etc.)
01955 
01956             pd = Diagrams->next();
01957         } //else
01958 
01959 
01960     Painting *pp = Paintings->first();
01961     while(pp != 0)      // test all paintings
01962     {
01963         if(pp->isSelected)
01964             if(pp->Name.at(0) != '.')    // do not delete "PortSym", "ID_text"
01965             {
01966                 sel = true;
01967                 Paintings->remove();
01968                 pp = Paintings->current();
01969                 continue;
01970             }
01971         pp = Paintings->next();
01972     }
01973 
01974     if(sel)
01975     {
01976         sizeOfAll(UsedX1, UsedY1, UsedX2, UsedY2);   // set new document size
01977         setChanged(sel, true);
01978     }
01979     return sel;
01980 }
01981 
01982 // ---------------------------------------------------
01988 bool Schematic::aligning(int Mode)
01989 {
01990     int x1, y1, x2, y2;
01991     int bx1, by1, bx2, by2, *bx=0, *by=0, *ax=0, *ay=0;
01992     QList<Element *> ElementCache;
01993     int count = copyElements(x1, y1, x2, y2, &ElementCache);
01994     if(count < 1) return false;
01995 
01996 
01997     ax = ay = &x2;  // = 0
01998     switch(Mode)
01999     {
02000     case 0:  // align top
02001         bx = &x1;
02002         by = &by1;
02003         y2 = 1;
02004         break;
02005     case 1:  // align bottom
02006         bx = &x1;
02007         y1 = y2;
02008         by = &by2;
02009         y2 = 1;
02010         break;
02011     case 2:  // align left
02012         by = &y1;
02013         bx = &bx1;
02014         y2 = 1;
02015         break;
02016     case 3:  // align right
02017         by = &y1;
02018         x1 = x2;
02019         bx = &bx2;
02020         y2 = 1;
02021         break;
02022     case 4:  // center horizontally
02023         x1 = (x2+x1) / 2;
02024         by = &x2;  // = 0
02025         ax = &bx1;
02026         bx = &bx2;
02027         y1 = 0;
02028         y2 = 2;
02029         break;
02030     case 5:  // center vertically
02031         y1 = (y2+y1) / 2;
02032         bx = &x2;  // = 0
02033         ay = &by1;
02034         by = &by2;
02035         x1 = 0;
02036         y2 = 2;
02037         break;
02038     }
02039     x2 = 0;
02040 
02041     Wire      *pw;
02042     Component *pc;
02043     Element   *pe;
02044     // re-insert elements
02045     // Go backwards in order to insert node labels before its component.
02046     QListIterator<Element *> elementCacheIter(ElementCache);
02047     elementCacheIter.toBack();
02048     while (elementCacheIter.hasPrevious()) {
02049         pe = elementCacheIter.previous();
02050         switch(pe->Type)
02051         {
02052         case isComponent:
02053         case isAnalogComponent:
02054         case isDigitalComponent:
02055             pc = (Component*)pe;
02056             pc->Bounding(bx1, by1, bx2, by2);
02057             pc->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
02058             insertRawComponent(pc);
02059             break;
02060 
02061         case isWire:
02062             pw = (Wire*)pe;
02063             bx1 = pw->x1;
02064             by1 = pw->y1;
02065             bx2 = pw->x2;
02066             by2 = pw->y2;
02067             pw->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
02068 //        if(pw->Label) {  }
02069             insertWire(pw);
02070             break;
02071 
02072         case isDiagram:
02073             // Should the axis label be counted for ? I guess everyone
02074             // has a different opinion.
02075 //        ((Diagram*)pe)->Bounding(bx1, by1, bx2, by2);
02076 
02077             // Take size without axis label.
02078             bx1 = ((Diagram*)pe)->cx;
02079             by2 = ((Diagram*)pe)->cy;
02080             bx2 = bx1 + ((Diagram*)pe)->x2;
02081             by1 = by2 - ((Diagram*)pe)->y2;
02082             ((Diagram*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
02083             break;
02084 
02085         case isPainting:
02086             ((Painting*)pe)->Bounding(bx1, by1, bx2, by2);
02087             ((Painting*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
02088             break;
02089 
02090         case isNodeLabel:
02091             if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent)
02092             {
02093                 pc = (Component*)(((WireLabel*)pe)->pOwner);
02094                 pc->Bounding(bx1, by1, bx2, by2);
02095             }
02096             else
02097             {
02098                 pw = (Wire*)(((WireLabel*)pe)->pOwner);
02099                 bx1 = pw->x1;
02100                 by1 = pw->y1;
02101                 bx2 = pw->x2;
02102                 by2 = pw->y2;
02103             }
02104             ((WireLabel*)pe)->cx += x1-((*bx)+(*ax))/y2;
02105             ((WireLabel*)pe)->cy += y1-((*by)+(*ay))/y2;
02106             insertNodeLabel((WireLabel*)pe);
02107             break;
02108 
02109         default:
02110             ;
02111         }
02112     }
02113 
02114     ElementCache.clear();
02115     if(count < 2) return false;
02116 
02117     setChanged(true, true);
02118     return true;
02119 }
02120 
02125 bool Schematic::distributeHorizontal()
02126 {
02127     int x1, y1, x2, y2;
02128     int bx1, by1, bx2, by2;
02129     QList<Element *> ElementCache;
02130     int count = copyElements(x1, y1, x2, y2, &ElementCache);
02131     if(count < 1) return false;
02132 
02133     Element *pe;
02134     WireLabel *pl;
02135     // Node labels are not counted for, so put them to the end.
02136     /*  for(pe = ElementCache.last(); pe != 0; pe = ElementCache.prev())
02137         if(pe->Type == isNodeLabel) {
02138           ElementCache.append(pe);
02139           ElementCache.removeRef(pe);
02140         }*/
02141 
02142     // using bubble sort to get elements x ordered
02143     QListIterator<Element *> elementCacheIter(ElementCache);
02144     if(count > 1)
02145         for(int i = count-1; i>0; i--)
02146         {
02147             pe = ElementCache.first();
02148             for(int j=0; j<i; j++)
02149             {
02150                 pe->getCenter(bx1, by1);
02151                 pe=elementCacheIter.peekNext();
02152                 pe->getCenter(bx2, by2);
02153                 if(bx1 > bx2)    // change two elements ?
02154                 {
02155                     ElementCache.replace(j+1, elementCacheIter.peekPrevious());
02156                     ElementCache.replace(j, pe);
02157                     pe = elementCacheIter.next();
02158                 }
02159             }
02160         }
02161 
02162     ElementCache.last()->getCenter(x2, y2);
02163     ElementCache.first()->getCenter(x1, y1);
02164     Wire *pw;
02165     int x = x2;
02166     int dx=0;
02167     if(count > 1) dx = (x2-x1)/(count-1);
02168     // re-insert elements and put them at right position
02169     // Go backwards in order to insert node labels before its component.
02170     elementCacheIter.toBack();
02171     while (elementCacheIter.hasPrevious())
02172     {
02173         pe = elementCacheIter.previous();
02174         switch(pe->Type)
02175         {
02176         case isComponent:
02177         case isAnalogComponent:
02178         case isDigitalComponent:
02179             pe->cx = x;
02180             insertRawComponent((Component*)pe);
02181             break;
02182 
02183         case isWire:
02184             pw = (Wire*)pe;
02185             if(pw->isHorizontal())
02186             {
02187                 x1 = pw->x2 - pw->x1;
02188                 pw->x1 = x - (x1 >> 1);
02189                 pw->x2 = pw->x1 + x1;
02190             }
02191             else  pw->x1 = pw->x2 = x;
02192 //        if(pw->Label) { }
02193             insertWire(pw);
02194             break;
02195 
02196         case isDiagram:
02197             pe->cx = x - (pe->x2 >> 1);
02198             break;
02199 
02200         case isPainting:
02201             pe->getCenter(bx1, by1);
02202             pe->setCenter(x, by1, false);
02203             break;
02204 
02205         case isNodeLabel:
02206             pl = (WireLabel*)pe;
02207             if(((Element*)(pl->pOwner))->Type & isComponent)
02208                 pe->cx += x - ((Component*)(pl->pOwner))->cx;
02209             else
02210             {
02211                 pw = (Wire*)(pl->pOwner);
02212                 if(pw->isHorizontal())
02213                 {
02214                     x1 = pw->x2 - pw->x1;
02215                     pe->cx += x - (x1 >> 1) - pw->x1;
02216                 }
02217                 else  pe->cx += x - pw->x1;
02218             }
02219             insertNodeLabel(pl);
02220             x += dx;
02221             break;
02222 
02223         default:
02224             ;
02225         }
02226         x -= dx;
02227     }
02228 
02229     ElementCache.clear();
02230     if(count < 2) return false;
02231 
02232     setChanged(true, true);
02233     return true;
02234 }
02235 
02240 bool Schematic::distributeVertical()
02241 {
02242     int x1, y1, x2, y2;
02243     int bx1, by1, bx2, by2;
02244     QList<Element *> ElementCache;
02245     int count = copyElements(x1, y1, x2, y2, &ElementCache);
02246     if(count < 1) return false;
02247 
02248     // using bubble sort to get elements y ordered
02249     QListIterator<Element *> elementCacheIter(ElementCache);
02250     Element *pe;
02251     if(count > 1)
02252         for(int i = count-1; i>0; i--)
02253         {
02254             pe = ElementCache.first();
02255             for(int j=0; j<i; j++)
02256             {
02257                 pe->getCenter(bx1, by1);
02258                 pe = elementCacheIter.peekNext();
02259                 pe->getCenter(bx2, by2);
02260                 if(by1 > by2)    // change two elements ?
02261                 {
02262                     ElementCache.replace(j+1, elementCacheIter.peekPrevious());
02263                     ElementCache.replace(j, pe);
02264                     pe = elementCacheIter.next();
02265                 }
02266             }
02267         }
02268 
02269     ElementCache.last()->getCenter(x2, y2);
02270     ElementCache.first()->getCenter(x1, y1);
02271     Wire *pw;
02272     int y  = y2;
02273     int dy=0;
02274     if(count > 1) dy = (y2-y1)/(count-1);
02275     // re-insert elements and put them at right position
02276     // Go backwards in order to insert node labels before its component.
02277     elementCacheIter.toBack();
02278     while (elementCacheIter.hasPrevious())
02279     {
02280         pe = elementCacheIter.previous();
02281         switch(pe->Type)
02282         {
02283         case isComponent:
02284         case isAnalogComponent:
02285         case isDigitalComponent:
02286             pe->cy = y;
02287             insertRawComponent((Component*)pe);
02288             break;
02289 
02290         case isWire:
02291             pw = (Wire*)pe;
02292             if(pw->isHorizontal())  pw->y1 = pw->y2 = y;
02293             else
02294             {
02295                 y1 = pw->y2 - pw->y1;
02296                 pw->y1 = y - (y1 >> 1);
02297                 pw->y2 = pe->y1 + y1;
02298             }
02299 //        if(pw->Label) { }
02300             insertWire(pw);
02301             break;
02302 
02303         case isDiagram:
02304             pe->cy = y + (pe->y2 >> 1);
02305             break;
02306 
02307         case isPainting:
02308             pe->getCenter(bx1, by1);
02309             pe->setCenter(bx1, y, false);
02310             break;
02311 
02312         case isNodeLabel:
02313             if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent)
02314                 pe->cy += y - ((Component*)(((WireLabel*)pe)->pOwner))->cy;
02315             else
02316             {
02317                 pw = (Wire*)(((WireLabel*)pe)->pOwner);
02318                 if(!pw->isHorizontal())
02319                 {
02320                     y1 = pw->y2 - pw->y1;
02321                     pe->cy += y - (y1 >> 1) - pw->y1;
02322                 }
02323                 else  pe->cy += y - pw->y1;
02324             }
02325             insertNodeLabel((WireLabel*)pe);
02326             y += dy;
02327             break;
02328 
02329         default:
02330             ;
02331         }
02332         y -= dy;
02333     }
02334 
02335     ElementCache.clear();
02336     if(count < 2) return false;
02337 
02338     setChanged(true, true);
02339     return true;
02340 }
02341 
02342 
02343 /* *******************************************************************
02344    *****                                                         *****
02345    *****                Actions with components                  *****
02346    *****                                                         *****
02347    ******************************************************************* */
02348 
02349 // Finds the correct number for power sources, subcircuit ports and
02350 // digital sources and sets them accordingly.
02351 void Schematic::setComponentNumber(Component *c)
02352 {
02353     Property *pp = c->Props.getFirst();
02354     if(!pp) return;
02355     if(pp->Name != "Num") return;
02356 
02357     int n=1;
02358     QString s = pp->Value;
02359     QString cSign = c->Model;
02360     Component *pc;
02361     // First look, if the port number already exists.
02362     for(pc = Components->first(); pc != 0; pc = Components->next())
02363         if(pc->Model == cSign)
02364             if(pc->Props.getFirst()->Value == s) break;
02365     if(!pc) return;   // was port number not yet in use ?
02366 
02367     // Find the first free number.
02368     do
02369     {
02370         s  = QString::number(n);
02371         // look for existing ports and their numbers
02372         for(pc = Components->first(); pc != 0; pc = Components->next())
02373             if(pc->Model == cSign)
02374                 if(pc->Props.getFirst()->Value == s) break;
02375 
02376         n++;
02377     }
02378     while(pc);     // found not used component number
02379     pp->Value = s; // set new number
02380 }
02381 
02382 // ---------------------------------------------------
02383 void Schematic::insertComponentNodes(Component *c, bool noOptimize)
02384 {
02385     // simulation components do not have ports
02386     if (c->Ports.empty()) return;
02387 
02388     // connect every node of the component to corresponding schematic node
02389     foreach(Port *pp, c->Ports)
02390         pp->Connection = insertNode(pp->x+c->cx, pp->y+c->cy, c);
02391 
02392     if(noOptimize)  return;
02393 
02394     Node    *pn;
02395     Element *pe, *pe1;
02396     Q3PtrList<Element> *pL;
02397     // if component over wire then delete this wire
02398     QListIterator<Port *> iport(c->Ports);
02399     // omit the first element
02400     Port *pp = iport.next();
02401     while (iport.hasNext())
02402     {
02403         pp = iport.next();
02404         pn = pp->Connection;
02405         for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
02406             if(pe->Type == isWire)
02407             {
02408                 if(((Wire*)pe)->Port1 == pn)  pL = &(((Wire*)pe)->Port2->Connections);
02409                 else  pL = &(((Wire*)pe)->Port1->Connections);
02410 
02411                 for(pe1 = pL->first(); pe1!=0; pe1 = pL->next())
02412                     if(pe1 == c)
02413                     {
02414                         deleteWire((Wire*)pe);
02415                         break;
02416                     }
02417             }
02418     }
02419 }
02420 
02421 // ---------------------------------------------------
02422 // Used for example in moving components.
02423 void Schematic::insertRawComponent(Component *c, bool noOptimize)
02424 {
02425     // connect every node of component to corresponding schematic node
02426     insertComponentNodes(c, noOptimize);
02427     Components->append(c);
02428 
02429     // a ground symbol erases an existing label on the wire line
02430     if(c->Model == "GND")
02431     {
02432         c->Model = "x";    // prevent that this ground is found as label
02433         Element *pe = getWireLabel(c->Ports.first()->Connection);
02434         if(pe) if((pe->Type & isComponent) == 0)
02435             {
02436                 delete ((Conductor*)pe)->Label;
02437                 ((Conductor*)pe)->Label = 0;
02438             }
02439         c->Model = "GND";    // rebuild component model
02440     }
02441 }
02442 
02443 // ---------------------------------------------------
02444 void Schematic::recreateComponent(Component *Comp)
02445 {
02446 
02447     WireLabel **plMem=0, **pl;
02448     int PortCount = Comp->Ports.count();
02449 
02450     if(PortCount > 0)
02451     {
02452         // Save the labels whose node is not connected to somewhere else.
02453         // Otherwise the label would be deleted.
02454         pl = plMem = (WireLabel**)malloc(PortCount * sizeof(WireLabel*));
02455         foreach(Port *pp, Comp->Ports)
02456             if(pp->Connection->Connections.count() < 2)
02457             {
02458                 *(pl++) = pp->Connection->Label;
02459                 pp->Connection->Label = 0;
02460             }
02461             else  *(pl++) = 0;
02462     }
02463 
02464 
02465     int x = Comp->tx, y = Comp->ty;
02466     int x1 = Comp->x1, x2 = Comp->x2, y1 = Comp->y1, y2 = Comp->y2;
02467     QString tmp = Comp->Name;    // is sometimes changed by "recreate"
02468     Comp->recreate(this);   // to apply changes to the schematic symbol
02469     Comp->Name = tmp;
02470     if(x < x1)
02471         x += Comp->x1 - x1;
02472     else if(x > x2)
02473         x += Comp->x2 - x2;
02474     if(y < y1)
02475         y += Comp->y1 - y1;
02476     else if(y > y2)
02477         y += Comp->y2 - y2;
02478     Comp->tx = x;
02479     Comp->ty = y;
02480 
02481 
02482     if(PortCount > 0)
02483     {
02484         // restore node labels
02485         pl = plMem;
02486         foreach(Port *pp, Comp->Ports)
02487         {
02488             if(*pl != 0)
02489             {
02490                 (*pl)->cx = pp->Connection->cx;
02491                 (*pl)->cy = pp->Connection->cy;
02492                 placeNodeLabel(*pl);
02493             }
02494             pl++;
02495             if((--PortCount) < 1)  break;
02496         }
02497         for( ; PortCount > 0; PortCount--)
02498         {
02499             delete (*pl);  // delete not needed labels
02500             pl++;
02501         }
02502         free(plMem);
02503     }
02504 }
02505 
02506 // ---------------------------------------------------
02507 void Schematic::insertComponent(Component *c)
02508 {
02509     // connect every node of component to corresponding schematic node
02510     insertComponentNodes(c, false);
02511 
02512     bool ok;
02513     QString s;
02514     int  max=1, len = c->Name.length(), z;
02515     if(c->Name.isEmpty())
02516     {
02517         // a ground symbol erases an existing label on the wire line
02518         if(c->Model == "GND")
02519         {
02520             c->Model = "x";    // prevent that this ground is found as label
02521             Element *pe = getWireLabel(c->Ports.first()->Connection);
02522             if(pe) if((pe->Type & isComponent) == 0)
02523                 {
02524                     delete ((Conductor*)pe)->Label;
02525                     ((Conductor*)pe)->Label = 0;
02526                 }
02527             c->Model = "GND";    // rebuild component model
02528         }
02529     }
02530     else
02531     {
02532         // determines the name by looking for names with the same
02533         // prefix and increment the number
02534         for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02535             if(pc->Name.left(len) == c->Name)
02536             {
02537                 s = pc->Name.right(pc->Name.length()-len);
02538                 z = s.toInt(&ok);
02539                 if(ok) if(z >= max) max = z + 1;
02540             }
02541         c->Name += QString::number(max);  // create name with new number
02542     }
02543 
02544     setComponentNumber(c); // important for power sources and subcircuit ports
02545     Components->append(c);
02546 }
02547 
02548 // ---------------------------------------------------
02549 void Schematic::activateCompsWithinRect(int x1, int y1, int x2, int y2)
02550 {
02551     bool changed = false;
02552     int  cx1, cy1, cx2, cy2, a;
02553     // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2
02554     cx1 = (x1 < x2) ? x1 : x2;
02555     cx2 = (x1 > x2) ? x1 : x2;
02556     cy1 = (y1 < y2) ? y1 : y2;
02557     cy2 = (y1 > y2) ? y1 : y2;
02558     x1 = cx1;
02559     x2 = cx2;
02560     y1 = cy1;
02561     y2 = cy2;
02562 
02563 
02564     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02565     {
02566         pc->Bounding(cx1, cy1, cx2, cy2);
02567         if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2)
02568                     {
02569                         a = pc->isActive - 1;
02570 
02571                         if(pc->Ports.count() > 1)
02572                         {
02573                             if(a < 0)  a = 2;
02574                             pc->isActive = a;    // change "active status"
02575                         }
02576                         else
02577                         {
02578                             a &= 1;
02579                             pc->isActive = a;    // change "active status"
02580                             if(a == COMP_IS_ACTIVE)  // only for active (not shorten)
02581                                 if(pc->Model == "GND")  // if existing, delete label on wire line
02582                                     oneLabel(pc->Ports.first()->Connection);
02583                         }
02584                         changed = true;
02585                     }
02586     }
02587 
02588     if(changed)  setChanged(true, true);
02589 }
02590 
02591 // ---------------------------------------------------
02592 bool Schematic::activateSpecifiedComponent(int x, int y)
02593 {
02594     int x1, y1, x2, y2, a;
02595     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02596     {
02597         pc->Bounding(x1, y1, x2, y2);
02598         if(x >= x1) if(x <= x2) if(y >= y1) if(y <= y2)
02599                     {
02600                         a = pc->isActive - 1;
02601 
02602                         if(pc->Ports.count() > 1)
02603                         {
02604                             if(a < 0)  a = 2;
02605                             pc->isActive = a;    // change "active status"
02606                         }
02607                         else
02608                         {
02609                             a &= 1;
02610                             pc->isActive = a;    // change "active status"
02611                             if(a == COMP_IS_ACTIVE)  // only for active (not shorten)
02612                                 if(pc->Model == "GND")  // if existing, delete label on wire line
02613                                     oneLabel(pc->Ports.first()->Connection);
02614                         }
02615                         setChanged(true, true);
02616                         return true;
02617                     }
02618     }
02619     return false;
02620 }
02621 
02622 // ---------------------------------------------------
02623 bool Schematic::activateSelectedComponents()
02624 {
02625     int a;
02626     bool sel = false;
02627     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02628         if(pc->isSelected)
02629         {
02630             a = pc->isActive - 1;
02631 
02632             if(pc->Ports.count() > 1)
02633             {
02634                 if(a < 0)  a = 2;
02635                 pc->isActive = a;    // change "active status"
02636             }
02637             else
02638             {
02639                 a &= 1;
02640                 pc->isActive = a;    // change "active status"
02641                 if(a == COMP_IS_ACTIVE)  // only for active (not shorten)
02642                     if(pc->Model == "GND")  // if existing, delete label on wire line
02643                         oneLabel(pc->Ports.first()->Connection);
02644             }
02645             sel = true;
02646         }
02647 
02648     if(sel) setChanged(true, true);
02649     return sel;
02650 }
02651 
02652 // ---------------------------------------------------
02653 // Sets the component ports anew. Used after rotate, mirror etc.
02654 void Schematic::setCompPorts(Component *pc)
02655 {
02656     WireLabel *pl;
02657     Q3PtrList<WireLabel> LabelCache;
02658 
02659     foreach(Port *pp, pc->Ports)
02660     {
02661         pp->Connection->Connections.removeRef((Element*)pc);// delete connections
02662         switch(pp->Connection->Connections.count())
02663         {
02664         case 0:
02665             pl = pp->Connection->Label;
02666             if(pl)
02667             {
02668                 LabelCache.append(pl);
02669                 pl->cx = pp->x + pc->cx;
02670                 pl->cy = pp->y + pc->cy;
02671             }
02672             Nodes->removeRef(pp->Connection);
02673             break;
02674         case 2:
02675             oneTwoWires(pp->Connection); // try to connect two wires to one
02676         default:
02677             ;
02678         }
02679     }
02680 
02681     // Re-connect component node to schematic node. This must be done completely
02682     // after the first loop in order to avoid problems with node labels.
02683     foreach(Port *pp, pc->Ports)
02684         pp->Connection = insertNode(pp->x+pc->cx, pp->y+pc->cy, pc);
02685 
02686     for(pl = LabelCache.first(); pl != 0; pl = LabelCache.next())
02687         insertNodeLabel(pl);
02688 }
02689 
02690 // ---------------------------------------------------
02691 // Returns a pointer of the component on whose text x/y points.
02692 Component* Schematic::selectCompText(int x_, int y_, int& w, int& h)
02693 {
02694     int a, b, dx, dy;
02695     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02696     {
02697         a = pc->cx + pc->tx;
02698         if(x_ < a)  continue;
02699         b = pc->cy + pc->ty;
02700         if(y_ < b)  continue;
02701 
02702         pc->textSize(dx, dy);
02703         if(x_ > a+dx)  continue;
02704         if(y_ > b+dy)  continue;
02705 
02706         w = dx;
02707         h = dy;
02708         return pc;
02709     }
02710 
02711     return 0;
02712 }
02713 
02714 // ---------------------------------------------------
02715 Component* Schematic::searchSelSubcircuit()
02716 {
02717     Component *sub=0;
02718     // test all components
02719     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02720     {
02721         if(!pc->isSelected) continue;
02722         if(pc->Model != "Sub")
02723             if(pc->Model != "VHDL")
02724                 if(pc->Model != "Verilog") continue;
02725 
02726         if(sub != 0) return 0;    // more than one subcircuit selected
02727         sub = pc;
02728     }
02729     return sub;
02730 }
02731 
02732 // ---------------------------------------------------
02733 Component* Schematic::selectedComponent(int x, int y)
02734 {
02735     // test all components
02736     for(Component *pc = Components->first(); pc != 0; pc = Components->next())
02737         if(pc->getSelected(x, y))
02738             return pc;
02739 
02740     return 0;
02741 }
02742 
02743 // ---------------------------------------------------
02744 // Deletes the component 'c'.
02745 void Schematic::deleteComp(Component *c)
02746 {
02747     // delete all port connections
02748     foreach(Port *pn, c->Ports)
02749         switch(pn->Connection->Connections.count())
02750         {
02751         case 1  :
02752             if(pn->Connection->Label) delete pn->Connection->Label;
02753             Nodes->removeRef(pn->Connection);  // delete open nodes
02754             pn->Connection = 0;     //  (auto-delete)
02755             break;
02756         case 3  :
02757             pn->Connection->Connections.removeRef(c);// delete connection
02758             oneTwoWires(pn->Connection);  // two wires -> one wire
02759             break;
02760         default :
02761             pn->Connection->Connections.removeRef(c);// remove connection
02762             break;
02763         }
02764 
02765     Components->removeRef(c);   // delete component
02766 }
02767 
02768 // ---------------------------------------------------
02769 int Schematic::copyComponents(int& x1, int& y1, int& x2, int& y2,
02770                               QList<Element *> *ElementCache)
02771 {
02772     Component *pc;
02773     int bx1, by1, bx2, by2, count=0;
02774     // find bounds of all selected components
02775     for(pc = Components->first(); pc != 0; )
02776     {
02777         if(pc->isSelected)
02778         {
02779             pc->Bounding(bx1, by1, bx2, by2);  // is needed because of "distribute
02780             if(bx1 < x1) x1 = bx1;             // uniformly"
02781             if(bx2 > x2) x2 = bx2;
02782             if(by1 < y1) y1 = by1;
02783             if(by2 > y2) y2 = by2;
02784 
02785             count++;
02786             ElementCache->append(pc);
02787 
02788             // rescue non-selected node labels
02789             foreach(Port *pp, pc->Ports)
02790                 if(pp->Connection->Label)
02791                     if(pp->Connection->Connections.count() < 2)
02792                     {
02793                         ElementCache->append(pp->Connection->Label);
02794 
02795                         // Don't set pp->Connection->Label->pOwner=0,
02796                         // so text position stays unchanged, but
02797                         // remember component for align/distribute.
02798                         pp->Connection->Label->pOwner = (Node*)pc;
02799 
02800                         pp->Connection->Label = 0;
02801                     }
02802 
02803             deleteComp(pc);
02804             pc = Components->current();
02805             continue;
02806         }
02807         pc = Components->next();
02808     }
02809     return count;
02810 }
02811 
02812 // ---------------------------------------------------
02813 void Schematic::copyComponents2(int& x1, int& y1, int& x2, int& y2,
02814                                 QList<Element *> *ElementCache)
02815 {
02816     Component *pc;
02817     // find bounds of all selected components
02818     for(pc = Components->first(); pc != 0; )
02819     {
02820         if(pc->isSelected)
02821         {
02822             // is better for unsymmetrical components
02823             if(pc->cx < x1)  x1 = pc->cx;
02824             if(pc->cx > x2)  x2 = pc->cx;
02825             if(pc->cy < y1)  y1 = pc->cy;
02826             if(pc->cy > y2)  y2 = pc->cy;
02827 
02828             ElementCache->append(pc);
02829 
02830             // rescue non-selected node labels
02831             foreach(Port *pp, pc->Ports)
02832                 if(pp->Connection->Label)
02833                     if(pp->Connection->Connections.count() < 2)
02834                     {
02835                         ElementCache->append(pp->Connection->Label);
02836                         pp->Connection->Label = 0;
02837                         // Don't set pp->Connection->Label->pOwner=0,
02838                         // so text position stays unchanged.
02839                     }
02840 
02841             deleteComp(pc);
02842             pc = Components->current();
02843             continue;
02844         }
02845         pc = Components->next();
02846     }
02847 }
02848 
02849 
02850 /* *******************************************************************
02851    *****                                                         *****
02852    *****                  Actions with labels                    *****
02853    *****                                                         *****
02854    ******************************************************************* */
02855 
02856 // Test, if wire connects wire line with more than one label and delete
02857 // all further labels. Also delete all labels if wire line is grounded.
02858 void Schematic::oneLabel(Node *n1)
02859 {
02860     Wire *pw;
02861     Node *pn, *pNode;
02862     Element *pe;
02863     WireLabel *pl = 0;
02864     bool named=false;   // wire line already named ?
02865     Q3PtrList<Node> Cons;
02866 
02867     for(pn = Nodes->first(); pn!=0; pn = Nodes->next())
02868         pn->y1 = 0;   // mark all nodes as not checked
02869 
02870     Cons.append(n1);
02871     n1->y1 = 1;  // mark Node as already checked
02872     for(pn = Cons.first(); pn!=0; pn = Cons.next())
02873     {
02874         if(pn->Label)
02875         {
02876             if(named)
02877             {
02878                 delete pn->Label;
02879                 pn->Label = 0;    // erase double names
02880             }
02881             else
02882             {
02883                 named = true;
02884                 pl = pn->Label;
02885             }
02886         }
02887 
02888         for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
02889         {
02890             if(pe->Type != isWire)
02891             {
02892                 if(((Component*)pe)->isActive == COMP_IS_ACTIVE)
02893                     if(((Component*)pe)->Model == "GND")
02894                     {
02895                         named = true;
02896                         if(pl)
02897                         {
02898                             pl->pOwner->Label = 0;
02899                             delete pl;
02900                         }
02901                         pl = 0;
02902                     }
02903                 continue;
02904             }
02905             pw = (Wire*)pe;
02906 
02907             if(pn != pw->Port1) pNode = pw->Port1;
02908             else pNode = pw->Port2;
02909 
02910             if(pNode->y1) continue;
02911             pNode->y1 = 1;  // mark Node as already checked
02912             Cons.append(pNode);
02913             Cons.findRef(pn);
02914 
02915             if(pw->Label)
02916             {
02917                 if(named)
02918                 {
02919                     delete pw->Label;
02920                     pw->Label = 0;    // erase double names
02921                 }
02922                 else
02923                 {
02924                     named = true;
02925                     pl = pw->Label;
02926                 }
02927             }
02928         }
02929     }
02930 }
02931 
02932 // ---------------------------------------------------
02933 int Schematic::placeNodeLabel(WireLabel *pl)
02934 {
02935     Node *pn;
02936     int x = pl->cx;
02937     int y = pl->cy;
02938 
02939     // check if new node lies upon an existing node
02940     for(pn = Nodes->first(); pn != 0; pn = Nodes->next())
02941         if(pn->cx == x) if(pn->cy == y) break;
02942 
02943     if(!pn)  return -1;
02944 
02945     Element *pe = getWireLabel(pn);
02946     if(pe)      // name found ?
02947     {
02948         if(pe->Type & isComponent)
02949         {
02950             delete pl;
02951             return -2;  // ground potential
02952         }
02953 
02954         delete ((Conductor*)pe)->Label;
02955         ((Conductor*)pe)->Label = 0;
02956     }
02957 
02958     pn->Label = pl;   // insert node label
02959     pl->Type = isNodeLabel;
02960     pl->pOwner = pn;
02961     return 0;
02962 }
02963 
02964 // ---------------------------------------------------
02965 // Test, if wire line is already labeled and returns a pointer to the
02966 // labeled element.
02967 Element* Schematic::getWireLabel(Node *pn_)
02968 {
02969     Wire *pw;
02970     Node *pn, *pNode;
02971     Element *pe;
02972     Q3PtrList<Node> Cons;
02973 
02974     for(pn = Nodes->first(); pn!=0; pn = Nodes->next())
02975         pn->y1 = 0;   // mark all nodes as not checked
02976 
02977     Cons.append(pn_);
02978     pn_->y1 = 1;  // mark Node as already checked
02979     for(pn = Cons.first(); pn!=0; pn = Cons.next())
02980         if(pn->Label) return pn;
02981         else
02982             for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
02983             {
02984                 if(pe->Type != isWire)
02985                 {
02986                     if(((Component*)pe)->isActive == COMP_IS_ACTIVE)
02987                         if(((Component*)pe)->Model == "GND") return pe;
02988                     continue;
02989                 }
02990 
02991                 pw = (Wire*)pe;
02992                 if(pw->Label) return pw;
02993 
02994                 if(pn != pw->Port1) pNode = pw->Port1;
02995                 else pNode = pw->Port2;
02996 
02997                 if(pNode->y1) continue;
02998                 pNode->y1 = 1;  // mark Node as already checked
02999                 Cons.append(pNode);
03000                 Cons.findRef(pn);
03001             }
03002     return 0;   // no wire label found
03003 }
03004 
03005 // ---------------------------------------------------
03006 // Inserts a node label.
03007 void Schematic::insertNodeLabel(WireLabel *pl)
03008 {
03009     if(placeNodeLabel(pl) != -1)
03010         return;
03011 
03012     // Go on, if label don't lie on existing node.
03013 
03014     Wire *pw = selectedWire(pl->cx, pl->cy);
03015     if(pw)    // lies label on existing wire ?
03016     {
03017         if(getWireLabel(pw->Port1) == 0)  // wire not yet labeled ?
03018             pw->setName(pl->Name, pl->initValue, 0, pl->cx, pl->cy);
03019 
03020         delete pl;
03021         return;
03022     }
03023 
03024 
03025     Node *pn = new Node(pl->cx, pl->cy);
03026     Nodes->append(pn);
03027 
03028     pn->Label = pl;
03029     pl->Type  = isNodeLabel;
03030     pl->pOwner = pn;
03031 }
03032 
03033 // ---------------------------------------------------
03034 void Schematic::copyLabels(int& x1, int& y1, int& x2, int& y2,
03035                            QList<Element *> *ElementCache)
03036 {
03037     WireLabel *pl;
03038     // find bounds of all selected wires
03039     for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next())
03040     {
03041         pl = pw->Label;
03042         if(pl) if(pl->isSelected)
03043             {
03044                 if(pl->x1 < x1) x1 = pl->x1;
03045                 if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2;
03046                 if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2;
03047                 if(pl->y1 > y2) y2 = pl->y1;
03048                 ElementCache->append(pl);
03049             }
03050     }
03051 
03052     for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
03053     {
03054         pl = pn->Label;
03055         if(pl) if(pl->isSelected)
03056             {
03057                 if(pl->x1 < x1) x1 = pl->x1;
03058                 if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2;
03059                 if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2;
03060                 if(pl->y1 > y2) y2 = pl->y1;
03061                 ElementCache->append(pl);
03062                 pl->pOwner->Label = 0;   // erase connection
03063                 pl->pOwner = 0;
03064             }
03065     }
03066 }
03067 
03068 
03069 /* *******************************************************************
03070    *****                                                         *****
03071    *****                Actions with paintings                   *****
03072    *****                                                         *****
03073    ******************************************************************* */
03074 
03075 Painting* Schematic::selectedPainting(float fX, float fY)
03076 {
03077     float Corr = 5.0 / Scale; // size of line select
03078 
03079     for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next())
03080         if(pp->getSelected(fX, fY, Corr))
03081             return pp;
03082 
03083     return 0;
03084 }
03085 
03086 // ---------------------------------------------------
03087 void Schematic::copyPaintings(int& x1, int& y1, int& x2, int& y2,
03088                               QList<Element *> *ElementCache)
03089 {
03090     Painting *pp;
03091     int bx1, by1, bx2, by2;
03092     // find boundings of all selected paintings
03093     for(pp = Paintings->first(); pp != 0; )
03094         if(pp->isSelected)
03095         {
03096             pp->Bounding(bx1, by1, bx2, by2);
03097             if(bx1 < x1) x1 = bx1;
03098             if(bx2 > x2) x2 = bx2;
03099             if(by1 < y1) y1 = by1;
03100             if(by2 > y2) y2 = by2;
03101 
03102             ElementCache->append(pp);
03103             Paintings->take();
03104             pp = Paintings->current();
03105         }
03106         else pp = Paintings->next();
03107 }
03108 
03109 // vim:ts=8:sw=2:noet
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines