Az első harapások az almából

Miután tavaly nyáron tönkrement amúgy sem túl powa laptopom, úgy döntöttem, megválok pingvinemtől és SzuperTehenemtől, és veszek egy MacBookot (remélve, hogy nem fog MacBook-ni). Miért? Azt gondoltam, az OSX megvalósítja azt a közel ideális koncepciót, hogy egy szilárd alapra (UNIX) egy jól átgondolt architektúrával egy emberközeli, ergonomikus rendszer épüljön. Pár hónapos intenzív használat után az alábbi tapasztalatokat gyűjtöttem össze a Leoparddal kapcsolatban.

Ami a legnagyobb pozitívum: minden működik, nem kell semmivel szívni. Olyan alapdolgok, amelyek bár Linux alatt is triviálisak lennének, de valami rejtélyes okból kifolyólag csak konfigfájlokban való turkálásokkal lehetett megoldani, automatikusan vagy egy kattintásra működtek, pl. MIDI-lejátszás, fájl-, ill. vezetékes netmegosztás Windows géppel. Ugyanakkor azt hallottam, és ezt el is tudom képzelni, hogy valami viszont
nem működik, akkor alányúlni a rendszernek a javítás végett nagyon macerás. Szerencsére velem még nem történt ilyesmi.

Természetesen semmi sem tökéletes. Amikor sorra veszem a különböző aspektusokat, bizony bosszantó apróságokról is szót kell ejtenem, amelyek főleg kezdetben rontják az összképet, és hiába szokja meg őket az ember, még sok idő után is képesek néha meglepetést okozni. Sokszor bagatellnek tűnhetnek, de igenis számolni kell velük. Előre kell bocsátanom, hogy ha valamit hiányolok, természetesen előfordulhat, hogy csak én nem találtam a problémára megoldást, ilyenkor tessék nyugodtan szóvá tenni kommentben. 🙂 De akármennyire is kritikusnak tűnik az értékelés, ez ne legyen megtévesztő: végső soron nagyon elégedett vagyok a rendszerrel.

Felhasználói felület: parasztvakítás vagy célszerűség?

Kezdjük a felszínen. Tény: a felület jól néz ki. Ez néhol öncélú eye candy (pl. a default animációk közül a genie és a ripple lassú és zavaró), néhol viszont fontos használhatósági szempontokat szolgál. Ha szabad ilyen apróságokat is említenem, a window chrome minimális területet foglal, és mégis esztétikus. Az alapbeállítású fontméret pedig az én kijelzőm és szemem számára arany középutat képvisel az áttekinthetőség és kompaktság között. Viszont a hosszú neveket nem lehet mindig teljes egészében megjeleníteni, csak három ponttal lerövidítve: ez a Finderben bizonyos fájlneveknél fordult elő, sőt, a Thunderbirdben a “A szemétként megjelölt levelek törlése a mappában” menüpontnál is!

Mi a menü?

Az egységesítés igénye is nagy előny, mely a rendszer sok más részében is megnyilvánul. Ami elsőre feltűnik, hogy nem csak a menüsor helye, hanem a beállítások (és egyéb, minden alkalmazásra jellemző parancs) helye a menürendszerben is centralizált, és ami fontos, a billentyűparancsa is. A menük viszont nem ciklikusak, pedig ez igen jól jönne néhol billentyűzettel való navigáció esetén. Egér használatakor viszont az a furcsa, hogy a szöveges menüből lehet egeret mozgatva navigálni az ikonokra, fordítva viszont nem.

Ablakok (nem picipuha!)

Az is pozitív apróság, hogy a módosított dokumentum ablakának változik a bezárás ikonja. A maximalizálás funkció viszont néhol nem az elvárt módon működik (némely alkalmazásoknál nehéz is értelmezni, mi az a legkisebb terület, amin ugyanakkor minden látszik), különösen éppen a Finderben. A modális gyermekablakok szülőablakhoz kötése nagyon jó ötlet (így nem történhet meg, hogy eltűnik a gyermekablak, és nem tudjuk, miért nem válaszol a szülő), viszont mozgathatónak kénne lenniük, hisz előfordulhat, hogy éppen olyan információt takarnak el, ami szükséges lenne a megválaszolásukhoz. Az ablak-alkalmazás megkülönböztetés, bár szokatlan, de szerintem szerencsés. Viszont nem mindig egyértelmű, mi szolgál a bezárásra, és mi a kilépésre: pl. a System Preferences az ablakának bezárásákor kilép. Az ablakokról még annyit, hogy hiányzik a KDE-ben megszokott snap mechanizmus, amely ablakok mozgatásánál a képernyő vagy másik ablak széléhez passzintja őket. Erre igazán gondolhattak volna a fejlesztők.

