Als nächstes soll es ermöglicht werden, den aktuellen Bestand an Videos anzuzeigen. Außerdem sollen sowohl Einkaufs-, als auch Verkaufspreise editiert werden können. Es soll also der Katalog, in dem die Preise verzeichnet sind, verändert werden. Somit liegt es nahe, einen Prozeß zu verwenden.

Auf diese Weise kann dem Benutzer an einem UIGate der Stock zum Editieren angezeigt werden und die veränderten Preise mit einem Druck auf den "Ok"-Button übernommen oder die alten Preise mit dem "Cancel"-Button beibehalten werden.

Zum Darstellen der Tabelle ist natürlich ein TableEntryDescriptor notwendig. Dazu wird die Klasse EditableVideoStockTED wie folgt erstellt:

EditableVideoStockTED


  import sale.*;
  import util.swing.*;

  public class EditableVideoStockTED
    extends AbstractTableEntryDescriptor
  {
  }
        

Um die Preise editieren zu können, muß in der Klasse der darzustellende Stock und der zu verwendende DataBasket bekannt sein. Dazu werden entsprechende Variablen deklariert:


  private CountingStockImpl videoCountingStock;
  private DataBasket        db;
        

Die Pakete, aus denen die verwendeten Klassen DataBasket und CountingStockImpl stammen, müssen importiert werden:


  import data.*;
  import data.ooimpl.*;
        

Die Variablen müssen initialisiert werden. Dazu werden die notwendigen Werte dem Konstruktor als Parameter übergeben und entsprechend zugewiesen:

Konstruktor


  public EditableVideoStockTED(CountingStockImpl videoCountingStock,
                               DataBasket db)
  {
    super();
    this.videoCountingStock = videoCountingStock;
    this.db                 = db;
  }
        

Nun sollen zunächst die Eigenschaften des TableEntryDescriptors verändert werden, die mit dem Aussehen, und nichts mit der Editierbarkeit der Tabelle zu tun haben. Dies sind die Anzahl und die Namen der Spalten. Die Anzahl der Spalten wird durch die Methode getColumnCount bestimmt:

Eigenschaften des TED


  public int getColumnCount()
  {
    return 5;
  }
        

Anzahl der Spalten

Mit Hilfe eines Arrays werden die Namen Spalten wie folgt in der Methode getColumnName festgelegt:


  public String getColumnName(int index)
  {
    return (new String[]{"Name",
                         "Buy",
                         "Sell", 
                         "Pieces in Stock",
                         "Rent Pieces"})[index];  
  }
        

Namen der Spalten

Mit diesen zwei angepaßten Methoden ist die Klasse bereits in der Lage, die für den Videobestand darzustellende Tabelle korrekt zu beschreiben. Es kann eine Instanz dieses TableEntryDescriptors einer create-Methode aus SingleTableFormSheet übergeben werden. Daher soll als nächstes der Prozeß aufgebaut werden, der den noch vorhandenen Bestand anzeigt. Dieser wird in der Klasse SeeVideoStockProcess realisiert:

SeeVideoStockProcess


  import sale.*;

  public class SeeVideoStockProcess extends SaleProcess
  {
  }
        

Der Konstruktor dieser Klasse ruft einfach den Konstruktor der Oberklasse mit einem passenden Parameter auf:

Konstruktor


  public SeeVideoStockProcess()
  {
    super("SeeVideoProcess");
  }
        

Es werden weitere Variablendeklarationen für das benötigte Auswahl-Gate und die Transitions zum Hinzufügen und Entfernen von Videos gebraucht:

Gates und Transitions


  protected UIGate selectionGate;
 
  protected Transition newVideoTransition;
  protected Transition removeVideoTransition; 
        

Die Oberfläche wird, wie im RentProcess, mit der Methode setupMachine aufgebaut:


  protected void setupMachine()
  {
  }
        

