|
Delphi tools: Project manager
Erik Stok (aka Baldo)
Dynamische applicaties is een van mijn favoriete onderwerpen op
NL Delphi. 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.
Conslusie
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.
|