Jó és rossz ötletek kikötője

A Dock alapkoncepciója (egy felületen a kedvenc és futó alkalmazások) nekem bejön. De alapvető hibája, hogy nincs neki dedikált képernyőterület, és így (főleg a képernyő oldalára helyezve) mögékerülnek ablakok! Ha pedig lent helyezkedik el, a visszaverődő felület számomra zavaró tud lenni – ez az öncélúság, amire fent utaltam. Az, hogy a Dock változtatja a méretét, nem működik jól együtt a maximalizálással, valamint így mozognak a rajta levő ikonok, s nincs az elemeknek egy megszokott helyük, melyre ösztönösen oda lehetne kattintani. Nem kerülne sokba, ha az éppen aktuális alkalmazás ki lenne emelve, pedig olykor hasznos lenne.

Végül úgy oldottam meg a kérdést, hogy az itt leírt módszerrel megszüntettem a visszaverődést, a Dock maradt a képernyő alján, de bekapcsoltam az automatikus elrejtést – így felszabadul az értékes függőleges terület, és nincs gond a méretváltoztatással, a futó programok listája úgyis látszik Cmd+Tab-os programváltáskor.

Működés

Először igen meglepett, hogy a szövegdobozok natívan nem támogatják a visszavonás funkciót. Így van, amelyik alkalmazásban ez elérhető, van, amelyikben nem.

Billentyűzetkiosztás

Nem tudom, miért kellett oly sok konvenciótól elrugaszkodni az Apple-nek a funkciógombok kapcsán. A Cmd gomb nem a Ctrl helyén van, viszont nem is mindig a Ctrl-t helyettesíti. Az Alt és Fn billentyűk közül nem mindig egyértelmű, melyik szolgál módosítóként. Az, hogy nincs külön Home/End és PageUp/PageDn billentyűpáros, nem lenne nagy baj, ha konzisztensen kezelnék az alkalmazások, de én sajnos legalább 3-féle variációt láttam eddig az Fn/Ctrl/Cmd + navigációbillentyűk értelmezésére. Az AltGr hiányának egyik következménye, hogy (a default magyar billentyűzetkiosztásban, amit, amint megtudtam a módját, átírtam a PC-s változatra) sok gyakori karakter csak 2 módosítóbillentyűvel hívható elő, a másik, hogy a menüknek nincsenek gyorshívó billentyűi. Ez csak egy komponense annak, hogy (legalábbis az én szokásaimhoz képest) a rendszer nem eléggé billentyűzhető.

Fájlrendszer

A ponttal kezdődő rendszerfájlok kezelése szerintem túl szigorú, bár lehet, hogy csak fejlesztőként gondolom így, túl sokszor lehet dolgom ilyen fájlokkal (pl. .htaccess). Így nem csoda, hogy a .DS_Store megoldás is zavar. Az viszont tetszik, hogy a nézetek automatikusan frissülnek a fájlrendszer módosításakor. A társításkezelés ugyanakkor először megzavart: a társítás nem kiterjesztésenként, hanem fájlonként érvényesül, a kiterjesztésenkénti társítást bonyolultabban, a Finder Info ablakában kell beállítani.

Felhasználókezelés

Hiányzik az, hogy a rendszer megjegyezze a leállításkor éppen futó programokat, és újraindításkor újra elindítsa őket. A felhasználóváltást pedig cseles helyre tették: nem a rendszermenübe a kijelentkezés mellé mondjuk, hanem a Lock Desktop alkalmazás szolgál erre.

Alkalmazások

Az OSX alkalmazáskezelési mechanizmusa kétélű kard: a telepítés nagyon egyszerű és intuitív, az eltávolítás viszont nem mindig teljes értékű. Amikor pedig először találkoztam a netről letöltött alkalmazás futtatásának kérdésével, a Vista jutott eszembe, de ez csak reflex, ez a dialógusablak jó is, hogy figyelmeztet erre, és informatív.

Finder

