Színbeállítások Eclipse-ben – javított megoldás

Ahogy tegnap is írtam, [intlink id=”623″ type=”post”]Eclipse-hez beállító ablakokat[/intlink] könnyen lehet készíteni. De ez még mindig bonyolultabb, mint az optimum, ha csak színeket (és esetleg betűtípusokat) akar az ember beállíthatóvá tenni.

Hogy miért is mondom ezt? Azért, mert így teljesen úgy beállításlapot kell csinálni, amikor az Eclipse már tartalmaz egy színbeállítással foglalkozó oldalt (General/Appearance/Colors and Fonts). És ha az ember jobban megnézi, akkor itt bizony jó néhány olyan beállítás is szerepel, ami semmilyen hivatalos Eclipse csomagban nincs benne, innen kezdve adódik a következtetés: kiterjeszthető. 🙂

És valóban: az [cci]org.eclipse.ui.themes[/cci] kiterjesztési pont az, amit mi keresünk. Ami lényeges előrelépés az általános beállításpanelhez képest, hogy itt a beállításokat mindössze a plugin.xml megfelelő kitöltésével megoldhatjuk, és ez rögtön legenerálja a megfelelő felhasználói felületet. Lustaság fél egészség.:D

De a lényeg az egészben, hogy ez oda kerül, ahol a többi hasonló beállítás van, ezért talán a felhasználó is könnyebben megtalálhatja (nem szabad elfelejteni, hogy az Eclipse környezetnek a célközönsége nem a mezei felhasználó, hanem annál hozzáértőbbek, legalább poweruser-ek, de egyelőre még inkább programozók, így megengedhető, hogy az összes beállítás így jelenjen meg).

A kiterjesztéshez definiálhatok különböző paramétereket: ami az én esetemben lényeges volt, az a [cci]themeElementCategory[/cci] és a [cci]colorDefinition[/cci] attribútumok: az előbbivel egy kategóriát definiálhatok, míg a másodikkal színeket (a betűtípusok definiálásához a [cci]fontDefinition[/cci] attribútumot lehet használni, hasonlóan a colorDefinitionhöz).

A színekhez meg lehet adni egy alapértelmezett színt (nem kódban, hanem az XML-ben), ezt a value elemhez érdemes tenni, egy színazonosítót (a későbbi hivatkozáshoz), valamint egy categoryId-t (itt lehet megadni a korábban definiált kategóriát). A plugin.xml grafikus szerkesztőjén teljesen magától értetődő a kezelés.

A kategóriának meg egy Id-t és egy feliratot kell megadni.

Ha ezeket az elemeket megadtuk, akkor már késznek is tekinthető a beállítási felület, és nincs más hátra, minthogy a kódból elérjük a színeket. Ez hasonló bonyolultsággal, de kicsit eltérő kóddal kezelhető, mint a beállítások esetén. Kicsit konkrétabban:
[cc_java]IThemeManager themeManager = PlatformUI.getWorkbench()
.getThemeManager();
ITheme theme = themeManager.getCurrentTheme();
ColorRegistry colorRegistry = theme.getColorRegistry();
ENTITY_BG = colorRegistry
.get(“org.eclipse.viatra2.visualisation.entity.background”);[/cc_java]

Betűtípus lekéréséhez pedig a getFontRegistry hívással kell a témától elkérni a betűtípus-tárat, és annak a get metódusával a betűtípusokat lehet megkapni. Az így megkapott Color, ill. Font objektumokat nem kell felszabadítani, ezt a rendszer elvégzi helyettünk.

Ennyi munkával már össze lehet rakni egy jól működő beállításablakot, ezt képekkel illusztrálva a következő oldalon is lehet látni (angol nyelven): http://blog.eclipse-tips.com/2008/08/adding-color-and-font-preferences.html. Így ennyit se nagyon kellett volna írni, de egy aprósággal ezt is kiegészítettem még: a kiterjesztés megengedi, hogy egy előnézetet hozzak létre az így elkészült beállítási ablakhoz. Hogy megmutassam, ezzel mire gondolok, megmutatom az elkészült panelt.

Az elkészült színbeállítóablak grafikus képehttps://i1.wp.com/cubussapiens.hu/wp-content/uploads/2009/01/colors.png?w=500 500w" sizes="(max-width: 300px) 85vw, 300px" />
Az elkészült színbeállítóablak grafikus képe

Röviden: összerakhatok egy tetszőleges SWT formot, ami megjeleníti a beállítások eredményét. Ehhez a kategória class nevű attribútumát kell beállítani egy általunk létrehozott osztályra. Az interfész két metódus megvalósítását követeli meg: egy [cci]createControl[/cci] és egy [cci]dispose[/cci] metódust. A megvalósítás magától értetődő(nek tűnik): a createControl mindig meghívódna, amikor a beállítások módosulnak.

De sajnos nem. Az csak egyszer hívódik meg. Ezért a [cci]createControl[/cci] futása során fel kell iratkoznunk a téma változásaira az [cci]addPropertyChangeListener[/cci] metódus segítségével, és amikor ott befut az eredmény, akkor frissíteni kell az előnézetet.

Az előnézetet tényleg tetszőleges módon meg lehet valósítani, én például simán hozzácsaptam egy Zest Graph Viewert, és azt paramétereztem fel némi “dummy” adattal, és az eredmény a fenti képen látható (és a gyakorlatban tényleg azonnal frissül 🙂 ).

