Delphi tools - Project managerGeplaatst door Baldo op 13-08-03Dynamische applicaties is een van mijn favoriete onderwerpen op NLDelphi. Bij
het bouwen van dynamische applicaties wordt vaak gewerkt met project groups.
In het vorige
deel van Delphi tools heb ik compiler commands besproken die praktisch noodzakelijk
zijn om goed te kunnen werken met deze project groups. Deze keer voeg ik nog
wat functionaliteit toe aan de project manager om het echt vlot werkbaar te
maken.
Het idee
Het komt regelmatig voor dat ik in de project manager moet zijn om te wisselen
van project. Ik stap dan echter vervolgens in de editor regelmatig over naar
een openstaande unit uit een ander project. Wil ik dan een form of unit selecteren
uit het project van de unit die ik in de editor geselecteerd heb, dan ben ik
verplicht weer naar de project manager over te schakelen om het overeenkomstige
project te selecteren (of het form of de unit hierbinnen). Ik wil dit vanwege
RSI preventie met het toetsenbord kunnen doen, maar als je de project manager
dockt (wat ik doe voor het overzicht) dan ben je verplicht de muis te gebruiken.
Ook kan ik niet van project wisselen zonder naar de project manager over te
schakelen en daarbinnen een ander project te selecteren. Het zou toch
wel fijn zijn als ik met een enkele toetsaanslag het vorige of volgende project
kon selecteren zonder de editor te verlaten.
En wat bij het bouwen van dynamische applicaties helemaal ideaal zou zijn is
dat er een mogelijkheid zou zijn om de shell applicatie (voor meer informatie,
zie het artikel
over dynamische applicaties) te starten ongeacht welk project actief is.
Tijd dus om die project manager wat beter bedienbaar te maken. De vorige
artikelen over de open tools api hebben bij alle technieken besproken die
hiervoor noodzakelijk zijn, dus dit artikel is een goede samenvatting van reeds
vergaarde kennis.
We gaan de project manager uitbreiden met de volgende opties: Select
project of current unit, Select prior project, Select
next project en Run project group executable.
De OTA
Voor de eerste drie opties kan gebruik gemaakt worden van het IOTAProject interface
dat reeds besproken is in het
artikel over compiler commands.
Voor de optie Run project group executable zal wat meer werk verricht
moeten worden. Delphi biedt namelijk vanuit het IOTAProject interface wel faciliteiten
om het project te compileren of builden, maar niet om het te starten. Die functionaliteit
zit verrassend genoeg in het IOTAEditActions interface verstopt, een interface
op de Delphi editor. Maar meer daarover als we de specifieke code van dit onderdeel
bespreken.
Select project of current unit
Bij het
artikel over compiler commands was al te zien hoe het project van de huidig
geselecteerde unit kan worden bepaald. Daarbij dus weinig nieuws. Het enige
nieuwe van deze optie is hoe het betreffende project als actief project kan
worden geselecteerd. Het IOTAProjectGroup interface kent een ActiveProjectGroup
property die gezet kan worden naar een van de projecten uit de project group.
// Als er een project gevonden is, selecteer het dan if ModuleProjectIndex <> -1 then begin // Maak het project van de module het active project ProjectGroup.ActiveProject := ProjectGroup.Projects[ModuleProjectIndex]; end;
Zoals ook al eerder gezegd is de GetProjectGroup functie vaker opgenomen
en is het wellicht handig om een aparte unit met open tools api functies te
beginnen waarin al dergelijke functies zijn opgenomen. Om de eenvoud van distributie
van de individuele ide menu uitbreidingen te verhogen laat ik dat wederom achterwege.
Select prior project
Ook bij het selecteren van het vorige project kan gebruik gemaakt worden van
kennis uit het
artikel compiler commands. Het bepalen van het actieve project is reeds
uitgezocht, nu is het alleen nog een kwestie van het actief maken van het project
ervoor. Dit is terug te vinden in de method TIdeMenuSelectPriorProject.Execute
van unit uIdeMenuSelectPriorProject.
// Als er iets gevonden is en het is niet de eerste, selecteer dan if (CurrentProjectIndex <> -1) and (CurrentProjectIndex <> 0) then ProjectGroup.ActiveProject := ProjectGroup.Projects[CurrentProjectIndex - 1];
Select next project
Het volgende project selecteren is dan eigenlijk vrijwel hetzelfde, te vinden
TIdeMenuSelectNextProject.Execute in van unit uIdeMenuSelectNextProject.
// Als er iets gevonden is en het is niet de laatste, selecteer dan if (CurrentProjectIndex <> -1) and (CurrentProjectIndex <> (ProjectGroup.ProjectCount - 1)) then
ProjectGroup.ActiveProject := ProjectGroup.Projects[CurrentProjectIndex + 1];
Run project executable
Het interessante gedeelte zit in de Run project executable optie.
Hierbij wordt door alle projecten van de project group heen gelopen om te bepalen
of het project een executable is.
Executables onderscheiden zich van packages doordat de project extensie .dpr
is in plaats van .dpk. Maar het vervelende is dat dlls ook de .dpr
extensie gebruiken, en dat zijn nu juist niet de projecten die gestart moeten
worden.
De oplossing voor dit probleem is te vinden in de project options. Het IOTAProject
interface biedt toegang tot de project options van het project. Als de project
option met de naam GenDll op True staat, dan betekent dat voor Delphi
dat het project als dll gecompileerd moet worden. Door hierop te controleren
bij het zoeken naar de executable kan worden bepaald welke .dpr de eigenlijke
executable is.
// Als het geen dll betreft, dan is het de exe en kan de loop doorbroken worden if not ProjectGroup.Projects[p].ProjectOptions.Values['GenDll'] then begin ExeProjectIndex := p; Break; end;
Op deze manier is het dus mogelijk om de eerste executable uit de project group
te vinden. Ik ga er van uit dat er in een project group maar één
executable is die gestart moet worden (wat bij dynamische applicatie project
groups veelal het geval is).
Het starten van de executable is weer een heel ander probleem. Delphi beschouwd
de Run functionaliteit als een actie op de editor. Om deze functionaliteit
te kunnen benaderen zal het IOTAEditActions interface gebruikt moeten worden.
Het IOTAEditActions interface kan echter alleen benaderd worden via het IOTAEditView
interface, een interface op de code editor. En een interface op de code editor
kan worden vekregen via het IOTAEditorServices interface.
Door aan BorlandIDEServices te vragen of het IOTAEditorServices interface momenteel
beschikbaar is (met andere woorden: of de editor beschikbaar is) kan een referentie
naar EditorServices verkregen worden. Door vervolgens een referentie naar het
interface van het actieve venster in de editor op te vragen kunnen we bij een
IOTAEditView interface komen. In de code is dit geïmplementeerd in de GetTopView
functie.
function GetTopView: IOTAEditView; var EditorServices: IOTAEditorServices; begin if Supports(BorlandIDEServices, IOTAEditorServices, EditorServices) then Result := EditorServices.TopView else Result := nil; end;
Het IOTAEditView interface biedt de method RunProgram door gebruik te maken
van het IOTAEditActions interface. RunProgram is echter alleen van toepassing
op het actieve project. Het is dus van belang om het project van de executable
als actief project te zetten en we hebben zojuist kunnen zien hoe dat moet.
// Als er een project gevonden is, selecteer dit dan als actief project en // run het project if ExeProjectIndex <> -1 then begin // Maak exe project actief ProjectGroup.ActiveProject := ProjectGroup.Projects[ExeProjectIndex];
// Run (TopView as IOTAEditActions).RunProgram; end;
De menu opties
Om de nieuwe compiler opdrachten beschikbaar te maken wordt opnieuw gebruik
gemaakt van de IDE menu uitbreiding al eerder beschreven. En weer geldt dat
het toevoegen van de units uIdeMenuSelectUnitProject,
uIdeMenuSelectPriorProject, uIdeMenuSelectNextProject,
uIdeMenuRunExeProject en het aanmaken
van een instance van de overeenkomst classes in de constructor van de expert
voldoende is. Natuurlijk is voor de mensen die liever niet zelf de code aanpassen
weer een aangepaste versie van het IdeMenu package
beschikbaar.
Conclusie
De project manager mist op een aantal punten faciliteiten om er prettig mee
te werken, maar wederom bewijst de open tools api haar nut door voldoende mogelijkheden
te bieden om zelf oplossingen te maken. De in de vorige
artikelen opgedane kennis is zo goed als voldoende om nog een aantal zinvolle
toevoegingen op de Delphi IDE te maken. Ik hoop dat iedereen die zich beperkt
voelt door de faciliteiten die Delphi standaard biedt inmiddels inziet dat wat
ontbreekt op eenvoudige wijze kan worden toegevoegd.
|