In der Methode werden zuerst das Auswahl-Gate und das dort darzustellende FormSheet mit Hilfe des EditableVideoStockTED erzeugt:

SingleTableFormSheet


  selectionGate = new UIGate(null, null);

  final SingleTableFormSheet stfs = 
    SingleTableFormSheet.create(
      "See videos in stock and edit Process",  
      (CountingStockImpl)Shop.getTheShop().getStock(
        "Video-Countingstock"),
      selectionGate,
      getBasket(),
      true,
      new EditableVideoStockTED((CountingStockImpl)
        Shop.getTheShop().getStock("Video-Countingstock"),
        getBasket()));
        

Um SingleTableFormSheet und CountingStockImpl dem Compiler bekannt zu machen, wird der Kopf der Klasse um folgende import-Anweisungen ergänzt:


  import data.ooimpl.*;
  import data.stdforms.*;
        

Die Transition zum Anlegen eines neuen Videos wird erstellt und in ihr die Methode perform implementiert:

newVideoTransition


  newVideoTransition = new Transition()
  {
    public Gate perform(SaleProcess pOwner, User usr)
    {
    }
  };
        

Um User verwenden zu können, wird folgendes Paket importiert:


  import users.*;
        

Die Methode perform enthält alle notwendigen Schritte, die zum Erzeugen eines neuen Videos notwendig sind. Zuerst werden die Eingabefelder für alle relevanten Daten eines neues Videos erstellt:

perform-Methode


  JTextField jTextField1 = new JTextField();
  JTextField jTextField2 = new JTextField();
  JTextField jTextField3 = new JTextField();
  JTextField jTextField4 = new JTextField();
        

Um die swing-Klasse verwenden zu können, muß das entsprechende Paket importiert werden.


  import javax.swing.*;
        

Die Textfelder werden in ein JPanel eingebaut:


  JPanel jTextPanel = new JPanel();
  jTextPanel.setLayout(new BoxLayout(jTextPanel, BoxLayout.Y_AXIS));

  jTextPanel.add(new JLabel("Name"));
  jTextPanel.ass(jTextField1);
  jTextPanel.add(new JLabel("Buy (in Pf)"));
  jTextPanel.ass(jTextField2);
  jTextPanel.add(new JLabel("Sell (in Pf)"));
  jTextPanel.ass(jTextField3);
  jTextPanel.add(new JLabel("Amount"));
  jTextPanel.ass(jTextField4);
        

Der Dialog muß anschließend dargestellt werden:

Dialog


  JOptionPane.showMessageDialog(null,
                                jTextPanel,
                                "New Video-Cassette",
                                JOptionPane.QUESTION_MESSAGE);
        

Zunächst müssen der Video-Katalog und der Video-Bestand aus den globalen Listen des Shops geholt werden.


  Catalog videoCatalog =
    Shop.getTheShop().getCatalog("Video-Catalog");
  CountingStock videoCountingStock =
    (CountingStock)Shop.getTheShop().getStock(
      "Video-Countingstock"); 
        

Um Catalog und Stock benutzen zu können, wird eine weitere import-Anweisung gebraucht:


  import data.*;
        

Aus den vorhin erstellten Textfeldern werden die eingegebenen Daten für das hinzuzufügende Video ausgelesen. Einkaufs- und Verkauspreis, sowie die Anzahl sind int-Werte. Fehlerhafte Eingaben resultieren in einer NumberFormatException, die abgefangen werden muß.


  String name = jTextField1();

  int buy = 0;
  try {
    buy = new Integer(jTextField2.getText()).intValue();
  }
  catch (NumberFormatException ne) {
  }

  int sell = 0;
  try {
    sell = new Integer(jTextField3.getText()).intValue();
  }
  catch (NumberFormatException ne) {
  }

  int amount = 0;
  try {
    amount = new Integer(jTextField4.getText()).intValue();
  }
  catch (NumberFormatException ne) {
  }
        

