Cortiveo i GEngine - prirucnik

↑ Nazad

Nalazi 24. septembra 2026.

1. Redosled crtanja = redosled redova u tabeli

DataHPrintBaseUtilities.java:208:

for (int i = 0; i < dbtPrintL.getRowCount(); i++) {
    setCurrentRow(i);
    addPrintItem(dbtPrintL);        // puni mPrintItem u istom redosledu
}

A crtanje ide kroz mPrintItem po redu (DataHPrint.java:368), pa ko je poslednji — taj je na vrhu. Zato nova slika dodata na kraju prekrije tekst koji je definisan pre nje: slika nije „iznad" po nekom pravilu, nego zato što je kasnije upisana u tabelu (Id je auto-increment).

2. Isključivanje elementa

Danas se radi zaobilazno: element se stavi na stranu 9 koja nikad ne postoji. Radi, jer poređenje u štampi (piStrana != ObrazacStranaRb) nikad nije tačno — ali element se i dalje učita, napravi mu se font i objekat, i sledeći čovek koji to vidi ne zna da je „9" ugašen element, a ne greška.

3. Boja (već opisano) — ista vrsta izmene

Sve tri stvari su isti obrazac izmene: nova kolona u DefinitionPrintL + ALTER TABLE + čitanje u addPrintItem. Zato se rade zajedno, jednim ALTER-om:

ALTER TABLE definitionprintl
    ADD COLUMN Boja      char(9)   DEFAULT NULL AFTER FontSize,   -- #RRGGBB
    ADD COLUMN Redosled  bigint(4) DEFAULT NULL AFTER Boja,       -- NULL = kao do sada (po Id)
    ADD COLUMN Aktivan   tinyint(1) DEFAULT 1   AFTER Redosled;   -- 0 = ne stampa se

U Javi (generator3/DefinitionPrintL.java):

public static GColumnString  BOJA     = new GColumnString ("Boja", 9);
public static GColumnInteger REDOSLED = new GColumnInteger("Redosled", 4);
public static GColumnBoolean AKTIVAN  = new GColumnBoolean("Aktivan");

U addPrintItem (DataHPrintBaseUtilities.java:74):

protected void addPrintItem(DefinitionPrintL dbt) {
    if (!dbt.isEmpty("Aktivan") && !dbt.getBoolean("Aktivan"))
        return;                                  // iskljucen element - ni ne ulazi u listu
    ...
    pti.setColor(colorOf(dbt.getString("Boja")));  // vidi 2. stranicu prirucnika
}

A posle punjenja liste, jedno sortiranje (stabilno — elementi bez Redosled-a ostaju kako su bili):

Collections.sort(mPrintItem, new Comparator<PrintItem>() {
    public int compare(PrintItem a, PrintItem b) {
        return Integer.compare(a.piRedosled, b.piRedosled);   // 0 kad je NULL
    }
});

Zašto ovako, a ne drugačije: Collections.sort u Javi je stabilan, pa svi elementi sa istim (ili nepostavljenim) redosledom zadržavaju postojeći poredak — stare definicije se ne menjaju, a nove mogu da se podignu ili spuste. Bez Redosled-a bi „pomeri iznad slike" značilo brisanje i ponovni upis reda, što menja Id i kvari sve što na njega gleda.

⚠️ Kolone se dodaju ALTER-om. „(Ре)креирај табелу" radi DROP TABLE (vidi arhitekturu) i obrisalo bi 6874 reda definicija štampe.

4. Vektorski PDF — dobra vest: put je već vektorski

ObrazacPrintJobToFile koristi jPDFWriter (Qoppa):

import com.qoppa.pdfWriter.PDFPrinterJob;
...
job.setPrintable(new PrintPDF2(mObrazac), pg);

a PrintPDF2.print() dodeljuje taj Graphics2D direktno obrascu:

