// Klemmenplan/Kabelplan/Brückenplan für Elektro-Projekte // todo // Prüfen ob Netz auf Pin und nicht angeschlossen (pindatabase) // x-Verbindungen nach Namen sortieren string Version = "Version 1.03"; // History // 1.03 -- 2009-10-01 // nicht benötigte "\t\t" im Titel von dlgDialog() entfernt // // 1.02 // Verbindungen von Netzen mit mehr als zwei Kontakten werden jetzt in anderer Reihenfolge // erstellt (siehe Help) // // Ist auf einer Seite keine Klemme (Prefix X) vorhanden, werden alle Verbindungen als d // (Drahtverbindung) gekennzeichnet // // 1.01 Keine Fehlermeldung mehr, wenn Packages Smds enthalten #require 4.9206 #usage "Erstellen eines Klemmenplans\n

" "Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen " "der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die " "üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln " "realisiert werden. Interne, externe und Brücken-Verbindungen erscheinen nacheinander in der Liste.

" "Das Programm sollte erst dann verwendet werden, wenn die " "Schaltung nicht mehr oder nur noch geringfügig verändert wird.

" "Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm " "weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " "Schaltungszeichnung importiert werden.

" "Author: support@cadsoft.de" string s, cmd, f, ErrCmd; string tmpfile, listfile, errorfile, pinfile, vbdfile, klpfile, kapfile, brpfile, pfad; numeric string sh, PartPin, SigName, col, row, PartName, PinName; numeric string pindatabase[], b[]; string PartPinSep = " "; int YRef[]; int distY, netnr, n, i; // Debug string DebugString; // Variablen für main int SelAll = -1, SelConnection = -1, Sort = 0, SortAll = 0, NrLinesListAll; numeric string listall[], listsel[], listundo[], listundoOben[]; string h[]; // Header-Variablen ------------------------------------------------------------------------------------------- string head [], SelParam[], ChangeParam[]; int NrHeader; // Zahl der Rubriken enum {Nummer, Von, Quelle, Ziel, Nach, Art}; // head [] enthält ListHeader-Einträge: head[Farbe].. // head[Nummer].. v numeric string ListHeader = "Nummer\tVon\tQuelle\tZiel\tNach\tArt\tBrücke\tFarbe\tQuerschnitt\tKabeltyp\tFunktion"; // Ende Header-Variablen -------------------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////////////////////////// string HelpText = "Erstellen des Klemmenplans mit diesem User-Language-Programm (ULP)

" "Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen " "der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die " "üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln " "realisiert werden. Das Programm sollte erst dann verwendet werden, wenn die " "Schaltung nicht mehr oder nur noch geringfügig verändert wird.

" "Die obere Liste (Verbindungsliste) enthält immer alle Verbindungen mit diversen " "Parametern. Sie wird abgespeichert, wenn Sie den Button Speichern " "anklicken. Der Benutzer hat die Aufgabe, jeder Verbindung die passenden " "Parameter (Farbe, Kabeltyp etc.) zuzuordnen. Dabei unterstützt ihn dieses " "ULP.

" "Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm " "weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " "Schaltungszeichnung importiert werden.

" "Regeln für das Zeichnen von Mehrfachverbindungen

" "Sind mehr als zwei Klemmen im Schaltplan miteinander verbunden, dann gelten folgende Regeln:

" "Die Klemmen werden der Reihe nach von oben nach unten und von links nach rechts verbunden. " "Das heißt, wenn sich auf diese Weise eine Reihenfolge der Klemmen von A, B, C, D ergibt, " "dann entstehen die Drahtverbindungen A-B, B-C, C-D. Die Art, wie die Netzlinien gezeichnet sind, " "spielt dabei keine Rolle. Sollen die Einzelverbindungen auf andere Art realisiert werden, " "etwa A-C, C-B, B-D, dann müssen die Klemmen im Schaltplan entsprechend platziert werden. " "Erstreckt sich ein Netz über mehrere Seiten, dann wird die Klemme rechts unten mit der " "Klemme rechts oben auf der Folgeseite verbunden.

" "Bedeutung der Spalten

" "Die Spalten der beiden dargestellen Listen haben folgende Bedeutung:

" "Nummer: Laufende Nummer, die vom Programm automatisch erzeugt wird.

" "Von/Nach: 1.A1 bedeutet, die Verbindung startet/endet auf Seite 1, " "Rahmenkoordinaten A1.

" "Quelle/Ziel: F1 1 bedeutet, die Verbindung beginnt/endet an Bauteil F1, Kontakt 1.

" "Art:
" "\td = Drahtverbindung (intern, im Schaltschrank)
" "\tk = Kabelverbindung (extern, außerhalb des Schaltschranks)
" "\tx = Brücke (Klemme zu Klemme im gleichen Klemmenblock)

" "Das Programm kennzeichnet alle Verbindungen als extern, die auf einer Seite " "unterhalb der untersten Klemme (Präfix X..) beginnen.