Bei korrekter Eingabe in allen Textfeldern kann das neue Video mit seinen Daten in den Katalog übernommen werden. Existiert ein Video mit diesem Namen bereits, wird eine DuplicateKeyException erzeugt. Ist die Eingabe fehlerhaft, erscheint ein Dialog mit der entsprechenden Fehlermeldung.

VideoCassette hinzufügen


  if (sell>0 && buy>0 && amount>0
      && !name.equals("")) {
    try {
      videoCatalog.add(new VideoCassette(
        name,
        new QuoteValue(new IntegerValue(buy),
                       new IntegerValue(sell))),
        null);
      videoCountingStock.add(name, amount, null);
    }
    catch (DuplicateKeyException dke) {
      JOptionPane.showMessageDialog(null, "Element exists");
    }
  }
  else {
    JOptionPane.showMessageDialog(null,
      "The given input was not correct!"); 
  }  
        

Am Ende der perform-Methode wird das als nächstes zu betretende Gate zurückgegeben. In diesem Fall kehrt das Programm wieder zum selectionGate zurück.


  return selectionGate;
        

Die Transition zum Hinzufügen neuer Videos ist vollständig implementiert. Es fehlt noch die Transition zum Entfernen von Videos aus dem Angebot des Videoautomaten:

removeVideoTransition


  removeVideoTransition = new Transition()
  {
    public Gate perform(SaleProcess pOwner, User usr) 
    {
    }
  };
        

Zuerst wird die markierte Zeile, die das zu entfernende Video enthält, aus dem FormSheet in einer Variable abgespeichert:

perform-Methode


  Object record = stfs.getSelectedRecord();
  VideoCassette videoCassette = (VideoCassette)
    ((CountingStockTableModel.Record)record).getDescriptor();
        

CountingStockTableModel ist Bestandteil des Pakets data.swing:


  import data.swing.*;
        

Bevor ein Video aus dem Angebot des Automaten genommen werden kann, muß überprüft werden, ob Kunden Exemplare dieses Videos entliehen haben. Es werden alle Kundenkonten durchsucht und die Anzahl der ausgeliehenen Exemplare ermittelt.


  int rented = 0;
  try {
    Iterator i = VideoMachine.getAllCustomer().iterator();
    while (i.hasNext()) {
      rented = rented +
        ((Customer)i.next()).getStoringStock().countItems(
          videoCassette.getName(), null);
    }
  }
  catch (NullPointerException npe) {
  }
        

Um den Iterator verwenden zu können, bedarf es einer weiteren import-Anweisung:


  import java.util.*;
        

Wurden keine Exemplare des Videos entliehen, kann es entfernt werden. Besitzt mindestens ein Kunde ein Exemplar des zu löschenden Videos, kann der Manager dieses Video nicht aus dem Katalog entfernen. Andernfalls führt das zu (geschäftsschädigenden!) Dateninkosistenzen.

VideoCassette entfernen


  if (rented <= 0) {
    try {
      Shop.getTheShop().getCatalog("Video-Catalog").remove(
        videoCassette, null);
    }
    catch (VetoException ve) {
      ve.printStackTrace();
      JOptionPane.showMessageDialog(null, 
        "The selected item can't be removed!");
    }
  }
  else {
    JOptionPane.showMessageDialog(null,
      "There are still rented videos!");
  }
        

Die VetoException ist Bestandteil von data.events:


  import data.events.*;
        

Am Ende der Transition wird ebenfalls das selectionGate als nächstes zu betretendes Gate angegeben:


  return selectionGate;
        

Das Gate und die beiden Transitions sind fertig implementiert. Das vorhin erstellte FormSheet stfs wird am Auswahl-Gate angemeldet. Zusätzlich werden in der createFormSheetContent-Methode die entsprechenden Buttons festgelegt.

FormSheetContent festlegen


  stfs.addContentCreator(new FormSheetContentCreator()
  {
    protected void createFormSheetContent(FormSheet fs)
    {
    }
  });
        

