Programmierung

Hey Designer!

Im letzten Artikel ging es um den Aufbau und die Funktionalität der Plugin-Schnittstelle. In diesem Artikel möchte ich Ihnen mit Hilfe eines Beispiels diese näher erläutern.


Einleitung

Im Designer können Design-Forms über den Öffnen-Dialog geöffnet werden. Manchmal wäre es jedoch vorteilhaft, einen Assistenten zu haben, welcher permanent eine Liste der vorhandenen Dialoge darstellt, die dann einfach per Doppelklick geöffnet werden können, ohne dass die Arbeit im Designer unterbrochen werden muss (in Analogie zum Prozedur-Assistenten). Der vorliegende Artikel zeigt auf, wie dies mit einer Plugin-Anwendung realisiert werden kann.

Die Plugin-Anwendung soll in CONZEPT 16 entwickelt werden (siehe Abbildung unten) an. Neben der Liste wird ein Preview des Dialoges dargestellt (in der Abbildung rechts zu sehen). Durch Doppelklick auf einen Eintrag kann der Dialog im Designer geöffnet werden. Gleiches passiert bei Klick auf die Schaltfläche Öffnen. Einen Dialog können Sie mit ein paar Mausklicks über den Designer öffnen, aber mit Hilfe der Plugin-Anwendung und der Plugin-Funktionalität benötigen Sie nur einen Mausklick.

Da unsere Plugin-Anwendung in derselben Datenbank läuft wie der Designer, kann die Liste mit den Dialogen mit Hilfe des StoList-Objekts realisiert werden. Hierfür brauchen wir die Plugin-Funktionalität noch nicht. Erst wenn der Anwender auf die Liste doppelt klickt, kommen die Plugin-Funktionen ins Spiel, da dann der entsprechende Dialog im Designer geöffnet werden soll. Umgekehrt soll bei Aktivierung eines Dialoges im Designer der entsprechende Eintrag in der StoList ausgewählt werden.

Die Abbildung zeigt die fertige Plugin-Anwendung.

Erstellen der Instanz und Anmeldung

Zum Empfangen von Designer-Ereignissen bzw. zum Senden von Befehlen müssen wir eine Verbindung zwischen dem Designer und der Plugin-Anwendung aufbauen.

Voraussetzung für eine Kommunikation zwischen Designer und Plugin-Anwendung ist die Plugin-Instanz und die Authentifizierung.
Die Funktion Plugin.Core:InstanceNew() erstellt eine neue Plugin-Instanz.

// Plugin-Instanz erstellen
gPluginInstanceID # Plugin.Core:InstanceNew(sPluginPort,sPluginTimeout,gPluginWinFrame);

Die Plugin-Anwendung muss sich beim Designer auf dem Port des Designers und dem richtigen Passwort authentifizieren, damit eine Kommunikation stattfinden kann.

Die Anwendung wartet zuerst auf eine Authentifizierung der Designer-Seite, die unmittelbar nach dem Herstellen der Verbindung an die Plugin-Anwendung gesendet wird. Im Quelltext macht dies der Befehl Plugin.Converter:ReceiveAuth(). Er bekommt als Argument die zuvor erstellte Instanz-Nummer übergeben. Wurde die Authentifizierung erfolgreich empfangen, dann antwortet die Plugin-Anwendung mit dem Befehl Plugin.Converter:ReplyAuth() und sendet hiermit das Passwort an den Designer. War die Authentifizierung erfolgreich, liefert der Befehl _ErrOK. Damit ist die Initialisierung der Plugin-Anwendung abgeschlossen.

if (gPluginInstanceID > 0)
{
  // Plugin-Kennwort für Authentifizierung
  tPassword # sPluginPassword;

  // Name der Plugin-Anwendung in das Anwendungsprotokoll übernehmen
  tPluginName # 'Dialog-Manager - ' + mIntToAlphaDec(gPluginInstanceID);

  // Authentifizierung
  tResult # Plugin.Converter:ReceiveAuth(_ReceiverByInstanceID,gPluginInstanceID,var tSerial,var tUser,sPluginTimeout);
  if (tResult = _ErrOK)
    tResult # Plugin.Converter:ReplyAuth(gPluginInstanceID,tSerial,tPluginName,var tPassword,sPluginTimeout);

  if (tResult = _ErrOK)
    gPluginWinFrame->wpCaption # tPluginName;
  else
  {
    Plugin.Core:InstanceClose(gPluginInstanceID);
    gPluginInstanceID # 0;

    WinDialogBox(0,aCaption,'Anmeldung fehlgeschlagen.' + StrChar(13) + StrChar(10) +
                     'Fehler ' + mIntToAlphaDec(tResult) + '.',_WinIcoError,_WinDialogOk,1);
  }
//...
}

Die Plugin-Instanz schließen wir, wenn der Anwender die Plugin-Anwendung beendet mit der Funktion Plugin.Core:InstanceClose().

// Plugin-Instanz schließen
Plugin.Core:InstanceClose(gPluginInstanceID);

Öffnen eines Dialoges

Der folgende Quelltext-Ausschnitt zeigt, wie ein Dialog von der Plugin-Anwendung im Designer geöffnet wird, wenn der Anwender auf einen Eintrag doppelt klickt.