Ez az kiterjesztés láthatóan arra van kihegyezve, hogy egységes módon lehessen színbeállításokat tenni, és ennek a legjobb módja, hogy ne adjuk ki a kódot a kiterjesztő kezébe, hanem csak lehetőséget adjunk a felparaméterezésre. Ugyanakkor ez kellően rugalmasan sikerült megoldani, és a dokumentáció alapján tényleg magától értetődő a kitöltés. De nem szabad elfelejteni, hogy ez nem egy teljes körű megoldás, például vonalvastagságot vagy vonaltípust itt beállítani nem lehet, noha grafikus pluginek témabeállításaihoz ez is hozzátartozik.

Eclipse Preference Page készítésről röviden

A héten egy „egyszerű” problémát kellett megoldanom: egy Eclipse-pluginhoz konfigurációs lehetőségként kellett lehetővé tennem színek kiválasztását. Elhangzott ötletnek, hogy csináljak akár Java properties fájlokat vagy valami hasonlót (értsd: kódold le kézzel), de ha már Eclipse házinak készül a dolog, inkább úgy döntöttem, nézzük meg, hogy az Eclipse mit kínál.

Egyik természetes megoldásnak tűnik egy saját Property page létrehozása, amin be lehet állítani a megfelelő színeket. Ehhez kiderült (némi keresgélés után, ez tényleg gyorsan megvan), hogy az org.eclipse.ui.PreferencePages kiterjesztési ponthoz kell kapcsolódni. És még további próbálkozás után kiderül, hogy érdemes legeneráltatni a mintát az Eclipse-ből, mert lényegesen okosabb kódot rak össze, mint ami az interfész naiv implementációjából kijönne. De erről egy kicsit később.

Az extension point igényli, hogy megadjuk, milyen névvel illetve milyen másik Page alá szeretnénk betenni az új lapunkat, ami lehetővé teszi a kényelmes hierarchikus beállításszervezés összeállítását. Nice.

Ami meglepően egyszerűvé teszi az oldal tervezését, hogy a JFace API tartalmaz beépített FieldEditor osztályokat, így a beállítások lap tervezéséhez egyszerűen annyira van szükség, hogy ezeket (esetleges SWT konténerekkel együtt) kidobálok egy API-tól kapott konténerre. Triviális. És ami még fontosabb, egy percig sem kell azzal szórakoznom, hogy mikor/hogyan mentsem ki az adatokat a háttértárra, hogyan olvassam ki a mezőkből, mert ezt automatikusan elvégzi a rendszer. Nekem csak minden egyes mezőhöz egy azonosítót kell rendelnem, és a többi már gyorsan megy. Ha valami speciális feltételek vannak a kitöltéshez, ahhoz pedig a legtöbb komponens validator hozzátételével működik – ezzel az egyszerű struktúrával a legtöbb gyakorlatban előforduló eset kezelhető (szerintem).

A FieldEditor osztályok nagyon könnyen kezelhetőek: van köztük színválasztó, fontválasztó, egyszerű szöveges beviteli mező, checkbox, könyvtárválasztó és még sok minden más, egyszóval a gyakorlatban előkerülő legtöbb igényt le lehet fedni velük. És ami igazán fontos: ezek a megfelelő natív dialógusokat hívják be (pl. OSX-en a natív színválasztót, nem valami Javaból összetákolt valamit…).

A generált mintakód igazából három fájlból áll: a PreferenceConstants.java fájlban konstansokat lehet felvenni, amellyel később azonosíthatjuk az elmentett adatokat, a PreferenceInitializer.java fájlban a kezdőértékeket, míg az általunk választott nevű harmadik fájlban lehet összerakni a tényleges adatokat. Ezeket a fájlokat tovább nem is elemezném, ha valakit jobban érdekel, nézze meg, ennyi ismerettel könnyen érthető és módosítható igény szerint. Vagy meg lehet nézni a http://www.eclipsepluginsite.com/preference-pages.html oldalon a részletesebb kifejtést.

Inkább csak azt írom le, hogy ebbe hogyan lehet betenni a színkezelést (amit nem ír le az eredeti forrás). A form összerakásakor egyszerűen ColorFieldEditor-t kell létrehozni, hasonló paraméterezéssel, mint a mintában, míg az inicializálásnál a következő módon lehet gondolkodni:
PreferenceConverter.setDefault(store, PreferenceConstants.P_ENTITY_BG_COLOR, new RGB(216,226,248));

Azaz egy RGB értéket példányosítok, és ezt töltöm be alapértelmezésként. Ettől a pillanattól kezdve van egy kész színbeállító komponensem, menti is az adatait. Zsír. Akkor már csak egyszerűen be kell tudni olvasni. Szerencsére ez sem túl bonyolult. Ha egyszerűen Stringként akarom beolvasni a beállítást, és a stringet átadni a Color konstruktornak, akkor a következő kód jöhet számításba:
IPreferenceStore store = RmpPlugin.getDefault()
.getPreferenceStore();
String colorCode = store.getString(PreferenceConstants.P_ENTITY_BG_COLOR);

De lehet egyszerűbben is: a JFace tartalmaz egy PreferenceConvertert, aminek segítségével ez még egyszerűbben elintézhető.
RGB color = PreferenceConverter.getColor(store, PreferenceConstants.P_ENTITY_BG_COLOR);

Röviden összefoglalva ez is egy kényelmesen használható API, jól illeszkedik az Eclipse filozófiájába, aminek az az előnye, hogy gyorsan megtanulható, ráadásul kellően rugalmas is. Az előre megírt FieldEditorok pedig tényleg egyszerűvé teszik az egységes (ráadásul ugyanakkor platformfüggő!) kinézet összerakását a beállítópanelen is.

Ugyanakkor a végleges megoldásom nem ezt a menetet követi, helyette egy másik beépített megoldást használtam, de arról majd inkább legközelebb írok egy kicsit.