Übersicht Pluginentwicklung

Aus TV-Browser Wiki
Version vom 26. November 2007, 19:13 Uhr von Ds10⧼word-separator⧽⧼parentheses⧽ ⧼parentheses⧽
⧼revision-nav⧽
Wechseln zu: Navigation⧼comma-separator⧽Suche

Dieser Artikel ist nicht auf aktuellem Stand, wird aber nach und nach auf die Plugin-Schnittstelle von TV-Browser 2.6 aktualisiert.

In dieser Übersicht werden alle Möglichkeiten aufgeführt, wie ein Plugin mit TV-Browser oder anderen Plugins interagieren kann.

Wenn du bisher noch keine Erfahrungen mit der Entwicklung von Plugins gesammelt hast, dann solltest du erst das Tutorial: Entwicklung eines Java-Plugins machen.

Wichtig: Diese Übersicht zeigt, wie man Plugins für das neue Plugin-System von TV-Browser 2.0 schreibt. Ein Plugin das diese neuen Möglichkeiten nutzt, funktioniert nicht in TV-Browser-Versionen kleiner als 2.0.

Mehr Infos zu den Neuerungen im Pluginsystem in TV-Browser 2.0 gibt es hier.

Gundlagen

Da TV-Browser zwei Verzeichnisse berücksichtigt, die Plugins enthalten können, einmal das plugins-Verzeichnis im Programmverzeichnis und das plugins-Verzeichnis im Einstellungsverzeichnis des Benutzers, ist es ab TV-Browser 2.2.4 und 2.6 notwendig, dass alle Plugins und TvDataServices die Methode

public static Version getVersion()

enthalten. Diese dient zur Überprüfung, welche Plugindatei die aktuellste Version enthält. Die aktuellste Version wird dann von TV-Browser geladen.

Wichtig: Die Versionierung von TV-Browser Plugins ist aus historischen Gründen etwas anders aufgebaut, als man das erwarten würde. Deshalb ist es empfehlenswert die genaue Beschreibung der Versionierung zu lesen.

Außerdem sollte jedes Plugin die Methode

public PluginInfo getInfo()

überschreiben um wenigstens den Namen und die Beschreibung des Plugins festzulegen. Es ist mit dieser Methode aber auch möglich zusätzlich den Autor, eine Internetseite mit einer Hilfe zum Plugin und die Lizenz des Plugins anzugeben.

Auswahl über die Einstellungen

Einstellungen MarkerPlugin.png

Der Einstellungen-Dialog sieht für jedes Plugin, das diese Funktion unterstützt, einen eigenen Karteireiter vor. Auf diese Weise kann der Benutzer ein bestimmtes Plugin konfigurieren.

Implementierung:

public SettingsTab getSettingsTab()

Diese Methode gibt das SettingsTab deines Plugins zurück. Ein SettingsTab besteht aus einem JPanel, in dem die Einstellungen vorgenommen werden können, einer Methode zum Abspeichern der Einstellungen, aus einem Titel und einem Icon. Letztere werden dann im Einstellungen-Dialog gezeigt.

Auswahl über das Menü

Plugin Menue.png

Plugins können aber auch direkt über das Menü oder die Symbolleiste aufgerufen werden. Plugins, die diese Funktion unterstützen, erscheinen im Menü und in der Symbolleiste.

Das Erinnerungen-Plugin kann auf diese Weise die gespeicherten Erinnerungen anzeigen. Das Sendungsinfo-Plugin hingegen unterstützt diese Funktion nicht (und wird deshalb auch nicht angezeigt).

Implementierung:

public Action getButtonAction()

Gibt die Aktion zurück, die ausgeführt werden soll, wenn das Plugin über im Menü angewählt wurde.

Beispiel:

Der folgende Code zeigt einen Dialog, sobald das Plugin im Menü ausgewählt wurde.