A beépített programok közül éppen a Finderrel volt a legtöbb bajom. Míg pl. a Mailben az accounttól függetlenül egyesített mappák ötlete olyasmi, amit minden levelezőprogramban szeretnék látni, a Findert rövidesen lecseréltem a muCommanderre, abban többek között tömörítvényekben is tudok járkálni, amit gyakran szoktam, de ez se ideális megoldás, lévén lassú és nagyon instabil. Szóval, mi is a bajom a Finderrel? Érdekes módon azok, amiket az internetes közösség már jó ideje egyhangúlag nagyon gáznak minősít. Csak címszavakban:

  • Az Enter átnevez és nem megnyit, és ezt még át sem lehet konfigurálni. Bár léteznek segédprogramok, melyekkel ezt át lehet hackelni, de akkor pl. az átnevezés végén lenyomott Enter is megnyitást eredményez, ill. előfordulhat, hogy nem működnek a Spotlightot és a QuickSilvert aktiváló default billentyűkombinációk.
  • Könyvtárak felülírásakor a Finder a struktúrát nem merge-eli, hanem ami a régi könyvtárban megvolt, de az újban nincs, azt törli. Az így elveszett fájlokat vissza sem lehet állítani.
  • Ami igazán elvárható lenne: az ablakban sehol nem látszik az aktuális elérési út. (Az ablak fejlécére jobb gombbal kattintva ez elérhető, de én valami breadcrumb-szerűséget hiányolok.)
  • Az oszlop nézet nem lenne rossz, de itt is hiányosságok tapasztalhatóak: a kezdeti méret nagyon kicsi, maximalizáláskor pedig előfordul, hogy kilóg a képernyőterületről az ablak. Nem találtam olyan billentyűkombinációt, amellyel a lista tetejére és aljára ugrani.
  • Átnevezésnél nincs lehetőség felülírásra.

Ami viszont tetszett, az a lista nézet tetszőleges mélységig kinyitható könyvtárfája, valamint a pluginekkel látványosan egy csomó tartalomtípusra kiterjeszthető Quick Look.

Automator

Ez az eszköz nagyon ott van! Az, hogy ilyen magas szintű automatizálás rendszerszinten van támogatva, és újrafelhasználható, paraméterezhető munkafolyamatokat lehet létrehozni, sok lehetőséget nyit meg az ember előtt. Én elsősorban tömeges fájl- és képműveletekre szoktam használni (ezekhez más oprendszereken alkalmazásonként külön vagy van támogatás, vagy nincs), de még annyi minden lehetséges. (Ugyanakkor nem mindegyik paraméter van korrektül implementálva, pl. bizonyos fotóműveleteknél a százalékos értéket nem lehet százalék pontossággal megadni.)

Szolgáltatások

  • Growl: Az egységes notifikációs API természetes felhasználói igény, és nagy lépés afelé, hogy ami általános szolgáltatás, arra egyetlen interfész legyen a rendszerben.
  • Spotlight: Az inkrementális keresés jó, de akad egy kis kellemetlenség: amikor folytatom a gépelést, akkor amíg még folyik a keresés, már nem kéne érvényesnek lennie az eddigi találatoknak, hiszen a keresési kulcs már megváltozott.
  • AirPort: Csak egy dolgot hiányolok: az elérhető hálózatok jelerősségének kijelzését.

Konklúzió

Mint már mondtam, az összbenyomás egyértelmű elégedettség: az említett negatívumok egyike sem megkerülhetetlen vagy megszokhatatlan, és egy megbízható, produktivitást serkentő rendszert kapunk, melyhez sok remek program létezik (és ezen belül a szabad szoftverek száma örvendetesen nő), ld. [intlink id=”683″ type=”post”]Stampie válogatását[/intlink]. És végül fontosnak tartom hangsúlyozni, hogy az itt leírtak az én személyes tapasztalataim és az én felhasználói szokásaimhoz igazodnak: your mileage may vary, ahogy a művelt francia mondaná. 🙂 Ha esetleg valakinek megjött az étvágya az ominózus almához: jó falatozást!

Kottaszerkesztés LilyPonddal OSX-en

A LilyPond ugyanaz a kottaszedésben, mint a LaTeX dokumentumszedésben, minden szempontból: tipográfiai szabványoknak és konvencióknak eleget tevő, gyönyörű kimenetet generál egy szöveges formában megadott forrásfájlból. Azonban nincs könnyű dolguk azoknak, akik össze szeretnék házasítani kedvenc Leopardjukkal. Sem a LilyPond grafikus felülete, sem a magyar fejlesztésű, nagyon sokat tudó LilyPondTool nevű jEdit plugin nem működik az OSX legújabb verziója alatt.

