01.11.2013 Aufrufe

DIPLOMARBEIT SSAP - HTL- Innovativ Austria

DIPLOMARBEIT SSAP - HTL- Innovativ Austria

DIPLOMARBEIT SSAP - HTL- Innovativ Austria

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

HTBLuVA Innsbruck<br />

Höhere Lehranstalt für Elektronik<br />

Ausbildungsschwerpunkt: Technische Informatik<br />

<strong>DIPLOMARBEIT</strong><br />

<strong>SSAP</strong><br />

Swarovski Shop Administration Program<br />

Ausgeführt im Schuljahr 2012/13 von:<br />

Tobias Lanzanasto<br />

Gregor Neumann<br />

Michael Plattner<br />

Betreuer:<br />

Dipl.- lng. Mag(FH) Felix Klingler<br />

Innsbruck, am 22.05.2013


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Eidesstattliche Erklärung<br />

Wir erklären an Eides statt, dass wir die vorliegende<br />

Diplomarbeit selbstständig und ohne fremde Hilfe<br />

verfasst, andere als die angegebenen Quellen und<br />

Hilfsmittel nicht benutzt und die den benutzten<br />

Quellen wörtlich und inhaltlich entnommen Stellen als<br />

solche erkenntlich gemacht haben.<br />

Verfasser:<br />

Lanzanasto Tobias<br />

Innsbruck, am 22.05.2013<br />

Neumann Gregor<br />

Plattner Michael<br />

Seite 1


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Kurzbeschreibung<br />

Die Diplomarbeit befasst sich mit dem Shop Administration Program für das<br />

Unternehmen Swarovski. Unser Projekt soll das jahrelang verwendete Excel File,<br />

welches zur Shop Administration verwendet wird, ablösen.<br />

Die Grundidee zur Verbesserung der Administration besteht darin, die Shops in eine<br />

Datenbank zu importieren und diese mittels eines User Interfaces zu verwalten.<br />

Das Projekt kann in folgende Teile unterteil werden:<br />

1. Daten Import in die Datenbank<br />

Mithilfe eines Visual Basic Programmes sollen die Daten des Excel Files in die<br />

Datenbank importiert werden. Dies geschieht einmalig zur Einführung dieses<br />

Projektes.<br />

2. Datenbank<br />

Die MySQL Datenbank dient zur Speicherung aller Daten. Sie ermöglicht das<br />

schnelle Suchen und Editieren der Datensätze.<br />

3. Benutzeroberfläche<br />

Um die Datenbank einfach zu verwalten wird mit Java-RCP eine<br />

Benutzeroberfläche programmiert. Über diese kann man Datensätze in der<br />

MySQL Datenbank suchen, editieren, hinzufügen und löschen.<br />

Seite 2


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Summary<br />

This work covers the Swarovski Shop Administration Program for the company<br />

Swarovski. It should replace the current Excel-File to administrate Swarovski<br />

shops used for years.<br />

The main theory to improve the administration is to fill a database with all<br />

information about the shops and manage this database with a specific user<br />

interface.<br />

This project can be divided into following parts:<br />

1. Import data into the database (Visual Basic)<br />

Import the data from the Excel file into the database by using a Visual Basic<br />

Program. This is done only once for the implementation of this project.<br />

2. Database (MySQL)<br />

The MySQL database is used to store all data. The database allows quick<br />

searching and editing of the records.<br />

3. User Interface<br />

The User Interface is programmed with Java-RCP-technology, to enable<br />

simple managing of the database. With the UI is it possible to search, edit,<br />

add and remove data from the database.<br />

Seite 3


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Inhaltsverzeichnis<br />

1. Einleitung ............................................................................................................. 6<br />

1.1. Verlauf Diplomarbeit ...................................................................................... 6<br />

1.2. Zielsetzung und Aufgabenstellung................................................................. 7<br />

1.3. Aufbau der Diplomarbeit ................................................................................ 8<br />

1.4. Partnerfirma ................................................................................................... 9<br />

2. Visual Basic Import ............................................................................................ 10<br />

2.1. Allgemein ..................................................................................................... 10<br />

2.2. Excel File ..................................................................................................... 11<br />

2.3. Microsoft Visual Basic 2010 ........................................................................ 12<br />

2.4. Programmübersicht ..................................................................................... 13<br />

2.4.1. Connection Excel .................................................................................. 13<br />

2.4.2. Connection DB ...................................................................................... 14<br />

2.4.3. Import Country ...................................................................................... 14<br />

2.4.4. Import Shops ......................................................................................... 15<br />

2.4.5. Import Hardware ................................................................................... 17<br />

3. MySQL Database .............................................................................................. 19<br />

3.1. Allgemein ..................................................................................................... 19<br />

3.2. MySQL Workbench ..................................................................................... 20<br />

3.3. Datenbankübersicht ..................................................................................... 21<br />

4. Java RCP Userinterface .................................................................................... 24<br />

4.1. Allgemein ..................................................................................................... 24<br />

4.2. Programmierumgebung ............................................................................... 24<br />

4.2.1. Eclipse .................................................................................................. 24<br />

4.2.2. Eclipse 4 – Eclipse Juno ....................................................................... 25<br />

4.2.3. Subversion Client .................................................................................. 25<br />

4.3. Java-RCP .................................................................................................... 25<br />

4.4. JDBC ........................................................................................................... 26<br />

4.5. Programmübersicht ..................................................................................... 27<br />

4.5.1. Basis-Projekt ......................................................................................... 27<br />

4.5.2. RCP-Struktur ......................................................................................... 28<br />

4.5.3. Oberfläche und Application Model ........................................................ 30<br />

4.5.4. Verbindung zur DB ................................................................................ 37<br />

Seite 4


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.5. Handler ................................................................................................. 43<br />

4.5.6. Gesamttabellen ..................................................................................... 45<br />

4.5.7. TreePart ................................................................................................ 46<br />

4.5.8. TreeListener .......................................................................................... 50<br />

4.5.9. Search .................................................................................................. 53<br />

4.5.10. Statistics ............................................................................................ 57<br />

4.5.11. Details ................................................................................................ 59<br />

4.5.12. Add .................................................................................................... 69<br />

5. Manual/Bedienungsanleitung ............................................................................ 70<br />

5.1. Oberfläche ................................................................................................... 70<br />

5.2. Menü ........................................................................................................... 71<br />

5.3. Tree ............................................................................................................. 72<br />

5.4. Arbeitsfläche ................................................................................................ 72<br />

5.5. Suche .......................................................................................................... 73<br />

5.6. Neues Element hinzufügen ......................................................................... 74<br />

5.7. Statistiken .................................................................................................... 75<br />

5.8. Details ......................................................................................................... 75<br />

Bilder-Verzeichnis ..................................................................................................... 78<br />

Seite 5


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

1. Einleitung<br />

Diese Diplomarbeit beschreibt die Entwicklung eines neuen Shop Administrations<br />

Programmes, das das bisherige Excel Shopfile ablösen wird. Dieses wird im<br />

Auftrag von Swarovski im Rahmen einer Diplomarbeit verwirklicht.<br />

1.1. Verlauf Diplomarbeit<br />

Dank Herrn Prof. Schwarz, Professor an unserer Schule sowie Dienstnehmer bei<br />

Swarovski, erfuhren wir über die Möglichkeit bei Swarovski unsere Diplomarbeit<br />

zu verfassen. Von Swarovski wurden uns grundlegende Informationen über die<br />

Administration deren Shops gegeben, sowie der Aufbau der Excel Tabelle erklärt.<br />

Ebenfalls wurden die zu verwendende Datenbank und die Programmiersprachen<br />

festgelegt. Die Entwicklung, angefangen von Informationssammlungen über die<br />

Realisierbarkeit bis hin zum funktionsfähigen Programm, war selbstständig<br />

durchzuführen. Natürlich standen die Firma Swarovski, unser Betreuer Herrn<br />

Prof. Klingler sowie mehrere andere Personen bei auftretenden Fragen immer<br />

gerne zur Verfügung. Während des Sommers konnten wir ein vierwöchiges<br />

Ferialpraktikum bei Swarovski (Außenstelle Hall) absolvieren, in welchem wir<br />

ausschließlich an unserer Diplomarbeit arbeiteten konnten. Dies hatte für uns den<br />

großen Vorteil, dass wir bei auftretenden Problemen und Fragen immer sofort<br />

eine Ansprechperson hatten.<br />

Nach dem Vertrautmachen mit der Excel Tabelle wurde der Grundstein mit der<br />

Erstellung eines Datenbank-Strukturplanes gelegt. Alle Daten aus der Excel<br />

Tabelle, die nicht berechnet werden können, müssen in die Datenbank<br />

übernommen werden. Jene Informationen, die sich aus anderen Einträgen<br />

ergeben, werden nicht in der Datenbank gespeichert, sondern direkt vom<br />

Benutzeroberflächen-Programm aus den Datenbankeinträgen ermittelt.<br />

Anschließend schrieben wir ein Programm zur Übertragung der Daten aus der<br />

Excel Tabelle in die Datenbank.<br />

Seite 6


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Zum Verwalten der Datenbank für den Endnutzer implementierten wir eine<br />

Benutzeroberfläche, mit welcher Datensätze in der Datenbank erstellt, gelöscht,<br />

editiert und gesucht werden können.<br />

Nach Fertigstellung des Programmes wurde es Swarovski gegeben, wo es in der<br />

Abteilung RETAIL zum Testen verwendet wird.<br />

1.2. Zielsetzung und Aufgabenstellung<br />

Die Motivation der Diplomarbeit liegt darin, etwas im Fachbereich technische<br />

Informatik zu entwickeln, sowie mit einer namhaften Firma zusammenzuarbeiten<br />

und deren Arbeitsumfeld kennenzulernen.<br />

Die generelle Aufgabenstellung wurde von der Firma Swarovski gestellt, jedoch<br />

wurde uns in der Ausführung viel Spielraum gelassen. Laut Aufgabenstellung der<br />

Firma, soll eine Lösung gefunden werden Datensätze aus einer bestehenden<br />

Excel-Tabelle in eine MySQL-Datenbank zu übertragen. Zur Verwaltung der<br />

Datenbank soll eine in Java Rich Client Platform (RCP) geschriebene<br />

Benutzeroberfläche implementiert werden.<br />

Von Seiten der Firma wurde uns nahegelegt, das Import-Programm von der Excel<br />

Tabelle in die Datenbank mittels eines Visual Basic Programmes zu<br />

verwirklichen. Die Abteilung RETAIL arbeitet mit Microsoft-SQL-Datenbanken, da<br />

diese jedoch Closed Source sind, wurde vereinbart, dass wir eine MySQL-<br />

Datenbank mit einer General Public License lokal auf unseren eigenen Rechnern<br />

für die Entwicklung des Programmes verwenden. Für die spätere Einbindung des<br />

Programmes in die MS-SQL-Datenbank muss lediglich der Verbindungsaufbau<br />

zur Datenbank angepasst werden, die restlichen SQL-Befele sind in ANSI-SQL<br />

geschrieben, wodurch es zu keinen weiteren Problemen kommen sollte. Ebenso<br />

wurde vereinbart, dass die Benutzeroberfläche mittels Java Rich Client Platform<br />

(RCP) implementiert wird.<br />

Zeitliche Begrenzungen gibt es seitens der Firma keine. Der Zeitplan ist uns<br />

überlassen worden.<br />

Seite 7


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

1.3. Aufbau der Diplomarbeit<br />

Die Arbeit kann prinzipiell in drei Teilgebiete gegliedert werden:<br />

Visual Basic<br />

Das Visual Basic Programm dient zur Übertragung der Datensätze<br />

aus der Excel Tabelle in die Datenbank.<br />

MySQL-Datenbank<br />

Die Aufgabe der MySQL Datenbank ist es, die Datensätze effizient,<br />

widerspruchsfrei und dauerhaft zu speichern und benötigte<br />

Datensätze in unterschiedlichen bedarfsgerechten Darstellungsformen<br />

bereitzustellen.<br />

Java Rich Client Platform<br />

Das Java Rich Client Platform (RCP) Program ermöglicht die<br />

Verwaltung der Datenbank mittels eines User-Interfaces.<br />

Abb. 1: Grundaufbau<br />

Diese drei Teilgebiete werden in den folgenden Seiten, in entsprechender<br />

Reihenfolge, möglichst genau beschrieben und die Funktionen erklärt. Es wurde<br />

darauf Wert gelegt, dass jeder Funktionsblock zuerst allgemein beschrieben wird<br />

und erst im weiteren Verlauf auf die Details eingegangen wird.<br />

Seite 8


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

1.4. Partnerfirma<br />

Abb. 2: Firmenlogo Swarovski<br />

Die Firma Swarovski ist ein österreichisches Familienunternehmen, welches 1895<br />

in Wattens gegründet wurde. Zum einen produziert Swarovski Kristall diverse<br />

Schmuckstücke aus Kristallglas, zum anderen gehören der Swarovski Gruppe<br />

ebenfalls die Tyrolit Schleifmittel in Schwaz und die Swarovski Optik in Absam an.<br />

Swarovski und seine Tochterunternehmen beschäftigen knapp 30.000 Mitarbeiter<br />

in 40 Länder.<br />

Die Standpunkte in Wattens und Hall sind durch ihre Nähe zu Innsbruck ideal für<br />

unsere Partnerschaft.<br />

Seite 9


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

2. Visual Basic Import<br />

2.1. Allgemein<br />

Die erste Aufgabe unserer Arbeit war es, die vorhandenen Daten der Excel-<br />

Tabelle in die Datenbank zu importieren. Dies soll mit einem Programm<br />

geschehen, das in Visual Basic geschrieben ist. Was sich zu Beginn recht einfach<br />

anhörte, führte jedoch gleich zu einigen Schwierigkeiten. Was die Arbeit an<br />

diesem Import-Programm erschwerte, war, dass die Struktur der Daten, die im<br />

Excel-File verwendet wurde, nicht unbedingt geeignet für eine Datenbank war.<br />

Somit konnten wir die einzelnen Tabellen nicht einfach in der Datenbank<br />

übernehmen, sondern mussten zuerst eine geeignete Datenbankstruktur<br />

zusammenstellen. Durch die neue Struktur wurde das Import-Programm jedoch<br />

um einiges komplizierter, da nun teilweise Daten aus mehreren verschiedenen<br />

Sheets der Excel Tabellen zusammengefasst werden mussten. Durch dieses<br />

Zusammenfassen der Daten dauert die Ausführung des Programms auch recht<br />

lange. Bei einem kompletten Durchlauf des Programms kommt es zu einer Dauer<br />

von ca. 30 Minuten. Das Programm muss jedoch nur einmal ausgeführt werden,<br />

weshalb nicht zusätzlicher Aufwand in Zeitoptimierung des Programms gesteckt<br />

wurde.<br />

Da dieses Programm nur zum einmaligen Importieren der Daten verwendet wird,<br />

wäre eine aufwändige Oberfläche nicht notwendig. Daher öffnet sich beim Start<br />

der Übertragung nur ein Konsolenfenster, das den Fortschritt des Programms<br />

grob darstellt. Es wird angezeigt, aus welcher Excel-Tabelle gerade Daten<br />

importiert werden und für jede erfolgreiche Übertragung wird ein Punkt auf dem<br />

Fenster angezeigt.<br />

Seite 10


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

2.2. Excel File<br />

Bisher wurden die Shops der Firma Swarovski mit Hilfe einer Excel-Tabelle<br />

verwaltet. Angefangen hat das vor ca. 10 Jahren mit noch einigen wenigen<br />

Shops. Da die Firma mittlerweile stark expandiert, gibt es 1000 Shops, die auf der<br />

ganzen Welt verteilt sind. Dadurch wurde die anfangs noch recht übersichtliche<br />

Excel-Tabelle immer größer und mit der Zeit, durch zum Teil auch fehlerhafte<br />

Einträge, komplizierter und unübersichtlicher.<br />

Dieses Excel-File ist in mehrere Sheets aufgeteilt. Im ersten Sheet, dem „ROC<br />

Info“-Sheet, sind Informationen über die einzelnen Länder gespeichert, in denen<br />

Shops der Firma Swarovski ihren Standpunkt haben. Man kann diesem Sheet<br />

beispielsweise entnehmen, auf welchem Kontinent das Land liegt, wie viel<br />

Steuern zu zahlen sind oder in welcher Zeitzone es liegt. Außerdem sind<br />

Kennungsnummern wie VG-Nummer oder Country-Code ersichtlich.<br />

In den Sheets „EUROPE“, „AMERICAS” und „ASIA PACIFIC” sind Details zu den<br />

einzelnen Shops gespeichert. Dabei werden im Sheet „EUROPE“ alle<br />

europäischen Shops, im Sheet „AMERICAS“ alle Nord-, Mittel- und Südamerikanischen<br />

Shops und im Sheet „ASIA PACIFIC“ alle Shops im Raum Asien,<br />

Ozeanien und Australien zusammengefasst. In diesen Sheets sind Informationen<br />

wie Shop-Nummer, Shop-Name, Stadt, Land, Adresse, Telefonnummer, Verkaufsfläche<br />

und noch einiges mehr gespeichert. Zusätzlich wird die im Shop<br />

vorhandene Hardware inklusive einiger Details angezeigt. Eine Ausnahme sind<br />

dabei die europäischen Shops, da hier noch ein weiterer Sheet existiert, in dem<br />

nur Informationen über die einzelnen Hardwarekomponenten zu sehen sind.<br />