Es werden alle eventuell schon vorhandenen Buttons entfernt:


  fs.removeAllButtons();
        

Zuerst wird ein "New"-Button benötigt, der in seiner doAction-Methode die newVideoTransition auslöst.

New-Button


  fs.addButton("New", 100, new sale.Action()
  {
    public void doAction(SaleProcess p, SalesPoint sp)
    {
      selectionGate.setNextTransition(newVideoTransition);
    }
  });
        

Analog dazu führt der "Remove"-Button zur removeVideoTransition.

Remove-Button


  fs.addButton("Remove", 101, new sale.Action()
  {
    public void doAction(SaleProcess p, SalesPoint sp)
    {
      selectionGate.setNextTransition(removeVideoTransition);
    }
  });
        

Weiterhin wird ein "Ok"-Button erstellt, der ein Commit ausführt, und ein "Cancel"-Button, welcher ein Rollback auslöst.

Ok- und Cancel-Button


  fs.addButton("Ok", 102, new sale.Action()
  {
    public void doAction(SaleProcess p, SalesPoint sp)
    {
      selectionGate.setNextTransition(
        GateChangeTransition.CHANGE_TO_COMMIT_GATE);
    }
  });

  fs.addButton("Cancel", 103, new sale.Action()
  {
    public void doAction(SaleProcess p, SalesPoint sp)
    {
      selectionGate.setNextTransition(
        GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
    }
  });
        

Die setupMachine-Methode ist fertig implementiert. Die Klasse SeeVideoStockProcess wird durch die Methoden getInitialGate und getLogGate vervollständigt. Die erste Methode baut den Automaten auf und setzt das Start-Gate. Die zweite Methode übergibt das LogGate. Beim Beenden des Prozesses soll kein Log-Eintrag geschrieben werden, deshalb wird das StopGate zurückgegeben.

InitialGate und LogGate festlegen


  public Gate getInitialGate()
  {
    setupMachine();
    return selectionGate;
  }

  public Gate getLogGate()
  {
    return getStopGate();
  }
        

Der so aufgebaute Prozeß kann an einem SalesPoint gestartet werden. Der Manager erhält in seinem Menü einen neuen Menüpunkt. Dazu wird am Ende der getDefaultMenuSheet-Methode der Klasse Office folgendes eingefügt:

Prozeß starten


  msSubMenu.add(new MenuSheetItem("Edit Video-Stock",
    new sale.Action()
    {
      public void doAction(SaleProcess p, SalesPoint sp)
      {
        sp.runProcess(new SeeVideoStockProcess());
      }
    }));
        

Jetzt ist es dem Manager möglich, Einsicht in den Bestand des Automaten zu nehmen und ihn ggf. zu verändern. Um die Preise der einzelnen Videos editieren zu können, muß die Klasse EditableVideoStockTED um weitere Methoden ergänzt werden. Im einzelnen sind das die im Interface TableEntryDescriptor definierten Methoden getCellRenderer, die die Darstellung der einzelnen Spalten festlegt, und getValueAt, die den Zellinhalt für das übergebene Objekt und die angebene Spalte liefert, desweiteren die Methoden istElementEditable, um zu überprüfen, ob das Element überhaupt editiert werden darf, getCellEditor, um ein Objekt zu ermitteln, mit Hilfe dessen die Elemente einer bestimmten Spalte editiert werden können und setValueAt, um einen bestimmten Wert in einem Datensatz festzulegen.

EditableVideoStockTED erweitern

Für die Realisierung der getCellRenderer-Methode werden Variablen zur Darstellung der einzelnen Formate benötigt. Es werden über dem Konstruktor von EditableVideoStockTED Variablen für Spalteneinträge mit Währung und für Einträge, die Namen und Mengenangaben repräsentieren, angelegt:

Darstellungsformate festlegen


  private TableCellRenderer tcrMoney;
  private TableCellRenderer tcrName;
  private TableCellRenderer tcrCount;
        

Am Ende des Konstruktors der Klasse werden die Variablen dann initialisiert. Die Ausrichtung für die Darstellung der Anzahl wird auf zentriert festgelegt.


  tcrMoney = new CurrencyRenderer(
    (Currency)Shop.getTheShop().getCatalog("DM"));
  tcrName  = new DefaultTableCellRenderer();
  tcrCount = new DefaultTableCellRenderer();

  ((DefaultTableCellRenderer)tcrCount).setHorizontalAlignment(
    SwingConstants.CENTER);
        

CurrencyRenderer verlangt folgende import-Anweisung:


  import data.swing.*;
        

Die Methode getCellRenderer liefert z.B. bei den Spalten 1 und 2 tcrMoney als CellRenderer zurück. Mit Hilfe einer switch-Anweisung erfolgt die jeweilge Zuweisung:

getCellRenderer-Methode


  public TableCellRenderer getCellRenderer(int index)
  {
    switch (index) {
      case 0 : return tcrName;
      case 3 : return tcrCount;
      case 4 : return tcrCount;
      default: return tcrMoney;
    }
  }
        

Die Methode ist damit abgeschlossen und die getValueAt-Methode kann erstellt werden.

getValueAt-Methode


  public Object getValueAt(Object record, int index)
  {
  }
        

Zuerst wird die ausgewählte VideoCassette bestimmt und in einer typgleichen Variable abgespeichert. Danach wird die Anzahl der Videos, die sich von dieser Sorte im Automaten befinden, ermittelt.


  VideoCassette videoCassette =
    (VideoCassette)((CountingStockTableModel.Record)
      record).getDescriptor();
  int count =
    ((CountingStockTableModel.Record)record).getCount();
        

Der übergebende gewünschte Spalteneintrag wird mit Hilfe einer switch-Anweisung zurückgegeben:


  switch (index) {
    case 0:
      return videoCassette.getName();
    case 1:
      return ((QuoteValue)videoCassette.getValue()).getOffer;
    case 2:
      return ((QuoteValue)videoCassette.getValue()).getBid;
    case 3:
      return new IntegerValue(count);
  }
        

Die Anzahl der ausgeliehenen Videos läßt sich nicht so einfach feststellen. Mit einem Iterator werden alle Kundenkonten durchsucht und die Anzahl der Videos darüber ermittelt. Für die Verwendung des Iterators wird die Klasse um eine weitere import-Anweisung ergänzt:


  import java.util.*;
        

Der switch-Anweisung wird ein weiterer Fall hinzugefügt:


  case 4:
    int rented = 0;
    try {
      Iterator i = VideoMachine.getAllCustomer().iterator();
      while (i.hasNext()) {
        rented = rented +
          ((Customer)i.next()).getStoringStock().countItems(
            videoCassette.getName, null);
      }
    }
    catch (NullPointerException npe) {
    }
    return new IntegerValue(rented);
        

Tritt durch einen Fehler im Programm ein Wert kleiner null oder größer vier auf, wird als Standard-Wert null geliefert:


  default:
    return null;
        

Die Methode ist damit vollständig implementiert, und die weiteren Methoden können entwickelt werden.

isElementEditable ist in diesem Fall sehr einfach: Alle Elemente, die in der zweiten oder dritten Spalte stehen, also alle Einkaufs- und Verkaufspreise, sind editierbar. Es ist zu beachten, daß die Zählung der Spalten bei null beginnt.

isElementEditable-Methode


  public boolean isElementEditable(Object record, int index)
  {
    return index==1 || index==2;
  }
        

Die Implementation von getCellEditor ist schwieriger. Diese Methode soll einen TableCellEditor, also ein Objekt zum Editieren von Zellen einer Tabelle, zurückgeben, das in der Lage ist, Geldbeträge korrekt verändern zu lassen. Das Interface TableCellEditor ist im Paket javax.swing.table definiert und besitzt lediglich eine exisiterende Implementation: DefaultCellEditor. Diese ist im Paket javax.swing enthalten. Die Klasse ist in der Lage, ein JTextField zum Editieren eines Wertes einer Zelle zu verwenden. Es liegt also nahe, von DefaultCellEditor eine neue Klasse abzuleiten und an die eigenen Bedürfnisse anzupassen. Die Klasse DMCellEditor wird angelegt:

getCellEditor-Methode


  import javax.swing.*;

  public class DMCellEditor extends DefaultCellEditor
  {
  }
        

DMCellEditor

Zum Editieren soll eine Unterklasse von JTextField, nämlich das im Framework enthaltene JTextInput, verwendet werden. Der Konstruktor dieser Klasse benötigt als Parameter einen Array von Strings, in dessen ersten Feld zu jeder Zeit der in das Feld eingebene Wert steht, und einen Initialwert. Diese beiden Werte werden als Parameter des Konstruktors von JTextInput weitergereicht. Der Konstruktor von DMCellEditor hat folgendes Aussehen:


  public DMCellEditor(String[] result, String init)
  {
    super(new JTextInput(result, init));
  }
        

Konstruktor

Für JTextInput wird das Paket util.swing importiert:


  import util.swing.*;
        

Da das Ergebnis der Eingabe später ausgewertet werden muß, wird die an den Konstruktor übergebene Variable in einer typgleichen Variable in der Klasse gespeichert. Dazu muß sie zunächst vor dem Konstruktor deklariert werden.


  private String[] result;
        

Dieser Variable wird im Konstruktor der entsprechende Parameter unter dem super-Befehl zugewiesen.


  this.result = result;
        

Wenn man sich die in DefaultCellEditor vorhandenen Methoden ansieht, wird deutlich, daß drei Methoden angepasst werden müssen:

getTableCellEditor gibt die zum Editieren verwendete Komponente, in diesem Fall also ein Objekt vom Typ JTextInput, mit gesetztem Initialwert zurück. Dazu wird die Komponente zunächst von der entsprechenden Methode der Oberklasse geholt. An ihr wird mit Hilfe der toString-Methode, der unter dem Namen "DM" in der globalen Katalogliste verzeichneten Währung, der Initialwert gesetzt und die Komponente zurückgeben:


  public Component getTableCellEditorComponent(
    JTable jTable, Object value, boolean isSelected,
    int row, int column)
  {
    Component component =
      super.getTableCellEditorComponent(
        jTable, value, isSelected, row, column);
    ((JTextInput)component).setText(((Currency)
      Shop.getTheShop().getCatalog("DM")).toString(
        (NumberValue)value));
    return component;  
  }
        

Für die in der Methode verwendeten Klassen werden weitere Pakete importiert:


  import data.*;
  import sale.*;
  import java.awt.*;
        

Die nächste anzupassende Methode ist getCellEditorValue. Diese muß einen, dem Inhalt der Zelle entsprechenden, Geldbetrag zurückgeben. Dazu wird versucht, das erste Feld von result mit Hilfe der Währung "DM" zu parsen und als Rückgabewert zu verwenden.

getCellEditorValue-Methode


  public Object getCellEditorValue()
  {
    try {
      return ((Currency)Shop.getTheShop().getCatalog(
        "DM").parse(result[0]);
    }
    catch(ParseException psex) {
      return new IntegerValue(0);
    }
  }
        

Die ParseException befindet sich im Paket java.text:


  import java.text.*;
        

Zuletzt muß stopCellEditing angepaßt werden. Diese Methode versucht das Editieren der Tabellenzellen zu beenden und liefert einen Booleschen Wert zurück, der angibt, ob die Operation erfolgreich war. Mit dieser Methode läßt sich verhindern, daß ungültige Werte eingegeben werden. Im Fall der Klasse DMCellEditor darf das Editieren nur beendet werden, wenn der eingegebene Text als Geldbetrag der Währung "DM" geparst werden kann. Demzufolge wird genau das versucht und im Erfolgsfall der Rückgabewert vom Urteil der entsprechenden Methode der Oberklasse abhängig gemacht. Wurde beim Parsen eine Exception erzeugt, wird false zurückgegeben.

stopCellEditing-Methode


  public boolean stopCellEditing()
  {
    try {
      ((Currency)Shop.getTheShop().getCatalog(
        "DM")).parse(result[0]);
    }
    catch(ParseException pexc) {
      return false;
    }
    return super.stopCellEditing();
  }
        

Damit ist DMCellEditor fertiggestellt und kann in EditableVideoStockTED verwendet werden. Dort ist nun die Methode getCellEditor zu implementieren. Sie deklariert ein Objekt vom Typ TableCellEditor als Rückgabewert. Diese Klasse muß dem Compiler über eine import-Anweisung bekannt gemacht werden:


  import javax.swing.table.*;
        

Die zu implementierende Methode gibt für die zweite und dritte Spalte ein Objekt des gerade erstellten DMCellEditors zurück. Für alle anderen Spalten bleibt die entsprechende Methode der Oberklasse AbstractTableEntryDescriptor verantwortlich.


  public TableCellEditor getCellEditor(int index)
  {
    if (index==1 || index==2)
      return new DMCellEditor(new String[1], "");
    else
      return super.getCellEditor(index);
  }
        

Die letzte, für diese Klasse zu implementierende, Methode ist setValueAt. Sie bekommt den aktuellen Datensatz, die Spalte und den zu setzenden Wert übergeben.


  public void setValueAt(Object record, int index,
                         Object value)
  {
  }
        

setValueAt-Methode

In dieser Methode wird zunächst die zu verändernde VideoCassette aus dem Datensatz ermittelt.


  VideoCassette videoCassette =
    (VideoCassette)((CountingStockTableModel.Record)
      record).getDescriptor();
        

Die so ermittelte VideoCassette darf jedoch nicht direkt verändert werden. Sie wurde nur zur Darstellung in der Tabelle empfangen, aber nicht zum Editieren. Es besteht Lese-, aber kein Schreibrecht. Um die VideoCassette verändern zu können, muß sie mit Schreibrecht empfangen werden. Dazu muß der dafür zuständigen get-Methode des Catalogs explizit mitgeteilt werden, daß eine Veränderung geplant ist. Das Item wird darauf speziell vorbereitet:


  try {
    Videocassette videoCassetteToEdit =
      (VideoCassette)videoCountingStock.getCatalog(null).get(
      videoCassette.getName(), db, true);
    QuoteValue quoteValue =
      (QuoteValue)videoCassetteToEdit.getValue();

    if (index == 1)
      videoCassetteToEdit.setValue(
        new QuoteValue(quoteValue.getBid(), (Value)value));
    if (index == 2)
      videoCassetteToEdit.setValue(
        new QuoteValue((Value)value, quoteValue.getOffer()));
  }
  catch(VetoException vexc) {
    JOptionPane.showMessageDialog(null,
      "The editing of that item was vetoed. It might be in use.");
  } 
        

Die VetoException ist Bestandteil des Pakets data.events und JOptionPane von javax.swing.


  import data.events.*;
  import javax.swing.*;
        

Zum Abschluß der Klasse EditableVideoStock wird die Methode getColumnClass mit Code gefüllt. Diese wird immer dann benötigt, wenn die Methoden getCellRenderer und getCellEditor null zurückgeben.


  public Class getColumnClass(int index)
  {
    return null;
  }
        

getColumnClass-Methode

Die Entwicklung des Videoautomaten ist damit beendet. Viel Spaß beim Betreiben des Automaten!!

Hier der Quelltext der in diesem Kapitel geänderten Klassen:

Zeit weiterschalten und Logfile einsehen

last modified on 24.09.2001
by kk15 and ch17