" "Die Spalteneinträge bis Art werden vom Programm automatisch erzeugt. Die " "Spalten rechts davon trägt der Benutzer ein. Art kann ebenfalls verändert werden, " "dieser Parameter ist dafür verantwortlich, wo die Verbindung in der Ausgabeliste " "erscheint (wenn das Feld leer ist, wird die Zeile nicht ausgegeben).

" "Bedienung des Programms

" "In die untere Liste (Auswahlliste) holen Sie eine Gruppe von Verbindungen, die " "gemeinsame Parameter erhalten sollen, abhängig davon, welche Auswahl-Parameter " "eingetragen sind (Button Holen). Danach setzen sie für die ganze Gruppe " "die Werte, die Sie unter Parameter ändern eingetragen haben (Button " "Alle eintragen oder Alle außer leere). Dann übertragen Sie die " "Parameter in die obere Liste mit dem Button Anwenden. " "Sie können die Parameter der selektierten Auswahllisten-Zeile auch in einem " "separaten Fenster editieren, das sich nach einem Doppelklick auf diese Zeile öffnet.

" "Beispiel: Es sollen alle Bauteile als Farbe rot erhalten, die mit F " "beginnen.

" "Löschen Sie zunächst die Auswahlliste mit dem Button Alle löschen.

" "Klicken Sie dann Alle * an, damit das Wildcard-Zeichen * in alle " "Suchfelder eingetragen wird. In die Felder kann ein sogenannter Wildcard-Text " "eingegeben werden, bei dem das Zeichen * beliebige Zeichen ersetzt. Ein Stern " "bedeuted, es spielt keine Rolle, wie der Eintrag lautet.

" "Jetzt tippen Sie in das Feld Quelle/Ziel der Gruppe Auswahl-Parameter F* ein und " "klicken dann auf Holen. Alle F..-Bauteile erscheinen jetzt in der " "unteren Liste.

" "Tragen Sie jetzt rot im Feld Farbe des Blocks Parameter " "ändern ein, und klicken Sie auf den Button Anwenden. Die Parameter " "werden dann in die obere Liste übertragen.

" "Bedeutung der Buttons

" "Undo oben: Die letzte Veränderung der Verbindungsliste wird " "rückgängig gemacht (nur ein Schritt möglich).

" "Nach oben/Nach unten: Die in der Verbindungsliste selektierte Zeile wird nach " "oben oder unten verschoben. Damit ändert sich die laufende Nummer der Zeile. Auf " "diese Weise lässt sich die Ausgabereihenfolge verändern.

" "Quelle - Ziel: Quelle und Ziel des selektierten Eintrags in der " "Verbindungsliste werden vertauscht.

" "Undo unten: Die letzte Veränderung der Auswahlliste wird " "rückgängig gemacht (nur ein Schritt möglich).

" "Eintrag löschen: Die in der Auswahlliste selektierte Zeile wird gelöscht.

" "Alle löschen: Alle Zeilen der Auswahlliste werden gelöscht.

" "Anwenden: Die Parameter der Auswahlliste werden in die entsprechenden " "Verbindungen der Verbindungsliste eingetragen: Dabei werden die bisherigen " "Parameter (einschließlich leere Felder) überschrieben.

" "Löschen: Alle Felder der Blöcke Auswahl-Parameter und Parameter " "ändern werden gelöscht.

" "Alle *: Setze alle Suchfelder auf das Wildcard-Zeichen *. Es sind auch Muster " "wie *F* oder *F*1* erlaubt.

" "Holen: Hole alle Verbindungen, bei denen die eingetragenen Suchparameter " "zutreffen. Die Felder untereinander sind UND-Verknüpft, das heißt nur wenn bei " "allen Feldern ein entsprechender Eintrag in der Verbindungsliste gefunden wird, " "wird die Verbindung in die Auswahlliste geholt. Wenn Sie etwa alle Verbindungen " "auf Seite 1 mit der Farbe rot holen wollen, dann tragen Sie in Von/Nach " "1.* ein und in das Feld Farbe rot. Alle anderen Felder enthalten *.
" "Ein Doppelklick auf einen Eintrag in der Verbindungsliste bringt diese " "eine Verbindung in die Auswahlliste.

" "Alle eintragen: Die in den Feldern eingetragenen Parameter werden in alle " "Verbindungen der Auswahlliste eingetragen (auch leere Felder).

" "Alle außer leere: Die in den Feldern eingetragenen Parameter werden in alle " "Verbindungen der Auswahlliste eingetragen. Ist ein Feld im Block Parameter " "ändern leer, dann wird das entsprechende Feld in der Auswahlliste nicht " "verändert.

" "Fehlerliste: Zeigt eine Liste mit möglichen Fehlern in der Schaltung.

" "Lade ext. Liste: Falls Sie bereits einen Klemmenplan erstellt haben und " "anschließend nur noch geringfügige Änderungen durchgeführt wurden (Namen der " "Bauteile im Wesentlichen gleich), dann starten Sie das ULP und klicken als " "erstes auf diesen Button, damit die bisherigen Parameter in die Verbindungsliste " "übernommen werden. Verbindungen, die aufgrund von Schaltungsänderungen nicht " "zugeordnet werden können, erscheinen in der Auswahlliste.