Details für Hardware sind zum Beispiel Seriennummer, Installationsdatum, Alter,<br />

Modellbezeichnung und MAC-Adresse.<br />

Seite 11


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Ein weiterer Sheet ist der „TOTALS & Licenses“-Sheet. Hier werden die Inhalte<br />

aller anderen Sheets zu einer Statistik zusammengefasst. Es wird beispielsweise<br />

angezeigt, wie viele Shops eines bestimmten Typs in einem Land vorhanden<br />

sind. Außerdem sind dort Informationen zum jeweiligen Kassensystem in den<br />

jeweiligen Ländern gespeichert.<br />

2.3. Microsoft Visual Basic 2010<br />

Das Visual Basic Programm wird mit mit Hilfe der von Microsoft angebotenen<br />

Programmierumgebung Microsoft Visual Basic 2010 Express implementiert. Für<br />

die Verwirklichung des Import-Programms mittels Microsoft Visual Basic spricht,<br />

dass schlussendlich sowohl eine Microsoft Datenbank also auch eine Microsoft<br />

Excel Tabelle verwendet wird und durch die ausschließliche Verwendung von<br />

Microsoft Produkten die hundertprozentige Kompatibilität gegeben ist.<br />

Die Programmiersprache Visual Basic ist zwar sehr simpel und kann mit<br />

Vorkenntnissen von C oder anderen Sprachen sehr schnell erlernt werden,<br />

jedoch kann ein komplexes Programm sehr unübersichtlich werden. Es werden<br />

Variablen zum Beispiel nicht als INT, VCHAR, etc. deklariert sondern alle als Dim<br />

und das Programm erkennt den Typen automatisch, jedoch kann dadurch der<br />

Überblick über die verschiedenen Variablen schneller verloren gehen.<br />

Seite 12


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

2.4. Programmübersicht<br />

2.4.1. Connection Excel<br />

Um mit dem Transfer der Daten in die Datenbank beginnen zu können, muss<br />

zuerst eine Verbindung mit dem Excel-File aufgebaut werden. Dazu wird als<br />

erstes mit der Funktion CreateObject(„Excel-Application“) ein neues<br />

Objekt generiert. Mit der Funktion Workbooks.Open(FileName, ,true) wird nun<br />

eine Verbindung zum gewünschten Excel-File aufgebaut. Dabei wird das File<br />

schreibgeschützt im Hintergrund geöffnet. Bei einem unerwarteten Programmabsturz<br />

würde das File geöffnet bleiben, daher wird es zur Vorsicht sichtbar<br />

gemacht, um zu sehen, dass es geöffnet wurde,und man es dann zu schließen<br />

hat.<br />

Dim objExcel, FileName, objWorkbook<br />

objExcel = CreateObject("Excel.Application")<br />

FileName = "...\SR Shops - IT Info.xlsm"<br />

objWorkbook = objExcel.Workbooks.Open(FileName, , True) ' Open Read Only<br />

objExcel.Visible = True<br />

Anschließend werden einzelne Unterprogramme zum Import nacheinander<br />

gestartet. Zuerst werden die Länder übertragen, danach die Shops und zuletzt die<br />

Hardware. Die Unterprogramme für Shops und Hardware werden immer für jeden<br />

Kontinent einzeln gestartet, da so für eine Übertragung weniger Worksheets aus<br />

dem Excelfile verwendet werden müssen.<br />

Seite 13


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

2.4.2. Connection DB<br />

Am Beginn jedes Unterprogramms wird immer eine Verbindung zur Datenbank<br />

aufgebaut. Für die Verbindung wird ein Connection-String benötigt, der sämtliche<br />

Informationen zur Anmeldung enthält. Dieser besteht aus Serveradresse,<br />

Username, Passwort und Datenbank. Mit der Funktion conn.Open() wird nun die<br />

Verbindung eröffnet. Jetzt können MySqlCommands mit einer Abfrage in Form<br />

eines Strings und der passenden Datenbankverbindung generiert werden, welche<br />

anschließend mit Hilfe eines MySqlDataReaders ausgeführt werden können.<br />

2.4.3. Import Country<br />

Zu Beginn des Imports der Länder werden alle Einträge der „Country“-Tabelle<br />

gelöscht. Dadurch wird das Programm stark vereinfacht, da nicht darauf geachtet<br />

werden muss, ob ein Eintrag bereits in der Datenbank vorhanden ist und somit<br />

keine Fehler durch Duplikate entstehen können.<br />

Anschließend werden für jede Spalte des Datensatzes zwei Variablen erstellt. In<br />

einer werden später die Einträge des Excel-Files zwischengespeichert, in der<br />

anderen wird „hard coded“ angegeben, in welcher Spalte des Excel-Files der<br />

passende Eintrag zu finden ist.<br />

Nun wird in einer „Do Until“-Schleife für jede Zeile im Excel-File, in diesem Fall<br />

beginnend mit Zeile 5, ein Datensatz in der Datenbank erstellt. Zum Auslesen der<br />

Excel-Einträge können zwei Funktionen verwendet werden. Die Funktion<br />

objWorkSheet.Cells(row, column).Text gibt einfach den Text zurück den<br />

man beim Betrachten der Tabelle in den Zellen lesen kann. Das ist bei fast allen<br />

Einträgen die richtige Lösung, außer bei den meisten Datumswerten. Die<br />

Tabellen sind nämlich so formatiert, dass beispielsweise beim Datum<br />

„01.10.2011“ in der Zelle nur der Text „10.11“ zu sehen ist. Erst wenn man auf die<br />

Zelle klickt, erscheint oben in der Eingabeleiste das richtige Datum. In solchen<br />

Fällen wird die Funktion objWorkSheet.Cells(row, column).Value benötigt,<br />

um den kompletten Wert der Zelle zu entnehmen. Außerdem ist bei<br />

Datumswerten darauf zu achten, dass wirklich ein gültiges Datum verwendet wird,<br />

Seite 14


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

da es ansonsten beim Eintrag in die Datenbank zu Fehlern kommt. Daher wird<br />

überprüft, ob der erhaltene Eintrag aus dem Excel-File stimmen kann, falls nicht,<br />

wird er wenn möglich in ein einheitliches Datumformat umgewandelt oder durch<br />

einen Default-Wert ersetzt.<br />

Wenn alle Werte des Datensatzes aus dem Excel-File übernommen wurden, wird<br />

daraus eine „INSERT INTO“-Abfrage erstellt, welche anschließend in einem<br />

MySqlCommand verpackt und mit dem MySqlDataReader an der Datenbank ausgeführt<br />

wird. Nach einem solchen Durchlauf wird ein Punkt im Konsolenfenster<br />

geschrieben, um den erfolgreichen Eintrag eines Datensatzes in die Datenbank<br />

zu signalisieren.<br />

Dieser Vorgang wird für jede ausgefüllte Zeile der Excel-Tabelle wiederholt.<br />

2.4.4. Import Shops<br />

Dieses Unterprogramm ist im Prinzip ähnlich gegliedert wie das zum Importieren<br />

der Länder. Auch hier werden zu Beginn vorhandene Einträge in den Tabellen<br />

„shopinfo.shops“ und „shopinfo.closed_shops“ der Datenbank gelöscht. Das darf<br />

aber nur dann geschehen, wenn Daten aus dem EUROPE-Sheet (dem ersten<br />

Sheet) des Excel-Files übertragen werden, da dieses Unterprogramm für jeden<br />

Kontinent neue ausgeführt wird und sonst schon regulär importierte Shops wieder<br />

gelöscht werden würden.<br />

Anschließend werden wieder Variablen zur Zwischenspeicherung angelegt und<br />

die passenden Spaltennummern eingetragen. Dabei muss jedoch darauf geachtet<br />

werden, dass die drei Excel-Sheets „EUROPE“, „AMERICAS“ und „ASIA<br />

PACIFIC“ nicht genau gleich formatiert sind, daher variieren die Spaltennummern<br />

für bestimmte Einträge zwischen den verschiedenen Sheets.<br />

Nun beginnt wieder die eigentliche Übertragung der Daten aus dem Excel-File in<br />

das VB-Programm. Dieser Vorgang ist bei den Shops jedoch um einiges<br />

komplizierter als bei den Ländern, da im Excel-File manchmal Shops ohne SAP-<br />

Nummer auftreten, die die einzelnen Shops identifizieren. In der neuen<br />

Datenbank wird diese Nummer als „Primary Key“ gehandhabt und muss daher für<br />

alle Shops eindeutig sein. Shops ohne eine solche SAP-Nummer werden als<br />

Seite 15


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

„Dummy-Shops“ behandelt, das heißt, sie bekommen vorübergehend die SAP-<br />

Nummer „999999999“, somit werden sie vom Programm als gültiger Shop<br />

erkannt und sind gleichzeitig als Dummy-Shop gekennzeichnet. Nachdem nun<br />

alle Daten aus dem Excel-File ausgelesen wurden, wird überprüft, ob es sich<br />

beim vorhandenen Shop um einen Dummy-Shop handelt. Falls das der Fall ist,<br />

wird nun eine einzigartige SAP-Nummer generiert. Diese setzt sich aus drei<br />

Teilen zusammen. Die ersten drei Ziffern sind immer „999“. Darauf folgt die<br />

vierstellige VG-Nummer des Landes, in dem der Shop seinen Standpunkt hat.<br />

Diese Nummer wird dem „ROC Info“-Sheet des Excel-Files entnommen.<br />

Abschließend wird noch die Shop-Nummer, die innerhalb eines Landes eindeutig<br />

ist, angehängt.<br />

Ähnlich wie Dummy-Shops werden auch VG-Shops behandelt. Sie besitzen im<br />

Excel-File ebenfalls keine SAP-Nummer, daher muss auch hier eine Nummer<br />

generiert werden. Auch sie setzt sich aus drei Teilen zusammen. Die ersten drei<br />

Ziffern sind dieses Mal „802“. Darauf folgt wieder die VG-Nummer des jeweiligen<br />

Landes. Um den VG-Shop innerhalb eines Landes zu identifizieren, wird nun die<br />

Workstation-Nummer als zweistellige Zahl verwendet.<br />

Danach müssen wieder Einträge überprüft und verändert werden, die für einen<br />

Eintrag in die Datenbank nicht geeignet sind. Wie schon bei den Ländern werden<br />

Datumswerte umformatiert bzw. durch Default-Werte ersetzt. Bei diesen Daten<br />

kann es aber zusätzlich vorkommen, dass Namen von Shops, Shop-Managern,<br />

Straßen oder Ähnlichem ein einfaches Hochkomma enthalten. Das führt beim<br />

Ausführen der SQL-Abfrage zu Fehlern. Daher müssen alle einfachen<br />

Hochkommas durch zwei einfache Hochkommas für das Einfügen in die<br />

Datenbank ersetzt werden, sodass die Daten ohne Fehler korrekt in der<br />

Datenbank stehen.<br />

Beim Erstellen der SQL-Abfrage muss nun noch entschieden werden, ob der<br />

Shop in die shopinfo.shops-Tabelle oder in die shopinfo.closed_shops-Tabelle<br />

geschrieben werden muss. Geschlossene Shops werden dadurch gekennzeichnet,<br />

dass sich ein „X“ im Shop-Typ befindet.<br />

Seite 16


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Nachdem eine passende „INSERT INTO“-Abfrage erstellt wurde, wird diese an<br />

der Datenbank ausgeführt und dieser Vorgang für alle anderen Shops wiederholt.<br />

2.4.5. Import Hardware<br />

Zum Importieren der Hardware werden zwei Unterfunktionen benötigt. Die<br />

Unterfunktion Import_hardware stellt die Hauptkomponente der Übertragung dar.<br />

Gleich wie bei der Shop-Importierung werden auch hier zu Beginn bei der<br />

Übertragung aus dem EUROPE-Sheet alle vorhandenen Datensätze aus der<br />

shopinfo.hardware-Tabelle der Datenbank gelöscht. Anschließend werden auch<br />

hier die Spaltennummern je nach Sheet gespeichert, da diese nicht bei allen<br />

Kontinenten übereinstimmen. Eine weitere Besonderheit dabei ist, dass für<br />

Europa ein weiterer Sheet im Excel-File existiert, der detaillierte Informationen<br />

über die Hardware in europäischen Shops enthält, wie zum Beispiel bisherige<br />

Standorte. Daher wird in der „DO UNTIL“-Schleife immer unterschieden, ob die<br />

folgenden Informationen eine europäische Hardware betreffen oder eine andere.<br />

Die allgemeinen Details werden bei beiden Möglichkeiten gleich ausgelesen.<br />

Da es in einem Shop mehrere Hardwarekomponenten geben kann, muss die<br />

richtige SAP-Nummer des Shops gefunden werden. Dabei wird darauf geachtet,<br />

ob sich die Shop-Nummer ändert. Immer wenn das der Fall ist, handelt es sich<br />

um einen neuen Shop und die Reihe in der die richtige SAP-Nummer zu finden<br />

ist, wird aktualisiert. Anschließend werden alle notwendigen Informationen aus<br />

dem jeweiligen Sheet des Kontinents ausgelesen. Mit Hilfe des Country-Codes<br />

werden nun noch zusätzliche Informationen aus dem „ROC Info“-Sheet<br />

gewonnen.<br />

Handelt es sich um einen europäischen Shop, muss nun mit Hilfe der<br />

Seriennummer die passende Zeile im „EUR HW Details“-Sheet herausgesucht<br />

werden. Hier werden nun spezielle Informationen für die europäischen Shops<br />

übertragen. Bei anderen Shops werden diese Spalten in der Datenbank mit<br />

einem Leerstring bzw. einem Default-Wert gefüllt.<br />

Anschließend werden die Einträge wieder überprüft und wenn notwendig<br />

verändert. Vor allem beim „ASIA PACIFIC“-Sheet kommt es vor, dass<br />

Seite 17


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Seriennummern identisch sind und sie werden daher erweitert, um sie eindeutig<br />

identifizieren zu können. Es kommt auch vor, dass keine Seriennummer im Excel-<br />

File eingetragen ist. Wenn dabei jedoch ein gültiger Hostname vorhanden ist, wird<br />

eine Seriennummer als Platzhalter generiert. Diese Nummer beginnt immer mit<br />

„unknown“. Danach kommen der Country-Code und die Nummer der Zeile, aus<br />

der die Information stammt.<br />

Damit auch Hardware aus einem VG-Shop richtig verknüpft werden kann, muss<br />

wieder die SAP-Nummer generiert werden. Sie muss gleich wie beim Shop selbst<br />

generiert werden, damit auch das gleiche Ergebnis geliefert wird und somit auch<br />

die Verknüpfung möglich ist.<br />

Anschließend wird wieder eine „INSERT INTO“-Abfrage erstellt und der Vorgang<br />

für alle weiteren Hardwarekomponenten wiederholt.<br />

Sogenannte „Retired Hardware“, also Hardware, die nicht mehr in Shops<br />

verwendet wird, wird mit dieser Funktion nicht importiert. Für diese Einträge wird<br />

die zweite Unterfunktion Import_retired_hardware verwendet.<br />

Einziger Unterschied zur ersten Funktion ist, dass hier alle Informationen nur aus<br />

dem Sheet „EUR HW Details“ kommen. Es werden jedoch nur Hardwarekomponenten<br />

importiert, die in der Spalte „active/retired“ als retired markiert sind.<br />

Seite 18


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

3. MySQL Database<br />

3.1. Allgemein<br />

Wir verwenden zum Testen unseres Projekts eine auf unseren Rechnern lokal<br />

installierte MySQL-Datenbank, da diese in der Basisversion eine sehr anerkannte<br />

Freeware Lösung für eine Datenbank ist. Zum Bearbeiten der Datenbank wird<br />

von uns die MySQL Workbench verwendet, welche wie die MySQL Datenbank<br />

frei zur Verfügung steht. Der Entwickler der MySQL Datenbank sowie der MySQL<br />

Workbench ist Oracle Corporation.<br />

Die von uns eingerichtete MySQL Datenbank wird später in eine bestehende<br />

Microsoft Datenbank von Swarovski implementiert. Da die SQL-Befehle in ANSI-<br />

SQL geschrieben sind, ist es unerheblich, ob eine Microsoft-SQL- oder eine<br />

MySQL-Datenbank verwendet wird. Lediglich der Datenbankzugriff von dem<br />

Visual Basic Programm, beziehungsweise des Java Programms muss angepasst<br />

werden.<br />

Um die Datenbank an sich zu übertragen, werden einfach die Create-Statements<br />

kopiert und beim Erstellen einer weiteren Datenbank direkt ausgeführt. Es wird<br />

dabei nur die Datenbankstruktur erstellt.<br />

Seite 19


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

3.2. MySQL Workbench<br />

Die MySQL-Workbench ist ein Modellierungswerkzeug zur Planung und Wartung<br />

von Datenbanken. Der Entwickler dieses Modellierungstools ist Oracle Corporation<br />

und steht es für alle gängigen Betriebssysteme zur Verfügung. Die<br />

MySQL Workbench wird sowohl als „Community Edition“ unter der General Public<br />

License (GPL) als auch mit zusätzlichen Funktionalitäten als „Standard Edition“<br />

kommerziell in Form eines Jahresabos angeboten. Es wurde bei diesem Projekt<br />

die Version 5.2.40 verwendet. Trotz umfangreichen Funktionen liegt der Haupt-<br />

Einsatzbereich der Workbench bei der Modellierung der Daten.<br />