Kompromisszumos megoldásként nekem a TeXShop használata jött be. Amit így kapunk, az a PDF-előnézet, az ismerős munkafolyamat és a szintaxiskiemelés. Sajnos a hangról forrásfájlra ugrás nem működik, valamint a generált MIDI-t is kézzel kell megnyitnunk.

  1. Telepítés: Töltsük le innen a 2.12 verziót MacOS X alá, méghozzá a G3, G4, G5 Macs (sic!) változatot, akkor is, ha Intel alapú Mac-ünk van! Szokásos módon tegyük az /Applications könyvtárba a LilyPond.app-ot.
  2. Parancssori támogatás: A PDF-generálás sajnos ékezetes fájlneveknél nem működik, így írtam egy cseles shell scriptet, ami ezt megoldja, és az ideiglenes PostScript fájlt is eltakarítja:

    #! /bin/sh
    dirname=$(dirname "$1")
    basename=$(basename "$1" .ly)
    filename="${dirname}/${basename}"
    tempname="${dirname}/.tmp"
    /Applications/LilyPond.app/Contents/Resources/bin/lilypond -o "${tempname}" "$1"
    if [ -f "${tempname}.pdf" ]; then
    mv "${tempname}.pdf" "${filename}.pdf"
    fi
    if [ -f "${tempname}.midi" ]; then
    mv "${tempname}.midi" "${filename}.midi"
    fi
    rm -f "${tempname}.ps"

    Mentsük el /usr/bin/lilypond néven, és varázsoljuk futtathatóvá:

    sudo chmod +x /usr/bin/lilypond
  3. TexShop támogatás: Mivel a piszkos munkát elvégzi a fenti script, már csak az alábbi hihetetlenül bonyolult TeXShop engine-nel kell bővíteni a repertoárt ([cci]~/Library/TeXShop/Engines/LilyPond.engine[/cci]):

    #! /bin/sh
    echo "Processing..."
    lilypond "$1"
    echo "Done."

    Itt van még egy dummy LilyPond template ([cci]~/Library/TeXShop/Templates/LilyPond.tex[/cci]):
    [cc]
    \version “2.12.2”

    \header {
    title = “”
    composer = “”
    tagline = “”
    }

    \score {
    <>

    \midi {
    }

    \layout {
    }
    }

    \paper {
    }[/cc]

    Ezután nincs más dolgunk, mint hozzátársítani a [cci].ly[/cci] kiterjesztést a TeXShop.app-hoz, és készen is vagyunk.

Még egy dolog. Ha Finale vagy Sibelius kottáinkat át szeretnénk konvertálni LilyPondba, a migrációs folyamat köztes lépéseként a MusicXML formátumot vehetjük igénybe. A Finale alapból tartalmaz MusicXML plugint, a File/MusicXML/Export… paranccsal végezhető el az exportálás. Sibeliushoz külön le kell tölteni a megfelelő plugint, ehhez ez az oldal nyújt segítséget. (A plugin batch mode-ot is támogat, ezt érdemes kihasználni.)

A MusicXML fájlokat a [cci]/Applications/LilyPond.app/Contents/Resources/bin/musicxml2ly[/cci] programmal konvertálhatjuk LilyPondba. Ez nem tökéletes, sajnos még picit bugzik a segédprogram, én főleg a dalszövegek melizmáinál tapasztaltam problémát, úgyhogy ne felejtsük el utólag átnézni az eredményt, és szükség esetén kézzel finomhangolni.

Források

2D adatszerkezet modellezése Javában

…avagy hogyan lehet pozitív tulajdonság a gyengeség és a lustaság. 🙂

Arról a gyakran előforduló modellről van szó, amikor sorok és oszlopok metszeteiben rácselemek csücsülnek, melyek automatikusan létrejönnek a nekik megfelelő sor-oszlop párra való hivatkozáskor, valamint automatikusan megszűnnek soruk vagy oszlopuk törlése esetén.
A megvalósítás kézenfekvőnek tűnik: a sorokban/oszlopokban egy map-ben tároljuk az oszlopokkal/sorokkal indexelve a rácselemeket.

Valahogy így:
[cc_java]
public class Node {
}

public class Column {
}

public class Row {

protected final Map nodes = new HashMap();

public Map getNodes() {
return nodes;
}

}
[/cc_java]

