DIPLOMARBEIT SSAP - HTL- Innovativ Austria
DIPLOMARBEIT SSAP - HTL- Innovativ Austria
DIPLOMARBEIT SSAP - HTL- Innovativ Austria
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