Mittels der MySQL-Workbench können Entity-Relationship-Diagramme (ER-<br />

Diagramme) erstellt werden. Diese sind oft der erste Schritt bei einer Datenbank<br />

Modellierung. Das ER-Diagramm stellt die Zusammenhänge zwischen einzelnen<br />

Tabellen graphisch dar, wodurch ein Verlust der Übersicht über eine komplexe<br />

Datenbankstruktur verhindert werden soll. Zusätzlich können Relationen<br />

zwischen den einzelnen Tabellen definiert werden, welche die Übersicht der<br />

Tabellenverknüpfungen verbessern sollen.<br />

Die Verbindung zur Datenbank wurde mittels einer TCP/IP-Verbindung<br />

ermöglicht.<br />

Seite 20


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

3.3. Datenbankübersicht<br />

Seite 21


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Die gesamte Datenbank besteht aus 4 miteinander verknüpften Tabellen, in der<br />

ersten Tabelle werden die verschiedenen Länder gespeichert.<br />

Für die einzelnen Shops gibt es zwei verschiedene Tabellen, eine für die<br />

geöffneten Shops und eine für die geschlossenen Shops. Diese beiden Tabellen<br />

sind im Prinzip genau gleich, sie haben nur einen einzigen Unterschied: In der<br />

„shops“-Tabelle wird die SAP-Nummer als Primary Key verwendet, in der<br />

„closed_shops“-Tabelle übernimmt diese Aufgabe ein automatischer Index. Das<br />

kommt daher, dass die SAP-Nummern geschlossener Shops wieder freigegeben<br />

sind und somit neu vergeben werden dürfen. Würde man dann einen Shop<br />

schließen, dessen SAP-Nummer mit der eines geschlossenen Shops<br />

übereinstimmt, würde ein Fehler in der Datenbank auftreten, da der Primary Key<br />

einzigartig sein muss. Um solchen Problemen vorzubeugen, wird hier ein<br />

automatischer Index von der Datenbank generiert.<br />

In der vierten und letzten Tabelle sind Informationen über die Hardware<br />

gespeichert, die in den einzelnen Shops eingesetzt wird.<br />

Die Pfeile im Datenbankstrukturplan stellen die einzelnen Verknüpfungen<br />

zwischen den Tabellen dar. Diese Verknüpfungen sind in der Datenbank nicht<br />

fest vorgegeben, sondern werden bei jeder Abfrage, bei der sie benötigt werden,<br />

angegeben.<br />

Die Verknüpfungen zwischen „shops“-Tabelle bzw. „closed_shops“-Tabelle und<br />

„country“-Tabelle müssen immer korrekt sein. Sollte ein User versuchen, einen<br />

Shop-Datensatz so zu verändern, dass die Spalte mit dem Country-Code mit<br />

keinem Land übereinstimmt, wird eine Fehlermeldung ausgegeben.<br />

Bei der Verknüpfung der Spalte „ship_to“ der „hardware“-Tabelle mit dem Primary<br />

Key eines Shop-Datensatzes muss nicht unbedingt eine passende Nummer<br />

angegeben werden. Wenn die Nummer existiert, besteht eine Verknüpfung, wenn<br />

nicht, wird dem Programm signalisiert, dass die ausgewählte Hardware in keinem<br />

Shop verwendet wird und somit entweder an einen neuen Shop vergeben werden<br />

kann oder bereits ausrangiert wurde. Außerdem kann keine Hardware mit einem<br />

geschlossenen Shop verknüpft werden, auch wenn die SAP-Nummer zufällig<br />

zusammenstimmen würde, wären die beiden Datensätze trotzdem nicht<br />

miteinander verknüpft.<br />

Seite 22


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Die Verknüpfungen, welche strichliert zwischen Hardware und Shop eingezeichnet<br />

sind, werden vom Programm eigentlich nicht benötigt. Hierbei handelt es<br />

sich um die Nummern der Shops, in denen die Hardware früher verwendet wurde.<br />

Da jedoch früher andere Nummern zur Identifizierung eines Shops verwendet<br />

wurden, stehen hier meist noch Nummern des alten Systems. Normalerweise<br />

sollte jedoch auch hier eine gültige SAP-Nummer aufscheinen, welche auf den<br />

vorherigen Shop hinweist.<br />

Seite 23


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4. Java RCP Userinterface<br />

Das Nachfolgende Kapitel (inkl. Bilder) wurde bis auf weiteres mit Hilfe des Buches “Eclipse 4<br />

Application Development“ von Lars Vogel verfasst. (ISBN: 3943747034)<br />

4.1. Allgemein<br />

Für das User-Interface wurde die Java-RCP (Rich Client Project) Technologie<br />

empfohlen, weil diese plattformunabhängig ausführbar ist und leicht in RAP (Rich<br />

Ajax Platform) für Online-Verfügbarkeit umgeschrieben werden kann.<br />

Eine generelle Web-Application ist aus rechtlichen Gründen nicht realisierbar<br />

gewesen.<br />

4.2. Programmierumgebung<br />

Zum Programmieren der GUI verwenden wir speziell Eclipse for RCP and RAP<br />

Developers (Juno Release) mit folgenden Add-Ons: E4 CSS Spy (incubation) und<br />

Eclipse e4 Tools (incubation). Der Hauptdownload bietet die Möglichkeit Java-<br />

RCP zu programmieren, die Add-Ons bieten diverse Hilfen.<br />

Zur einfacheren Abgleichung unter den Mitarbeitern wurde uns ein Subversion<br />

Client (siehe 4.2.3. Subversion Client) von Swarovski zur Verfügung gestellt.<br />

4.2.1. Eclipse<br />

Eclipse ist eine Entwicklungsumgebung, welche ursprünglich zum Programmieren<br />

von Java gedacht war. Heute kann man mit passenden Plug-Ins auch andere<br />

Sprachen mit Eclipse programmieren. Der modulare Aufbau von Eclipse hilft beim<br />

genauen Anpassen der Programmieroberfläche an die eigenen Bedürfnisse. Die<br />

Formatierungstools und Autokomplettierung sind äußerst hilfreich für ein flüssiges<br />

Programmieren.<br />

Seite 24


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.2.2. Eclipse 4 – Eclipse Juno<br />

Eclipse 4 bietet neue Sets an Technologie, welche die Flexibilität der Eclipse<br />

Plug-In Entwicklung erhöhen. Die letzte veröffentlichte Version von Eclipse ist<br />

Juno, und basiert auf Eclipse 4.2. Dieses beinhaltet alle Vorteile von der Eclipse<br />

3.x Serie, lässt aber die wunden Punkte der Version aus. Grundsätzlich sind aber<br />

viele Konzepte von Eclipse 3 in der neuen Version vorhanden.<br />

Es können auch weiterhin Eclipse 3.x Plug-Ins mit Eclipse 4 ohne Änderungen<br />

ausgeführt werden.<br />

4.2.3. Subversion Client<br />

Mit dem entsprechenden Add-On kann von Eclipse direkt auf einen Subversion<br />

Client zugegriffen werden. So liegt das Projekt nicht mehr lokal auf einem<br />

Rechner, sondern wird auf einen angegebenen Server ausgelagert. Mit einem<br />

Update des Projektes wird die neueste Version heruntergeladen und lokal am<br />

Rechner in einer Workspace gespeichert. Nach Änderungen im Projekt wird<br />

dieses Commited, um diese Version wieder auf den Server zu laden. Neben der<br />

einfachen Abgleichung mit den Mitarbeitern ist ein weiterer großer Vorteil, dass in<br />

einer History ebenfalls Zugriff auf ältere Versionen des Projektes besteht.<br />

4.3. Java-RCP<br />

Java-RCP (Rich Client Platform) ist eine bestimmte Art, wie man mit Java<br />

programmiert. Dabei ist die Grundstruktur der große Unterschied zu „normalem“<br />

Java. Die Sprache ist weiterhin dieselbe. Die Vorteile der Rich Client Struktur<br />

liegen in der Anpassungsfähigkeit des Programms an das Problem und die<br />

leichte Umsetzung in ein webbasierendes Programm.<br />

Seite 25


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.4. JDBC<br />

Dieses Unterkapitel (inkl. Bilder) wurde mit Hilfe der Oracle-Homepage erstellt.<br />

http://www.oracle.com/technetwork/java/javase/jdbc/index.html (30.04.2013 17:00)<br />

JDBC (Java Data Base Connectivity) ist eine Datenbankschnittstelle, die eine<br />

Kommunikation zwischen einem Java-Programm und einer Datenbank<br />

ermöglicht. Die JDBC API ist Bestandteil der Java-Plattform und ist somit bereits<br />

überall vorhanden.<br />

Im Prinzip übersetzt diese Java-Statements in für die Datenbank leserliche<br />

Stücke und umgekehrt. Es gibt dabei vier verschiedene Typen:<br />

Links: Typ 4<br />

Mit dem Pure Java JDBC Driver wird<br />

ein Java Befehl direkt in einen DBMS<br />

Befehl übersetzt.<br />

Links: Typ 1<br />

Die Java Anfrage wird zuerst in einen<br />

ODBC (Open Data Base Connectivity)<br />

Code umgewandelt und muss dann auch<br />

von der Datenbank wieder eigens<br />

umgewandelt werden.<br />

Seite 26


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Rechts: Typ 3<br />

Über eine DB Middleware wird mit der<br />

Datenbank kommuniziert. Der Java<br />

Befehl wird dann speziell für die<br />

vorliegende Datenbank übersetzt.<br />

Java muss sich somit keine Gedanken<br />

über die Datenbank oder sonstige<br />

Sonderheiten machen.<br />

Rechts: Typ 2<br />

Die Java Anfrage wird in Anfragen der<br />

eigenen Client-API übersetzt. Dabei<br />

muss auf beiden Seiten ein zusätzlicher<br />

Code hinzugefügt werden.<br />

Diese sind die gängigsten Methoden.<br />

Diese beiden werden nur bei keiner<br />

anderen Möglichkeit verwendet.<br />

In diesem Projekt wird der Treiber-Typ 4 verwendet, weil dieser klein und<br />

ausreichend für die Anforderungen ist.<br />

Um diesen JDBC-Treiber verwenden zu können, muss neben der bereits<br />

vorhandenen JDBC API noch ein Jar-File eingebunden werden. Dieses muss im<br />

Manifest-File in den Classpath eingefügt werden.<br />

4.5. Programmübersicht<br />

4.5.1. Basis-Projekt<br />

Um das Basis-Projekt zu erstellen, verwendet man am besten den vorhandenen<br />

Wizard, damit alle benötigten Files und Strukturen automatisch erstellt werden.<br />

Dazu wählt man File → New → Others → Eclipse 4 → Eclipse 4 Application<br />

Project aus und gibt einen Projektnamen an und wählt entsprechende weitere<br />

Optionen aus.<br />

Nachdem das Projekt erstellt wurde, kann man das .product-File auswählen, und<br />

im Übersicht-Tab auf den Launch an Eclipse Apllication Button klicken. Das RCP-<br />

Projekt startet.<br />

Seite 27


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Dies kann je nach Optionenwahl schon mit Beispiel-Komponenten gefüllt sein,<br />

wie zum Beispiel einer Menü-Leiste.<br />

Um Fehler beim Start zu vermeiden, müssen die Plug-Ins geprüft werden und bei<br />

Bedarf die fehlenden hinzugefügt werden. Dies geschieht im Plug-In-Tab des<br />

Product-Files. Dort können mit dem Klick auf Add Required Plug-Ins automatisch<br />

die fehlenden Plug-Ins hinzugefügt werden. Mit dem Aktivieren der Checkbox<br />

Validate plug-ins prior to launching werden dann vor jedem Start des Programms<br />

automatisch die Plug-Ins überprüft.<br />

4.5.2. RCP-Struktur<br />

Abb. 3: Ordnerstruktur<br />

Ein fertiges Projekt besteht aus<br />

diversen Files und Ordnern. Wie<br />

in der Abb. 3: Ordnerstruktur zu<br />

erkennen ist, sind grundsätzlich<br />

einmal die JRE (Java Runtime<br />

Environment) System Library und<br />

die Plug-in Dependencies vorhanden.<br />

Diese stellen die Grundfunktion<br />

von Java dar.<br />

Im Application.e4xmi File ist die<br />

Oberfläche des Programms definiert.<br />

Beim Öffnen dieser Datei<br />

öffnet sich ein Tool, mit dem die<br />

Oberfläche verändert werden<br />

kann. Die Oberflächenbearbeitung<br />

ist im Kapitel 4.5.3<br />

Oberfläche genauer beschrieben.<br />

Das wichtigste File des Projekts ist das *.product File (hier:<br />

at.swarovski.rcp.shopinfo.product). Dabei handelt es sich nicht um ein Textfile,<br />

sondern um eine graphische Oberfläche, die formularartig Parameter für das<br />

Projekt umsetzt. In diesem File kann das Programm unter anderem auch<br />

Seite 28


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

gestartet werden. Dort befindet sich auch ein Export-Wizard, mit dem das Projekt<br />

exportiert werden kann. In weiteren Reitern lassen sich z. B. die Dependencies<br />

eintragen oder ein Branding (Icons) hinzufügen.<br />

Im File build.properties können weitere Einstellungen zum Generieren des<br />

Programms vorgenommen werden.<br />

Das plugin.xml File öffnet wieder ein Optionen-Feld mit mehreren Reitern. Das<br />

plugin.xml File ist dabei so ein Reiter. Dieses File wird automatisch erstellt und<br />

kann nicht „per Hand“ abgeändert werden.<br />

Mit diesem Optionen-Feld lassen sich fast alle Einstellungen für das Projekt<br />

vornehmen. Es beinhaltet auch manche Reiter des *.product Files.<br />

Zu diesen vorgenerierten Dateien kommen noch einige vorgenerierte Ordner und<br />

selbsterstellte Ordner.<br />

Im Ordner src befinden sich alle Source-Files, der Quelltext sozusagen. Diese<br />

Files nennt man Klassen und sie sind in Packages aufgeteilt. Diese Packages<br />

haben aber keine große Rolle, sie agieren wie Ordner.<br />

Im ersten Package at.swarovski.rcp.shopinfo befindet sich Activator.java. Dies ist<br />

ein automatisch generiertes File, welches für unser Projekt nicht abgeändert<br />

werden muss.<br />

Im Package at.swarovski.rcp.shopinfo.database sind alle notwendigen Klassen<br />

vorhanden, um mit einer Datenbank Verbindung aufzunehmen und auch Daten<br />

auszutauschen. Die Verbindung zur Datenbank wird im Kapitel 4.5.4 Verbindung<br />

zur DB genauer beschrieben.<br />

Das Package at.swarovski.rcp.shopinfo.handlers beinhaltet alle Funktionen des<br />

Programms. Im Kapitel 4.5.5 Handler werden diese genauer beschrieben.<br />

Im Package at.swarovski.rcp.shopinfo.listener befindet sich der Treelistener, eine<br />

Klasse, welche das ausgewählte Item im Tree feststellen kann.<br />

Im Package at.swarovski.rcp.shopinfo.view werden die Oberflächen der einzelnen<br />

Parts definiert. Im Kapitel 4.5.3 Oberfläche und Application Model wird dies<br />

genauer beschrieben.<br />

Seite 29


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Im Ordner css befindet sich das Style-Sheet File, welches für dieses Projekt nicht<br />

verändert wird.<br />

Im Ordner icons sind alle Icons vorhanden, die für das Projekt benötigt werden.<br />

Sie werden z. B. in der Menüleiste verwendet.<br />

Im Ordner lib befindet sich der Treiber für die Verbindung zur Datenbank.<br />

Und schlussendlich befindet sich im Ordner META-INF das MANIFEST.MF.<br />

Dieses öffnet auch das Optionen-Feld, welches weiter oben in diesem Kapitel<br />

schon beschrieben wurde.<br />

4.5.3. Oberfläche und Application Model<br />

Um das Basis-Projekt an die jeweiligen Bedürfnisse des Kunden anzupassen,<br />

muss zuerst einmal die Oberfläche verändert werden, bevor die Intelligenz<br />

hineinprogrammiert werden kann.<br />

Mit den zusätzlichen Tools, die nachträglich zu Eclipse hinzugefügt wurden, kann<br />

relativ einfach die Oberfläche des Programms verändert werden. Dazu muss das<br />

Application-File geöffnet werden. Es erscheint ein Menü, mit dem man die<br />

benötigten Komponenten hinzufügen kann.<br />

Die wichtigsten User Interface Komponenten einer Eclipse 4 Applikation sind<br />

Windows, Parts, Perspectives, PartStacks und PartSashContainers.<br />

Typischerweise besteht eine Applikation, ein Programm, aus einem Window<br />

(Fenster). Man ist aber nicht darauf beschränkt, es ist möglich, weitere Fenster<br />

hinzuzufügen.<br />

Parts sind User Interface Komponenten, die einem ermöglichen, Daten zu<br />

navigieren und zu modifizieren. Diese Parts sind meistens eingeteilt in Views und<br />

Editors. Diese Unterteilung basiert primär aber nicht auf technischen<br />

Unterschieden, sondern auf der Art der Verwendung dieser Parts.<br />

Ein View wird verwendet, um ein Daten-Set, welches möglicherweise hierarchisch<br />

aufgebaut ist, direkt zu verändern. Wird in einer View eine Änderung<br />

vorgenommen, so geschieht diese auch direkt in der darunterliegenden Daten-<br />

Struktur.<br />

