Právě jsme viděli, jak vytvořit dávku změn prostředků v procesu runnable (Dávkové zpracování změn prostředků). Podívejme se, jak vypadá druhá strana mince. Co když chcete sledovat všechny změny pracovního prostoru, ke kterým dojde, když je spuštěný váš modul plug-in? Můžete pomocí pracovního prostoru zaregistrovat IResourceChangeListener. Váš listener bude upozorňován na změny prostřednictvím objektu IResourceChangeEvent, který popisuje změny.
Nejprve musíte v pracovním prostoru zaregistrovat listener změn prostředků.
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener( listener, IResourceChangeEvent.POST_CHANGE);
Váš listener bude upozorněn po provedení úprav v pracovním prostoru. Metody API prostředků, které upravují prostředky, spouští tyto události jako součást svého zdokumentovaného chování. Komentář metody pro metodu API prostředku explicitně uvádí, zda spouští událost změny prostředku či nikoli. Například komentář k metodě IFile.setContents() obsahuje následující text:
Tato metoda mění prostředky; tyto změny budou hlášeny v následné události změny prostředků, včetně indikace, že byl změněn obsah tohoto souboru.
Metody, které vytvářejí, odstraňují nebo mění prostředek, zpravidla spouštějí tyto události. Metody, které prostředky čtou, ale nezapisují do nich, zpravidla tyto události nespouštějí.
Událost změny prostředku popisuje specifika dané změny (nebo množiny změn), ke které došlo v pracovním prostoru. Tato událost obsahuje rozdílová data prostředku, která popisují čistý efekt daných změn. Pokud například během jedné dávky změn přidáte prostředek a později jej znovu odstraníte, tento prostředek se v rozdílových datech neobjeví.
Rozdílová data prostředku jsou strukturovaná jako strom s kořenem v kořenu pracovního prostoru. Strom rozdílových dat prostředku popisuje tyto typy změn:
Pro procházení stromu rozdílových dat můžete implementovat rozhraní IResourceDeltaVisitor nebo tento strom procházet explicitně pomocí IResource.getAffectedChildren. Návštěvníci rozdílových dat prostředku implementují metodu visit, kterou rozdílová data prostředku volají, když tvoří výčet jednotlivých změn ve stromě.
Poznámka: V rozdílových datech nejsou označeny změny provedené ve vlastnostech relace prostředku nebo v trvalých vlastnostech prostředku.
Události změn prostředků se posílají, kdykoli dojde ke změně (nebo dávkové množině změn) pracovního prostoru. Kromě toho se události změn prostředků posílají také u jistých specifických operací pracovního prostoru. Níže uvedená tabulka shrnuje typy událostí změn prostředků a kdy jsou hlášeny.
Typ události |
Popis |
---|---|
PRE_CLOSE |
Oznamuje listenerům, že projekt bude zavřen. Tuto událost lze použít k extrakci a uložení nezbytných informací z paměťové reprezentace (např. vlastností relace) projektu, než bude zavřen. (Když je projekt zavřen, je paměťová reprezentace odstraněna.) Během této události je pracovní prostor uzamčen (nelze aktualizovat prostředky). Tato událost obsahuje projekt, který je zavírán. |
PRE_DELETE |
Oznamuje listenerům, že bude projekt odstraněn. Tuto událost lze použít k provádění operací vyčištění, například odebrání libovolného uloženého stavu, který se týká projektu, z adresáře vašeho modulu plug-in. Během této události je pracovní prostor uzamčen (nelze aktualizovat prostředky).Tato událost obsahuje projekt, který je odstraňován. |
PRE_AUTOBUILD |
Upozorňuje listenery předtím, než dojde k automatickému sestavení. Tato událost se vysílá, když platforma zjistí, že je třeba provést automatické sestavení, nezávisle na tom, zda je automatické sestavování vůbec aktivováno. Během této události není pracovní prostor uzamčen (prostředky je možné aktualizovat). Tato událost obsahuje rozdílová data prostředku popisující změny, ke kterým došlo od okamžiku, kdy byla hlášena poslední událost POST_CHANGE. |
POST_AUTOBUILD |
Upozorňuje listenery poté, co došlo k automatickému sestavení. Tato událost se vysílá potom, co by platforma provedla automatické sestavení, nezávisle na tom, zda je automatické sestavení vůbec aktivováno. Během této události není pracovní prostor uzamčen (prostředky je možné aktualizovat). Tato událost obsahuje rozdílová data prostředku popisující změny, ke kterým došlo od okamžiku, kdy byla hlášena poslední událost POST_CHANGE. |
POST_CHANGE |
Popisuje množinu změn, ke kterým došlo v pracovním prostoru od okamžiku, kdy byla hlášena poslední událost POST_CHANGE. Je spouštěna po použití API změny prostředků, ať již jednotlivě nebo v dávkové množině změn pracovního prostoru. Také je spouštěna po dokončení jakéhokoli upozornění PRE_AUTOBUILD nebo POST_AUTOBUILD. Tato událost obsahuje rozdílová data popisující čisté změny od poslední události POST_CHANGE. Během této události je pracovní prostor uzamčen (nelze aktualizovat prostředky). |
Následující příklad implementuje listener změn prostředků na bázi konzoly. Listener změn prostředků je registrovaný pro konkrétní typy událostí a informace o těchto událostech se tisknou na konzole:
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_AUTO_BUILD | IResourceChangeEvent.POST_AUTO_BUILD | IResourceChangeEvent.POST_CHANGE);
Listener hlídá výskyt jednotlivých typů událostí a hlásí informace o prostředku, který byl změněn, a druhy změn, k nimž došlo. Ačkoli má tento příklad ukázat obecný listener, který ošetřuje všechny typy událostí prostředků, typický listener by se registroval pouze pro jeden typ události.
Implementace pro POST_CHANGE používá jinou třídu, kterou lze využít k návštěvě změn v rozdílových datech prostředků.
import org.eclipse.resources.*; import org.eclipse.runtime.*; public class MyResourceChangeReporter implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { IResource res = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to close."); break; case IResourceChangeEvent.PRE_DELETE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to be deleted."); break; case IResourceChangeEvent.POST_CHANGE: System.out.println("Resources have changed."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.PRE_AUTO_BUILD: System.out.println("Auto build about to run."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.POST_AUTO_BUILD: System.out.println("Auto build complete."); event.getDelta().accept(new DeltaPrinter()); break; } } }
Třída DeltaPrinter implementuje rozhraní IResourceDeltaVisitor pro zjišťování informací o rozdílových datech. Metoda visit() je volána pro každou změnu prostředku v rozdílových datech prostředků. Pomocí návratové hodnoty návštěvník udává, zda navštívit rozdílová data pro podřízené prostředky.
class DeltaPrinter implements IResourceDeltaVisitor { public boolean visit(IResourceDelta delta) { IResource res = delta.getResource(); switch (delta.getKind()) { case IResourceDelta.ADDED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was added."); break; case IResourceDelta.REMOVED" System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was removed."); break; case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" has changed."); break; } return true; // navštívit podřízené prvky } }
Další informace lze získat z dodaných rozdílových dat prostředku. Následující úsek kódu ukazuje, jak může být implementován případ IResourceDelta.CHANGED, aby blíže popisoval změny prostředků.
... case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(delta.getFullPath()); System.out.println(" has changed."); int flags = delta.getFlags(); if ((flags & IResourceDelta.CONTENT) != 0) { System.out.println("--> Content Change"); } if ((flags & IResourceDelta.REPLACED) != 0) { System.out.println("--> Content Replaced"); } if ((flags & IResourceDelta.MARKERS) != 0) { System.out.println("--> Marker Change"); IMarkerDelta[] markers = delta.getMarkerDeltas(); // pokud vás zajímají značkovače, projděte si tato rozdílová data } break; ...
Úplný popis rozdílových dat prostředků, návštěvníků a rozdílových dat značek naleznete ve specifikaci API pro IResourceDelta, IResourceDeltaVisitor a IMarkerDelta.
Poznámka: Listenery změn prostředků jsou užitečné pro sledování změn, ke kterým u prostředků dochází, když je váš modul plug-in aktivovaný. Pokud si váš modul plug-in registruje listener změn prostředků během spouštěcího kódu, je možné, že bylo mnoho událostí změn prostředků spuštěno ještě před aktivací samotného modulu plug-in. Rozdílová data prostředků obsažená v první události změny prostředku, kterou váš plug-in obdrží, nebudou obsahovat všechny změny, k nimž došlo od okamžiku, kdy byl váš plug-in naposledy aktivovaný. Pokud potřebujete dohledat změny provedené v době mezi aktivacemi vašeho modulu plug-in, měli byste využít poskytovanou podporu pro ukládání pracovního prostoru. Ta je popsána v tématu Účast na uložení pracovního prostoru.
Poznámka: Některé události změn prostředků se spouštějí během zpracování, k němuž dochází ve vláknu na pozadí. Listenery změn prostředků by měly být z hlediska vláken bezpečné. Debatu o bezpečnosti vláken a uživatelském rozhraní naleznete v tématu Problematika používání vláken.