" "Abbrechen: Programm ohne Abspeichern des Klemmenplans verlassen. Achtung, Sie " "verlieren alle Änderungen am Klemmenplan.

" "Speichern: Abspeichern des Klemmenplans.

" "Ausgabe

" "In der vorliegenden Version wird eine tabulatorseparierte Liste ausgegeben, " "die Sie entweder in einem Texteditor (mit passend gesetzten Tabulatorwerten) " "oder z. B. mit Excel oder OpenOffice weiterverarbeiten können.

" "Verändern der Spaltenüberschriften

" "Wenn Sie die Spaltenüberschriften an eigene Bedürfnisse anpassen wollen, " "verändern Sie im Programm die Zeile:

" "\"Nummer\\tVon\\tQuelle\\tZiel\\tNach\\tArt\\tBrücke\\tFarbe\\tQuerschnitt\\tKabeltyp\\tFunktion\";

" "Sie können zwischen den Tabulatorzeichen (\\t) die Texte verändern oder neue " "Texte hizufügen, z.B.:

" "\"...\\tFunktion\\tBeschreibung\";

" "Achtung: Die Bedeutung der Spalten von Nummer bis Art bleibt " "unverändert!

" ; //////////////////////////////////////////////////////////////////////////////////////////////////// void SetFileNames(void) { // in Schematic-Kontext aufrufen if (!schematic) { // dlgMessageBox("Dieses Programm muss vom Schaltplan-Editor aus aufgerufen werden"); exit(1); } schematic(SCH) { tmpfile = filesetext(SCH.name, ".$$$"); listfile = filesetext(SCH.name, ".kp$"); errorfile = filesetext(SCH.name, ".log"); pinfile = filesetext(SCH.name, ".pi$"); vbdfile = filesetext(SCH.name, ".vbd"); klpfile = filesetext(SCH.name, ".klp"); kapfile = filesetext(SCH.name, ".kap"); brpfile = filesetext(SCH.name, ".brp"); } } string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Whitespaces im Inneren werden 1 Whitespace int i, n; string t; while (s && isspace(s[0])) s = strsub(s, 1); while (s && isspace(s[strlen(s) - 1])) s = strsub(s, 0, strlen(s) - 1); // Doppel-Blanks for (i = 0; i < strlen(s); i++) { if (!isspace(s[i])) t[n++] = s[i]; else { if ((strlen(s) > i+1) && isspace(s[i+1])); else t[n++] = s[i]; }; } s = t; return s; } void ErrorMessage(string PartPin, string msg) { string s, sh, col, row; sh = lookup(pindatabase, PartPin, "Sheet", '\t'); col = lookup(pindatabase, PartPin, "Column", '\t'); row = lookup(pindatabase, PartPin, "Row", '\t'); sprintf(s, "S. %s/%s-%s \tKontakt %s: \t%s", sh, row, col, PartPin, msg); ErrCmd += s + "\n"; } ///////////////////////////////////////// // pindatabase anlegen // // ermittle Zahl der Wires, die von Pin bzw. x,y aus starten int NrOfWiresFromPin(string net, int shnr, int x, int y) { string s; int n; schematic(SCH) { SCH.sheets(SH) { if (SH.number == shnr) { SH.nets(N) { if (N.name == net) { N.segments(SEG) { SEG.wires(W) { if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // Wire beginnt an x, y n++; } } } } } } } } if (net && !n) n = 1; // wenn Pin auf Pin, net vorhanden, deshalb n auf 1 return n; } // ermittle Zahl der Wires, die nach dem ersten Wire-Segment vom Pin aus starten // Wire vom Pin weg wird mitgezählt int NrOfWiresAfterPin(string net, int shnr, int x, int y) { string s; int n, n1, u; schematic(SCH) { SCH.sheets(SH) { if (SH.number == shnr) { SH.nets(N) { if (N.name == net) { N.segments(SEG) { n1 = 0; SEG.wires(W) { if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // suche ersten Wire if (x == W.x1 && y == W.y1) { // stelle Endkoordinaten des Wires fest x = W.x2; y = W.y2; } else { x = W.x1; y = W.y1; } if (y == W.y1 || y == W.y2) { // Wire-Anfang zweigt nach erstem Wire-Segment über/unter Pin ab n1 = NrOfWiresFromPin(net, shnr, x, y); // x, y nach erstem Wire-Stück distY = y; // global, Distanz des Abzweigs in vertikaler Richtung if (n1) break; } } } } } } } } } return n1; } void SetupPinDatabase(void) { string s, cmd, pname; int np, nw; schematic(SCH) { cmd = "PartContact\tNet\tSheet\tRow\tColumn\tx\ty\tNP\tNW\tdistY\n"; SCH.sheets(SH) { // # Wires ab Pin SH.parts(PRT) { // # Wires nach erstem Wire PRT.instances (I) { // Abstand des Abzweigs vertikal I.gate.symbol.pins(P) { if (P.contact) { pname = P.contact.name; } else { pname = P.name; } np = NrOfWiresFromPin(P.net, SH.number, P.x, P.y); nw = NrOfWiresAfterPin(P.net, SH.number, P.x, P.y); sprintf(s, "%s%s%s\t%s\t%d\t%s\t%s\t%d\t%d\t", PRT.name, PartPinSep, pname, P.net, SH.number, I.row, I.column, P.x, P.y); cmd += s; sprintf(s, "\t%d\t%d\t%d\n", np, nw, distY); cmd += s; // Hier lassen sich alle Pin-Parameter prüfen if (nw > 3 || np > 2) { sprintf(s, "S. %d/%s-%s \tKontakt %s %s: \tMehr als zwei Abzweigungen vom Kontakt!", SH.number, I.row, I.column, PRT.name, pname); ErrCmd += s + "\n"; } // todo: Prüfen, ob ein nicht angeschlossenes Netz auf dem Pin liegt } } } } } strsplit(pindatabase, cmd, '\n'); output(pinfile, "wtD") { printf(cmd); } } //ende pindatabase ///////////////////////////////// void ReadConnects(void) { int i, n, x[], y[], index[], loopcnt; numeric string Part_Pin[]; schematic(SCH) { SCH.nets(NET) { loopcnt = 0; SCH.sheets(SH) { SH.nets(N) { if (NET.name == N.name) { loopcnt++; if (loopcnt == 1) { cmd += "\n"; } n = 0; N.segments(SEG) { SEG.pinrefs(P) { if (P.pin.contact) { Part_Pin[n] = P.part.name + "\t" + P.pin.contact.name; } else { Part_Pin[n] = P.part.name + "\t" + P.pin.name; } x[n] = P.pin.x; y[n] = INT_MAX - P.pin.y; // scanne Klemmen von oben nach unten ++n; } } sort(n, index, x, y, Part_Pin); // sortiere PartPin innerhalb eines Segments nach Position // scanne Klemmen: erst alle y auf x = 0 etc. for (int i = 0; i < n; ++i) { sprintf(s, "%s\t", Part_Pin[index[i]]); cmd += s; } } } } } } output(tmpfile, "wtD") { printf(cmd); } } // Ermittle y-Wert für Trennung zwischen interner und externer Verdrahtung // Hier: Klemme mit niedrigstem y pro Sheet void GetYReference(void) { // YRef[] liefert: #sheets, yref-sh1, yref-sh2 .. int sn, ymin, klemme_exists; schematic(S) { S.sheets(SH) { sn++; ymin = INT_MAX; klemme_exists = 0; SH.parts(P) { P.instances(I) { if (strchr(I.name, 'X') == 0) { // Alle, die mit X beginnen ymin = min(ymin, I.y); // sprintf(s, "%s: %d\n", I.name, ymin); ErrCmd += s; klemme_exists = 1; } } } YRef[SH.number] = ymin; // sprintf(s, " %d: %d\n", SH.number, YRef[SH.number]); ErrCmd += s; if (klemme_exists == 0) { YRef[SH.number] = 0; } } YRef[0] = sn; } } string AssembleNetLine(string line){ int i, j, n, npar, snr; string s, st, lxy, rxy; string ps[]; // Einzelparameter, Source string pair[]; // Name-Pin-Paar mit Blank string x[]; string y[]; string distY[];// Distanz der Abzweigung vom Pin string np[]; // # Wires ab Pin string nw[]; // # Wires ab erstem Wire-Segment nach Pin string Sep = "\t"; string net[]; string sht[]; string row[]; string col[]; npar = strsplit(ps, line, '\t'); for (j = 0; j < npar/2;) { // Zusammenfassen von Part und Pin mit Blank pair[j++] = ps[n++] + " " + ps[n++]; } n = 0; while (pair[n]) { // Sammeln der Pin-Informationen // np[n] = lookup(pindatabase, PartPin, "NP", '\t'); x[n] = lookup(pindatabase, pair[n], "x", '\t'); y[n] = lookup(pindatabase, pair[n], "y", '\t'); net[n] = lookup(pindatabase, pair[n], "Net", '\t'); sht[n] = lookup(pindatabase, pair[n], "Sheet", '\t'); row[n] = lookup(pindatabase, pair[n], "Row", '\t'); col[n] = lookup(pindatabase, pair[n], "Column", '\t'); if (!sht[n]) { sht[n] = "?"; col[n] = "?"; row[n] = "?"; } n++; } if (npar <= 2) { ErrorMessage(pair[0], "Netz nicht abgeschlossen!"); return ""; } netnr++; sprintf (lxy, "%08d %08d", strtol(x[0]), strtol(y[0])); sprintf (rxy, "%08d %08d", strtol(x[1]), strtol(y[1])); // Art voranstellen snr = min (strtol(sht[0]), strtol(sht[1])); // Sheetnr if (strtol(y[0]) <= YRef[snr] && strtol(y[1]) > YRef[snr]) ErrorMessage(pair[0], "Verbindung nicht eindeutig (intern oder extern?)"); if (strtol(y[0]) > YRef[snr]) s = "d\t"; if (strtol(y[0]) <= YRef[snr]) s = "k\t"; if (strsub(pair[0], 0, 1) == "X" && ps[0] == ps[2]) s = "x\t"; st += s; if ((lxy > rxy && strtol(sht[0]) == strtol(sht[1])) || (strtol(sht[0]) > strtol(sht[1]))) { // Reihenfolge Quelle-Ziel etc. tauschen sprintf(s, "%03d%s", strtol(sht[1]), Sep); st+= s; sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[1]), strtol(y[1]), Sep, strtol(x[0]), strtol(y[0]), Sep); st += s; sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[1], Sep, sht[1], row[1], col[1], Sep); st += s + pair[1] + Sep + pair[0]; sprintf(s, "%s%s.%s%s", Sep, sht[0], row[0], col[0]); st += s; } else { sprintf(s, "%03d%s", strtol(sht[0]), Sep); st+= s; sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[0]), strtol(y[0]), Sep, strtol(x[1]), strtol(y[1]), Sep); st += s; sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[0], Sep, sht[0], row[0], col[0], Sep); st += s + pair[0] + Sep + pair[1]; sprintf(s, "%s%s.%s%s", Sep, sht[1], row[1], col[1]); st += s; } st += "\n"; if (npar <= 4) return st; // nur Zweipunktverbindung if (npar > 4) { // jeden mit dem Nachbarn verbinden (gleiches y hat Vorrang) n = 2; while (pair[n]) { netnr++; sprintf (lxy, "%08d %08d", strtol(x[n-1]), strtol(y[n-1])); sprintf (rxy, "%08d %08d", strtol(x[n]), strtol(y[n])); // Art voranstellen snr = min (strtol(sht[n-1]), strtol(sht[n])); // Sheetnr if (strtol(y[n-1]) <= YRef[snr] && strtol(y[n]) > YRef[snr]) ErrorMessage(pair[n-1], "Verbindung nicht eindeutig (intern oder extern?)"); if (strtol(y[n-1]) > YRef[snr]) s = "d\t"; if (strtol(y[n-1]) <= YRef[snr]) s = "k\t"; if (strsub(pair[n-1], 0, 1) == "X" && ps[(n-1)*2] == ps[n*2]) s = "x\t"; st += s; if ((lxy > rxy && strtol(sht[n-1]) == strtol(sht[n])) || (strtol(sht[n-1]) > strtol(sht[n]))) { sprintf(s, "%03d%s", strtol(sht[n]), Sep); st+= s; sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n]), strtol(y[n]), Sep, strtol(x[n-1]), strtol(y[n-1]), Sep); st += s; sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n], Sep, sht[n], row[n], col[n], Sep); st += s + pair[n] + Sep + pair[n-1]; sprintf(s, "%s%s.%s%s", Sep, sht[n-1], row[n-1], col[n-1]); st += s; } else { sprintf(s, "%03d%s", strtol(sht[n-1]), Sep); st+= s; sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n-1]), strtol(y[n-1]), Sep, strtol(x[n]), strtol(y[n]), Sep); st += s; sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n-1], Sep, sht[n-1], row[n-1], col[n-1], Sep); st += s + pair[n-1] + Sep + pair[n]; sprintf(s, "%s%s.%s%s", Sep, sht[n], row[n], col[n]); st += s; } st += "\n"; n++; } } return st; } // Verbindungsliste aufbereiten void ChangeList(void) { int i, j, nl, np; numeric string a[], c[], s, sh; GetYReference(); // YRef[sheet] enthält y von unterstem Klemmenkontakt nl = fileread(a, tmpfile); // sort(n, a); output(tmpfile, "wtD") { // leere Zeilen entfernen for (i = 0; i < nl; i++) { if (a[i]) printf("%s\n",a[i]); } } nl = fileread(a, tmpfile); if (nl > 0) { output(listfile, "wtD") { // sheetnr \t x y \t x y \t Nummer \t Netz \t Von .. for (i = 0; i < nl; i++) { a[i] = StripWhiteSpace(a[i]); // a[] enthält urspr. Connect-Zeilen b[i] = a[i]; // b[] enthält Zeilen eines Signals und wird verändert (global) b[i] = AssembleNetLine(b[i]); if (b[i]) printf("%s", b[i]); // b[0..nl] -> alle Zeilen eines Signals geordnet nach Pos. } } } nl = fileread(a, listfile); // sortieren nach sheetnr und erstem x y \t xy sort(nl, a); output(listfile, "wtD") { for (i = 0; i < nl; i++) { strsplit(c, a[i], '\t'); printf("%d\t%s\t%s\t%s\t%s\t%s\n", i + 1, c[6], c[7], c[8], c[9], c[0]); // printf("%s\n", a[i]); } } } //************** von Main benutzt ********************** void PushUndo(void) { int i; while (listundo[i]) { listundo[i] = ""; i++; } i = 0; while (listsel[i]) { listundo[i] = listsel[i]; i++; } } void PullUndo(void) { int i; while (listsel[i]) { listsel[i] = ""; i++; } i = 0; while (listundo[i]) { listsel[i] = listundo[i]; i++; } } void PushUndoOben(void) { int i; while (listundoOben[i]) { listundoOben[i] = ""; i++; } i = 0; while (listall[i]) { listundoOben[i] = listall[i]; i++; } } void PullUndoOben(void) { int i; while (listundoOben[i]) { i++; } if (i == 0) return; // wenn alte Liste leer (nach dem Start) i = 0; while (listall[i]) { listall[i] = ""; i++; } i = 0; while (listundoOben[i]) { listall[i] = listundoOben[i]; i++; } } // Lies rohe Verbindungsliste void ReadList(void) { int i, j, np; numeric string h[]; NrLinesListAll = fileread(listall, listfile) -1; for (i = 0; i < NrLinesListAll; i++) { while (strsplit(h, listall[i], '\t') < NrHeader) listall[i] += "\t"; listsel[i] = listall[i]; // erst, Auswahliste füllen, damit Listen gleich formatiert werden } } void ShowErrorList(void) { dlgDialog("Fehlerliste") { dlgHBoxLayout dlgSpacing(600); dlgHBoxLayout{ dlgTextEdit(ErrCmd); } dlgHBoxLayout { } dlgHBoxLayout { dlgStretch(1); dlgPushButton("&Hilfe") dlgMessageBox( "Überprüfen Sie die in der Liste aufgeführten Kontakte!\n" "Sie können die Fehlerliste auch editieren und mit Cut&Paste \n" "zu einem Texteditor übertragen." ); dlgPushButton("+OK") dlgAccept(); } }; } // Übertrage eine Verbindung in Auswahlliste, wenn noch nicht vorhanden void TransferOneEntry(int Sel) { int i, n; string h1[], h2[]; PushUndo(); strsplit(h1, listall[Sel], '\t'); while(listsel[i]) { strsplit(h2, listsel[i], '\t'); if (h1[Nummer] == h2[Nummer] && h1[Von] == h2[Von] && h1[Quelle] == h2[Quelle] && h1[Ziel] == h2[Ziel] && h1[Nach] == h2[Nach] ) return; // Zeilen identisch -> kein neuer Eintrag (nur feste Felder bis Nach geprüft) i++; } i = 0; while(listsel[i++]) { // finde letzte Zeile } listsel[i-1] = listall[Sel]; } // Lösche eine Verbindung aus Auswahlliste void DelOneEntry(int Sel) { int i, n, imax; string x[]; PushUndo(); if (Sel < 0) return; //SelConnection = -1; while(listsel[i++]) { } imax = i; for (i = 0; i < imax; i++) { if (i <= Sel) { x[i] = listsel[i]; } else { x[i-1] = listsel[i]; } } listsel[imax-1] = ""; listsel[imax] = ""; imax = imax -1; for (i = 0; i < imax; i++) { listsel[i] = x[i]; } } void SetSelParams(string c) { int i; for (i = 1; i < NrHeader; i++) { SelParam[i] = c; // einige nicht relevant } } void SetChangeParams(string c) { int i; for (i = 1; i < NrHeader; i++) { ChangeParam[i] = c; // einige nicht relevant } } // Suche mit Wildcard * int WildMatch(string wild, string st) { // wild = Suchmuster, st = zu durchsuchender Sting int wx, sx, pos; string sw, ss; wild = StripWhiteSpace(wild); st = StripWhiteSpace(st); if (wild == st || wild == "*") return 1; if (!wild && st) return 0; if (strchr(wild, '*') < 0 && strlen(wild) > 0 && st == "") return 0; // wild exist., aber kein * if (strlen(wild) > 0 && st == "") { // wild exist. mit Nicht-*-Zeichen, st = "" pos = 0; sw = wild; while (sw[pos]) { // Zeichen außer * in wild vorhanden -> return 0 if (sw[pos] != '*') return 0; pos++; } return 1; // wild ist **... } while (wild[wx] && st[sx]) { while (wild[wx] != '*') { // vgl. bis zum nächsten * if (wild[wx++] != st[sx++]) return 0; if (sx == strlen(st) && !(wx == strlen(wild))) { // Ende von st erreicht aber nicht Ende von wild if (wild[wx] == '*' && !wild[wx+1]) return 1; // nächstes Zeichen von wild ist *, dann Stringende else return 0; } if (wx == strlen(wild) && !(sx == strlen(st))) return 0; // Ende von wild erreicht aber nicht Ende von st if (wx == strlen(wild) && (sx == strlen(st))) return 1; // Ende von wild erreicht aber nicht Ende von st } // jetzt kommt zwingend ein *, wx steht auf Index von * if (wx == strlen(wild) - 1) return 1; // Ende von wild erreicht und * wx++; while (st[sx] != wild[wx] && wild[wx] != '*') { // bis zum Match nach Stern if (sx == strlen(st) -1) return 0; // Ende von st erreicht ohne Match sx++; } } return 1; } // Von Verbindungs- in Auswahlliste void TransferMatchingEntries(void) { int iall, i, match1, match2, np; string h[]; // Einzelparameter PushUndo(); SelParam[Quelle] = strupr(SelParam[Quelle]); SelParam[Von] = strupr(SelParam[Von]); while (listall[iall]) { match1 = 0; np = strsplit(h, listall[iall], '\t'); // bisherige Einzelpar. in h[] if ((WildMatch(SelParam[Quelle], h[Quelle]) || WildMatch(SelParam[Quelle], h[Ziel])) && (WildMatch(SelParam[Von], h[Von]) || WildMatch(SelParam[Von], h[Nach])) ) match1 = 1; match2 = 0; for (i = Nach + 1; i < NrHeader; i++) { if (WildMatch(SelParam[i], h[i]) ) { match2 = 1; } else { match2 = 0; break; } } if (match1 && match2) { // nach break TransferOneEntry(iall); } iall++; } SelAll = -1; } // Lösche alle Verbindungen aus Auswahlliste void DelAllEntries(void) { int i; PushUndo(); while(listsel[i]) { listsel[i] = ""; i++; } } void ChangeOneEntry(int Sel) { int i; PushUndo(); for (i = Nach + 1; i < NrHeader; i++) { h[i] = ChangeParam[i]; } listsel[Sel] = strjoin(h, '\t'); } void EditOneEntry(int Sel) { int i, np; np = strsplit(h, listsel[Sel], '\t'); for (i = np; i < NrHeader; i++) h[i] = ""; dlgDialog("Editiere Verbindungs-Parameter") { for (i = Nach + 1; i < NrHeader; i++) { ChangeParam[i] = h[i]; } for (i = Nach + 1; i < NrHeader; i++) { dlgHBoxLayout { dlgLabel(head[i] + "\t"); dlgStringEdit(ChangeParam[i]); } } dlgHBoxLayout { dlgStretch(1); dlgPushButton("-Abbrechen") dlgReject(); dlgPushButton("+OK") {dlgAccept(); ChangeOneEntry(Sel);} } }; } void CopyChangeParams(int all) { int i, j; string h[]; PushUndo(); while (listsel[j]) { strsplit(h, listsel[j], '\t'); for (i = Nach + 1; i < NrHeader; i++) { if (ChangeParam[i] != "" || all) h[i] = ChangeParam[i]; } listsel[j] = strjoin(h, '\t'); j++; } } void ApplyChanges(void) { int j, k; string ls[], la[]; PushUndoOben(); while (listall[j]) { strsplit(la, listall[j], '\t'); // bisherige Zeile in la[] k = 0; while (listsel[k]) { strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[] if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) || (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle]) ) { // Match-Zeile gefunden ls[0] = la[0]; // alte Nummer verwenden listall[j] = strjoin(ls, '\t'); } k++; } j++; } } // Übertrage Parameter der externen Liste nach listall und lösche die verwendeten aus listsel void ApplyChangesOldList(void) { int j, k; string ls[], la[]; while (listall[j]) { strsplit(la, listall[j], '\t'); // bisherige Zeile in la[] k = 0; while (listsel[k]) { strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[] if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) || (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle]) ) { // Match-Zeile gefunden ls[0] = la[0]; // alte Nummer verwenden listall[j] = strjoin(ls, '\t'); DelOneEntry(k); break; } k++; } j++; } } int LoadOldListOk(void) { int LoadOk; dlgDialog("Verbindungsliste laden") { dlgHBoxLayout dlgSpacing(400); dlgHBoxLayout { dlgTextView ( "Achtung, wenn Sie eine vorhandene Verbindungsliste laden, " "werden alle bisher definierten Parameter der Verbindungen " "überschrieben, die in der aktuellen und der gespeicherten " "Liste vorhanden sind!\n\n" "Nicht gefundene Verbindungen sind im Auswahlfenster aufgelistet.\n\n" ); } dlgHBoxLayout { dlgStretch(1); dlgPushButton("+Abbrechen") dlgReject(); dlgPushButton("-Weiter") {LoadOk = 1; dlgAccept();} } }; if (LoadOk) return 1; else return 0; } int CancelOk(void) { int CancelOk; dlgDialog("Programm verlassen") { dlgHBoxLayout dlgSpacing(400); dlgHBoxLayout { dlgTextView ( "Wenn Sie das Programm abbrechen, verlieren Sie alle veränderten Parametereinträge!\n\n" "Abbrechen?" ); } dlgHBoxLayout { dlgStretch(1); dlgPushButton("+Nein") dlgReject(); dlgPushButton("-Ja") {CancelOk = 1; dlgAccept();} } }; if (CancelOk) return 1; else return 0; } void ApplyOldList(void) { int NrLines; string FileName = dlgFileOpen("Verbindungsliste/Klemmenplan/Kabelplan/Brückenplan wählen", vbdfile, "Klemmenplan-Dateien (*.vbd);;Alle Dateien (*)"); if (FileName) { PushUndo(); PushUndoOben(); DelAllEntries(); NrLines = fileread(listsel, FileName); DelOneEntry(0); // Header löschen ApplyChangesOldList(); } } void SaveList(void) { int i; schematic(SCH) vbdfile = filesetext(SCH.name, ".vbd"); string FileName = dlgFileSave("Speichere Verbindungsliste", vbdfile); if (FileName) { string a[]; output(FileName, "wt") { printf ("%s\n", ListHeader); while (listall[i]) { printf("%s\n", listall[i]); // "%s" um Probleme zu vermeiden, wenn listall '%' enthält i++; } } } } void MoveDown(int Sel) { int i; string hi[], lo[], tmp; if (listall[Sel + 1]) { PushUndoOben(); while (listsel[i]) listsel[i++] = ""; strsplit(hi, listall[Sel + 1], '\t'); strsplit(lo, listall[Sel], '\t'); tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang listall[Sel] = strjoin(hi, '\t'); listall[Sel + 1] = strjoin(lo, '\t'); SelAll = Sel + 1; } } void MoveUp(int Sel) { int i; string hi[], lo[], tmp; if (Sel > 0) { PushUndoOben(); while (listsel[i]) listsel[i++] = ""; strsplit(hi, listall[Sel], '\t'); strsplit(lo, listall[Sel - 1], '\t'); tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang listall[Sel] = strjoin(lo, '\t'); listall[Sel - 1] = strjoin(hi, '\t'); SelAll = Sel - 1; } } void ChangeSourceDest (int Sel) { string h[], s; if (Sel < 0) return; PushUndoOben(); strsplit(h, listall[Sel], '\t'); s = h[Quelle]; h[Quelle] = h[Ziel]; h[Ziel] = s; listall[Sel] = strjoin(h, '\t'); } void ShowHelp(void) { dlgDialog("Hilfe") { dlgHBoxLayout dlgSpacing(600); dlgHBoxLayout{ dlgVBoxLayout dlgSpacing(600); dlgTextView(HelpText); } dlgHBoxLayout { } dlgHBoxLayout { dlgStretch(1); dlgPushButton("+OK") dlgAccept(); } }; } //***************************************************** void ShowUserInterface(void) { dlgDialog("Klemmenplan/Kabelplan erstellen - " + Version) { dlgHBoxLayout dlgSpacing(800); dlgGroup("") { dlgLabel("Verbindungsliste"); dlgListView(ListHeader, listall, SelAll, SortAll) TransferOneEntry(SelAll); dlgSpacing(10); } dlgGroup("") { dlgLabel("Auswahlliste"); dlgListView(ListHeader, listsel, SelConnection, Sort) EditOneEntry(SelConnection); dlgHBoxLayout { dlgPushButton("Undo oben") PullUndoOben(); dlgPushButton("Nach oben") MoveUp(SelAll); dlgPushButton("Nach unten") MoveDown(SelAll); dlgPushButton("Quelle <-> Ziel") ChangeSourceDest(SelAll); dlgStretch(1); dlgPushButton("Undo unten") PullUndo(); dlgPushButton("Eintrag löschen") DelOneEntry(SelConnection); dlgPushButton("Alle löschen") DelAllEntries(); dlgPushButton("Anwenden") ApplyChanges(); } } dlgSpacing(10); dlgHBoxLayout { dlgGroup("Auswahl-Parameter") { dlgHBoxLayout { dlgVBoxLayout { dlgHBoxLayout { dlgLabel(head[Quelle] + "/" + head[Ziel] + "\t"); dlgStringEdit(SelParam[Quelle]); } dlgHBoxLayout { dlgLabel(head[Von] + "/" + head[Nach] + "\t"); dlgStringEdit(SelParam[Von]); } dlgGroup("") { } } dlgVBoxLayout { for (i = Nach + 1; i < NrHeader; i++) { dlgHBoxLayout { dlgLabel(head[i] + "\t"); dlgStringEdit(SelParam[i]); } } dlgHBoxLayout { dlgStretch(1); dlgPushButton("Löschen") SetSelParams(""); dlgPushButton("Alle *") SetSelParams("*"); dlgPushButton("Holen") TransferMatchingEntries(); } } } } dlgGroup("Parameter ändern") { for (i = Nach + 1; i < NrHeader; i++) { dlgHBoxLayout { dlgLabel(head[i] + "\t"); dlgStringEdit(ChangeParam[i]); } } dlgHBoxLayout { dlgStretch(1); dlgPushButton("Löschen") SetChangeParams(""); dlgPushButton("Alle eintragen") CopyChangeParams(1); dlgPushButton("Alle außer leere") CopyChangeParams(0); } } } dlgHBoxLayout { dlgPushButton("&Hilfe") ShowHelp(); dlgStretch(1); dlgPushButton("Fehlerliste") ShowErrorList(); dlgPushButton("Lade ext. Liste") if (LoadOldListOk()) ApplyOldList(); dlgPushButton("-Abbrechen") if (CancelOk()) dlgReject(); dlgPushButton("+Speichern") SaveList(); } }; } //***************** Main ****************************** NrHeader = strsplit(head, ListHeader, '\t'); SetFileNames(); SetupPinDatabase(); ReadConnects(); ChangeList(); output(errorfile, "wt") printf(ErrCmd + "\n"); // hier sind alle Listen fertig (*.kp$ ohne Parameter-Einträge // Oberfläche ReadList(); ShowUserInterface();