Mi a gond ezzel?

  • Ha törlünk egy oszlopot, az összes sor map-jében még ott marad a rá mutató referencia, mint kulcs. Ez memory leakhez vezet: a szemétgyűjtő nem tudja eltakarítani a “zombi” oszlopokat és a hozzájuk tartozó, ugyancsak zombi rácselemeket. Ez ráadásul az adatstruktúra perzisztálásánál is problémát jelent.
  • Hogyan s mikor hozzuk létre a rácselemeket? Mindig, amikor létrehozunk egy oszlopot? Ezt jobban lehetne automatizálni, ráadásul ha nem minden rácspontba akarunk elemet tenni, fölöslegesen hozzuk létre ezeket.

Több megoldás is lehetséges, gondolhatnánk elsőre:

  • Gondolkodhatnánk egy címkézett gráfban, és a beépített kollekciók helyett alkalmazhatnánk valamiféle gráfkezelő könyvtárat, pl. a JGraphT-t, mely gondoskodik csúcs törlésekor a hozzá tartozó élekről.
  • Kibővíthetnénk a lista adatszerkezetet eseménykezelőkkel, melyek elem hozzáadásakor és törlésekor végrehajtanak egy megadott kódot.

Azonban a probléma megoldható a Java Collections Framework keretein belül, karöltve természetes kiegészítőjével, a Collections Generic API-val (a Commons Collections generikus változata). Nehogy már egy ilyen általános jelenséget ne tudjunk a megannyi hasznos absztrakciót tartalmazó Java nyelv elemeivel modellezni! A kulcsfogalom a gyenge referencia, mellyel befolyásolhatjuk a garbage collector működését, ezzel rábízva az elárvult elemek törlését.

Javában az alapértelmezett referencia erős (strong), de ezenkívül még létezik a gyenge (weak), lágy (soft) és fantom (phantom) referencia. A weak reference lényege, hogy amennyiben egy objektumra csak ilyenek mutatnak, a szemétgyűjtő teljes lelki nyugalommal eltakarítja. Nekünk pont ez a viselkedés jön kapóra: a map-ben gyenge referenciákat fogunk csak tárolni az oszlopokra/sorokra. (A másik két típus most nem érdekes számunkra, pedig azok is hasznosnak bizonyulhatnak más esetekben.)

A Collections API tartalmazza a WeakHashMap osztályt, mely a HashMap-hez hasonló, azonban kulcsai gyenge referenciák. A WeakHashMap ezeket átlátszóan kezeli, önmagától létrehozva és dereferálva nekünk őket. Így programunkban az automatikus törléshez csak két dolgot kell módosítanunk: HashMap helyett WeakHashMap-et használunk, és a kívánt pillanatban meghívjuk a garbage collectort.

A létrehozás pedig lusta map segítségével történik: a rácselemek példányosítása akkor és csak akkor történik, amikor először hivatkozunk az őket azonosító sor-oszlop párosra. Ehhez is kész eszközt kapunk a kezükbe a Collections Generic Libraryben: a LazyMap-et és az InstantiateFactory-t, melyek a Decorator és a Factory pattern alkalmazásával érik el céljukat.

Imhol a forráskód módosított része. Figyelemreméltó, hogy mennyi minden változott…
[cc_java]
public class Row {

protected final Map nodes = LazyMap.decorate(new WeakHashMap(), new InstantiateFactory(Node.class)); // !

}
[/cc_java]

És egy kis tesztosztály, a kiértékelés a kedves olvasó feladata:
[cc_java]
public class GridTest {

public static void main(String[] args) {
Grid grid = new Grid();
for (int i = 0; i < 2; i++) {
grid.getRows().add(new Row());
grid.getColumns().add(new Column());
}
for (Row row : grid.getRows()) {
for (Column column : grid.getColumns()) {
System.out.println(row.getNodes().get(column));
}
}
grid.getColumns().remove(1);
System.gc(); // !
for (Row row : grid.getRows()) {
for (Column column : row.getNodes().keySet()) {
System.out.println(row.getNodes().get(column));
}
}

}

}
[/cc_java]

Hát ilyen power a Collections Framework, amint már Stampie is [intlink id=”587″ type=”post”]rámutatott[/intlink], ami pedig esetleg hiányzik belőle, azt a Collections Generic pótolja. Mi a tanulság? Használjuk ki a nyelvi lehetőségeket, amelyek rendelkezésünkre állnak!