mObrazac.mGraphics = (Graphics2D) g;
mObrazac.mGraphics.translate(pf.getImageableX(), pf.getImageableY());
mObrazac.printData(mObrazac.mGraphics, pf, page);

Nema rasterizacije strane — drawString postaje tekst u PDF-u, drawLine postaje linija. Znači PrintType.print(o, 6, ...) (ono što koristi i Autoprint) je već vektorski put.

Rasterizacija ulazi na dva konkretna mesta, ne u celoj strani:

mestošta radišta se može
DataHPrint.java:202-225 — barkodcrta crte u BufferedImage(TYPE_BYTE_GRAY), pa drawImagecrtati drawLine direktno na mGraphics → vektor, oštrije i manji fajl. Sitna izmena, velik efekat
DataHPrint.java:576 — slikadrawImage(lImage, ...) za logo/memorandumslika je po prirodi raster; fajl zavisi od rezolucije izvora. Ako je memorandum skeniran, tu je težina

Ako vidiš pikselizovan tekst, onda strana nije išla kroz case 6. PrintType ima i case 5: ObrazacFullPrintJobHighResolution(o, factor) — to je put koji skalira i može da rasterizuje. Provera je jedan minut: napravi isti dokument kroz print(o, 6, fajl, 0.5) i uporedi veličinu i oštrinu teksta sa onim što sada dobijaš. Ako je case 6 oštar, rešenje je „koristi 6", ne prepravka.


Ima li Dependency Injection?

Kratko: ne. Ali ima Inversion of Control, i zato izgleda kao DI.

Merenje u GEngine izvoru:

springframework / guice / javax.inject / @Inject / @Autowired :  0 fajlova
Class.forName : 6 mesta
getActiveDatabase(), getActiveDataServer(), getActivePanel(), getCurrentCell() ... : statika

Nema kontejnera, nema konstruktorske injekcije, nema konfiguracije koja spaja komponente. Ono zbog čega ne možeš da nađeš gde se stvari kreiraju su četiri druga mehanizma:

mehanizamprimerzašto grep ne pomaže
Service Locator / refleksijaClass.forName(getString("Id")).newInstance() u SysTable; addOption(Klasa.class) u menijuime klase je podatak (red u bazi, stavka menija), ne kod. Nema new nigde
Registry / PoolGDbtPool, GDatabase.mPoolinstanca se uzima iz pula, ne pravi na mestu upotrebe
Singleton / ambient stateGDatabase.getActiveDatabase(), GDataServer.getActiveDataServer()zavisnost se nalazi, ne dobija
Inversion of Control (callback)engine zove tvoj callback(GCbMessage), loadData(), setParameters(master)ti ne zoveš engine, engine zove tebe — „ko ovo poziva" se ne vidi statički

Najbliže DI-ju je ono četvrto: GDetailParametersSettable.setParameters(GDataSource master) — engine ubacuje matičnu tabelu u detalj-tabelu kroz setter. To je setter injection, samo ručno napisan, bez kontejnera.

Razlika između DI i ovoga je klasična tema: Fowler, „Inversion of Control Containers and the Dependency Injection pattern" — https://martinfowler.com/articles/injection.html — tamo se Service Locator i Dependency Injection izričito porede kao dva rešenja istog problema. GEngine je na Service Locator strani.

Praktično: kako naći gde se nešto stvarno kreira

  1. Ne traži new X — traži string sa imenom klase (u bazi: systable.Id, Package; u kodu: addOption(...)).
  2. Traži getActive...() / pool: možda se instanca nikad i ne kreira na tom mestu.
  3. Kad ni to ne pomaže — pitaj program dok radi, Cortiveo tracerom:
cortiveo trace --app db.,gjava. --call db.tehnobiro.generator3.DataHPrint.<init> --args 3

Breakpoint na konstruktoru kaže ko ga je pozvao i sa čim — to je odgovor koji statička pretraga u ovoj arhitekturi ne može da da.

Izvor: 08-stampa-redosled-boja-vektor-i-di.md