Seite 30


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Mit einem Editor werden einzelne Daten-Elemente verändert, zum Beispiel eine<br />

Datei. Vorgenommene Änderungen treten aber erst in Kraft, wenn diese explizit<br />

gespeichert werden.<br />

Perspectives sind visuelle Container, welche Parts beinhalten. Sie werden<br />

verwendet, um Parts für verschiedene Anwendungen zu positionieren. Parts<br />

können in den Perspectives geöffnet, geschlossen und neu arrangiert werden.<br />

Parts können direkt im Window oder in einer Perspective platziert werden. Um<br />

solche Parts zu arrangieren, können PartStacks und PartSashContainer<br />

verwendet werden. PartStacks beinhalten Parts, welche immer nur zur gleichen<br />

Zeit dargestellt werden können. Solche PartStacks können über Tabs ausgewählt<br />

werden.<br />

PartSashContainer stellen den Inhalt entweder horizontal oder vertikal zur<br />

gleichen Zeit dar.<br />

Zu den visuellen Teilen in Eclipse (Perspectives, Parts, etc.) gibt es noch<br />

verschiedene nicht-visuelle Komponenten wie zum Beispiel Handlers, Commands<br />

und Key Bindings.<br />

Bei Eclipse 4 wird das sogenannte Application Model verwendet, um die Struktur<br />

einer Applikation zu beschreiben. In diesem Modell sind sowohl die sichtbaren als<br />

auch die nicht sichtbaren Elemente der Oberfläche enthalten.<br />

Jedes Element hat bestimmte Eigenschaften, welche den derzeitigen Zustand<br />

beschreiben. Manche Elemente müssen in einer hierarchischen Struktur<br />

angeordnet werden (Parts in Perspectives).<br />

Dieses Application Model definiert jedoch nur die Struktur der Oberfläche und<br />

nicht den Inhalt des User Interfaces. Es stellt die Parts zur Verfügung, wo dann<br />

später zum Beispiel SWT-Widgets integriert werden können. Diese müssen nach<br />

wie vor im Source-Code eingebettet werden. Das Application model entspricht<br />

sozusagen nur einem Haus mit Räumen, der Inhalt muss extra programmiert<br />

werden.<br />

Seite 31


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Abb. 4 Application Model<br />

Dieses Application Model ist ein einziges File mit dem Namen<br />

Application.e4xmi und befindet sich im Hauptverzeichnis des Projekts.<br />

Die Verbindung der einzelnen Elemente zu den Java Klassen geschieht über<br />

Uniform Resource Identifier (URI). Diese beschreibt den Ort, wo sich die Klasse<br />

befindet. Die Klasse beschreibt nun den Inhalt und das Verhalten dieses Inhalts.<br />

Wird nun ein Element aus dem Application Model aktiviert, so wird gleichzeitig die<br />

Klasse instanziert.<br />

4.5.3.1. Commands, Handlers<br />

Das Application Model kann auch Commands und Handlers beinhalten. Ein<br />

Command ist in diesem Fall eine Beschreibung einer Aktion, wie zum Beispiel<br />

„speichern“ oder „kopieren“.<br />

Das Verhalten eines Commands wird bestimmt von Handler. Ein Handler definiert<br />

eine Klasse über den contributionURI. Dieses Attribut wird als Class URI im<br />

Model Editor dargestellt.<br />

Solche Handler können global für die gesamte Applikation fungieren oder nur für<br />

einzelne Parts. So kann es zum Beispiel eine Save-Aktion für die gesamte<br />

Applikation geben, und eine eigene Save-Aktion für einen speziellen Part.<br />

Seite 32


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.3.2. Menus, Toolbars<br />

Für Windows und Parts können Menus und Toolbars erstellt werden. Menu und<br />

Toolbar Items enthalten Referenzen zu Commands. Ist dann so ein Command<br />

ausgewählt, wird von der Runtime der dazugehörende Handler ausgewählt.<br />

Toolbars sind im Application Model als Trimbar eingebunden. Eine Trimbar kann<br />

für Windows definiert werden. Es können hier zur Übersicht auch Separatoren<br />

und Untermenüs erstellt werden.<br />

Um eine Toolbar/Menüleiste im Fenster zu implementieren, so benötigt man<br />

dreierlei Dinge: ein Handled Tool Item, einen Command und einen Handler.<br />

Das Handled Tool Item beschreibt dabei die optischen Eigenschaften des<br />

Menüeintrags. Dabei kann unter anderem der angezeigte Text, die Art des<br />

Eintrags (Push, Radial, Check) oder ein Icon verändert werden. Diesem Item<br />

muss noch der vorher erwähnte Command eingetragen werden.<br />

Dem Handler müssen der Command und eine URI zugewiesen werden, denn<br />

diese weist auf die dazugehörende Klasse in Java hin.<br />

Schlussendlich wird bei einer Aktion mit dem Menüeintrag diese Klasse<br />

ausgeführt.<br />

Damit alle Änderungen im Application Model auch gleich übernommen werden,<br />

muss im Product-Configuration-File bei im Reiter Launching beim Unterpunkt<br />

Programm Arguments folgender Eintrag hinzugefügt werden:<br />

-clearPersistedState<br />

Seite 33


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.3.3. Inhalt des Application Model<br />

Das Application Model beschreibt nur die Struktur des UI. Alles, was in diese<br />

Struktur hinein kommt, Labels, Textfelder, Buttons usw., kann mit SWT-Widgets<br />

in den Parts integriert werden. SWT bedeutet Standard Widget Toolkit und<br />

umfasst eine große Bibliothek an diversen graphischen Ein- und Ausgabe-<br />

Komponenten. Um diese zu verwenden, muss die Bibliothek<br />

org.eclipse.swt.widgets und org.eclipse.swt.custom zuerst eingebunden<br />

werden.<br />

Die Widgets werden per Snippet (Code-Besipiel) im Internet angeboten. Der<br />

Code kann einfach in den Quellcode hineinkopiert werden.<br />

Um diese Widgets optisch ansprechend zu positionieren, muss zuerst ein Layout<br />

mit SWT erstellt werden. Dann kann das Widget genau positioniert werden.<br />

SWT beitet eine Reihe von Layout-Managern. Dabei gibt es AbsoluteLayout,<br />

FillLayout, RowLayout, GridLayout und FormLayout. Jedes Layout verfügt über<br />

andere Eigenschaften und ist somit nicht für jeden Fall geeignet.<br />

In diesem Projekt werden hauptsächlich GridLayouts verwendet, da diese den<br />

Anforderungen am ehesten entsprechen. Grundsätzlich ordnet dieses die<br />

Widgets in einer Gitterform an. Es können dabei die Anzahl der Spalten und die<br />

Spalten- und Abstand-Größe angegeben werden.<br />

Zu jedem Layout Manager gibt es auch noch eine Layout Data, in dem<br />

widgetspezifische Eigenschaften eingetragen werden können. Dabei muss die<br />

Data dem Manager entsprechen, ansonsten kommt es zu einem Fehler bei der<br />

Ausführung des Programms.<br />

Durch die Benützung eines GridLayouts wird das GridData Objekt verwendet.<br />

Seite 34


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.3.4. Fenster-Struktur<br />

Dieses Programm besteht aus nur einem<br />

Window (Trimmed Window). In diesem<br />

Window wird ein PerspectiveStack und<br />

darin eine Perspective erstellt, um Parts<br />

zu beherbergen. Um immer zwei Parts<br />

gleichzeitig darstellen zu lassen benötigt<br />

es einen PartSashContainer. Dieser<br />

trennt das Fenster vertikal in zwei Hälften,<br />

dass die Parts nebeneinander angezeigt<br />

werden. In diesem PartSashContainer<br />

befinden sich zwei PartStacks.<br />

Abb. 5: Fenster-Struktur<br />

Einer besteht aus zwei, der andere aus drei Parts. Diese können per Tabs<br />

durchgeschalten werden.<br />

Am oberen Fensterrand befindet sich eine<br />

Toolbar. Dazu muss ein Window Trim<br />

erstellt werden, und darin eine Toolbar.<br />

Diese wird dann mit Handled Tool Items<br />

und Separatoren befüllt.<br />

Abb. 6: Toolbar<br />

Zusätzlich zu den visuellen Komponenten kommen noch acht Handlers und acht<br />

Commands. Diese beziehen sich hauptsächlich auf die Funktionen der Toolbar.<br />

Seite 35


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Abb. 7: Handlers<br />

Abb. 8: Commands<br />

Schlussendlich sieht die Grundstruktur des Programms, gestaltet im Application<br />

Model wie folgt aus:<br />

Toolbar<br />

PartStack 1 PartStack 2<br />

Abb. 9: Grundstruktur<br />

Seite 36


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.4. Verbindung zur DB<br />

Die Verbindung zur Datenbank wird mit Hilfe der „DatabaseConnection“-Klasse<br />

verwirklicht. Wichtig ist, dass von dieser Klasse immer nur eine Instanz existiert,<br />

da ansonsten Fehler auftreten können, wenn gleichzeitig mehrere Verbindungen<br />

zur Datenbank aufgebaut werden. Daher verwendet man einen sogenannten<br />

Singleton. Somit wird beim Generieren einer solchen Instanz immer zuerst<br />

abgefragt, ob diese schon existiert und anschließend der weitere Vorgang<br />

entschieden.<br />

public static DatabaseConnection getInstance() {<br />

if (instance == null) {<br />

instance = new DatabaseConnection();<br />

}<br />

return instance;<br />

}<br />

Innerhalb der Klasse existieren zwei verschiedene Variablen, die möglicherweise<br />

verwechselt werden könnten.<br />

DatabaseConnection:<br />

Hier spricht man von der Instanz dieser Klasse, die sämtliche Informationen nach<br />

außen hin bereithält.<br />

Connection:<br />

So wird die eigentliche Verbindung zur Datenbank bezeichnet.<br />

Seite 37


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.4.1. Verbindungsaufbau<br />

In der Methode „DatabaseConnection()“ wird die Verbindung zur Datenbank<br />

mittels JDBC -Treiber (siehe 4.4 JDBC) aufgebaut.<br />

private DatabaseConnection() {<br />

try {<br />

Class.forName("com.mysql.jdbc.Driver").newInstance();<br />

connection = DriverManager.getConnection(<br />

"jdbc:mysql://localhost/shopinfo?zeroDateTimeBehavior=convertToNull",<br />

"root", "gipfelkreuz");<br />

}<br />

connection.setReadOnly(false);<br />

} catch (InstantiationException e) {<br />

System.out.println("InstantiationException: " + e);<br />

} catch (IllegalAccessException e) {<br />

System.out.println("IllegalAccessException: " + e);<br />

} catch (ClassNotFoundException e) {<br />

System.out.println("ClassNotFoundException: " + e);<br />

} catch (SQLException e) {<br />

System.out.println("SQLException: " + e);<br />

}<br />

Wie man sieht, handelt es sich hier um die Verbindung zu einer lokalen MySQL<br />

Datenbank, die während der Entwicklung verwendet wird. Die Argumente<br />

beziehen sich dabei erstens auf die Adresse der Datenbank, zweitens auf den<br />

Benutzer und drittens auf das Passwort der Datenbank.<br />

Die Adresse der Datenbank ergibt sich aus dem Treiber, dann die Art der<br />

Datenbank und schlussendlich der wirklichen Adresse der Datenbank. In diesem<br />

Fall muss zusätzlich noch ein zeroDateTimeBehavior=convertToNull Statement<br />

hinzugefügt werden, um Fehler mit Datumswerten in der Datenbank zu<br />

vermeiden.<br />

Da beim Verbindungsaufbau Fehler auftreten können, wenn beispielsweise die<br />

Datenbank nicht erreicht werden kann oder Benutzer und Passwort nicht<br />

stimmen, muss dieser Code in einer Try-Catch-Anweisung ausgeführt werden,<br />

um diverse Exceptions abzufangen.<br />

Seite 38


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.4.2. Auslesen der Daten<br />

Zum Auslesen der Daten aus der Datenbank gibt es für jede Tabelle der<br />

Datenbank drei verschiedene Methoden.<br />

public List getShops() {<br />

.<br />

.<br />

.<br />

}<br />

public List getShops(String sSQLStatement) {<br />

.<br />

.<br />

.<br />

}<br />

public List getShops(TreeListener treeListener) {<br />

.<br />

.<br />

.<br />

}<br />

Bei der ersten Methode werden keine Parameter übergeben, da immer die<br />

gesamte Tabelle als Liste von Datensätzen zurückgegeben wird. Diese Methode<br />

wird hauptsächlich für die Gesamttabellen und für die Erstellung der Baumstruktur<br />

verwendet.<br />

Die beiden weiteren Methoden sind für die speziellere Rückgabe von<br />

Datensätzen konzipiert. Dabei kann entweder eine fertige SQL-Abfrage als String<br />

übergeben werden, wie es zum Beispiel bei der erweiterten Suche der Fall ist,<br />

oder es wird die im TreeListener gespeicherte Information übergeben, um daraus<br />

eine SQL-Abfrage zu formen und einzelne Datensätze, unter anderem für die<br />

Details-Anzeige, zu erhalten.<br />

Seite 39


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

sSQLStatement = "SELECT Shops.sap_ship_to, Shops.country_code, Shops.type,..."<br />

sSQLStatement = sSQLStatement + "FROM shopinfo.country Country, shopinfo.shops Shops";<br />

sSQLStatement = sSQLStatement + " WHERE Country.country_code = Shops.country_code ";<br />

if (treeListener.getSelectedRegion() != "") {<br />

sSQLStatement = sSQLStatement + "AND Country.region = '"<br />

+ treeListener.getSelectedRegion() + "'";<br />

}<br />

if (treeListener.getSelectedCountry() != "") {<br />

sSQLStatement = sSQLStatement + "AND Shops.country_code = '"<br />

+ treeListener.getSelectedCountry() + "'";<br />

}<br />

if (treeListener.getSelectedShop() != "") {<br />

sSQLStatement = sSQLStatement + "AND Shops.sap_ship_to = '"<br />

+ treeListener.getSelectedShop() + "'";<br />

}<br />

ResultSet rs = stmt.executeQuery(sSQLStatement + " LIMIT 10000");<br />

Obwohl nur ein Datensatz zurückgegeben werden muss, wird aus<br />

Einfachheitsgründen eine Liste zurückgegeben, die jedoch nur einen Eintrag<br />

besitzt, dieser eine Eintrag wird im Anschluss über die „get(0)“-Funktion<br />

herausgeholt.<br />

Die vorhin angesprochenen Listen bestehen aus mehreren Objekten, bei denen<br />

die Inhalte eines Datensatzes mittels „set“-Funktion in privaten Variablen<br />

eingetragen werden. Es gibt hierbei vier verschiedene Klassen für die<br />

verschiedenen Tabellen der Datenbank. Darin befinden sich nur private Variablen<br />

entsprechend der Spalten einer Tabelle, welche mittels „set“- und „get“-<br />

Funktionen verarbeitet werden.<br />

public class Shop {<br />

private String sapShipTo;<br />

.<br />

.<br />

.<br />

public String getSapShipTo() {<br />

return sapShipTo;<br />

}<br />

}<br />

public void setSapShipTo(String sapShipTo) {<br />

this.sapShipTo = sapShipTo;<br />

}<br />

.<br />

.<br />

.<br />

Seite 40


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Zum Verändern von Datensätzen der Datenbank werden in der Klasse zwei<br />

weitere Methoden verwendet. Beide haben prinzipiell die gleiche Funktion, sie<br />

führen die als String übergebene SQL-Schreib-Abfrage auf der Datenbank durch.<br />

Einziger Unterschied ist, dass eine Funktion mögliche Exceptions selbst abfängt,<br />

die andere Funktion gibt solche nur an die ausführende Instanz zurück, wo diese<br />

dann weiter verarbeitet werden, zum Beispiel wird diese Vorgangsweise bei der<br />

Ausgabe von Pop-Up-Fehlermeldungen benötigt.<br />

public void editDatabase(String sSQLStatement) {<br />

try {<br />

Statement stmt = connection.createStatement();<br />

stmt.execute(sSQLStatement);<br />

stmt.close();<br />

} catch (SQLException e) {<br />

e.printStackTrace();<br />

}<br />

}<br />

public void editDatabaseWithException(String sSQLStatement) throws SQLException {<br />

Statement stmt = connection.createStatement();<br />

stmt.execute(sSQLStatement);<br />

stmt.close();<br />

}<br />

Weitere Funktionen sind die „getSingleCount()“- und die „getHwAge()“-Methoden.<br />

Die „getSingleCount()“-Methode wird vor allem zum Erstellen von Statistiken<br />

verwendet, findet aber auch Anwendung in verschiedenen<br />

Überprüfungsvorgängen. Hier wird wieder als String eine SQL-Abfrage<br />

übergeben, welche jedoch nur einen „Count“-Befehl enthält und somit lediglich<br />

eine Zahl wieder zurückgibt, diese Zahl wird anschließend als String<br />

weitergegeben und muss dann verarbeitet werden.<br />

public String getSingleCount(String sSQLStatement) {<br />

try {<br />

Statement stmt = connection.createStatement();<br />

ResultSet rs = stmt.executeQuery(sSQLStatement);<br />

String sCount = "Error";<br />

if (rs.next())<br />

sCount = rs.getString(1);<br />

rs.close();<br />

stmt.close();<br />

return sCount;<br />

} catch (SQLException e) {<br />

e.printStackTrace();<br />

Seite 41


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

}<br />

}<br />

return null;<br />

