Nalazi 24. septembra 2026.
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).
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.
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 seU 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 dodajuALTER-om. „(Ре)креирај табелу" radiDROP TABLE(vidi arhitekturu) i obrisalo bi 6874 reda definicija štampe.
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 — barkod | crta crte u BufferedImage(TYPE_BYTE_GRAY), pa drawImage | crtati drawLine direktno na mGraphics → vektor, oštrije i manji fajl. Sitna izmena, velik efekat |
DataHPrint.java:576 — slika | drawImage(lImage, ...) za logo/memorandum | slika 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.
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() ... : statikaNema 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:
| mehanizam | primer | zašto grep ne pomaže |
|---|---|---|
| Service Locator / refleksija | Class.forName(getString("Id")).newInstance() u SysTable; addOption(Klasa.class) u meniju | ime klase je podatak (red u bazi, stavka menija), ne kod. Nema new nigde |
| Registry / Pool | GDbtPool, GDatabase.mPool | instanca se uzima iz pula, ne pravi na mestu upotrebe |
| Singleton / ambient state | GDatabase.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.
new X — traži string sa imenom klase (u bazi: systable.Id, Package; u kodu: addOption(...)).getActive...() / pool: možda se instanca nikad i ne kreira na tom mestu.cortiveo trace --app db.,gjava. --call db.tehnobiro.generator3.DataHPrint.<init> --args 3Breakpoint 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.