public Action getButtonAction() {
  // Eine Aktion erzeugen, die die Methode showDialog() aufruft, sobald sie ausgelöst wird.
  AbstractAction action = new AbstractAction() {
    public void actionPerformed(ActionEvent evt) {
      showDialog();
    }
  };

  // Der Aktion einen Namen geben. Dieser Name wird dann im Menü und in der Symbolleiste gezeigt
  action.putValue(Action.NAME, "Dialog anzeigen");

  // Der Aktion ein kleines Icon geben. Dieses Icon wird im Menü gezeigt
  // Das Icon sollte 16x16 Pixel groß sein
  action.putValue(Action.SMALL_ICON, createImageIcon("SomeCategory","SomeIcon",16));

  // Der Aktion ein großes Icon geben. Dieses Icon wird in der Symbolleiste gezeigt
  // Das Icon sollte 22x22 Pixel groß sein
  action.putValue(BIG_ICON, createImageIcon("SomeCategory","SomeIcon",22));

  // Die Aktion zurückgeben
  return action; 
}


protected void showDialog() {
  // Einen modalen Dialog erzeugen
  JDialog dlg = UiUtilities.createDialog(getParentFrame(), true);

  // Hier den Dialog füllen
  ...

  // Dialog zeigen
  dlg.show();
}

Auswahl über eine Sendung

Programmtabelle Kontextmenue.png

Klickt der Benutzer mit der rechten Maustaste auf eine Sendung, so werden jene Plugins angezeigt, die auf dieses Ereignis reagieren können. Hier z.B das Erinnerungen-Plugin sowie das Sendungsinfo-Plugin. Der Benutzer kann nun ein Plugin wählen, das ausgeführt werden soll. Das Plugin erhält dann alle vorliegenden Informationen über die jeweilige Sendung. Das Erinnerungen-Plugin beispielsweise fügt die Sendung zu den Erinnerungen hinzu, das Sendungsinfo-Plugin zeigt die Sendungs-Informationen an.

Implementierung:

public Action[] getContextMenuActions(Program program)

Gibt die Aktionen zurück, die das Plugin für die übergebene Sendung anbietet.

Beispiel:

Angenommen, du willst ein Plugin schreiben, das die Daten einer Sendung als E-Mail verschickt. Dann könnte deine Implementierung so aussehen:

public Action[] getContextMenuActions(Program program) {
  // Eine Aktion erzeugen, die die Methode sendMail(Program) aufruft, sobald sie aktiviert wird.
  AbstractAction action = new AbstractAction() {
    public void actionPerformed(ActionEvent evt) {
      sendMail(getProgramFromContextMenuActionEvent(evt));
    }
  };

  // Der Aktion einen Namen geben. Dieser Name wird dann im Kontextmenü gezeigt
  action.putValue(Action.NAME, "Sendungsinfos als E-Mail versenden");

  // Der Aktion ein Icon geben. Dieses Icon wird mit dem Namen im Kontextmenü gezeigt
  // Das Icon sollte 16x16 Pixel groß sein
  action.putValue(Action.SMALL_ICON, createImageIcon("SomeCategory","SomeIcon",16));

  // Die Aktion zurückgeben
  return new Action[] { action }; 
}


protected void sendMail(Program program) {
  // Hier die Mail verschicken
  ...
}

Markieren von Sendungen

Plugins haben die Möglichkeit, Sendungen zu markieren. Diese Sendungen werden dann in der Farbe der höchsten Priorität, mit der die Sendung markiert ist, dargestellt.

Programmtabelle Markierungen.png

Das Plugin kann dabei für alle Sendungen das gleiche Icon oder für jede Sendung ein eigenes Icon oder auch mehrere Icons gleichzeitig verwenden. Die Icons werden dann in der unteren rechten Ecke der Sendung angezeigt, so dass dadurch die Plugins, die die Sendung markieren, erkannt werden können.

Implementierung:

Wenn ein Plugin alle Sendungen mit dem gleichen Icon markieren möchte, muss das Plugin folgende Methode überschreiben:

public ThemeIcon getMarkIconFromTheme() {

Beispiel:

public ThemeIcon getMarkIconFromTheme() {
  return new ThemeIcon("devices", "printer", 16);
}

Das zurückgegebene Icon sollte 16x16 Pixel groß sein. Eine Sendung kann dann durch folgenden Aufruf markiert und ent-markiert werden:

Program program = ...;

// Markieren der Sendung
program.mark(this);

// Ent-Markieren der Sendung
program.unmark(this);

Soll die Sendung dabei in einer anderen als der Standardfarbe markiert werden, muss das Plugin folgende Methode überschreiben:

public int getMarkPriorityForProgram(Program p) {

Beispiel:

public int getMarkPriorityForProgram(Program p) {
  if(p != null) {
    if(p.getTitle().contains("Asterix")) {
      return Program.MAX_MARK_PRIORITY;
    }
  }
  
  return Program.MIN_MARK_PRIORITY;
}

Die Sendung wird dann mit der Farbe, die der Priorität entspricht angezeigt. Sollte die Sendung allerdings noch von einem anderen Plugin mit einer höheren Priorität versehen sein, wird die Farbe dieser Priorität angezeigt. Ein Plugin kann außerdem auch festlegen, dass die Sendung von ihm gar nicht farblich markiert werden soll, dazu muss die Methode folgendes zurückgeben:

public int getMarkPriorityForProgram(Program p) {
  return Program.NO_MARK_PRIORITY;
}

Das Plugin kann die Sendung aber auch mit mehreren Icons oder unterschiedliche Sendungen mit unterschiedlichen Icons markieren. Dazu muss folgende Methode überschrieben werden:

public Icon[] getMarkIconsForProgram(Program p) {

Beispiel:

public Icon[] getMarkIconsForProgram(Program p) {
  if(p != null) {
    if(p.getTitle().contains("Asterix")) {
      return new Icon[] {createImageIcon("emotes,"face-grin",16)};
    }
  }
  
  return new Icon[] {createImageIcon("SomeCategory","SomeIcon",16)};
}

Daten speichern und laden

Viele Plugins arbeiten mit Daten, die sie beim Beenden von TV-Browser speichern wollen, damit sie beim nächsten Start wieder geladen werden können. Damit nicht jedes Plugin sich damit herumschlagen muss, wohin es seine Daten speichert und wann es das am besten macht, liefert die Plugin-Schnittstelle entsprechende Methoden, die vom TV-Browser zur gegebenen Zeit aufgerufen werden.

Die Daten können dabei auf zwei Arten gespeichert werden: Als Properties und als serialisierte Objekte.

Properties sind einfache Schlüssel-Wert-Paare von Strings (siehe java.util.Properties). Sie haben den Vorteil, dass sie sehr einfach zu benutzen sind. Ein Nachteil ist, dass man damit nur Strings abspeichern kann. Simple Datentypen, wie z.B. Integers, können zwar in String umgewandelt werden, aber komplexe Datenstrukturen lassen sich auf diese Weise nur mit großen Verrenkungen speichern.

Serialisierte Objekte haben den Vorteil, dass man so beliebige Objekte speichern kann (sofern sie java.io.Serializable implementieren). Der Nachteil dabei ist, dass man die genaue Reihenfolge der Speicherung beim Laden wieder einhalten muss. Außerdem muss man darauf achten, dass man auch alte Dateien noch laden kann, selbst wenn sich etwas an diesem Format geändert hat (Wenn man z.B. etwas zusätzliches speichert oder wenn bei einem Objekt ein Feld hinzugekommen ist).

Diese beiden Techniken können auch parallel verwendet werden. Man kann also manche Werte als Properties speichern, andere als serialisierte Objekte.

Implementierung:

public Properties storeSettings()
public void loadSettings(Properties settings)

Speichert bzw. lädt Daten als Properties.

public void writeData(ObjectOutputStream out)
public void readData(ObjectInputStream in)

Speichert bzw. lädt Daten als serialisierte Objekte.

Die Methoden zum Laden der Daten, also loadSettings(Properties) und readData(ObjectInputStream), werden direkt nach der Erzeugung der Plugin-Instanz aufgerufen, also nach dem Konstruktor.

Die Methoden zum Speichern der Daten, also storeSettings() und writeData(ObjectOutputStream), werden beim Beenden von TV-Browser, sowie alle paar Minuten aufgerufen. Letzteres dient als Schutz davor, falls TV-Browser "abgeschossen" wird.

Beispiel (Properties):

private Properties mSettings;

public Properties storeSettings() {
  return mSettings;
}

public void loadSettings(Properties settings) {
  mSettings = settings;
}

private void someOtherMethod() {
  // Eine Property setzen
  String username = ...;
  mSettings.put("username", username);

  // Eine Property lesen
  String username = mSettings.get("username");
}

Beispiel (Serialisierte Objekte):

private String mUserName;

public void writeData(ObjectOutputStream out) {
  out.writeInt(1); // Dateiformat-Version
  out.writeObject(mUserName);
}

public void readData(ObjectInputStream in) {
  int version = in.readInt();
  if (version == 1) {
    mUserName = (String) in.readObject();
  }
}

PluginManager

PluginManager getPluginManager()

Der PluginManager stellt den Plugins eine Reihe nützlicher Funktionen zur Verfügung. Dabei hervorzuheben ist besonders der FilterManager, der es ermöglicht mit die Filter in TV-Browser anzusprechen.

Weitere Infos hierzu sind in der JavaDoc-Dokumentation zu TV-Browser zu finden.

Sendungen empfangen

Ein Plugin kann Sendungen von anderen Plugins empfangen. Um anzuzeigen, dass es Sendungen empfangen kann muss folgende Methode überschrieben werden:

public boolean canReceiveProgramsWithTarget() {
  return true;
}

Standardmäßig gibt hier jedes Plugin false zurück um anzuzeigen, dass es keine Sendungen empfangen kann.


Um nun Sendungen zu empfangen muss das Plugin die folgende Methode überschreiben:

public void receivePrograms(Program[] programArr, ProgramReceiveTarget target)

Die Variable programArr enthält die Sendungen, die von anderen Plugins gesendet wurden. Diese können nun vom Plugin verarbeitet werden, zum Beispiel indem sie markiert werden:

public void receivePrograms(Program[] programArr, ProgramReceiveTarget target) {
  if(programArr != null) {
    for(Program p : programArr) {
      p.mark(this);
    }
  }
}

Über die Variable target kann das Plugin, das die Sendungen an dieses Plugin sendet eine bestimmte Verarbeitung festlegen. Die möglichen Verarbeitungen legt man fest, indem man im Plugin die folgende Methode überschreibt:

public ProgramReceiveTarget[] getProgramReceiveTargets()

Diese Verarbeitungsmöglichkeiten, kann der Benutzer dann in der Auswahlmaske für das Senden der Sendungen in einem anderen Plugin auswählen. Dieses Plugin sollte dann auf die vorgesehene Weise mit den Sendungen umgehen, die es mit einer Verarbeitungsmöglichkeit empfängt.

Beispiel:

public ProgramReceiveTarget[] getProgramReceiveTargets() {
  return new ProgramReceiveTarget[] {new ProgramReceiveTarget(this,"Markieren",this.getId()+"mark"),
                      new ProgramReceiveTarget(this,"Ent-Markieren",this.getId()+"unmark")};
}

public void receivePrograms(Program[] programArr, ProgramReceiveTarget target) {
  if(programArr != null && target != null) {
    for(Program p : programArr) {
      if(target.isReceiveTargetWithIdOfProgramReceiveIf(this, this.getId()+"mark")) { 
        p.mark(this);
      }
      else if(target.isReceiveTargetWithIdOfProgramReceiveIf(this, this.getId()+"unmark")) {
        p.unmark(this);
      }
    }
  }
}

TODO

public Icon[] getProgramTableIcons(Program program)
public String getProgramTableIconText()
public void handleTvDataUpdateFinished()
public void handleTvDataAdded(ChannelDayProgram newProg)
public void handleTvDataDeleted(ChannelDayProgram oldProg)
public PluginsProgramFilter[] getAvailableFilter()
public boolean isAllowedToDeleteProgramFilter(PluginsProgramFilter programFilter)
public Class<? extends PluginsFilterComponent>[] getAvailableFilterComponentClasses()
public boolean canUseProgramTree()
public PluginTreeNode getRootNode()
protected final boolean saveMe()

Erklärung wie man ein Programm aus der Datenbank bekommt