Die „getHwAge()“-Methode wird eigentlich nur bei der Anzeige der Hardware-<br />

Details benötigt, um das Alter der Hardware zu ermitteln. Hier wird das Datum der<br />

Erstinstallation als String übergeben und anschließend mittels SQL-DATEDIFF-<br />

Abfrage die Differenz zum aktuellen Datum in Jahren über die Datenbank<br />

ermittelt.<br />

public String getHwAge(String sDate) {<br />

String sSQLStatement;<br />

String sAge = "-";<br />

int iAge = 0;<br />

float fAge = 0;<br />

try {<br />

Statement stmt = connection.createStatement();<br />

sSQLStatement = "SELECT DATEDIFF ( NOW(), \"";<br />

sSQLStatement = sSQLStatement + sDate;<br />

sSQLStatement = sSQLStatement + "\")";<br />

ResultSet rs = stmt.executeQuery(sSQLStatement);<br />

if (rs.next())<br />

iAge = rs.getInt(1);<br />

rs.close();<br />

stmt.close();<br />

fAge = iAge;<br />

fAge = fAge / 365;<br />

sAge = Float.toString(fAge);<br />

try {<br />

sAge = sAge.substring(0, sAge.indexOf(".") + 3);<br />

} catch (StringIndexOutOfBoundsException e1) {<br />

}<br />

if (fAge > 1000)<br />

sAge = "-";<br />

}<br />

return sAge;<br />

} catch (SQLException e) {<br />

e.printStackTrace();<br />

return "-";<br />

}<br />

Seite 42


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.5. Handler<br />

Alle Klassen im Package „at.swarovski.rcp.shopinfo.handlers“ werden für die<br />

Schaltflächen in der Menüleiste benötigt. Dabei existiert für jeden Button ein<br />

Handler. Die meisten dieser Handler öffnen beim Auslösen einen neuen Part, um<br />

beispielsweise das Suchfenster oder Statistiken anzuzeigen. Dabei wird der neue<br />

Part im Prinzip immer gleich generiert.<br />

Nachdem der Part erschaffen wurde, werden Eigenschaften wie Label und<br />

„Closeable“-Status eingestellt. Anschließend wird definiert, mit der Instanz<br />

welcher View-Klasse der Part gefüllt werden soll. Danach wird der passende<br />

PartStack gesucht, um dann den neuen Part zu diesem Stack hinzuzufügen.<br />