// Plugin-Kommando erstellen
tPluginCmd # Plugin.Converter:CreateCmd(sPluginCmdKindCmd, 'Designer.Forms.Open');
if (tPluginCmd > 0)
{
  // Name und Typ des Dialogs übergeben
  tPluginCmd->Plugin.Converter:AddArgStr('Name', aValue, sPluginArgStrC16);
  tPluginCmd->Plugin.Converter:AddArgInt('Type', 0);

  // Kommando an den Designer schicken
  Plugin.Converter:SendCmd(gPluginInstanceID, tPluginCmd);

  // Handle des Plugin-Kommandos löschen
  tPluginCmd->Plugin.Converter:DeleteCmd();
}

Mit Hilfe des Befehls Designer.Forms.Open wird ein Form-Objekt im Designer geöffnet. Hierzu wird mit der Anweisung Plugin.Converter:CreateCmd() ein Plugin-Kommando erstellt.

Jeder Befehl hat Argumente, die übergeben werden müssen. In diesem Fall sind die Argumente vom Typ alpha und int. Sie werden mit den Funktionen Plugin.Converter:AddArgStr() und Plugin.Converter:AddArgInt() gesetzt.

In aValue steht der Name des zu öffnenden Form-Objekts.

In der Funktion Plugin.Converter:AddArgInt() wird der Typ des Form-Objekts festgelegt. Da wir einen Dialog öffnen möchten, muss der Typ mit einer 0 (Frame) gesetzt werden.

Das Plugin-Kommando wird anschließend mit der Funktion Plugin.Converter:SendCmd() an den Designer versendet.

Plugin.Converter:DeleteCmd() löscht das Kommando, um den Speicherplatz wieder freizugeben, welcher mit Plugin.Converter:CreateCmd() belegt wurde.

Auswählen des aktiven Dialoges

Wenn der Anwender im Designer bestimmte Aktionen durchführt, sendet dieser Ereignisse an die Plugin-Anwendung. So informiert zum Beispiel das Ereignis Designer.Forms.ActivateDone darüber, dass der Anwender eine Design-Form aktiviert hat. Die Plugin-Anwendung erhält die Benachrichtigung über das Ereignis EvtJob, da beim Erstellen der Instanz durch Plugin.Core:InstanceNew() das Frame-Handle der Plugin-Anwendung angegeben wurde. Der Quelltext-Ausschnitt zeigt die Ereignis-Verarbeitung.

sub EvtJob
(
  aEvt                  : event;        // Ereignis
  aJobCtrlHdl           : handle;       // Job-Kontroll-Objekt
)
: logic;

  local
  {
    tInstanceID         : int;
    tPluginCmd          : handle;
    tResult             : int;
    tDialogName         : alpha;
  }

{
  // Plugin-Kommando erstellen
  tPluginCmd # Plugin.Converter:CreateCmd();
  // Plugin-Ereignis empfangen
  tResult # Plugin.Converter:ReceiveCmd(_ReceiverByJobControl,aJobCtrlHdl,tPluginCmd,var tInstanceID);

  if (tResult = _ErrPluginCoreThreadTerm)
    TermExample();
  else if (tResult = _ErrOK and Plugin.Converter:IsCmdKindEvt(tPluginCmd))
  {
    if (tPluginCmd->Plugin.Converter:IsCmdName('Designer.Forms.ActivateDone'))
    {
      // Name des aktivierten Dialogs ermitteln
      tPluginCmd->Plugin.Converter:GetArgStr('Name',var tDialogName);
      gPluginStoList->wpCurrent # tDialogName;
    }
  }
  return(true);
}

Zunächst wird auch hier wieder ein Plugin-Kommando (Plugin.Converter:CreateCmd()) erstellt. Die Funktion Plugin.Converter:ReceiveCmd() empfängt anschließend das Plugin-Ereignis.
Gibt die Funktion _ErrPluginCoreThreadTerm zurück, wurde die Verbindung zum Designer getrennt. In diesem Fall terminieren wir die Plugin-Anwendung.

Wurde das Plugin-Kommando dagegen erfolgreich empfangen, dann liefert die Funktion _ErrOK zurück. In diesem Fall überprüfen wir, ob es sich bei der empfangenen Nachricht um das Ereignis Designer.Forms.ActivateDone handelt. Dies läuft zweistufig ab. Zunächst wird durch den Aufruf von Plugin.Converter:IsCmdKindEvt() überprüft, ob es sich bei der Nachricht um ein Ereignis handelt. Wenn das so ist, überprüfen wir mit Plugin.Converter:IsCmdName() ob es sich dabei um Designer.Forms.ActivateDone handelt.

Anschließend kann mit Plugin.Converter:GetArgStr() der Name des aktivierten Dialoges ermittelt werden. Zum selektieren des Eintrages in der Liste braucht dann lediglich die Eigenschaft wpCurrent des StoList-Objekts gesetzt zu werden.

Das vollständige Beispiel können Sie in der Datenbank CodeLibrary unter dem Namen Plugin.Example finden.

2 Kommentare

2 Kommentare “Hey Designer!”

Kommentar abgeben