public class NewShopHandler {<br />

@Execute<br />

public void execute(EPartService partService, MApplication application,<br />

EModelService modelService) {<br />

MPart part = MBasicFactory.INSTANCE.createPart();<br />

part.setLabel("New");<br />

part.setCloseable(true);<br />

part.setContributionURI("bundleclass://at.swarovski.rcp.shopinfo/<br />

at.swarovski.rcp.shopinfo.view.NewShop");<br />

List stacks = modelService.findElements(application, null,<br />

}<br />

MPartStack.class, null);<br />

stacks.get(1).getChildren().add(part);<br />

partService.showPart(part, PartState.ACTIVATE);<br />

}<br />

Der Handler des „showDetails“-Buttons in der Menüleiste generiert die Parts auch<br />

nach genau diesem Verfahren, jedoch wird dabei vorher mittels TreeListener<br />

entschieden, welche Art von Details angezeigt werden soll, damit schlussendlich<br />

auch die richtige Label-Beschriftung ausgewählt wird.<br />

Seite 43


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

public class DetailsHandler {<br />

@Execute<br />

public void execute(EPartService partService, MApplication application,<br />

EModelService modelService) {<br />

TreeListener treeListener = TreeListener.getInstance();<br />

if (treeListener.getSelectedShop() != "") {<br />

MPart part = MBasicFactory.INSTANCE.createPart();<br />

}<br />

part.setLabel("Shop-Details: " + treeListener.getSelectedShop());<br />

part.setCloseable(true);<br />

.<br />

.<br />

.<br />

else if (treeListener.getSelectedClosedShop() != "") {<br />

MPart part = MBasicFactory.INSTANCE.createPart();<br />

}<br />

part.setLabel("Closed Shop-Details: " +<br />

treeListener.getSelectedClosedShop());<br />

part.setCloseable(true);<br />

.<br />

.<br />

.<br />

else if (treeListener.getSelectedHardware() != "") {<br />

MPart part = MBasicFactory.INSTANCE.createPart();<br />

}<br />

part.setLabel("HW-Details: " + treeListener.getSelectedHardware());<br />

.<br />

.<br />

.<br />

else if (treeListener.getSelectedCountry() != "") {<br />

MPart part = MBasicFactory.INSTANCE.createPart();<br />

part.setLabel("Country-Details: " +<br />

treeListener.getSelectedCountry());<br />

.<br />

.<br />

.<br />

}<br />

}<br />

}<br />

Andere Handler wie der „About“-Handler oder der „Quit“-Handler werden<br />

automatisch bereitgestellt und müssen bei Bedarf nur abgeändert werden, um<br />

zum Beispiel die „About“-Information anzupassen.<br />

Seite 44


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.6. Gesamttabellen<br />

Die Gesamttabellen werden sofort nach Start des Programms angezeigt. Sie<br />

stellen den kompletten Inhalt der Datenbank-Tabellen „country“, „shops“ und<br />

„closed_shops“ dar. Dabei wird für jede Tabelle ein eigener Part erstellt.<br />

Zuerst wird dabei eine Tabelle mit sämtlichen Spalten für die Datensätze erstellt.<br />

final Table tableShop = new Table(parentShop, SWT.MULTI | SWT.BORDER |<br />

SWT.FULL_SELECTION);<br />

tableShop.setLinesVisible(true);<br />

tableShop.setHeaderVisible(true);<br />

GridData dataShop = new GridData(SWT.FILL, SWT.FILL, true, true);<br />

dataShop.heightHint = 200;<br />

tableShop.setLayoutData(dataShop);<br />

final String[] titlesShop = { "SAP ship-to", "country code", "Type", "Pilote",...<br />

for (int i = 0; i < titlesShop.length; i++) {<br />

TableColumn column = new TableColumn(tableShop, SWT.NONE);<br />

column.setText(titlesShop[i]);<br />

}<br />

Anschließend werden die Datensätze eingelesen und in einer Liste<br />

zwischengespeichert. Diese Liste wird dann in einer for-each-Schleife<br />

durchlaufen und dabei jeder Eintrag in die Tabelle geschrieben.<br />

shops = db_conShop.getShops();<br />

if (shops != null) {<br />

for (Shop entry : shops) {<br />

TableItem item = new TableItem(tableShop, SWT.NONE);<br />

item.setText(0, entry.getSapShipTo());<br />

item.setText(1, entry.getCountryCode());<br />

item.setText(2, entry.getType());<br />

item.setText(3, entry.getPilote());<br />

.<br />

.<br />

.<br />

Abschließend wird noch ein Listener generiert. So kann ein Datensatz in der<br />

Tabelle durch Klicken ausgewählt werden, um später in der Detailansicht Einträge<br />

zu verändern.<br />

Seite 45


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Rectangle clientArea = parentShop.getClientArea();<br />

tableShop.setLocation(clientArea.x, clientArea.y);<br />

Point size = tableShop.computeSize(SWT.DEFAULT, 200);<br />

tableShop.setSize(size);<br />

tableShop.addListener(SWT.MouseDown, new Listener() {<br />

public void handleEvent(Event event) {<br />

Rectangle clientArea = tableShop.getClientArea();<br />

Point pt = new Point(event.x, event.y);<br />

int index = tableShop.getTopIndex();<br />

while (index < tableShop.getItemCount()) {<br />

boolean visible = false;<br />

TableItem item = tableShop.getItem(index);<br />

for (int i = 0; i < titlesShop.length; i++) {<br />

Rectangle rect = item.getBounds(i);<br />

if (rect.contains(pt)) {<br />

final TreeListener searchListener = TreeListener.getInstance();<br />

searchListener.setSelectedShop(tableShop.getItem(index).getText(0));<br />

System.out.println(tableShop.getItem(index).getText(0));<br />

}<br />

if (!visible && rect.intersects(clientArea)) {<br />

visible = true;<br />

}<br />

}<br />

if (!visible)<br />

return;<br />

index++;<br />

}<br />

}<br />

});<br />

4.5.7. TreePart<br />

Der TreePart stellt im Programm das Kernelement zur schnellen, strukturierten<br />

Suche von Datensätzen dar. Einerseits besteht die Möglichkeit über ein Textfeld<br />

direkt einen Shop auszuwählen, indem man die zu ihm gehörige SAP-Nummer<br />

eintippt, andererseits wird die eigentliche Baumstruktur zur Auswahl der<br />

Datensätze angezeigt.<br />

Seite 46


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.7.1. Quick search<br />

Zur schnellen Suche wird im Prinzip nur ein Textfeld verwendet, das mit einem<br />

Listener ausgerüstet wird, sodass die Eingabe mittels Entertaste bestätigt werden<br />

kann. Dabei wird die eingegebene Nummer versucht im TreeListener zu speichern,<br />

um so den gewünschten Shop auszuwählen (siehe 4.5.8 TreeListener).<br />

textstyle;<br />

parent.setLayout(new GridLayout(1, false));<br />

final TreeListener searchListener = TreeListener.getInstance();<br />

Listener listener = new Listener() {<br />

public void handleEvent(Event event) {<br />

Text t = (Text) event.widget;<br />

String msg = t.getMessage();<br />

if (event.detail == SWT.ICON_CANCEL) {<br />

System.out.println("Cancel on " + msg);<br />

} else if (event.detail == SWT.ICON_SEARCH) {<br />

System.out.println("ICON on " + msg);<br />

} else {<br />

System.out.println("Default selection on " + msg + ": "<br />

+ t.getText());<br />

searchListener.setSelectedShop(t.getText());<br />

}<br />

}<br />

};<br />

textstyle = new Text(parent, SWT.SEARCH);<br />

textstyle.setMessage("Quick search");<br />

textstyle.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));<br />

textstyle.addListener(SWT.DefaultSelection, listener);<br />

4.5.7.2. Baumstruktur<br />

Um die Baumstruktur aufbauen zu können, müssen zuerst alle Datensätze aus<br />

der Datenbank eingelesen und zwischengespeichert werden. Dazu wird jeweils<br />

eine Liste für Shops, Länder und Hardware generiert. Zusätzlich werden noch<br />

Listen für Regionen und Shoptypen benötigt, in denen die bereits generierten<br />

Items gespeichert werden. Außerdem wird eine bool‘sche Variable verwendet, um<br />

anzugeben, ob der aktuelle Datensatz als neues Item erstellt werden muss oder<br />

nicht.<br />

Zuerst werden beim dynamischen Aufbau der Baumstruktur alle Datensätze der<br />

„country“-Tabelle durchlaufen. Dabei wird überprüft, ob der Region-Eintrag des<br />

Landes mit einem Punkt des Trees übereinstimmt, genauer gesagt wird der<br />

Seite 47


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Eintrag mit der Liste der Items verglichen, denn hier werden diese immer<br />

eingetragen, wenn ein solches erstellt wird.<br />

if (countries != null) {<br />

for (Country entryRegion : countries) {<br />

bNewItem = true;<br />

for (String sUniqueRegion : ItemsRegion) {<br />

if (entryRegion.getRegion().equals(sUniqueRegion)) {<br />

bNewItem = false;<br />

}<br />

}<br />

if (bNewItem == true) {<br />

// Region------------------------------------------------------<br />

TreeItem treeItemRegion = new TreeItem(tree, 0);<br />

treeItemRegion.setText(entryRegion.getRegion());<br />

ItemsRegion.add(entryRegion.getRegion());<br />

.<br />

.<br />

.<br />

}<br />

}<br />

}<br />

Wenn also der Region-Eintrag des Landes noch nicht verwendet wurde, wird für<br />

diese Region ein Punkt erstellt und in der Item-Liste eingetragen. Anschließend<br />

werden in einer for-each-Schleife alle Country-Datensätze durchlaufen und immer<br />

dann wird ein neuer Unterpunkt erstellt, wenn die Region des Landes mit der<br />

ausgewählten Region übereinstimmt. Außerdem wird hier die Item-Liste, in der<br />

die Shoptypen zwischengespeichert sind, geleert, da natürlich in jedem Land<br />

immer wieder die gleichen Shoptypen vorkommen können.<br />

.<br />

.<br />

.<br />

// Country------------------------------------------------------<br />

for (Country entryCountry : countries) {<br />

if (entryCountry.getRegion().equals(entryRegion.getRegion())) {<br />

ItemsType.clear();<br />

TreeItem treeItemCountry = new TreeItem(treeItemRegion, 0);<br />

treeItemCountry.setText(entryCountry.getCountryCode() +<br />

" (" + entryCountry.getVgNr() + ")");<br />

ItemsCountry.add(entryCountry.getCountryCode());<br />

.<br />

.<br />

.<br />

}<br />

}<br />

.<br />

.<br />

.<br />

Seite 48


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Nun werden die Shops in einer for-each-Schleife durchlaufen, um für jeden neu<br />

gefunden Shoptypen einen neuen Unterpunkt zu erstellen. Dabei muss aber<br />

zusätzlich noch überprüft werden, ob der gefundene Eintrag auch wirklich einen<br />

Shop dieses Landes beinhaltet. Wenn dies der Fall ist, wird wieder ein neues<br />

Item erstellt und in der Item-Liste für Shoptypen eingetragen.<br />

.<br />

.<br />

.<br />

// Shop-Type------------------------------------------------------<br />

for (Shop entryType : shops) {<br />

bNewItem = true;<br />

for (String sUniqueType : ItemsType) {<br />

if (entryType.getType().equals(sUniqueType)) {<br />

bNewItem = false;<br />

}<br />

}<br />

if (bNewItem == true) {<br />

if (entryCountry.getCountryCode().equals(entryType.getCountryCode())) {<br />

TreeItem treeItemType = new TreeItem(treeItemCountry, 0);<br />

treeItemType.setText(entryType.getType());<br />

ItemsType.add(entryType.getType());<br />

.<br />

.<br />

.<br />

}<br />

}<br />

}<br />

.<br />

.<br />

.<br />

Als Nächstes werden die Datensätze der „shops“-Tabelle ein weiteres Mal in<br />

einer for-each-Schleife durchlaufen, um hier für jeden Shop, der sich im richtigen<br />

Land befindet und den passenden Shoptypen besitzt, einen neuen Unterpunkt zu<br />

erstellen.<br />

Zum Abschluss werden noch die Hardware-Einträge mit einer for-each-Schleife<br />

durchsucht, um auch für die zum Shop gehörige Hardware noch weitere<br />

Unterpunkte zu erstellen.<br />

Seite 49


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

.<br />

.<br />

.<br />

// SAP_Ship-to------------------------------------------------------<br />

for (Shop entrySap : shops) {<br />

if (entrySap.getCountryCode().equals(entryCountry.getCountryCode()) &&<br />

entrySap.getType().equals(entryType.getType())) {<br />

}<br />

.<br />

.<br />

.<br />

}<br />

TreeItem treeItemSap = new TreeItem(treeItemType, 0);<br />

treeItemSap.setText(entrySap.getSapShipTo() + " ("<br />

+ entrySap.getLocation() + " - "<br />

+ entrySap.getStoreName() + ")");<br />

// Hardware------------------------------------------------------<br />

for (Hardware entryHardware : hardware) {<br />

if (entryHardware.getShipTo().equals(entrySap.getSapShipTo())) {<br />

TreeItem treeItemHardware = new TreeItem(treeItemSap, 0);<br />

treeItemHardware.setText(entryHardware.getHostname()<br />

+ " - (" + entryHardware.getSn() + ")");<br />

ItemsHw.add(entryHardware.getHw());<br />

}<br />

}<br />

ItemsSap.add(entrySap.getCountryCode());<br />

Nachdem die Baumstruktur nun dynamisch erstellt wurde, wird diese noch mit<br />

dem TreeListener verknüpft, um durch Klicken eines Unterpunktes auch wirklich<br />

einen Eintrag auswählen zu können.<br />

TreeListener treeListener = TreeListener.getInstance();<br />

treeListener.SelectionListener(tree);<br />

4.5.8. TreeListener<br />

Die TreeListener-Klasse hatte in den ersten Versionen des Programms eigentlich<br />

nur die Aufgabe, herauszufinden, welcher Eintrag der Baumstruktur geklickt<br />

wurde, und diese Information für die weitere Verarbeitung zu speichern. Mit<br />

Voranschreiten der Programmierung gewann diese Klasse aber immer mehr an<br />

Bedeutung und stellt schlussendlich einen zentralen Punkt des Programms dar.<br />

Seite 50


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Während des Programmablaufs existiert immer nur eine Instanz dieser Klasse,<br />

ein sogenannter Singleton. Das bedeutet, wenn diese Instanz benötigt wird, wird<br />

nicht in einer anderen Klasse eine Instanz generiert, sondern immer die Anfrage<br />

„TreeListener.getInstance();“ an diese Klasse gesendet. Hier wird<br />

überprüft, ob die Instanz bereits existiert, wenn nötig generiert und anschließend<br />

zurückgegeben. Das gleiche Prinzip wird bei der Datenbankverbindung<br />

verwendet, da auch hier natürlich immer nur einmal eine Verbindung aufgebaut<br />

werden darf.<br />

Würde man beim TreeListener eine Instanz erstellen, einen ausgewählten Eintrag<br />

zwischenspeichern und anschließend in einem anderen Teil des Programms<br />

wieder eine andere TreeListener-Instanz erstellen, könnte man nicht auf den<br />

gespeicherten Eintrag zugreifen und der Zweck dieser Klasse wäre nicht erfüllt.<br />

Der TreeListener arbeitet also sozusagen als globale Variable, auf die beinahe<br />

alle Instanzen anderer Klassen zugreifen.<br />

public static TreeListener getInstance() {<br />

if (instance == null) {<br />

instance = new TreeListener();<br />

}<br />

return instance;<br />

}<br />

Der TreeListener beinhaltet im Prinzip nur sechs String-Variablen, in denen die<br />

jeweilige Auswahl gespeichert ist. Diese Variablen sind jedoch „private“, können<br />

also von außen nicht beeinflusst werden. Daher gibt es für jede Variable eine<br />

„set“- und eine „get“-Methode. Bei jeder „set“-Methode wird überprüft, ob die<br />

gewünschte Änderung Sinn macht und man schützt somit die zugehörige<br />

Variable vor fehlerhaften Einträgen. Die „get“-Methoden liefern nur die<br />

gewünschte Variable, haben aber sonst keine weitere Funktion. Hier die „set“-<br />

und „get“-Methode für die Shop-Variable:<br />

Seite 51


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

public String getSelectedShop() {<br />

return sSelectedShop;<br />

}<br />

public void setSelectedShop(TreeItem selectedShop) {<br />

String sNewSelectedShop = selectedShop.getText();<br />

int iSAP;<br />

if ((sNewSelectedShop.indexOf('(')) > 0) {<br />

sNewSelectedShop = sNewSelectedShop.substring(0,<br />

sNewSelectedShop.indexOf('(')).trim();<br />

if (sNewSelectedShop.length() >= 4 && sNewSelectedShop.length()


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

public void SelectionListener(final Tree tree) {<br />

tree.addListener(SWT.MouseDown, new Listener() {<br />

public void handleEvent(Event event) {<br />

Point point = new Point(event.x, event.y);<br />

if (tree.getItem(point) != null) {<br />

setSelectedRegion(tree.getItem(point));<br />

setSelectedCountry(tree.getItem(point));<br />

setSelectedShop(tree.getItem(point));<br />

}<br />

}<br />

});<br />

}<br />

4.5.9. Search<br />

Bei der Suche wird der Part in einen TabFolder mit zwei Elementen unterteilt. Je<br />

nachdem, welches der beiden Elemente ausgewählt wurde, wird entweder nach<br />

einem Shop oder nach einer Hardware gesucht. Die beiden Elemente des<br />

TabFolders sind im Prinzip genau gleich aufgebaut, es befinden sich jeweils zwei<br />

ContentGroups darin, eine für die Eingabe der Suchkriterien, die andere<br />

beinhaltet eine Tabelle, in der die Suchergebnisse dargestellt werden. Diese<br />

Tabelle ist so programmiert, dass beim Klick auf eine der Zeilen die SAP-Nummer<br />

des Shops bzw. die Seriennummer der Hardware zwischengespeichert wird und<br />

somit genauere Informationen durch einen Klick auf „Details“-Button angezeigt<br />

werden (siehe 4.5.11 Details).<br />

Wichtigster Bestandteil der Programmierung des Suchfensters ist natürlich der<br />

„Search“-Button beziehungsweise die Funktion, die beim Klick dieses Buttons<br />

aufgerufen wird. Hier wird eine SQL-Abfrage mit mehreren WHERE-Bedingungen<br />

erstellt, die alle Suchkriterien beinhalten.<br />

Bei der Suche nach einem Shop besteht außerdem noch die Möglichkeit nach<br />

geschlossenen Shops zu suchen, indem in der CheckBox „Closed Shop“ ein<br />

Haken gesetzt wird. Im Prinzip wählt man mit dieser Suchoption lediglich aus, in<br />

welcher Tabelle der Datenbank nach Datensätzen gesucht werden soll, da mit<br />

der Datenbankstruktur getrennte Tabellen für geöffnete und geschlossene Shops<br />

verwendet werden.<br />

Im Anschluss wird das Suchergebnis entweder in einer Objektliste der Klasse<br />

„Shop“ oder der Klasse „ClosedShops“ gespeichert, je nachdem, welche Art der<br />

Seite 53


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Suche ausgewählt wurde. Diese Unterteilung zieht sich die weiteren Schritte<br />

immer weiter hindurch, da die beiden Tabellen der Datenbank nicht genau gleich<br />

sind (siehe 3.3 Datenbankübersicht).<br />

if (btnCheckClosedShop.getSelection() == false) {<br />

sSQLStatement = "SELECT Shops.sap_ship_to, Shops.country_code, Shops.type, ...<br />

sSQLStatement = sSQLStatement + "FROM shopinfo.country Country, shopinfo.shops Shops ";<br />

} else if (btnCheckClosedShop.getSelection() == true) {<br />

sSQLStatement = "SELECT Shops.auto_id, Shops.sap_ship_to, Shops.country_code, ...<br />

sSQLStatement = sSQLStatement + "FROM shopinfo.country Country, shopinfo.closed_shops Shops<br />

";<br />

}<br />

sSQLStatement = sSQLStatement + "WHERE Country.country_code = Shops.country_code ";<br />

sSQLStatement = sSQLStatement + "AND Shops.sap_ship_to LIKE '%" + textShopShipTo.getText() + "%'<br />

";<br />

sSQLStatement = sSQLStatement + "AND Shops.type LIKE '%" + textShopType.getText() + "%' ";<br />

sSQLStatement = sSQLStatement + "AND Shops.store_name LIKE '%" + textShopShopname.getText() +<br />

"%' ";<br />

sSQLStatement = sSQLStatement + "AND (Shops.country_code LIKE '%" + textShopCountry.getText() +<br />

"%' OR Country.country LIKE '%" + textShopCountry.getText() + "%') ";<br />

sSQLStatement = sSQLStatement + "AND (Shops.location LIKE '%" + textShopLocation.getText() +<br />

"%' OR Shops.city LIKE '%" + textShopLocation.getText() + "%') ";<br />

sSQLStatement = sSQLStatement + "AND Shops.zip_code LIKE '%" + textShopZIP.getText() + "%' ";<br />

sSQLStatement = sSQLStatement + "AND Shops.phone LIKE '%" + textShopPhone.getText() + "%' ";<br />

sSQLStatement = sSQLStatement + "LIMIT 10000";<br />

if (btnCheckClosedShop.getSelection() == false)<br />

searchResult = db_con.getShops(sSQLStatement);<br />

else if (btnCheckClosedShop.getSelection() == true)<br />

searchResultClosed = db_con.getClosedShops(sSQLStatement);<br />

Danach werden sämtliche bereits vorhandenen Einträge, die nach der<br />

vorhergehenden Suche in der Ergebnistabelle angezeigt werden, entfernt. Sollte<br />

die Suche mit den eingegebenen Kriterien keine Ergebnisse liefern, wird ein<br />

Popup-Fenster am Bildschirm angezeigt, welches den Benutzer auf dieses<br />

Problem hinweist.<br />

if (searchResult != null) {<br />

if (searchResult.size() == 0) {<br />

System.out.println("No shop was found!");<br />

MessageBox dialogSQLError = new MessageBox(shell,<br />

SWT.ICON_WARNING | SWT.OK);<br />

dialogSQLError.setText("No result!");<br />

dialogSQLError.setMessage("No shop was found with this parameters!");<br />

returnCode = dialogSQLError.open();<br />

} else {<br />

System.out.println(searchResult.get(0).getSapShipTo());<br />

}<br />

}<br />

Seite 54


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Bei der Suche nach Hardware sieht die prinzipielle Suchfunktion ähnlich aus, wie<br />

die der Shop-Suche. Es werden auch hier alle Bedingungen in ein SQL-Abfrage<br />

verpackt. Aus Sicht des Benutzers fungiert auch die CheckBox zur Suche nach<br />

entfernter Hardware nach dem gleichen Prinzip wie bei der Suche nach<br />

geschlossenen Shops. Programmintern wird diese Suchbedingung aber etwas<br />

anders abgehandelt, da bei der Hardware nur eine Tabelle in der Datenbank<br />

vorhanden ist, in der alle Hardware-Datensätze gespeichert sind.<br />

Hier wird diese Auswahloption zur eigentlichen Suche in der Datenbank ignoriert,<br />

es werden also alle Hardware-Datensätze, egal ob entfernt oder nicht, in einer<br />

Objektliste der Klasse „Hardware“ gespeichert. Anschließend werden alle<br />

Datensätze in einer for-each-Schleife in die Tabelle eingetragen, dabei wird<br />

jedoch bei jedem Datensatz vorher mit einer SQL-Abfrage (COUNT-Funktion),<br />

wie sie auch beim Erstellen der Statistiken verwendet wird (siehe 4.5.10 Statistic),<br />

überprüft, wie oft die jeweilige Hardware mit einem Shop verlinkt ist. Diese<br />

Abfrage gibt entweder den Wert 1, die Hardware wird in einem Shop verwendet,<br />

oder den Wert 0, die Hardware ist in keinem Shop vorhanden (also entfernt),<br />

zurück.<br />

Anschließend wird mit einer IF-Abfrage entschieden, ob der Datensatz in der<br />

Ergebnistabelle angezeigt wird, indem überprüft wird, ob die Hardware der<br />

gewünschten Suchbedingung entspricht.<br />

Diese kleine Abfrage muss für jeden Datensatz, der bei der ursprünglichen SQL-<br />

Abfrage zurückgegeben wurde, wiederholt werden. Dadurch dauert die Suche bei<br />

ungenauen Angaben der Kriterien etwas länger, was dem Benutzer jedoch nicht<br />

zu sehr auffallen wird.<br />

Seite 55


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

if (searchHWResult != null) {<br />

for (Hardware entry : searchHWResult) {<br />

sSQLHWStatement = "SELECT COUNT(sap_ship_to) FROM shopinfo.shops ";<br />

sSQLHWStatement = sSQLHWStatement + "WHERE sap_ship_to='";<br />

sSQLHWStatement = sSQLHWStatement + entry.getShipTo();<br />

sSQLHWStatement = sSQLHWStatement + "'";<br />

}<br />

}<br />

if (((btnCheckRemoved.getSelection() == false) &&<br />

(Integer.parseInt(db_con.getSingleCount(sSQLHWStatement)) == 1)) ||<br />

((btnCheckRemoved.getSelection() == true) &&<br />

(Integer.parseInt(db_con.getSingleCount(sSQLHWStatement)) == 0))) {<br />

bNoResult = false;<br />

TableItem item = new TableItem(tableHWResult, SWT.NONE);<br />

item.setText(0, entry.getSn());<br />

item.setText(1, entry.getShipTo());<br />

item.setText(2, entry.getHostname());<br />

item.setText(3, entry.getHw());<br />

item.setText(4, entry.getStoreType());<br />

item.setText(5, entry.getOsVersion());<br />

}<br />

Auch bei dieser Suche wird wieder ein Popup-Fenster angezeigt, falls keine<br />

Suchergebnisse vorliegen. Da jedoch nicht alle Ergebnisse der eigentlichen SQL-<br />

Abfrage angezeigt werden, kann hier nicht die Objektliste zur Speicherung auf<br />

„null“ abgefragt werden, sondern es muss eine eigene bool’sche Variable<br />

„bNoResult“ generiert werden, die kennzeichnet, ob die Suche erfolgreich war.<br />

Diese Variable ist standardmäßig auf „true“, also kein Ergebnis, und wird, sobald<br />

der erste Datensatz in die Ergebnistabelle eingetragen wird, auf „false“ gesetzt.<br />

Eine Besonderheit bei der Suche von Hardware ist die Auswahl des gewünschten<br />

Datensatzes zur Anzeige der Details. Beim Klick auf eine Zeile der<br />

Ergebnistabelle wird überprüft, ob die ausgewählte Hardware mit einem Shop<br />

verlinkt ist. Wenn dies der Fall ist, wird nicht die Seriennummer der Hardware,<br />

sondern die SAP-Nummer des Shops in Verbindung mit dem Hostnamen der<br />

Hardware im TreeListener gespeichert. So kann später bei der Anzeige der<br />

Details der Shop dargestellt werden und zugleich die gesuchte Hardware im<br />

TabFolder ausgewählt werden (siehe 4.5.11 Details).<br />

Am Ende der „Search“-Klasse wird noch die Selection des TabFolders auf „0“<br />

gesetzt, damit schon beim Öffnen des Parts die Shop-Suche angezeigt wird und<br />

nicht nur ein leerer Bildschirm.<br />

Seite 56


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.10. Statistics<br />

Zuerst wird im Stastistics-Part ein „TabFolder“ für die einzelnen Regionen erstellt.<br />

Darin werden anschließend Tabellen eingefügt. Hier werden bereits alle Spalten<br />

fertig beschriftet und angepasst.<br />

Nun startet die eigentliche Auswertung der Daten. Zur Zwischenspeicherung wird<br />

für jede Spalte eine Variable erstellt, zusätzlich werden Felder definiert, in denen<br />

die zusammengehörigen Daten der einzelnen Länder immer zusammengezählt<br />

werden, um am Ende die Gesamtwerte für die Regionen ausgeben zu können.<br />

Anschließend werden in einer Schleife die drei Kontinente abgearbeitet. Dabei<br />

werden zu Beginn die Daten aller Länder eines Kontinents eingelesen. Wichtig<br />

sind hier im Prinzip nur die Country-Codes, da mit Hilfe dieser die richtigen Shops<br />

aus der „shops“-Tabelle herausgeholt werden. Mit diesem Ergebnis wird nun eine<br />

„for-each“-Schleife für alle Länder des Kontinents durchgeführt.<br />

sSQLStatement = "SELECT * FROM shopinfo.country WHERE region='";<br />

sSQLStatement = sSQLStatement + sRegion;<br />

sSQLStatement = sSQLStatement + "'";<br />

searchResultCountries = db_con.getCountries(sSQLStatement);<br />

Wichtigster Bestandteil des Programms ist für die Erstellung der Statistiken die<br />

Funktion „getSingleCount()“. Dieser Funktion wird immer eine SQL-Query<br />

übergeben, die eine einzige „Count“-Abfrage enthält. In diesem Fall enthält die<br />

Antwort der Datenbank nur einen Wert, welcher von der Funktion als String<br />

zurückgegeben wird, anschließend wird dieser String jedoch immer in einen<br />

Integer-Wert umgewandelt. Genaueres über diese Funktion ist bei der<br />

Datenbankverbindung zu finden. (siehe 4.5.4 Verbindung zur DB)<br />

Diese Funktion wird immer wieder ausgeführt. Das Einzige, das sich ändert, ist<br />

bei der Abarbeitung eines Landes der Typ der Shops, die gezählt werden sollen.<br />

Hier sieht man die Code-Zeilen zum Zählen der AW-Shops:<br />

Seite 57


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

sSQLStatement = "SELECT COUNT(country_code) FROM shopinfo.shops WHERE country_code='";<br />

sSQLStatement = sSQLStatement + entry.getCountryCode();<br />

sSQLStatement = sSQLStatement + "' AND type='AW'";<br />

iCountAW = Integer.parseInt(db_con.getSingleCount(sSQLStatement));<br />

if (sRegion.equals("EUROPE"))<br />

iCountEurope[0] += iCountAW;<br />

if (sRegion.equals("AMERICAS"))<br />

iCountAmericas[0] += iCountAW;<br />

if (sRegion.equals("ASIA PACIFIC"))<br />

iCountAsia[0] += iCountAW;<br />

Sobald alle Shops des Landes durchgezählt wurden, wird eine Tabellenzeile in<br />

der passenden Tabelle angelegt und mit den in den Variablen zwischengespeicherten<br />

Werten gefüllt.<br />

Wurde der Vorgang für alle Länder und auch alle Kontinente beendet, müssen<br />

nun noch die Statistiken für die Regionen in die Tabelle eingetragen werden. Die<br />

Werte wurden für die Kontinente bei jedem Land aufsummiert und sind in den<br />

Variablen-Feldern gespeichert. Diese müssen nur noch addiert werden, um auch<br />

die Gesamtwerte der ganzen Welt anzeigen zu können.<br />

for (iLoop = 0; iLoop < 13; iLoop++) {<br />

iCountWorld[iLoop] = iCountEurope[iLoop] + iCountAmericas[iLoop]<br />

+ iCountAsia[iLoop];<br />

}<br />

Um diese Statistik nach dieser Methode zu erstellen, wird ca. eine Sekunde<br />

benötigt. Bei einem ersten Versuch ließen wir alle Daten der Shops einlesen und<br />

wollten die Shops eines Typs innerhalb des Java-Programms zählen lassen.<br />

Diese Methode funktionierte zwar auch, es brauchte aber um ein Vielfaches mehr<br />

Zeit, die beim normalen Gebrauch des Programms nicht zumutbar gewesen<br />

wäre, deshalb entschieden wir uns die Shops direkt von der Datenbank zählen zu<br />

lassen.<br />

Seite 58


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.11. Details<br />

Bei einem Klick auf den „Details“-Button im Menü wird ein Part der Klasse<br />

„ShopDetails“ geöffnet. Dabei wird als erster Schritt die Funktion „showDetails“<br />

ausgeführt. Im Prinzip wird mit dieser Funktion lediglich herausgesucht, welche<br />

Details welchen Country’s, welchen Shops bzw. welcher Hardware angezeigt<br />

werden sollen. Dazu wird das TreeListener-Objekt importiert, in der die Auswahl<br />

immer zwischengespeichert wird (siehe 4.5.8 TreeListener).<br />

Je nachdem, welcher Eintrag des TreeListeners ein Ergebnis liefert, wird die<br />

passende Funktion zur Anzeige aufgerufen und dabei unter anderem auch der<br />

TreeListener übergeben, um in der Funktion den passenden Datensatz aus der<br />

Datenbank herauszusuchen.<br />

TreeListener treeListener = TreeListener.getInstance();<br />

if (treeListener.getSelectedShop().equals("") == false) {<br />

showShopDetails(parent, treeListener);<br />

}<br />

else if (treeListener.getSelectedClosedShop().equals("") == false) {<br />

showClosedShopDetails(parent, treeListener);<br />

}<br />

else if (treeListener.getSelectedHardware().equals("") == false) {<br />

showHardwareDetails(parent, treeListener);<br />

}<br />

else if (treeListener.getSelectedCountry().equals("") == false) {<br />

showCountryDetails(parent, treeListener);<br />

}<br />

4.5.11.1. showShopDetails()<br />

Diese Funktion wird erst aufgerufen, wenn die Funktion<br />

„treeListener.getSelectedShop()“ eine SAP-Nummer zurückgibt. Hier wird zu<br />

Beginn eine Verbindung zur Datenbank hergestellt und alle Shops mit der<br />

übergebenen SAP-Nummer werden eingelesen und in einer Liste gespeichert. Da<br />

die Shops mittels SAP-Nummer ausgefiltert werden und die SAP-Nummer in der<br />

Datenbank als Primary Key verwendet wird, dürfte jedoch maximal nur ein Shop<br />

gefunden werden. Aus Einfachheitsgründen wird hier aber die gleiche Funktion<br />

angewandt, wie wenn nach mehreren Shops gesucht werden würde. Da also nur<br />

Seite 59


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

ein Eintrag in der Liste vorhanden ist, wird beim Eintragen in die TextBoxes mit<br />

der „get(0)“-Funktion immer der erste Eintrag verwendet.<br />

Im Anschluss wird für jedes Detail des Shops jeweils ein Label, das die<br />

Beschreibung anzeigt, und, wie schon erwähnt, eine TextBox, die mit dem<br />

passenden Detail befüllt wird, innerhalb einer ContentGroup generiert. Der<br />

„editable“-Status der TextBoxes wird dabei auf „false“ gesetzt, somit kann der<br />

Inhalt nicht verändert, aber trotzdem markiert und kopiert werden.<br />

List shop;<br />

shop = db_con.getShops(treeListener);<br />

Label labelShopname = new Label(contentGroupShop, SWT.NONE);<br />

labelShopname.setText("Store Name: ");<br />

final Text textShopname = new Text(contentGroupShop, SWT.SINGLE);<br />

textShopname.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));<br />

textShopname.setText(shop.get(0).getStoreName());<br />

textShopname.setEditable(false);<br />

Label labelSAP = new Label(contentGroupShop, SWT.NONE);<br />

labelSAP.setText("SAP - Ship to: ");<br />

final Text textSAP = new Text(contentGroupShop, SWT.SINGLE);<br />

textSAP.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));<br />

textSAP.setText(shop.get(0).getSapShipTo());<br />

textSAP.setEditable(false);<br />

.<br />

.<br />

.<br />

Am unteren Ende der Gruppe befinden sich zwei Buttons, einer zum Verändern<br />

der Details und einer zum Schließen des Shops. Noch eine Zeile weiter unten<br />

befindet sich eine unsichtbare TextBox, in der die derzeitige SAP-Nummer des<br />

Shops noch einmal hinterlegt ist, diese versteckte Information ist für den Benutzer<br />

nicht zu sehen und wird beim Editieren von Shop-Informationen benötigt.<br />

Seite 60


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Editieren<br />

Beim Klick auf den „Edit“-Button wird der „editable“-Status aller TextBoxes auf<br />

„true“ gesetzt. Ausnahmen bilden dabei die Informationen „Country“ und „VG-Nr.“.<br />

Diese beiden Informationen kommen nicht aus der „shops“-Tabelle der<br />

Datenbank, sondern sind Informationen, die über den Country-Code aus der<br />

„country“-Tabelle ausgelesen werden. Diese beiden Einträge können also nur in<br />

Verbindung mit dem Country-Code verändert werden.<br />

Außerdem wird der Hintergrund der Einträge „Store Name“, „SAP – Ship to“,<br />

„Type“ und „Country Code“ gelb eingefärbt, da es sich hierbei um Pflichtfelder<br />

handelt. Weiters wird der „Edit“-Button in einen „Save“-Button umgewandelt,<br />

indem die Beschriftung des Buttons verändert wird. Daher wird auch bei jedem<br />

Klick auf den Button mittels If-Abfrage auf die Buttonbeschriftung ausgewählt,<br />

welche Funktionen ausgeführt werden sollen.<br />

buttonEditSave.addSelectionListener(new SelectionAdapter() {<br />

public void widgetSelected(SelectionEvent e) {<br />

.<br />

.<br />

.<br />

if (buttonEditSave.getText().equals("Edit")) {<br />

textShopname.setEditable(true);<br />

textShopname.setBackground(ColorLightYellow);<br />

textSAP.setEditable(true);<br />

textSAP.setBackground(ColorLightYellow);<br />

.<br />

.<br />

.<br />

});<br />

}<br />

} else if (buttonEditSave.getText().equals("Save")) {<br />

.<br />

.<br />

.<br />

}<br />

Nachdem der Benutzer die gewünschten Daten geändert hat und den „Save“-<br />

Button geklickt hat, werden manche der neuen Einträge überprüft, um Fehler in<br />

der Datenbank zu verhindern. Überprüft werden dabei die gelb markierten<br />

Pflichtfelder und alle Datumsfelder. Bei den Feldern „Store Name“ und „Type“<br />

wird lediglich überprüft, ob ein Eintrag in dem Feld vorhanden ist. Beim Eintrag<br />

Seite 61


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

„SAP – Ship to“ wird überprüft, ob die eingetragene SAP-Nummer bereits in der<br />

Datenbank vorhanden ist. Falls dieser Eintrag beim Editieren jedoch nicht<br />

verändert wurde, befindet sich klarerweise bereits ein Datensatz mit diesem<br />

Primary Key in der Datenbank, hier kommt das versteckte „Current SAP“-Textfeld<br />

zum Einsatz. Falls die beiden Einträge übereinstimmen, liegt hier natürlich kein<br />

ungültiger Eintrag vor.<br />

Beim Eintrag „Country Code“ muss überprüft werden, ob der angegebene Code<br />

auch wirklich ein Eintrag in der „country“-Tabelle ist, damit eine gültige<br />

Verknüpfung der Tabellen gewährleistet werden kann.<br />

// Check "SAP-Ship to"<br />

sSQLStatement = "SELECT COUNT(sap_ship_to) FROM shopinfo.shops WHERE sap_ship_to='";<br />

sSQLStatement = sSQLStatement + textSAP.getText();<br />

sSQLStatement = sSQLStatement + "'";<br />

if (((Integer.parseInt(db_con.getSingleCount(sSQLStatement)) > 0)<br />

&& (textCurrentSAP.getText().equals(textSAP.getText()) == false))<br />

|| (textSAP.getText().equals(""))) {<br />

bFailed = true;<br />

textSAP.setBackground(ColorLightRed);<br />

} else {<br />

textSAP.setBackground(ColorLightYellow);<br />

}<br />

.<br />

.<br />

.<br />

// Check "Country-Code"<br />

sSQLStatement = "SELECT COUNT(country_code) FROM shopinfo.country WHERE<br />

country_code='";<br />

sSQLStatement = sSQLStatement + textCountryCode.getText();<br />

sSQLStatement = sSQLStatement + "'";<br />

if ((Integer.parseInt(db_con.getSingleCount(sSQLStatement)) != 1)<br />

|| (textCountryCode.getText().equals(""))) {<br />

bFailed = true;<br />

textCountryCode.setBackground(ColorLightRed);<br />

} else {<br />

textCountryCode.setBackground(ColorLightYellow);<br />

}<br />

Da in den einzelnen Tabellen des Öfteren Datumseinträge vorkommen, wurde für<br />

diese Überprüfung eine eigene Funktion angelegt, die „isDateFormatCorrect()“-<br />

Funktion. Hier wird der Datumswert als String übergeben und eine bool’sche<br />

Variable zurückgegeben. Innerhalb der Funktion wird der übergebene String in<br />

die Anteile für Jahr, Monat und Tag zerlegt. Diese Werte müssen durch einen<br />

Bindestrich getrennt sein. Anschließend wird überprüft, ob die Einträge plausibel<br />

sind, wobei die Werte nicht genau überprüft werden. Beispielsweise würde die<br />

Seite 62


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Funktion den Eintrag „2013-02-30“ als gültig einstufen, obwohl dieses Datum<br />

natürlich nicht korrekt wäre.<br />

boolean isDateFormatCorrect(String sDate) {<br />

boolean bCorrect = true;<br />

String sYear;<br />

String sMonth;<br />

String sDay;<br />

int iYear;<br />

int iMonth;<br />

int iDay;<br />

if (sDate.length() != 10)<br />

bCorrect = false;<br />

if (bCorrect) {<br />

sYear = sDate.substring(0, 4);<br />

sMonth = sDate.substring(5, 7);<br />

sDay = sDate.substring(8, 10);<br />

if (sDate.substring(4, 5).equals("-") == false)<br />

bCorrect = false;<br />

if (sDate.substring(7, 8).equals("-") == false)<br />

bCorrect = false;<br />

try {<br />

iYear = Integer.valueOf(sYear).intValue();<br />

iMonth = Integer.valueOf(sMonth).intValue();<br />

iDay = Integer.valueOf(sDay).intValue();<br />

}<br />

if (iYear < 1 || iYear > 9999)<br />

bCorrect = false;<br />

if (iMonth < 1 || iMonth > 12)<br />

bCorrect = false;<br />

if (iDay < 1 || iDay > 31)<br />

bCorrect = false;<br />

} catch (NumberFormatException e1) {<br />

bCorrect = false;<br />

}<br />

}<br />

return bCorrect;<br />

Sollten bei den überprüften Einträgen ein oder mehrere ungültige entdeckt<br />

worden sein, werden die entsprechenden TextBoxes rot hinterlegt und ein Popup-<br />

Fenster wird geöffnet, welches den User auf diese Felder hinweist. Falls jedoch<br />

alle Einträge als korrekt anerkannt wurden, wird versucht, die nun generierte<br />

UPDATE-Abfrage auf der Datenbank auszuführen. Sollte hierbei ein, trotz der<br />

Überprüfungen, Fehler auftreten, wird ein Popup-Fenster geöffnet, das die<br />

Fehlernachricht der Datenbank anzeigt. Solche Fehler können beispielsweise ein<br />

Seite 63


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Datumswert sein oder ein zu langer Eintrag. Diese Einträge können aber vom<br />

Programm leider nicht gekennzeichnet werden, sie müssen also vom Benutzer<br />

selbst gefunden werden, was mit Hilfe der Error-Message jedoch kein Problem<br />

darstellen sollte.<br />

Nun wird noch überprüft, ob die SAP-Nummer des Shops verändert wurde. Ist<br />

dies der Fall, muss auch die SAP-Nummer der verknüpften Hardware-<br />

Komponenten geändert werden, um die Verknüpfung nicht zu verlieren.<br />

Sollten all diese Prozesse ohne Fehler abgelaufen sein, werden alle TextBoxes<br />

wieder auf den ursprünglichen Status zurückgesetzt und der „Save“-Button wird<br />

wieder zum „Edit“-Button umgewandelt. Außerdem muss für die nächste<br />

Änderung der Eintrag für die „CurrentSAP“ aktualisiert werden.<br />

Shop schließen<br />

Der „Close this shop“-Button ermöglicht es dem Benutzer einen Shop zu<br />

schließen. Aus Sicht der Datenbank wird der Shop nicht gelöscht, sondern der<br />

Datensatz lediglich von der „shops“-Tabelle in die „closed_shops“-Tabelle<br />

übertragen. Beim Klick auf diesen Button wird zuerst ein Popup-Fenster geöffnet,<br />

in dem der User seine Absicht den Shop zu schließen bestätigen muss.<br />

Als Erstes wird überprüft, ob der gerade betrachtete Shop wirklich in der „shops“-<br />

Tabelle gespeichert ist und nicht schon vorher geschlossen wurde. Anschließend<br />

werden die Daten in die „closed_shops“-Tabelle eingetragen, das sollte unbedingt<br />

geschehen, bevor der Shop aus der „shops“-Tabelle entfernt wird, damit es bei<br />

einem Fehler zu keinem Datenverlust kommt. Danach wird der Shop aus der<br />

„shops“-Tabelle gelöscht.<br />

Sollte während der Übertragung ein Fehler auftreten, wird ein Popupfenster<br />

geöffnet, welches Informationen über den Zeitpunkt des Fehlers enthält und die<br />

Fehlermessage der Datenbank wiedergibt.<br />

Seite 64


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

if (bFailed == false) {<br />

// Check if shop is already closed<br />

sSQLStatement = "SELECT COUNT(sap_ship_to) FROM shopinfo.shops ";<br />

sSQLStatement = sSQLStatement + "WHERE sap_ship_to='";<br />

sSQLStatement = sSQLStatement + textSAP.getText();<br />

sSQLStatement = sSQLStatement + "'";<br />

if ((Integer.parseInt(db_con.getSingleCount(sSQLStatement)) == 0)) {...}<br />

}<br />

if (bFailed == false) {<br />

// Insert shop into closed_shop - table<br />

sSQLStatement = "INSERT INTO shopinfo.closed_shops ";<br />

sSQLStatement += "(sap_ship_to, country_code,...) VALUES ('";<br />

sSQLStatement += textSAP.getText();<br />

sSQLStatement += "', '";<br />

sSQLStatement += textCountryCode.getText();<br />

sSQLStatement += "', '";<br />

.<br />

.<br />

.<br />

try {<br />

db_con.editDatabaseWithException(sSQLStatement);<br />

} catch (SQLException e2) {...}<br />

// Delete shop from shops - table<br />

if (bFailed == false) {<br />

sSQLStatement = "DELETE FROM shopinfo.shops WHERE sap_ship_to=\"";<br />

sSQLStatement += textSAP.getText();<br />

sSQLStatement += "\"";<br />

try {<br />

db_con.editDatabaseWithException(sSQLStatement);<br />

}<br />

}<br />

} catch (SQLException e2) {...}<br />

Bei der Darstellung der Shop-Details werden auf der rechten Seite der<br />

Arbeitsfläche in einem TabFolder die Details der verlinkten Hardware angezeigt.<br />

Dabei stellt jeder Tab des Folders eine Hardewarekomponente dar, die einzelnen<br />

Datensätze werden dabei mittels SAP-Nummer aus der „hardware“-Tabelle der<br />

Datenbank herausgefiltert. Der Inhalt eines solchen Tabs wird im Prinzip gleich<br />

generiert, wie wenn nur eine Hardwarekomponente einzeln dargestellt wird (siehe<br />

4.5.11.3 showHardwareDetails()).<br />

Abschließend wird nun noch die Selection des Tabfolders, in dem die Hardware<br />

dargestellt wird, ausgewählt. Bei normaler Auswahl des Shops wird einfach das<br />

erste Element des Folders angezeigt. Wurde jedoch eine spezielle Hardware über<br />

die Suche ausgewählt (siehe 4.5.9 Search), welche mit einem Shop verknüpft ist,<br />

Seite 65


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

wird jener Tab gesucht, welcher der gesuchten Hardware entspricht und<br />

ausgewählt.<br />

int iIndex = 0;<br />

int iLoop;<br />

for (iLoop = 0; iLoop < folder.getItemCount(); iLoop++) {<br />

if (folder.getItem(iLoop).getText().<br />

equals(treeListener.getSelectedHWHostname())) {<br />

iIndex = iLoop;<br />

}<br />

}<br />

folder.setSelection(iIndex);<br />

4.5.11.2. showClosedShopDetails()<br />

Diese Funktion wird nur dann ausgeführt, wenn die Details eines geschlossenen<br />

Shops angezeigt werden sollen. Das wiederum kann nur dann sein, wenn ein<br />

solcher Shop mit Hilfe der Suchfunktion ausgewählt wurde. Die Funktion an sich<br />

ähnelt sehr der Funktion „showShopDetails()“, es gibt nur wenige kleine<br />

Unterschiede.<br />

Zum einen befindet sich eine Zeile mehr in der Arbeitsfläche, nämlich die für die<br />

automatisch vergebene ID. Diese Nummer ist aber auch nach Klicken des „Edit“-<br />

Buttons nicht veränderbar, da es erstens nicht notwendig ist und zweitens die<br />

Handhabung einer UPDATE-Abfrage um einiges vereinfacht wird.<br />

Ein weiterer Unterschied ist der zweite Button neben dem „Edit“-Button, der „Re-<br />

Open this Shop“-Button. Diese Schaltfläche bildet das Gegenstück zum „Close<br />

this Shop“-Button aus der „showShopDetails()“-Funktion. Hiermit kann ein<br />

geschlossener Shop wieder geöffnet werden, indem der Datensatz von der<br />

„closed_shops“-Tabelle der Datenbank in die „shops“-Tabelle verschoben wird.<br />

Der dritte und letzte Unterschied ist, dass in der Anzeige immer nur die Details<br />

eines Shops dargestellt werden und nie die dazugehörigen Hardwarekomponenten,<br />

da Hardware-Datensätze nicht mit einem geschlossenen Shop verlinkt<br />

werden können.<br />

Ansonsten funktioniert die Darstellung und Veränderung von Einträgen gleich wie<br />

bei einem normalen Shop.<br />

Seite 66


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.11.3. showHardwareDetails()<br />

Diese Funktion wird immer dann ausgeführt, wenn eine Hardwarekomponente<br />

einzeln dargestellt werden soll. Das passiert aber nur dann, wenn über das<br />

Suchmenü ein Datensatz ausgewählt wurde, der mit keinem Shop verlinkt ist.<br />

Falls eine Verknüpfung vorliegt, wird immer der gesamte Shop inklusive aller<br />

Hardwarekomponenten angezeigt. Da aber die einzelnen Tabs in der Shop-<br />

Darstellung für die Hardwaredetails gleich generiert werden wie in dieser<br />

Funktion, wird diese Funktion nun auch genauer erklärt.<br />

Die Darstellung der einzelnen Details findet ähnlich wie bei der Anzeige der<br />

Shop-Details statt. Für eine bessere Übersicht werden TextBoxes eingefügt,<br />

deren „enable“-Status auf „false“ gesetzt wird, die eine Unterteilung in allgemeine<br />

Informationen, Software-spezifische Details und bisherige Standorte andeuten.<br />

Auch bei dieser Darstellung wurde wieder eine TextBox versteckt, die die<br />

derzeitige Seriennummer speichert. Hier befindet sich die TextBox direkt neben<br />

der „General“-Überschrift. Diese Nummer wird wie schon bei den Shops für<br />

Veränderungen der Details benötigt.<br />

Der „Edit“-Button funktioniert auch gleich wie bei den Shops, einziger kleiner<br />

Unterschied ist, dass manche Überprüfungen der Einträge nach einem etwas<br />

anderen Muster ablaufen.<br />

Bei der Seriennummer wird wieder überprüft, ob diese eindeutig ist, da es sich<br />

hierbei um den Primary Key in der Datenbank-Tabelle handelt, beim Hostnamen<br />

muss lediglich ein Eintrag vorhanden sein.<br />

Der Eintrag im Feld „Ship to“ muss entweder auf einen geöffneten Shop<br />

verweisen oder komplett leer sein. Ein leeres Feld gibt an, dass diese Hardware<br />

zu keinem Shop verlinkt ist. Auf Grund dieser Überprüfung kann es jedoch<br />

passieren, dass es Hardwarekomponenten gibt, die zwar nach dem Importieren<br />

aus der Excel-Tabelle eine SAP-Nummer eingetragen haben, diese aber zu<br />

keinem gültigen Shop eine Verknüpfung darstellt. Ein solcher Datensatz wird in<br />

der Datenbank zwar akzeptiert, kann aber nur verändert werden, wenn die<br />

eingetragene SAP-Nummer heraus gelöscht wird oder zu einer gültigen Nummer<br />

geändert wird.<br />

Seite 67


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.11.4. showCountryDetails()<br />

Die vierte und letzte „showDetails“-Funktion ist den vorhergehenden ziemlich<br />

ähnlich. Diese Funktion wird immer dann ausgeführt, wenn die Details eines<br />

Landes angezeigt werden sollen. Ein Land kann ausgewählt werden, indem man<br />

entweder links in der Baumstruktur auf die entsprechende Verzweigung klickt,<br />

oder indem man in der Gesamttabelle für die Länder eines auswählt.<br />

Die Anzeige der Details funktioniert im Prinzip gleich wie bei den anderen<br />

Funktionen. Um die Details veränderbar zu machen, wird wieder ein „Edit“-Button<br />

angezeigt. Eine kleine Besonderheit ist hier, dass im Feld „Region“ kein beliebiger<br />

Eintrag eingefügt werden kann. Hier wird also keine TextBox verwendet, sondern<br />

eine sogenannte ComboBox. Sie hat mehrere verschiedene Auswahlmöglichkeiten,<br />

die programmtechnisch festgelegt werden, in unserem Fall kann<br />

via „DropDown“-Funktion zwischen „Europe“, „Americas“ und „Asia Pacific“<br />

gewählt werden.<br />

Label labelRegion = new Label(contentGroupMain, SWT.NONE);<br />

labelRegion.setText("Region: ");<br />

final Combo comboRegion = new Combo(contentGroupMain, SWT.READ_ONLY);<br />

comboRegion.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));<br />

comboRegion.setItems(new String[] { "Europe", "Americas", "Asia Pacific" });<br />

comboRegion.setText(country.get(0).getRegion());<br />

comboRegion.setEnabled(false);<br />

Sonstige Maßnahmen zur Vorbeugung von fehlerhaften Einträgen werden bei<br />

den Feldern „Country-Code“, „Country“ und „VG-Nummer“ getroffen, wobei hier<br />

nur überprüft wird, ob ein Eintrag vorhanden ist bzw. ob dieser eine vorgegebene<br />

Länge einhält.<br />

Um Änderungen des „Country-Code“-Eintrags zu ermöglichen, wird wieder in<br />

einer versteckten TextBox der derzeitige Country-Code zwischengespeichert, da<br />

dieser den Primary Key in der Datenbanktabelle bildet, gleich wie die SAP-<br />

Nummer bei Shops bzw. die Seriennummer bei Hardware-Datensätzen.<br />

Seite 68


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

4.5.12. Add<br />

Beim Erschaffen einer Instanz dieser Klasse wird ein TabFolder im Part platziert.<br />

Über diese Tabs kann ausgewählt werden, welche Art von neuem Eintrag<br />

gemacht werden soll. Es kann zwischen Shop, Hardware und Country gewählt<br />

werden. In allen drei Tabs wird, gleich wie bei der Anzeige von Details, eine<br />

ContentGroup erstellt, in der sich sämtliche TextBoxes für die einzelnen Einträge<br />

befinden. Alle diese TextBoxes sind standardmäßig mit einem Leerstring gefüllt,<br />

außer jene, in denen ein Datumswert eingetragen werden soll. In diesen Feldern<br />

wird als Default-Wert „0001-01-01“ verwendet, um dem User auch gleich die<br />

richtige Datumsformatierung anzuzeigen.<br />

Um das richtige Verknüpfen von Datensätzen für den User zu erleichtern, werden<br />

die relevanten Einträge automatisch ausgefüllt. Dieser Eintrag wird aus der<br />

zurzeit getätigten Auswahl im treeListener abgeleitet. Falls der User beispielsweise<br />

ein Land ausgewählt hat, wird beim Klick auf den „Add“-Button im<br />

neu geöffneten Part sofort der „Add Shop“-Tab ausgewählt und der passende<br />

„Country-Code“ für des ausgewählte Land eingetragen. Diese Funktion ist vor<br />

allem beim Hinzufügen von Hardware sehr hilfreich, da der User so nicht die<br />

meist siebenstellige SAP-Nummer des dazugehörigen Shops eintragen muss. So<br />

wird fehlerhaften Verknüpfungen vorgebeugt.<br />

if (treeListener.getSelectedCountry() != "")<br />

folder.setSelection(itemShop);<br />

else if (treeListener.getSelectedShop() != "")<br />

folder.setSelection(itemHW);<br />

else if (treeListener.getSelectedRegion() != "")<br />

folder.setSelection(itemCountry);<br />

Falls bei der Eingabe Felder trotzdem falsch befüllt werden, werden diese Fehler<br />

beim Klick auf den „Save“-Button erkannt und gleich wie beim Editieren in der<br />

Detail-Ansicht farblich markiert. Es werden hier die gleichen Felder überprüft wie<br />

beim Editieren von Einträgen.<br />

Seite 69


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5. Manual/Bedienungsanleitung<br />

In diesem Kapitel wird das User Interface Punkt für Punkt beschrieben und<br />

erklärt, wie man es bedient und zu einem gewünschten Ergebnis kommt.<br />

5.1. Oberfläche<br />

Startet man das Programm, so erscheint folgende Oberfläche (hier mit gekennzeichneten<br />

Flächen):<br />

Menü<br />

Arbeitsfläche<br />

Tree<br />

Abb. 10: Oberflächen Übersicht<br />

Seite 70


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5.2. Menü<br />

Abb. 11: Menü<br />

Das Menü befindet sich in der oberen linken Ecke und ist dort immer zu sehen.<br />

Die Icons öffnen entweder einen neuen Tab in der Arbeitsfläche oder ein kleines<br />

Dialogfenster.<br />

Die Funktion der Icons von links nach rechts beschrieben:<br />

Suche: Es öffnet sich der Suche-Tab. Weitere Informationen bei 5.5 Suche.<br />

Neues Element hinzufügen: Es öffnet sich ein neuer Tab zur Erstellung<br />

eines neuen Elements. Weitere Informationen bei 5.6 Neues Element<br />

hinzufügen.<br />

Statistiken: Es öffnet sich ein neuer Tab mit diversen Statistiken. Weitere<br />

Informationen bei 5.7 Statistiken.<br />

Details aufrufen: Es öffnet sich ein neuer Tab mit den Details des ausgewählten<br />

Objekts. Weiter Informationen bei 5.8 Details.<br />

Über: Es öffnet sich eine Messagebox mit Informationen über das<br />

Programm.<br />

Beenden: Es wird eine „Beenden“-Dialogbox aufgerufen.<br />

Seite 71


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5.3. Tree<br />

Der Tree soll einen schnellen Überblick und Zugriff auf alle Inhalte der Datenbank<br />

liefern.<br />

Mit den zwei Tabs am oberen Rand<br />

des Trees kann ausgewählt werden,<br />

ob bestehende oder aufgelöste Shops<br />

angezeigt werden sollen.<br />

Das Textfeld darunter bietet einen<br />

Quick search, mit dem man sofort<br />

einen bestimmten Shop über die SAP-<br />

Nummer auswählen kann. Der Tree an<br />

sich besteht aus fünf Ebenen.<br />

Abb. 12: Tree<br />

Die Ebenen sind folgende: Kontinent – Land – Shoptyp – Shop – Hardware.<br />

So kann man sich intuitiv und hierarchisch von oben herab zum gewünschten<br />

Shop klicken und dort sofort auch die Hardware einsehen.<br />

5.4. Arbeitsfläche<br />

In der Arbeitsfläche werden mittels Tabs die gewünschten Anfragen angezeigt.<br />

Beim Programmstart sind drei nicht schließbare Tabs standardmäßig geöffnet: Es<br />

werden die Tabs Country, Shop und Closed Shop mit deren Informationen jeweils<br />

in Tabellenform angezeigt. Die Arbeitsfläche ist der einzige Bereich, in dem der<br />

Benutzer Änderungen vornehmen kann, wie zum Beispiel Einträge von der<br />

Datenbank editieren.<br />

Jede Aktion in der Toolbar öffnet einen neuen Tab in der Arbeitsfläche, der auch<br />

wieder geschlossen werden kann.<br />

Seite 72


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5.5. Suche<br />

Mit der Suche kann man nach speziellen Elementen in der Datenbank suchen,<br />

auch wenn man nicht ganz genau weiß, was man sucht. Es kann nicht nur nach<br />

einem Element gesucht werden, sondern auch nach mehreren.<br />

Um die Suche aufzurufen, drückt man den „Suche“-Button im Menü (siehe 5.2<br />

Menü). Es öffnet sich dann folgender Tab:<br />

Abb. 13 Suche<br />

Mit den zwei Tabs in der linken oberen Ecke kann ausgewählt werden, ob man<br />

nach Shops oder Hardware suchen will. Darunter befinden sich einige<br />

Suchparameter, die eingegeben werden können, um die Suche zu spezialisieren.<br />

Es müssen keine vollständigen Suchparameter sein, es können auch nur<br />

Wortphrasen eingegeben werden. Wird in mehreren Feldern etwas eingetragen,<br />

so liefert das Suchergebnis nur Elemente, die allen Suchparametern<br />

entsprechen.<br />

Ist die Checkbox „Closed Shop“ aktiviert, so wird nur nach aufgelösten Shops<br />

gesucht.<br />

Seite 73


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5.6. Neues Element hinzufügen<br />

Abb. 14: Hinzufügen einer Hardware<br />

Da das Unternehmen nicht schläft und sich im Bereich der Shops und Hardware<br />

immer etwas ändert, kann man mit diesem „Wizard“ ein neues Land, einen neuen<br />

Shop oder eine neue Hardware hinzufügen.<br />

Mit den drei Tabs am oberen Rand kann ausgewählt werden, ob nun ein Shop,<br />

eine Hardware oder ein Land hinzugefügt wird. Es erscheint dann ein Formular, in<br />

das alle Informationen eingetragen werden können, die das Element betreffen.<br />

Die gelben Felder zeigen Pflichtfelder an, die unbedingt ausgefüllt werden<br />

müssen. Die anderen Felder können, müssen aber nicht gefüllt werden.<br />

Datumsfelder müssen in folgendem Format eingetragen werden: YYYY-MM-DD.<br />

Wenn kein Datum eingetragen werden kann, so bleibt das Default-Datum im Feld<br />

stehen. Dies ist programmtechnisch bedingt. Zum Abschließen des Vorgangs<br />

drückt man den Save-Button am unteren Rand des Formulars.<br />

Seite 74


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

5.7. Statistiken<br />

Mit dieser Funktion erhält man einen Überblick über die Kontinente und Länder<br />

z.B. in Bezug auf die Anzahl der Shops und Hardware in einem Land.<br />

Abb. 15: Statistiken<br />

Mit den vier Tabs am oberen Rand kann man die gewünschte Region auswählen.<br />

Es werden dann jeweils die verschiedenen Shoptypen und weitere Elemente<br />

aufgelistet.<br />

5.8. Details<br />

Mit den Details ruft man die speziellen Eigenschaften eines Elements auf, man<br />

erhält alle eingetragenen Informationen auf einen Blick. Um die Details<br />

aufzurufen, wählt man das gewünschte Element im Tree, aus der Liste oder<br />

mittels der Suche aus und drückt anschließend den „Details“-Button im Menü<br />

(siehe 5.2 Menü). Es öffnet sich folgender Tab, wobei der Tabname aus „Shop<br />

Details: SAP-Nummer“ besteht, um den Überblick über die geöffneten Tabs zu<br />

behalten:<br />

Seite 75


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Abb. 16: Shop Details<br />

Ruft man einen Shop auf, so wie in Abb. 16: Shop Details, so sieht man auf der<br />

linken Seite der Arbeitsfläche die Details, die den Shop an sich betreffen. Auf der<br />

rechten Seite befindet sich die Hardware, die im Shop vorhanden ist. Bei<br />

mehreren Teilen kann man über die Tabs direkt oberhalb der Hardware zwischen<br />

den einzelnen Hardwarekomponenten wählen. Am unteren Ende beider Seiten<br />

befindet sich der Button „Edit“. Dieser wird zum Editieren der Elemente<br />

verwendet.<br />

Wird ein Shop aufgelöst, so kann man ihn im Programm mit dem „Close this<br />

Shop“-Button am unteren Ende des Formulars als geschlossen kennzeichnen.<br />

Der Shop ist nun nur noch unter den „Closed Shops“ im Programm zu finden.<br />

Seite 76


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Editieren<br />

Ändert sich irgendeine Information zu einem Element, so kann man einfach mit<br />

dem Button „Edit“ in der Details-Ansicht (siehe 5.8 Details) das Element editieren.<br />

Dabei bleibt der Tab derselbe, die Informationen lassen sich aber nun verändern.<br />

Abb. 17: Shop Editieren<br />

So wie beim Hinzufügen eines neuen Elements erscheinen auch hier Textfelder,<br />

die zum Eintragen der Informationen genutzt werden. Die gelben Textfelder<br />

zeigen Pflichtfelder an, die unbedingt ausgefüllt werden müssen. Sind alle<br />

Änderungen vorgenommen, so schließt man das Editieren mit einem Klick auf<br />

den Save-Button am unteren Ende des Formulars ab. Die Änderungen werden<br />

nun in der Datenbank übernommen.<br />

Seite 77


Diplomarbeit<br />

Lanzanasto, Neumann, Plattner<br />

Bilder-Verzeichnis<br />

Abb. 1: Grundaufbau .................................................................................................. 8<br />

Abb. 2: Firmenlogo Swarovski .................................................................................... 9<br />

Abb. 3: Ordnerstruktur .............................................................................................. 28<br />

Abb. 4 Application Model .......................................................................................... 32<br />

Abb. 5: Fenster-Struktur ........................................................................................... 35<br />

Abb. 6: Toolbar ......................................................................................................... 35<br />

Abb. 7: Handlers ....................................................................................................... 36<br />

Abb. 8: Commands ................................................................................................... 36<br />

Abb. 9: Grundstruktur ............................................................................................... 36<br />

Abb. 10: Oberflächen Übersicht ................................................................................ 70<br />

Abb. 11: Menü .......................................................................................................... 71<br />

Abb. 12: Tree ............................................................................................................ 72<br />

Abb. 13 Suche .......................................................................................................... 73<br />

Abb. 14: Hinzufügen einer Hardware ........................................................................ 74<br />

Abb. 15: Statistiken ................................................................................................... 75<br />

Abb. 16: Shop Details ............................................................................................... 76<br />

Abb. 17: Shop Editieren ............................................................................................ 77<br />

Seite 78

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!