České vysoké učení technické v Praze
Fakulta elektrotechnická
Katedra počítačů
Diplomová práce
Automatický rezervační systém
Bc. Jan Búda
Vedoucí práce: Ing. Martin Šlapák
Studijní program: Elektrotechnika a informatika, strukturovaný, Navazující magisterský
Obor: Výpočetní technika
květen 2012
Poděkování
Děkuji vedoucímu práce, Ing. Martinu Šlapákovi, za přínosné rady k vývoji aplikace,
doporučení vhodných technologií a také za podrobné připomínky k textu této práce.
iii
Prohlášení
Prohlašuji, že jsem předloženou práci vypracoval samostatně a že jsem uvedl veškeré použité
informační zdroje v souladu s Metodickým pokynem o dodržování etických principů při
přípravě vysokoškolských závěrečných prací.
Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000
Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých
zákonů (autorský zákon).
V Českých Budějovicích dne 8. 5. 2012
iv
.............................................................
Abstract
This thesis deals with the analysis and design of an application for automated booking of
free seats on Student Agency, s.r.o. lines.
The application is designed to allow easy implementation of new plug-in modules.
A module for checking free seats for theatre performances at the Žižkovské Divadlo Járy
Cimrmana was implemented too.
The thesis includes a programmer’s guide to creating new plug-in modules as well as
tests of usability.
Abstrakt
Tato diplomová práce se zabývá analýzou a návrhem programu pro automatickou kontrolu
a rezervaci volných míst ve spojích společnosti Student Agency, s.r.o.
Program je navržen tak, aby umožňoval jednoduché rozšíření v podobě zásuvných modulů. Byl implementován také zásuvný modul pro kontrolu volných míst na představení
Žižkovského Divadla Járy Cimrmana.
Součástí práce je programátorská příručka pro tvorbu nových zásuvných modulů a testy
použitelnosti aplikace.
v
vi
Obsah
1 Úvod
1.1 Motivace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Struktura a forma textu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Používané pojmy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
2
2
2 Popis aplikace, požadavky na řešení
2.1 Existující řešení . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Automatická detekce volného místa v autobusech na lince Liberec
Praha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.2 SA Notify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.3 SA Checker 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.4 PHP Skript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.5 Rozšíření ReloadEvery . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.6 Srovnání existujících řešení . . . . . . . . . . . . . . . . . . . . . .
2.2 Popis aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Cíloví uživatelé a jejich počítačová gramotnost . . . . . . . . . . .
2.2.2 Obecné požadavky, forma aplikace . . . . . . . . . . . . . . . . . .
2.3 Specifikace požadavků . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1 Nefunkční požadavky . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2 Funkční požadavky . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
–
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
.
.
.
.
.
.
.
.
.
.
.
.
3
4
6
8
9
10
11
11
12
12
12
12
3 Analýza a návrh řešení
3.1 Použité technologie . . . . . . . . . .
3.1.1 Java 1.7 . . . . . . . . . . . .
3.1.2 SWT . . . . . . . . . . . . . .
3.1.3 MigLayout . . . . . . . . . .
3.1.4 Jsoup . . . . . . . . . . . . .
3.1.5 Eclipse JFace Data Binding .
3.2 Analytický model . . . . . . . . . . .
3.2.1 Základní struktura aplikace .
3.2.2 Menu aplikace . . . . . . . .
3.2.3 Správa pluginů . . . . . . . .
3.2.4 Menu pluginů . . . . . . . . .
3.2.5 Univerzální třídy . . . . . . .
3.2.6 Statické vs. Dynamické třídy
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19
19
19
20
22
24
24
25
25
26
27
28
29
31
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
OBSAH
3.3
Návrh grafického rozhraní aplikace . . . . . . . . . . . . . . . . . . . . . . . . 32
4 Implementace
4.1 Univerzální třídy . . . . . . . . . . . . . .
4.1.1 ImageHandler . . . . . . . . . . . .
4.1.2 Messenger . . . . . . . . . . . . . .
4.1.3 Sounds . . . . . . . . . . . . . . .
4.1.4 UpdateChecker a UpdateInterface
4.1.5 CommentedProperties a Commons
4.2 Menu aplikace . . . . . . . . . . . . . . . .
4.2.1 Mnemonic . . . . . . . . . . . . . .
4.2.2 Akcelerátory . . . . . . . . . . . .
4.2.3 Menu Soubor . . . . . . . . . . . .
4.2.4 Menu Nastavení . . . . . . . . . .
4.2.5 Menu Nastavení – Možnosti . . . .
4.2.6 Menu Nápověda . . . . . . . . . .
4.3 Logování chyb aplikace . . . . . . . . . . .
4.4 Pluginy . . . . . . . . . . . . . . . . . . .
4.4.1 Soubory pluginů . . . . . . . . . .
4.4.2 Plugin menu . . . . . . . . . . . .
4.4.3 Tělo pluginu . . . . . . . . . . . .
4.4.4 Položky hledání . . . . . . . . . . .
4.4.5 Kontrola volných míst . . . . . . .
4.4.6 Nastavení pluginů . . . . . . . . .
4.4.7 Historie hledání . . . . . . . . . . .
4.4.8 Přehled tříd pluginu . . . . . . . .
4.5 Různé . . . . . . . . . . . . . . . . . . . .
4.5.1 Texty v dialozích . . . . . . . . . .
4.5.2 Jediná instance programu . . . . .
4.5.3 Přístupnost . . . . . . . . . . . . .
4.5.4 Název aplikace . . . . . . . . . . .
4.5.5 Komentáře . . . . . . . . . . . . .
5 Plugin SA Notify
5.1 Analýza a návrh řešení pluginu SA Notify
5.1.1 Specifikace požadavků . . . . . . .
5.1.2 Případy užití . . . . . . . . . . . .
5.1.3 Diagram aktivit - přidání spoje . .
5.1.4 Analytický model . . . . . . . . . .
5.1.5 Grafický návrh pluginu . . . . . .
5.2 Implementace pluginu . . . . . . . . . . .
5.2.1 Rezervační systém Student Agency
5.2.2 Grafické rozhraní . . . . . . . . . .
5.2.3 Implementace grafického rozhraní .
5.2.4 Kontrola volných míst . . . . . . .
5.2.5 Automatická rezervace . . . . . . .
viii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
35
35
35
36
37
37
38
38
38
38
39
39
41
44
44
45
45
45
47
48
49
50
51
52
53
53
54
55
56
56
.
.
.
.
.
.
.
.
.
.
.
.
57
57
57
58
61
62
64
64
64
65
70
72
75
OBSAH
5.2.6
5.2.7
5.2.8
5.2.9
5.2.10
Úspěšné hledání . . . . . . . .
Přestupní spoje . . . . . . . . .
Chyby při hledání volných míst
Chyby v synchronizaci vláken .
Nastavení pluginu . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Testování
6.1 Simple Code Metrics . . . . . . . . . . . . . .
6.1.1 Lack of Cohesion in Methods . . . . .
6.1.2 Cyclomatic complexity . . . . . . . . .
6.2 Uživatelské testy . . . . . . . . . . . . . . . .
6.3 Testování aplikace na různých platformách . .
6.4 Testování použitelnosti aplikace . . . . . . . .
6.4.1 Metoda kognitivního průchodu . . . .
6.4.2 Persony . . . . . . . . . . . . . . . . .
6.4.3 Zadané úkoly . . . . . . . . . . . . . .
6.4.4 Úkol 1 – nastavení rodičovské aplikace
6.4.5 Úkol 2 – práce s pluginem SA Notify .
6.4.6 Výsledky testování . . . . . . . . . . .
7 Plugin Divadlo Járy Cimrmana
7.1 Analýza a návrh řešení pluginu . . . .
7.1.1 Funkční požadavky . . . . . . .
7.2 Implementace pluginu . . . . . . . . .
7.2.1 Grafické rozhraní . . . . . . . .
7.2.2 Tlačítka . . . . . . . . . . . . .
7.2.3 Minimální počet míst . . . . .
7.2.4 Interval kontroly volných míst .
8 Distribuce
8.1 Licence: . . . . . . . . . . . . . .
8.2 Verze knihovny SWT . . . . . . .
8.3 Spuštění aplikace . . . . . . . . .
8.3.1 Launch4j . . . . . . . . .
8.3.2 Spouštění přes příkazovou
8.3.3 Spuštění bez GUI . . . . .
8.3.4 Adresářová struktura . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
75
77
77
78
79
.
.
.
.
.
.
.
.
.
.
.
.
81
81
81
81
82
82
83
83
84
85
85
85
86
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
87
87
87
87
88
89
89
89
. . . .
. . . .
. . . .
. . . .
řádku
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
91
91
91
92
92
92
92
93
9 Závěr
95
9.1 Přínos práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
A Použité zkratky a pojmy
97
A.1 Zkratky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
A.2 Pojmy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
B Adresářová struktura přiloženého CD
99
ix
OBSAH
C Výsledky testování metodou
kognitivního průchodu
101
C.1 Úkol 1 – nastavení rodičovské aplikace . . . . . . . . . . . . . . . . . . . . . . 101
C.1.1 1. Spusťte aplikaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
C.1.2 2. Nastavte minimalizaci programu do oznamovací oblasti (tj. do pravého
dolního rohu obrazovky) . . . . . . . . . . . . . . . . . . . . . . . . . . 102
C.1.3 3. Otevřete dialog Možnosti a nastavte přehrávání libovolného zvuku
u všech vyskakovacích dialogů . . . . . . . . . . . . . . . . . . . . . . . 103
C.1.4 4. Zkontrolujte, zda je k dispozici novější verze programu . . . . . . . 104
C.1.5 5. Otevřete dialog Možnosti a zkontrolujte, zda je vypnuto přehrávání
všech zvuků v Tichém režimu . . . . . . . . . . . . . . . . . . . . . . . 105
C.1.6 6. Zapněte Tichý režim . . . . . . . . . . . . . . . . . . . . . . . . . . 106
C.2 Úkol 2 – práce s pluginem SA Notify . . . . . . . . . . . . . . . . . . . . . . . 107
C.2.1 1. Přepněte na plugin SA Notify . . . . . . . . . . . . . . . . . . . . . 107
C.2.2 2. Zahajte hledání volných míst v libovolném spoji na trase Praha –
Brno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
C.2.3 3. V nastavení pluginu vypněte zobrazování starých hledání . . . . . . 109
C.2.4 4. V nastavení pluginu nastavte preferovaná sedadla V uličce . . . . . 110
C.2.5 5. V nastavení pluginu nastavte automatickou rezervaci.
Použijte libovolné přihlašovací údaje. . . . . . . . . . . . . . . . . . . . 111
C.2.6 6. Zahajte vyhledávání volných míst v libovolném spoji na trase Brno
– Praha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
C.2.7 7. Zobrazte historii hledaných spojů . . . . . . . . . . . . . . . . . . . 113
D Programátorská příručka
D.1 Úvod . . . . . . . . . . .
D.1.1 Technologie . . .
D.1.2 Knihovny . . . .
D.1.3 Pojmy . . . . . .
D.2 Struktura aplikace . . .
D.3 Jak začít . . . . . . . . .
D.4 Univerzální třídy . . . .
D.5 Logování chyb . . . . . .
D.6 Jazykové verze . . . . .
Literatura
x
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
115
115
115
115
116
117
118
119
119
120
121
Seznam obrázků
2.1
2.2
2.3
2.4
2.5
2.6
2.7
Existující řešení - SA Notify . . . . . . . .
Existující řešení - SA Notify, výběr spoje .
Existující řešení - SA Checker 2011 . . . .
Popis aplikace - Počítačová gramotnost .
Případy užití - Nastavení . . . . . . . . .
Případy užití - Nastavení - Možnosti . . .
Případy užití - Nápověda . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
7
11
13
15
16
3.1
3.2
3.3
3.4
3.5
3.6
3.7
Analytický model - základní struktura
Analytický model - menu . . . . . . .
Analytický model - správa pluginů . .
Analytický model - menu pluginů . . .
Analytický model - univerzální třídy .
Návrh GUI . . . . . . . . . . . . . . .
Návrh GUI - Splash Screen . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
26
27
28
29
33
33
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
Menu Nápověda . . . . . . . . . . . . .
Menu v oznamovací oblasti . . . . . .
Dialog Možnosti - Obecné . . . . . . .
Dialog Možnosti - Zvuky a upozornění
Třídní diagram pluginu . . . . . . . .
StyledText – výchozí kurzor . . . . . .
StyledText - vybraný text . . . . . . .
Dialog Aplikace je již spuštěna . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
40
41
43
52
53
53
54
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
5.10
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
případy užití 1 . . . . . . . . . . . . .
případy užití 1 . . . . . . . . . . . . .
diagram aktivit . . . . . . . . . . . . .
Analytický model - Hledání . . . . . .
Analytický model - Nastavení, historie
Analytický model - Chyby a obrázky .
Tabulka Spoje . . . . . . . . . . . . .
CCombo chyba . . . . . . . . . . . . .
Tabulka hledání . . . . . . . . . . . . .
Srovnání GUI návrhu s GUI aplikace .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
58
60
61
62
63
64
66
68
68
69
SA
SA
SA
SA
SA
SA
SA
SA
SA
SA
Notify
Notify
Notify
Notify
Notify
Notify
Notify
Notify
Notify
Notify
-
SEZNAM OBRÁZKŮ
5.11
5.12
5.13
5.14
5.15
5.16
Plugin
Plugin
Plugin
Plugin
Plugin
Plugin
SA
SA
SA
SA
SA
SA
Notify
Notify
Notify
Notify
Notify
Notify
-
Tabulka hledání 2 . . . . . .
Úspěšné hledání 1 . . . . . .
Úspěšné hledání 2 . . . . . .
Rezervace odstraněného spoje
Ztracené spojení . . . . . . .
Dialog Nastavení . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
73
75
75
76
78
79
7.1
7.2
Plugin DJC - Přihlašovací údaje . . . . . . . . . . . . . . . . . . . . . . . . . 88
Plugin DJC - Hlavní část těla pluginu . . . . . . . . . . . . . . . . . . . . . . 88
8.1
8.2
Distribuce - Adresářová struktura . . . . . . . . . . . . . . . . . . . . . . . . . 93
Distribuce - Obsah kořenového adresáře aplikace . . . . . . . . . . . . . . . . 93
B.1 Obsah přiloženého CD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
C.1
C.2
C.3
C.4
C.5
C.6
C.7
C.8
C.9
C.10
C.11
C.12
C.13
Testy použitelnosti – Adresář aplikace . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Menu Nastavení . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Dialog Možnosti, záložka Zvuky a upozornění . . . . .
Testy použitelnosti – Menu Nápověda . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Dialog Možnosti, záložka Zvuky a upozornění . . . . .
Testy použitelnosti – Tichý režim . . . . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Výběr pluginu . . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Plugin SA Notify . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Dialog Nastavení pluginu SA Notify, záložka Obecná
nastavení . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Dialog Nastavení pluginu SA Notify, záložka Výchozí
hledání . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Dialog Nastavení pluginu SA Notify, záložka Automatická rezervace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Testy použitelnosti – Nepodařilo se rezervovat preferované sedadlo . . . . .
Testy použitelnosti – Menu pluginu s tlačítkem Historie . . . . . . . . . . .
.
.
.
.
.
.
.
.
101
102
103
104
105
106
107
108
. 109
. 110
. 111
. 112
. 113
D.1 Programátorská příručka – Menu pluginů . . . . . . . . . . . . . . . . . . . . 116
D.2 Třídní diagram pluginu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
xii
KAPITOLA 1. ÚVOD
Kapitola 1
Úvod
Tématem této implementační diplomové práce (viz [6]) je Automatický rezervační systém v podobě volně šiřitelné, modulární desktopové aplikace, která umožní automatické
ověřování dostupnosti volných míst v internetových rezervačních systémech, zejména v rezervačním systému vnitrostátní autobusové a vlakové dopravy společnosti Student Agency
s.r.o.
1.1
Motivace
Společnost Student Agency s.r.o. (dále jen Student Agency) provozuje stále se zvětšující síť autobusové a vlakové dopravy, nabízející ve většině případů na české poměry nadprůměrný komfort a příznivé ceny, včetně cenových zvýhodnění pro studenty. Služeb Student
Agency proto využívá i značné množství dojíždějících studentů.
V exponované dny, jako je neděle, pondělí dopoledne, čtvrtek odpoledne a pátek, bývají
spoje Student Agency vyprodané na některých trasách i na několik týdnů dopředu.
Mnoho cestujících ale své rezervace těsně před cestou ruší, na což čeká množství těch,
na které se lístek nedostal a ihned rezervuje uvolněné lístky. Tím ovšem dochází ke stavu,
kdy při uvolnění místa ve spoji je toto místo opět zarezervováno během maximálně několika
málo minut.
Cestující, který doufá v uvolnění místa ve vyhlédnutém spoji tak musí sedět u počítače,
neustále aktualizovat webovou stránku rezervačního systému a snažit se být první, kdo objeví
případné uvolněné místo.
Rozhodl jsem se proto vytvořit aplikaci, která by umožňovala automatické kontrolování
volných míst ve spojích Student Agency, případně i následné automatické zarezervování
uvolněného místa.
Analogie s vyprodanými spoji Student Agency lze ovšem nalézt i u dalších webových
služeb: Například některá oblíbená divadla (za všechny Žižkovské divadlo Járy Cimrmana
nebo Divadlo v Dlouhé) mívají zarezervována všechna volná místa během několika málo
hodin od zveřejnění nového programu. I zde pak dochází k situacím, kdy si lidé rezervaci
nevyzvednou a místa se opět uvolní.
Aplikaci jsem proto navrhoval tak, aby bylo možné formou zásuvných modulů (pluginů)
přidat podporu pro další rezervační systémy.
1
1.2. STRUKTURA A FORMA TEXTU
1.2
Struktura a forma textu
Všechny odkazy v PDF verzi této práce jsou interaktivní. To platí jak pro interní (odkazy
na jinou kapitolu, obrázek apod.), tak internetové odkazy.
Internetové odkazy jsou od okolního textu odlišeny neproporcionálním fontem.
Použitá literatura je uváděna ve formátu odpovídajícím normě ISO 690 [1].
V textu jsou použity některé ikony z kolekce Function Icon Set ze stránek
http://www.wefunction.com. Kolekce je zdarma k použití pod Royalty free licencí [30].
Dále jsou použity ikony od uživatele Tatice ze stránky http://www.iconarchive.com pod
licencí CC Attribution-Noncommercial-No Derivate 3.0 [18].
1.2.1 Používané pojmy
Použité zkratky a pojmy jsou pro větší přehlednost definovány v příloze A.
Některé běžně užívané programátorské pojmy v příloze neuvádím – například getter,
setter, listener (zde obecně konstrukce spouštěná v reakci na definovanou akci uživatele),
fields (také počeštěný tvar fieldy - data třídy) ad.
2
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Kapitola 2
Existující řešení, Popis aplikace,
Specifikace požadavků
2.1
Existující řešení
Primárním důvodem vývoje aplikace je potřeba programu, který by dokázal upozorňovat na volná místa ve spojích společnosti Student Agency. Nicméně, jak již bylo zmíněno
výše, předpokládám, že upotřebení najdou i další pluginy, pro ověřování volných míst či
automatickou rezervaci míst například v oblíbených divadlech.
V době psaní tohoto textu neexistuje v České Republice žádný program, který by
umožňoval automatickou rezervaci ve více různých službách a který by bylo možné modulárním způsobem dále rozšiřovat.
Pokud se ale zaměříme na programy pro automatické ověřování volných míst v autobusech Student Agency, je situace odlišná. Takových programů existuje hned několik. Bohužel žádný z nich není v současné době funkční.
Společnost Student Agency neposkytuje žádné API (A.2) pro přístup k rezervačnímu systému. Všechny uváděné programy proto fungují na stejném principu – nejprve načtou celou
webovou stránku s vypsanými časy spojů pro zvolenou trasu a den a následně syntaktickou
analýzou naleznou požadovaný čas spoje a číslo, udávající počet volných míst.
Student Agency však v minulosti svůj webový rezervační systém několikrát změnila a
tvůrci své programy již neupravili tak, aby nadále fungovaly.
Následně popisované existující programy jsou tedy již nepoužitelné, je ale vhodné je vzájemně porovnat pro získání lepší představy o požadavcích na aplikaci a především o podobě
pluginu pro autobusy a vlaky Student Agency.
V době vzniku všech níže uváděných programů společnost Student Agency provozovala
pouze autobusové spoje, vlakové spoje proto v této kapitole nejsou brány v úvahu.
2.1.1 Automatická detekce volného místa v autobusech na lince Liberec –
Praha
Student Katedry měření Fakulty elektrotechnické ČVUT Jan Breuer na své osobní
stránce (http://jaybee.cz) v březnu 2008 zveřejnil v článku Automatická detekce volného
3
2.1. EXISTUJÍCÍ ŘEŠENÍ
místa v autobusech na lince Liberec – Praha [8] php skript pro detekci míst v autobusech Student Agency.
Během následujícího roku a půl byl skript postupně vylepšován. Byla přidána podpora
pro všechny tuzemské linky Student Agency a pro autobusy DPMLJ na lince Praha –
Liberec. Po změně webu rezervačního systému Student Agency v roce 2009 byl celý skript
přepracován a fungoval až do roku 2010. V roce 2010 došlo k další změně webu Student
Agency, skript se díky tomu stal nefunkčním a jeho další vývoj byl zastaven.
2.1.1.1
Použití
Skript se spouští přes příkazovou řádku, jako parametr je nutné zadat ID požadovaného
spoje, které lze zjistit z URL adresy rezervačního systému. Při nalezení volného místa je
pomocí PHP funkce exec() spuštěn program notify-send, který v Linuxových operačních
systémech zobrazí upozornění na volné místo. Skript je tedy určen pouze pro OS Linux
s nainstalovaným notify-send (je součástí balíku libnotify-bin).
Umožňuje sledování více autobusových spojů najednou. Sleduje pouze volná místa, neumožňuje žádné nastavení preferovaných míst apod.
Kontrola, zda se ve sledovaném spoji uvolnilo místo, probíhá periodicky každých 20 vteřin.
Takto krátký interval je výhodný pro uživatele, zejména v případě většího rozšíření aplikace
by ale mohl způsobovat nadměrné zatížení serverů rezervačního systému a vyvolat případné
protiopatření ze strany Student Agency.
Klady a zápory skriptu z webu http://jaybee.cz:
+ Lze sledovat více spojů najednou
- Použití pouze pod OS Linux
+ Kontroluje volná místa každých 20 s
- Použití pouze přes příkazovou řádku
+ Umí sledovat i autobusy DPMLJ na
lince Praha – Liberec
- Nutné ručně kopírovat ID spoje z URL
adresy
- Nelze zadat preferované sedadlo
- Na volné místo pouze upozorní
2.1.2 SA Notify
Matěj Humpál vytvořil, inspirován skriptem od Jan Breuera, prográmek SA Notify
(obr. 2.1), který zveřejnil na svých osobních stránkách http://weblog.finwe.info v polovině roku 2008.
Program má jednoduché a přehledné grafické rozhraní, je psán v programu C# za použití
frameworku .NET 2.0.
4
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Obrázek 2.1: Prográmek SA Notify, verze 1.7.1
Prošel poměrně dlouhým vývojem: první verze uměla hlídat pouze spoje na trase Praha Liberec a vstupní parametry bylo, podobně jako v předchozím případě, nutné ručně kopírovat
z URL adresy rezervačního systému.
Nejnovější verze již zvládá všechny tuzemské trasy Student Agency a požadovaný spoj
lze vybrat z kontextového rozbalovacího menu.
Příjemné také je, že program nevyžaduje instalaci a má pouhých 33 kB. Po stažení je
ihned připraven k použití. Vyžaduje pouze přítomnost .NET 2.0 frameworku (OS Windows)
nebo MONO frameworku pro Unixové operační systémy (Linux, Mac OS). .NET framework
je zapotřebí pro běh velkého množství aplikací pod OS Windows, většina počítačů s tímto
OS ho tedy nainstalovaný již má.
Obrázek 2.2: Prográmek SA Notify, výběr spoje
5
2.1. EXISTUJÍCÍ ŘEŠENÍ
2.1.2.1
Použití
Po spuštění si uživatel výběrem z kontextových menu (obr. 2.2) jednoduše navolí požadovanou trasu, výchozí a cílovou stanici a čas zvoleného spoje. Časy spojů jsou načítány
přímo z webu Student Agency, jsou tedy vždy aktuální, nevýhodou je někdy delší doba
odezvy. Oproti tomu dostupné trasy autobusů jsou do programu napevno zakomponovány
a není možné jednoduchým způsobem přidat trasy nové. Ke změnám obsluhovaných tras a
především k zavedení tras nových přitom dochází relativně často (i několikrát do roka).
Volná místa jsou kontrolována každých 90 vteřin, v případě úspěchu se zobrazí upozornění a ozve zvukový signál. 90 vteřin je znatelně větší interval než 20 vteřin v předchozím
případě, i tak se ale autor na stránkách zamýšlí, zda interval a datová náročnost programu
není příliš velká a v případě většího rozšíření nebude pro web Student Agency znamenat
příliš velkou zátěž. Zdá se, že se tato obava nenaplnila. Ovšem, stejně jako v případě skriptu
z kapitoly 2.1.1, po změně rezervačního systému v roce 2010 program přestal fungovat.
Klady a zápory programu SA Notify (verze 1.7.1):
+ Online načítání času spojů
- Načtení spojů někdy trvá delší dobu
+ Lze sledovat více spojů najednou
- Nelze aktualizovat trasy spojů
+ Jednoduché grafické rozhraní
- Na volné místo pouze upozorní
+ Funguje pod všemi rozšířenějšími OS
- Nelze zadat preferované sedadlo
+ Na OS Windows běží schován v pravé
dolní liště
2.1.3 SA Checker 2011
SA Checker 2011 (obr. 2.3) od Lukáše Hakulina je funkčností velmi podobný programu
SA Notify, je ale psán v jazyce Java. Je nutné jej instalovat, instalační soubor má velikost
1,04 MB. Byl zveřejněn začátkem roku 2011, bohužel již v létě téhož roku web Student
Agency doznal dalších změn, které by vyžadovaly přepracování větší části programu. Novou,
funkční verzi proto zatím autor neplánuje.
Za největší změnu oproti programu SA Notify považuji možnost uživatelů doplnit
jednoduchým zásahem do části zdrojových kódů případné nové autobusové trasy.
2.1.3.1
Použití
Použití je prakticky totožné s programem SA Notify, největší funkční změnou, kterou
uživatel pocítí, je kontrolování volných míst pouze jednou za 3 minuty.
6
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Obrázek 2.3: Prográmek SA Checker 2011, verze 1.1 (zdroj: http://lukashakulin.com)
U nejvíce exponovaných spojů je tento interval příliš velký. Například několik hodin
před odjezdem vyprodaného autobusu je případné uvolněné místo zabráno zpravidla během
minuty či dvou. To přitom platilo i v době, kdy žádný ze zde uváděných programů nebyl
funkční a zájemci o místo v daném spoji museli stránku rezervačního systému manuálně
aktualizovat.
Díky lépe zpracovanému grafickému rozhraní se s programem pracuje příjemně a velmi
intuitivně.
2.1.3.2
Hlavní rozdíly programu SA Checker 2011 oproti SA Notify:
• Umožňuje jednoduchou úpravou XML souboru implementovat nové trasy. Na stránkách
autora je podrobný a přehledný návod doplněný obrázky, přidat požadovanou trasu
trasu by měl být bez větších obtíží schopen i ne-programátor.
• Fungoval pod novějším rezervačním systémem Student Agency, který byl v provozu
v letech 2010-2011.
• Kontroluje volné spoje pouze každé 3 minuty (z obavy před přetížením serveru).
• Existuje-li více spojů ve stejný čas, program prohledává pouze poslední spoj v řadě. Na
mnoha trasách je ve špičce více autobusů ve stejný čas nasazováno běžně. Například
7
2.1. EXISTUJÍCÍ ŘEŠENÍ
na trase Praha-Brno odjíždí v obou směrech dva autobusy najednou hned 4x každý
všední den. Jedná se tedy o poměrně vážný nedostatek.
• Program dokáže sledovat i spoje, které mají volná místa (viz obr. 2.3).
• Vylepšené grafické rozhraní
• Program se instaluje a pro jeho funkčnost je nutné mít nainstalovanou Java Virtual
Machine. SA Notify instalaci nevyžaduje, pro svou funkčnost potřebuje nainstalovaný
.NET 2.0 framework.
• Výraznější zvukový signál při nalezení volného místa. Ten lze navíc v případě potřeby
jednoduše změnit nahrazením souboru alarm.wav v kořenovém adresáři programu.
• Na OS Windows při minimalizování zůstane na hlavní liště, SA Notify se minimalizuje
do oznamovací oblasti v pravém dolním rohu.
Klady a zápory programu SA Checker 2011 (verze 1.1):
+ Lze manuálně přidat nové trasy
- Kontroluje spoje jen 1× za 3 minuty
+ Jazyk Java – snadná přenositelnost
mezi platformami
- Při více spojích ve stejný čas umí hlídat
pouze jeden
+ Lze sledovat více spojů najednou
- Na volné místo pouze upozorní
+ Přehledné grafické rozhraní
- Nelze zadat preferované sedadlo
O existenci SA Checker 2011 jsem se, na rozdíl od programu SA Notify, dozvěděl
až v době, kdy již byl kvůli změněnému webu pro rezervace nefunkční. Nemohl jsem proto
zahrnout jeho hodnocení z hlediska rychlosti načítání spojů.
2.1.4 PHP Skript
Začátkem roku 2011, kdy nebyl funkční žádný z dosud uvedených programů, jsem napsal
svůj vlastní PHP skript pro hlídání volných míst v autobusech Student Agency.
Můj skript je v zásadě velmi podobným se skriptem, který popisuji v kapitole 2.1.1.
Hlavní rozdíl spočívá v určení pro webový server a spouštění přes běžný webový prohlížeč.
Pro spuštění na osobním počítači je vhodné použít balíček EasyPHP ( http://www.easyphp.
org/ ).
Skript byl určen pro mé osobní použití, případně pro několik málo mých známých, kterým
jsem mohl osobně ukázat instalaci i použití. Při jeho vývoji byl hlavní důraz kladen na
rychlost vývoje (pouze několik hodin). Není proto příliš uživatelsky přívětivý – neexistuje
žádné uživatelské rozhraní, parametry spoje se zadávají ručně do zdrojového kódu.
8
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Při nalezení volného místa je uživatel upozorněn spuštěním Javascriptového příkazu
alert(). Jeho nevýhodou je, že v novějších verzích webových prohlížečů není alert doprovázen
zvukem, uživatel si proto upozornění nemusí všimnout – z nejpoužívanějších prohlížečů je
zvuk pouze u Internet Exploreru 9. Prohlížeče Mozilla Firefox v. 10, Google Chrome v. 17,
Opera v. 11.6 ani Safari v. 5.2 zvukové upozornění nevydají.
Skript kontroluje volná místa každých 90 sekund, parametr je ale možné jednoduše
změnit. Experimentováním jsem zjistil, že u nejvytíženějších spojů je vhodné změnit interval
na 60 s, jinak roste nebezpečí propásnutí volného místa.
Klady a zápory PHP skriptu:
- Složitější na zprovoznění
+ Při umístění na webový server lze skript
spouštět vzdáleně z libovolného zařízení s
přístupem na internet
- Nutné ručně kopírovat parametry spoje
z URL adresy
- Umí sledovat jen jeden spoj
- Nelze zadat preferované sedadlo
- Na volné místo pouze upozorní
2.1.5 Rozšíření ReloadEvery
ReloadEvery je rozšíření pro prohlížeč Mozilla Firefox, které lze použít pro pohodlnější
manuální sledování volného místa, uvádím ho zde pouze pro úplnost.
Protože v současné době žádný z uvedených programů nelze použít, zájemci o uvolněná
místa ve vyprodaných spojí musí tyto spoje sledovat ručně.
Pomocníkem může být toto rozšíření, které v zadaném intervalu aktualizuje webovou
stránku. Okno prohlížeče pak stačí zmenšit a umístit na viditelné místo tak aby nepřekáželo
v další činnosti na PC a pouze průběžně sledovat počet volných míst bez nutnosti neustálého
ručního aktualizování stránky a zdlouhavého čekání, až se stránka opět načte.
9
2.1. EXISTUJÍCÍ ŘEŠENÍ
2.1.6 Srovnání existujících řešení
PHP Skript
1 (2.1.1)
PHP Skript
2 (2.1.4)
SA Notify
(2.1.2)
SA Checker
(2.1.3)
Programovací jazyk
PHP
PHP
C#
Java
Velikost
8 kB
6 kB
33 kB
1,04 MB
Multi-platformní
Grafické rozhraní
Sledování více spojů
najednou
Online načítání času
spojů
Možnost zadat nové
trasy spojů
Poradí si s více spoji v
1 čas
Minimalizace do
oznamovací oblasti
(OS Windows-pravý dolní
roh)
Lze změnit interval
hledání
Výrazné nebo
nastavitelné zvukové
upozornění při úspěchu
Volné místo zarezervuje
Lze zadat preferovaná
sedadla
Lze zadat preferovaný
spoj
(Při více spojích v 1 čas
mívá tzv. posilový spoj
méně služeb pro cestující)
Jak je vidět z tabulky, všechna řešení mají některé výrazné nedostatky, zároveň ale také
každé řešení nabízí i funkcionalitu, kterou zbylá řešení nemají.
10
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Analýza existujících řešení proto poskytla dobrý základ pro specifikaci požadavků na
plugin pro hlídání volných míst v autobusech Student Agency.
2.2
Popis aplikace
2.2.1 Cíloví uživatelé a jejich počítačová gramotnost
Obrázek 2.4: Počítačová gramotnost v ČR (zdroj: http://www.zive.cz)
Předpokládanými cílovými uživateli jsou v první řadě všichni zákazníci Student Agency.
Mezi lidmi, kteří se Student Agency cestují pravidelně, se dá o aplikaci očekávat poměrně
vysoký zájem.
Provedl jsem menší orientační průzkum potenciálního zájmu o aplikaci. Respondenty
bylo 10 studentů vysoké školy, kteří služeb Student Agency pravidelně využívají (typicky
nejméně několikrát do měsíce). Všichni uvedli velký zájem o podobnou aplikaci.
Vzhledem k tomu, že jediný společný předpoklad pro uživatele je cestování se společností
Student Agency, mohou být uživatelé velmi rozmanití. Silnou skupinu budou jistě tvořit
studenti vysokých škol. Zájem o podobnou aplikaci může ale mít kdokoli.
S vývojem dalších pluginů, např. pro rezervaci divadel, můžeme navíc očekávat i více
uživatelů středního či vyššího věku.
Na obrázku 2.4 je graf počítačové gramotnosti obyvatel v ČR (Více o metodice průzkumu
a údajích z obrázku viz článek na serveru Živě.cz [11]. Průzkum byl prováděn v roce 2005,
dnes tedy může být skutečnost mírně odlišná, pro přibližnou orientaci ale postačí.
11
2.3. SPECIFIKACE POŽADAVKŮ
Ve věku 18-60 let je pouze přibližně třetina populace považována za počítačově gramotnou, třetina neumí s počítačem pracovat vůbec.
2.2.2 Obecné požadavky, forma aplikace
Vzhledem ke skutečnostem uvedeným v podkapitole 2.2.1 by navrhovaná aplikace měla
být jednoduše spustitelná a maximálně uživatelsky přívětivá – předpokládá se velké množství
potenciálních uživatelů, z nichž mnozí mohou mít velmi malé nebo žádné zkušenosti s instalací programů apod.
Jednou z uvažovaných forem aplikace bylo i rozšíření pro webové prohlížeče. Výhodou
této formy je především možnost používání bez nutnosti instalovat či spouštět samostatnou
aplikaci, která zabírá více systémových prostředků a místo na obrazovce či v systémové liště.
Nevýhodou je nutnost vývoje pro každý prohlížeč zvlášť a malé obecné povědomí o možnostech rozšíření pro webové prohlížeče. Také zamýšlená modularita aplikace by se obtížně
realizovala. Toto řešení by bylo vhodné spíše pro jednoúčelový program pro kontrolu volných
míst ve spojích Student Agency.
Vzhledem k předpokládaným běžným uživatelům jsem se proto rozhodl pro samostatnou, desktopovou aplikaci, ideálně spustitelnou bez nutnosti instalace.
2.3
Specifikace požadavků
Následující požadavky jsou pro rodičovskou aplikaci, poskytující rozhraní pro jednotlivé
pluginy. Specifikace požadavků pro plugin SA Notify je v kapitole 5.
2.3.1 Nefunkční požadavky
• Uživatelsky přívětivá. Aplikace by měla být přehledná a jednoduše ovladatelná.
• Přenositelná a multiplatformní. Aplikace musí být spustitelná na nejrozšířenějších
operačních systémech – MS Windows, MacOS a Linux.
• Modulární. Měla by být rozšiřitelná formou zásuvných modulů a poskytovat API
rozhraní usnadňující tvorbu nových pluginů.
2.3.2 Funkční požadavky
Při sestavování funkčních požadavků jsem vycházel z obvyklých funkcí desktopových
programů (zejména pro menu Nápověda) a také z funkcí rozsahem či účelem podobných aplikací, například programu FreeRapid Downloader (http://wordrider.net/freerapid/) od
studenta ČVUT-FEL Ing. Ladislava Vitáska.
Autor program zveřejnil pod licencí GNU General Public License verze 2 [19] a psal o něm
svou diplomovou práci [13], kterou jsem také použil jako literaturu při výběru jednotlivých
technologií.
12
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
2.3.2.1
Uživatelské role
Aplikace nevyžaduje žádnou údržbu, nezahrnuje správu uživatelských účtů a obecně
neobsahuje funkce, které by měly být přístupné jen některým uživatelům. Existuje proto jen
jedna uživatelská role.
2.3.2.2
Případy užití
Následující UML diagramy zahrnují všechny základní případy užití aplikace. Při tvorbě
diagramů jsem se snažil respektovat obecná doporučení pro tvorbu UML diagramů – udržovat diagramy přehledné, v jednom diagramu mít ideálně nejvíce 7 položek.
2.3.2.3
Nastavení programu
Obrázek 2.5: Nastavení programu
• Zapnout Tichý režim
- aplikace v Tichém režimu nevydává žádné zvuky
- v Nastavení aplikace je možné upřesnit chování Tichého režimu
13
2.3. SPECIFIKACE POŽADAVKŮ
• Ukládat při ukončení
- uživatel může zvolit ukládání stávajících hledání při ukončení aplikace.
- ve výchozím nastavení je tato možnost zapnutá
• Spouštět při startu
- uživatel může zvolit automatické spouštění aplikace po startu operačního systému
- ve výchozím nastavení je tato možnost vypnutá
• Nastavit minimalizaci do oznamovací oblasti
- aplikace se při minimalizaci skryje do oznamovací oblasti v pravém dolním rohu
(OS Windows)
• Zobrazit Možnosti
- aplikace zobrazí okno s možnostmi nastavení. Více viz diagram 2.6
2.3.2.4
Nastavení – Možnosti
Diagram na obrázku 2.6 představuje konkrétní možnosti případu užití Zobrazit Možnosti
z obrázku 2.5.
• Kontrolovat aktualizace po spuštění
- aplikace po spuštění zkontroluje, zda je k dispozici nová verze.
- pokud ano, upozorní uživatele na existenci nové verze
• Změnit jazyk
- uživatel může změnit jazyk aplikace
- výchozím jazykem je čeština
• Správa pluginů
Aplikace zobrazí seznam instalovaných pluginů s těmito informacemi:
- jméno pluginu
- verze
- stav pluginu – Aktivní, nebo Neaktivní (uživatel může stav změnit)
- autor pluginu
• Změnit vzhled
Uživatel může upravit vzhled aplikace:
- může změnit velikost ikon v menu
- může změnit barvy pozadí jednotlivých pluginů
14
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
Obrázek 2.6: Možnosti nastavení programu
• Vytvořit zástupce
- uživatel může zvolit vytvoření zástupce programu na Ploše, v nabídce Start nebo
ve složce Po spuštění (vše pouze na OS Windows)
• Zvuky a upozornění
Uživatel může:
- změnit nebo vypnout zvuk aplikace při nalezení volného místa pluginem. Může
si vybrat z přednastavených zvuků, nebo vybrat zvuk vlastní.
- změnit nebo vypnout zvuk aplikace při zobrazování upozornění nebo chyb. Může
si vybrat z přednastavených zvuků, nebo vybrat zvuk vlastní.
- vypnout upozorňování na běžící vyhledávání při vypínání programu.
- specifikovat chování aplikace v Tichém režimu:
- vypnout, nebo zapnout zvuky v Tichém režimu
- vypnout, nebo zapnout vyskakující upozornění v Tichém režimu
15
2.3. SPECIFIKACE POŽADAVKŮ
Program může být spuštěn dlouhou dobu, po kterou se může měnit okolní prostředí.
Je proto důležité, aby si uživatel mohl nastavit vlastní profil (vyhovující systém upozornění a zvukových upozornění) a aby tento mohl jednoduše měnit, respektive vypínat
všechny zvuky zapnutím Tichého režimu.
2.3.2.5
Nápověda
Obrázek 2.7: Nápověda
• Zobrazit nápovědu
- aplikace otevře nápovědu ve webovém prohlížeči
Rozhodl jsem se pro nápovědu k rodičovské aplikaci i nápovědu k pluginům ve formě
HTML a k jejich umístění na webový server. Tuto formu využívají i jiné programy.
Většinou se jedná o lokální HTML stránky, distribuované spolu s programem.
Má aplikace je ale použitelná pouze s funkčním internetovým připojením, není tedy
důvod distribuovat nápovědu spolu s aplikací.
Umístění na webových stránkách má navíc výhodu ve snadnější správě nápovědy a
možnosti rychle reflektovat časté problémy uživatelů např. doplněním sekce „Často
kladené otázky“.
• Nápověda k pluginům
- aplikace otevře ve webovém prohlížeči nápovědu k jednotlivým pluginům
16
KAPITOLA 2. POPIS APLIKACE, POŽADAVKY NA ŘEŠENÍ
• Zkontrolovat aktualizace
- aplikace zkontroluje, zda je k dispozici novější verze. Pokud ano, nabídne možnost
přejít na webovou stránku s novou verzí.
• Přejít na domovskou stránku
- aplikace otevře ve webovém prohlížeči svojí domovskou stránku
• Zobrazit licenční ujednání
- aplikace zobrazí název licence, pod kterou je distribuována a její stručný popis
- zobrazí také webový odkaz na plné znění licenčního ujednání
• Zobrazit info o programu
Aplikace zobrazí informace o programu, zejména:
- aktuální verze
- datum vydání aktuální verze
- autor aplikace
- krátké info o pozadí vzniku aplikace
17
2.3. SPECIFIKACE POŽADAVKŮ
18
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
Kapitola 3
Analýza a návrh řešení
3.1
Použité technologie
3.1.1 Java 1.7
Vzhledem k požadavku na snadnou přenositelnost a multiplatformnost aplikace jsem
zvolil programovací jazyk Java 1.7.
Verze 1.7 dosud není mezi uživateli příliš rozšířená, oficiálně uvedena a nabídnuta ke
stažení na serveru Java.com na stránce Download (http://www.java.com/download/) byla
v květnu 2012.
Např. server Slunečnice.cz ale verzi 1.7. nabízí již od února 2012. Odkaz na server
Slunečnice je přitom na prvním místě vyhledávání hesla „java download“ ve dvou dominantních webových vyhledávačích v ČR (Seznam a Google).
Lze tedy očekávat brzké rozšíření této verze. Uživatelům, kteří Javu 1.7 dosud nemají,
by zprovoznění aplikace nemělo dělat přílišné problémy ani při případné distribuci bez Java
Runtime Enviroment.
Nejnovější verze má řadu výhod (plný výčet nových vlastností viz [4]). Vedle těch obecných (vylepšená stabilita, výkon, bezpečnost) obsahuje množství drobných vylepšení, která
usnadňují programování.
Z nových vlastností se ukázaly přínosné například:
• Zjednodušený zápis generických instancí
Místo
L i s t <S t r i n g > s t r i n g s = new A r r a y L i s t <S t r i n g > ( ) ;
lze nyní použít
L i s t <S t r i n g > s t r i n g s = new A r r a y L i s t ( ) ;
19
3.1. POUŽITÉ TECHNOLOGIE
• Řetězení výjimek
V konstrukci try{ } catch{ } lze použít zřetězení výjimek. Chceme-li odchytit více
výjimek, není nutné psát pro každou vlastní catch{ } :
try {
C l a s s a = C l a s s . forName ( " wrongClassName " ) ;
} c a t c h ( ClassNotFoundException | I l l e g a l A c c e s s E x c e p t i o n |
I n s t a n t i a t i o n E x c e p t i o n ex ) {
. . .
}
Tuto vlastnost považuji z nových syntaktických vlastností za nejužitečnější, velmi
pomáhá zlepšit přehlednost kódu.
• Switch pro String
Dosud bylo možné příkaz switch použít pouze pro proměnné typu integer.
• Konstrukce try-with-resources
Nová konstrukce umožňuje vynechat blok finally { } při otevírání „resources“. Použijemeli try-with-resources, Java se sama postará o zavření např. příslušného InputStreamu,
ať už blok try{ } skončí chybou, nebo ne:
t r y ( B u f f e r e d R e a d e r i n=new B u f f e r e d R e a d e r ( new F i l e R e a d e r ( " f i l e " ) ) )
{
String line = null ;
w h i l e ( ( l i n e = i n . r e a d L i n e ( ) ) != n u l l ) {
System . out . p r i n t l n ( l i n e ) ;
}
} c a t c h ( IOException ex ) { . . . }
3.1.2 SWT
Standard Widget Toolkit je open-source knihovna pro tvorbu grafických aplikací v Javě,
která je ve správě nadace Eclipse Foundation. Je alternativou ke knihovně Swing, jenž je
součástí Java SE. Knihovna SWT je uvolněna pod licencí Eclipse Public License v 1.0 [3].
Tato licence umožňuje libovolné použití knihovny, jedinou podmínkou je, že při zveřejnění
zdrojových kódů musí být tyto zveřejněny pod stejnou licencí.
3.1.2.1
Výhody SWT
Komponenty Operačního sytému
SWT na rozdíl od knihovny Swing nevykresluje jednotlivé GUI komponenty samostatně,
ale používá komponenty operačního systému. Vykreslování je proto rychlejší a SWT má
mnohem menší paměťové nároky.
Například autoři přednášky SWT & MigLayout z cyklu přednášek Czech Java User
Group uvádí příklad, kdy při testování stejné aplikace napsané v SWT i ve Swingu zabírala
20
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
aplikace používající knihovnu Swing stabilně 9 MB operační paměti, zatímco verze používající SWT maximálně 800 kB [22].
Univerzální konstanty
SWT také nabízí funkce pro jednoduchou tvorbu multiplatformních GUI. Například při
definování klávesových zkratek nebo jejich vypisování uživateli lze použít konstanty místo
názvů kláves – tedy např. místo použití klávesy Ctrl, která na některých platformách není,
lze použít konstantu SWT.MOD1. Knihovna při spuštění konstantu nahradí odpovídajícím
tlačítkem na dané platformě. Obdobně lze použít konstanty i pro další funkční klávesy, ale
také pro ikony:
Univerzální ikony
Konstrukce display.getSystemImage(SWT.ICON_ERROR) vrátí ikonu, kterou daná platforma používá pro chybové hlášky.
Při využití těchto vlastností tak aplikace spuštěná na určitě platformě vypadá, jako by
byla psaná nativně pro tuto platformu. Tato vlastnost může významně zvýšit uživatelský
komfort při práci s aplikací – umožňuje uživatelům pracovat v prostředí, na které jsou zvyklí.
SWT Snippets
SWT Snippets je sbírka příkladů použití SWT komponent, dostupná
na www.eclipse.org/swt/snippets/ a poskytovaná pod stejnou licencí jako SWT ([3]).
Sbírka obsahuje velké množství jednoduchých i složitějších příkladů implementace nejrůznějších
komponent a jejich vlastností. Spolu s kvalitní dokumentací je tak další výhodou SWT knihovny.
3.1.2.2
Nevýhody SWT
Různé verze pro různé platformy
Hlavní nevýhoda plyne z první uváděné výhody SWT: díky používání systémových komponent je třeba používat pro každou platformu jinou verzi SWT a dále na zvolené platformě
používat verzi podle bitovosti JRE (32, nebo 64 bitů). Je tedy nutné vytvořit samostatný distribuční balíček pro každou platformu nebo vytvořit balíček univerzální, obsahující všechny
verze SWT, a manuálně načíst správnou verzi podle platformy, na které je aplikace spuštěna.
Nelze dědit
Další nevýhodou je nemožnost dědění ze základních komponent. Tato vlastnost opět souvisí
s více verzemi SWT – jedna GUI komponenta bude mít různé implementace pro různé platformy. I námi vytvořená podtřída by proto musela brát tyto odlišnosti v úvahu a mít různé
verze pro různé platformy. SWT má ale komponenty Composite a Canvas, které dědění
umožňují (komponenta, dále také widget, Composite je nadtřídou všech ostatních komponent).
Ruční uvolňování prostředků
Poslední významnou nevýhodou je nutnost ručního uvolňování systémových prostředků [14].
Konkrétně všechny vytvořené fonty, barvy a obrázky je nutné ručně uvolnit zavoláním jejich
metody .dispose(), jinak by došlo k úniku paměti (memory leak). Tím je omezena jedna
21
3.1. POUŽITÉ TECHNOLOGIE
z velkých výhod Javy např. oproti jazykům C/C++.
Jedno vlákno
SWT běží pouze v jednom vlákně a pokus o přístup k widgetům z jiného vlákna skončí
chybou – přístup je nutné provádět pomocí konstrukce
D i s p l a y . g e t D e f a u l t ( ) . asyncExec ( new Runnable ( ) {
@Override
p u b l i c v o i d run ( ) {
// kód p ř i s t u p u j í c í k SWT komponentům
// i n i c i a l i z o v a n ý m v jiném v l á k n ě
}
});
Klady a zápory SWT (ve srovnání s knihovnou Swing):
+ Nativní vzhled na všech platformách
- Nelze dědit
+ Nativní chování na všech platformách
(funkční tlačítka, ikony)
- Složitější distribuce (jiná verze SWT pro
každou platformu)
+ Rychlejší načítání
- Ruční uvolňování prostředků
+ Menší systémové nároky
- Jedno vlákno
Použití nativních komponent operačního systému, zajišťující Look&Feel odpovídající
danému OS a rychlejší vykreslování, dle mého názoru daleko převáží všechny nevýhody
SWT, které jsou navíc nevýhodami především pro vývojáře a ne pro cílového uživatele.
3.1.3 MigLayout
MigLayout je open source Java Layout Manager pro Swing i SWT, který je volně ke
stažení na stránce www.miglayout.com. Jeho tvůrce se snažil o vytvoření Layout Manageru,
který dokáže nahradit všechny standardní Java Layout Managery (FillLayout, GridLayout
atd.) a přitom si zachová jednoduchost a přehlednost.
MigLayout je šířen pod BSD [28] nebo GNU GPL [20] licencí (autor dává uživatelům na
vybranou) a pravděpodobně bude přidán do Javy SE (má nejvíce hlasů mezi požadavky na
změny v Javě na http://bugs.sun.com).
Existuje pro něj i plugin do IDE NetBeans, umožňující tvorbu GUI ve vizuálním editoru,
systémem Drag&Drop, při vývoje aplikace jsem se ale rozhodl dát přednost manuálnímu
programování MigLayoutu.
22
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
3.1.3.1
Rychlost MigLayoutu s SWT
V benchmarcích (např. [10] nebo již zmiňovaná přednáška o SWT a MigLayoutu [22])
vycházejí rychlejší aplikace za použití MigLayoutu v kombinaci s knihovnou Swing, rozdíly
nejsou ale příliš výrazné (kolem 10%) a velmi závisí na použitém Look&Feel ve Swingu. Při
použití SWT s MigLayoutem aplikace navíc rychleji startuje (v benchmarku [10] trvá start
203 ms versus 360 až 390 ms pro Swing+MigLayout).
Při testování demo aplikace psané pomocí SWT a MigLayoutu (k dispozici
na miglayout.com) mi odezva přišla subjektivně velice dobrá, srovnatelná s odezvou oken
operačního systému.
3.1.3.2
Použití MigLayoutu
MigLayout nabízí mnoho způsobů nastavení layoutu pomocí mnoha různých parametrů.
Jednotlivé parametry se v SWT zadávají pomocí konstrukce
w i d g e t . setLayoutData ( S t r i n g [ z ř e t ě z e n é _ p a r a m e t r y ] ) ;
Jistou nevýhodou je, že díky zadávání parametrů a jejich hodnot ve Stringu MigLayout neumožňuje typovou kontrolu, programátor je upozorněn na syntaktickou chybu až při překladu.
Přehled všech parametrů MigLayoutu je k dispozici na jeho domovské stránce.
Obecně layout umožňuje jednoduše definovat pozici komponent relativní i absolutní, jejich zarovnání i zarovnání jejich vnitřku, odsazení, mezery mezi řádky i sloupci, způsob
vyplňování volného místa, minimální, preferovanou a maximální velikost komponenty atd.
K zajímavým parametrům layoutu patří např.:
• debug: Tento parametr způsobí vykreslení čárkovaného rámečku okolo všech komponent. Lze tak snadno zkontrolovat jejich rozložení a zjistit, která komponenta narušuje
zamýšlené rozložení.
• sizegroup [group_name]: Komponenty se stejnou sizegroup budou mít stejnou velikost (velikost největšího z nich).
• hidemode: Lze nastavit chování skryté komponenty (widget.setVisible(false);):
– hidemode 0: S neviditelnou komponentou je zacházeno stejně jako s viditelnou
(zabírá místo)
– hidemode 1: Velikost komponenty je nastavena na 0 × 0.
– hidemode 2: Velikost komponenty je nastavena na 0 × 0 a mezery kolem ní
(margin) také na 0.
– hidemode 3: Komponenta se neúčastní layoutu, není brána v úvahu.
23
3.1. POUŽITÉ TECHNOLOGIE
3.1.4 Jsoup
Vzhledem k tomu, že základem činnosti všech zamýšlených pluginů bude pravděpodobně
syntaktická analýza webových stránek a extrahování informací na nich uvedených, bylo
důležité vybrat vhodnou technologii usnadňující tuto činnost.
Jsoup (http://jsoup.org/)) je Java HTML parser, poskytovaný pod MIT licencí [23],
který umožňuje:
• Načíst HTML stránku z URL, Stringu nebo souboru
• Procházet a extrahovat data pomocí HTML DOM (A.2) nebo za použití CSS selektorů
• Odesílat a přijímat HTML requesty, nastavovat jejich parametry (hlavičky, cookies,
data,...)
• a další (viz http://jsoup.org/).
Jsoup umožňuje nejen jednoduché a rychlé extrahování hledaných dat z HTML dokumentu, ale díky možnosti odesílat HTML requesty a libovolně nastavovat jejich parametry
také dokáže věrně simulovat webový prohlížeč, včetně odesílání GET či POST requestů
apod.
3.1.5 Eclipse JFace Data Binding
Aplikace obsahuje množství formulářů s možnostmi nastavení a další formuláře lze očekávat pro předvolby pluginů. Je proto vhodné použít knihovnu usnadňující provázání hodnot
navolených ve formuláři s objekty, které daný formulář reprezentují.
Pro knihovnu Swing existuje JGoodies binding [5], snažil jsem se proto najít alternativu
pro SWT. Jednou ze zvažovaných možností byla knihovna SWT Binding od Mathiase
Mullera [29].
SWT Binding je uvolněn pod BSD licencí [28] a je založen na zmiňovaném JGoodies
binding, které portuje pro SWT. Nejnovější verze (0.2) je ovšem z roku 2009 a je nekompletní
(umí obsluhovat jen některé widgets). Nekompletní je také dokumentace.
Existuje sice oficiální javadoc dokumentace, většina funkcí ale komentář postrádá. Rozhodl
jsem se proto pro použití JFace Data Binding.
JFace Data Binding je součástí vývojového prostředí Eclipse. Pro vývoj aplikace jsem
používal prostředí NetBeans, bylo proto nutné importovat potřebné knihovny.
Framework umožňuje pomocí jednoduchých konstrukcí provázat GUI komponenty s Java
bean, respektive s jakýmkoli objektem, který má pro parametr provázaný s komponentou
getter a setter. Není tak nutné přidávat pro každou komponenty ve formuláři selection nebo
modification listenery ani ji ručně aktualizovat při změně hodnoty příslušného fieldu, o vše
se postará JFace Data Binding.
24
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
3.2
Analytický model
V této kapitole je rozebrán analytický model aplikace. Popisuji zde jednotlivé třídy a
jejich vzájemné vztahy.
3.2.1 Základní struktura aplikace
Struktura základní části aplikace je zobrazena na obrázku 3.1.
Obrázek 3.1: Základní struktura aplikace
MainClass je statická třída (obsahuje pouze statické metody a fieldy – diskuzi o použití
statických vs. dynamických tříd jsem provedl v kapitole 3.2.6) obsahující metodu main ().
Dále obsahuje proměnné s informacemi o programu – např. verze programu, autor apod.
Tyto informace jsou tak jednoduše přístupné z kterékoli části aplikace.
BaseAppGui je třída, instanciovaná třídou MainClass, která vytvoří a otevře GUI aplikace. Stará se tedy o inicializaci všech potřebných komponent, včetně jednotlivých pluginů
– k tomu jí slouží třída PluginLoader.
PluginLoader má na starosti načítání jednotlivých pluginů i jejich ukončování (implementuje případ užití „Ukládat při ukončení“).
25
3.2. ANALYTICKÝ MODEL
MyMenu je abstraktní třída, která je nadtřídou všech položek v hlavním menu aplikace.
Obsahuje společné metody pro položky menu.
MyFileMenu reprezentuje menu „Soubor“.
MySettingsMenu reprezentuje menu „Nastavení“ a implementuje tak případy užití z kapitoly 2.3.2.3.
MyHelpMenu reprezentuje menu „Nápověda“ a případy užití z kapitoly 2.3.2.5.
Podrobnější zobrazení návrhu menu aplikace je v kapitole 3.2.2.
3.2.2 Menu aplikace
Obrázek 3.2: Menu aplikace
26
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
Na obrázku 3.2 je menu aplikace 1 .
Třídy, které jsou inicializovány v objektech MySettingsMenu a MyHelpMenu reprezentují
jednotlivé případy užití:
• MyMenu_Save ... případ užití „Ukládat při ukončení“
• MyMenu_Startup ... „Spouštět při startu“
• MyMenu_Minimize ... „Nastavit minimalizaci do oznamovací oblasi“
• Preferences ... „Zobrazit Možnosti“ a všechny související případy užití z kapitoly 2.3.2.4
• UpdateChecker ... „Zkontrolovat aktualizace“
• About ... „Zobrazit info o programu“
• About_license ... „Zobrazit licenční ujednání“
3.2.3 Správa pluginů
Obrázek 3.3: Správa pluginů
Jak je vidět na obrázku 3.3, třída PluginLoader obsahuje 0...* referencí na interface
PluginInterface, který implementují všechny pluginy. PluginLoader obsluhuje pluginy (může
1
Dvojtečka před jménem třídy značí, že se jedná o instanci dané třídy
27
3.2. ANALYTICKÝ MODEL
je inicializovat, zobrazit, uložit atd.) přes PluginInterface, nezáleží proto, o jaký konkrétní
plugin se jedná.
Abstraktní třída Plugin obsahuje společné metody pluginů, aby nedocházelo ke zbytečným
duplicitám kódu v jednotlivých pluginech.
3.2.4 Menu pluginů
Obrázek 3.4: Menu pluginů
Menu pluginů představuje zároveň jakousi záložku, přes kterou uživatel vybere daný
plugin (viz návrh GUI aplikace na obrázku 3.6). Menu tedy může mít 2 stavy – menu
aktivního pluginu (plugin je vybrán, jeho tělo je momentálně zobrazeno uživateli) a menu
neaktivního pluginu.
Pro menu byl proto použit návrhový vzor Stav. PluginLoader zavolá metodu PluginInterface.getMenu(), která vrátí příslušné menu pro aktivní, nebo neaktivní plugin.
Každý plugin má vlastní třídu pro aktivní menu, díky čemuž může být aktivní menu
libovolně uzpůsobené konkrétnímu pluginu (na obr. 3.6 je jako příklad menu pluginu SA
Notify – SAMenu).
28
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
Naopak neaktivní menu mají všechny pluginy společné a reprezentuje ho třída IdleMenu.
Tím je zajištěn jednotný vzhled lišty s menu jednotlivých pluginů.
Dále jsem navrhl dvě abstraktní třídy, PluginMenu a PluginActiveMenu, které obsahují
metody společné pro všechny druhy menu (PluginMenu) a metody společné pro menu aktivního pluginu (PluginActiveMenu).
3.2.5 Univerzální třídy
Obrázek 3.5: Univerzální třídy
Na obrázku 3.5 jsou třídy, které mohou být instanciovány v kterékoli části aplikace nebo
se jedná o třídy statické. V obou případech jsou to třídy poskytující nějakou univerzální
funkci, která je potřeba v různých částech aplikace.
ImageHandler je statická třída, určená k načítání všech obrázků. Vzhledem k nutnosti
ručního disposingu (viz 3.1.2.2 – odstranění objektu a uvolnění jeho systémových prostředků)
obrázků jsem se rozhodl pro umístění všech objektů typu Image do této třídy. Tím je zajištěna snadnější správa všech obrázků a sníženo nebezpečí, že některé obrázky nebudou
disposovány. Při zavírání aplikace je zavolána metoda ImageHandler.dispose(), která zajistí
disposing všech obrázků.
ImageHandler má veřejné (public) metody pro načtení obrázku ze složky zadané
v parametru metody. Jednotlivé pluginy tak mohou mít vlastní obrázky ve své složce a
vlastní třídu pro načítání obrázků, dědící od třídy ImageHandler a využívající její public
metody.
ErrorHandler je metoda pro zobrazování chyb aplikace uživateli. Obsahuje statický objekt
Messenger messenger, inicializovaný při spouštění aplikace, který zajišťuje zobrazení chyb v
dialogovém okně. Objekt messenger je public, pluginy tedy opět mohou dědit od této třídy
a využívat její, již inicializovaný, Messenger.
29
3.2. ANALYTICKÝ MODEL
CommentedProperties Aplikace potřebuje při ukončení ukládat mnoho proměnných.
K tomu je vhodná třída Properties, poskytující jednoduché API pro načtení konfiguračního
souboru a získávání hodnot z tohoto souboru.
Nevýhodou třídy Properties, která je součástí Javy SE, je mazání komentářů: načteme-li
obsah souboru, který kromě hodnot obsahuje i komentáře nebo prázdné řádky, do objektu
Properties, ten upravíme a opět uložíme, původní soubor je přepsán a přijdeme o uložené
komentáře a formátování konfiguračního souboru.
Použil jsem proto upravenou verzi CommentedProperties extends Properties z diskuzního
fóra www.dreamincode.net, kde ji uživatel waltf zveřejnil k volnému použití. Tato třída zachovává komentáře i volné řádky v konfiguračním souboru.
Rozdíly CommentedProperties oproti Properties:
• metoda setProperty(String key, String value) funguje jen pokud už CommentedProperties daný klíč obsahuje, jinak neudělá nic (Properties.setProperty() v takovém
případě klíč vytvoří).
• CommentedProperties mají proto metodu add(String key, String value), která
vloží na konec souboru novou položku. Nekontroluje přitom, zda už se použitý klíč
v properties nachází. Upravil jsem proto tuto metodu tak aby zkontrolovala, zda se
zadaný klíč v properties již nachází a následně ho buď vytvořila, nebo pouze změnila
jeho hodnotu zavoláním metody setProperty().
• CommentedProperties mají metody addLine(String line), která na konec souboru
přidá komentář. Při vytváření nového klíče je tak možné před něj programově přidat
i komentář.
MenuListeners obsahuje množství metod s návratovou hodnotou Listener, které vrací
Listenery opakovaně používané zejména v menu aplikace. Jsou to například Listenery zajišťující zobrazení, nebo skrytí textu ve stavovém řádku (za tímto účelem má MenuListeners
statický field Label statusBar, inicializovaný při startu aplikace) nebo Listenery zajišťující
otevření URL adresy ve webovém prohlížeči.
Messenger zajišťuje zobrazování zpráv uživateli a to jak chybových, tak informačních.
Vytvoří nový Shell dialog se zprávou a ten zobrazí uprostřed okna aplikace.
Buttons je třída usnadňující tvorbu tlačítek (SWT Button). U většiny vytvářených tlačítek
jsou nastavovány vždy ty samé parametry, třída Buttons proto obsahuje univerzální metody
pro vytvoření tlačítka a nastavení nejobvyklejších parametrů, jako jsou Text, ToolTipText,
StatusBarText ad.
Sounds obsahuje metody pro přehrávání zvuků a také hodnoty z CommentedProperties
pro nastavení zvuků (jaké zvuky a kdy se mají přehrávat). Její instance je předávána jednotlivým pluginům, plugin tedy v případě potřeby může použít vlastní třídu a přehrávat
vlastní zvuky.
30
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
Výchozí nastavení zvuků, včetně cest k přehrávaným zvukům, je načteno z CommentedProperties v konstruktoru této třídy. Pro případ, že v CommentedProperties požadované
položky nejsou, jsou nastaveny výchozí hodnoty.
Commons je statická třída obsahující univerzální metody, které není vhodné zařadit do
žádné z předchozích tříd. Její součástí jsou metody
• int getIntegerProperty()
• boolean getBoolProperty()
• String getStringProperty(),
které mají shodné parametry CommentedProperties properties, String key, String defaultValue. Všechny tři vracejí hodnotu z CommentedProperties, parsovanou do návratového
typu metody. V případě, že properties hledaný parametr neobsahují, nebo dojde k chybě
parsování (např. položka, která má obsahovat číslo, obsahuje text) vrátí defaultValue a tuto
hodnotu také uloží do properties.
3.2.6 Statické vs. Dynamické třídy
Pozn.: Java nezná statické třídy, tímto pojmem označuji třídy, které mají statické všechny
fieldy i metody.
Obecně není doporučováno nadměrné použití statických metod či fieldů ([9], [7]). Například budou-li všechna konfigurační data aplikace v podobě statických fieldů v jedné třídě,
není možné spouštět aplikaci nebo části aplikace simultánně v různých konfiguracích.
Naopak použití centrálních, statických fieldů velmi zjednodušuje jejich úpravu, přístup
k nim apod. U atributů typu název aplikace lze přitom snadno předpokládat, že si i do
budoucna vystačíme s jediným statickým fieldem.
Všechny univerzální třídy uvedené v předchozí kapitole by teoreticky mohly být dynamické i statické. Snažil jsem se proto u každé z nich zvážit konkrétní situaci a způsob použití
a zvolit výhodnější možnost. Pokud jsem nenašel konkrétní důvody pro statičnost třídy nebo
jejích fieldů, navrhl jsem je jako dynamické.
Třídy ErrorHandler, Buttons nebo MenuListeners jsou dynamické. ErrorHandler má ale statický field Messenger messenger. Messenger pro inicializaci potřebuje jako
parametr Display a Shell, ErrorHandler může být ale volán z libovolného místa aplikace, kde
Shell ani Display nemusí být k dispozici. Jednoduchým a účelným řešením je tedy deklarovat
field Messenger jako statický a inicializovat ho při startu aplikace.
MenuListeners původně měly po vzoru SWT Snippet 152 některé Listenery jako statické fieldy:
p u b l i c s t a t i c L i s t e n e r s h o w L i s t e n e r = new L i s t e n e r ( ) {
@Override
p u b l i c v o i d handleEvent ( Event e v e n t ) {
. . . .
}};
31
3.3. NÁVRH GRAFICKÉHO ROZHRANÍ APLIKACE
V takovém případě by se ale zbytečně všechny tyto Listenery inicializovaly při vytvoření
každé instance MenuListener (i těch, které potřebují jiný Listener, tzn. např. tento field
Listener showListener vůbec nepoužijí). Raději jsem proto pro každý Listener vytvořil dynamickou metodu s návratovou hodnotou Listener.
Třída ImageHandler je z dříve uvedených důvodů statická (snadnější správa obrázků).
CommentedProperties jsou předávány objektům jako parametr. Zde by mohlo dojít
k výše popsané situaci, kdy budeme chtít určité části programu předat pozměněná konfigurační data, je tedy bezpečnější předávat je jako parametr – instanci třídy CommentedProperties.
Label statusBar, reprezentující stavový řádek aplikace, je statický. Nepředpokládám
potřebu více různých stavových řádků a vzhledem k tomu, že ke stavovému řádku potřebuje
přístup mnoho různých tříd, statický Label výrazně usnadňuje programování.
Konfigurace Tichého režimu, včetně booleanu isQM, který udává, zda je Tichý režim
zapnutý, je z podobných důvodů jako statusBar statická. Zde je dokonce žádoucí, aby
část aplikace nemohla použít jiné nastavení – zapne-li uživatel Tichý režim, pravděpodobně
nebude chtít, aby např. některý plugin měl vlastní nastavení Tichého režimu a globální
nastavení ignoroval.
3.3
Návrh grafického rozhraní aplikace
Na obrázku 3.6 je návrh GUI rodičovské aplikace a pluginu SA Notify2 , v této kapitole se zabývám pouze GUI rodičovské aplikace, které je tvořeno systémovým menu, menu
s výběrem pluginů (dále jako menu pluginů nebo plugin menu) a stavovým řádkem (ten na
obrázku není).
Při návrhu jsem se snažil ponechat maximum místa pro tělo pluginu, zároveň ale udělat
plugin menu dostatečně výrazné a velké, aby si ho uživatel ihned všiml.
Jednotlivé položky v plugin menu mají různé barvy a jejich barva je zároveň použita
jako podkladová pro tělo konkrétního pluginu (plugin body). Díky tomu si uživatel může
asociovat barvy s jednotlivými pluginy a i při letmém pohledu na otevřenou aplikaci ihned
pozná, který plugin je právě zvolen.
To může být důležité zejména v případě vzniku většího množství pluginů, které budou
mít podobné funkce (např. rezervaci autobusových spojů, kdy každý plugin bude umět
rezervaci jiného dopravce) a budou mít tedy velice podobné rozložení prvků v plugin body.
Na obrázku 3.7 je Splash Screen aplikace – obrázek, který se zobrazí ihned po startu
aplikace a je zavřen po načtení celé aplikace. Slouží tedy jako ukazatel pro uživatele, že
aplikace byla spuštěna a probíhá její načítání.
2
Návrh je určen především ke znázornění rozložení jednotlivých komponent. Jejich skutečná podoba (zejména rámečky, barva apod.) je závislá na platformně, na které je aplikace spuštěna.
32
KAPITOLA 3. ANALÝZA A NÁVRH ŘEŠENÍ
Obrázek 3.6: Návrh grafického rozhraní
Obrázek 3.7: Splash Screen
33
3.3. NÁVRH GRAFICKÉHO ROZHRANÍ APLIKACE
34
KAPITOLA 4. IMPLEMENTACE
Kapitola 4
Implementace
Vývoj aplikace probíhal v IDE NetBeans 7.1 na OS Windows 7. Zároveň jsem prováděl
kontrolu správného zobrazení i chování aplikace na OS Windows XP a Ubuntu (GUI GNOME).
Zjištěné rozdíly uvádím v kapitole 6.3.
4.1
Univerzální třídy
4.1.1 ImageHandler
Obrázků jsou řádově desítky, ImageHandler proto používá Just In Time (JIT) inicializaci: Každý obrázek je uložen jako private field a má svůj getter a setter. V getteru je
zkontrolováno, zda byl obrázek inicializován a pokud ne, je zavolán příslušný setter.
ImageHandler odchytí výjimky způsobené špatným formátem souboru, nebo neplatným
názvem souboru. V takovém případě vrátí getter pro požadovaný obrázek hodnotu null.
Dále v aplikaci je proto nutné ošetřit používání obrázku, který nesmí být null. Jedná se
například o metodu shell.setImages(Image [ ]), která nastaví ikonu v záhlaví okna1 . Při
každém nastavování ikon Shellu je tedy nutné tuto metodu obklopit konstrukcí
try { . . .
}
catch ( IllegalArgumentException e ) {
. . .
}
Animované GIF SWT neumí jednoduše zobrazit animovaný GIF soubor. Použili jsem
proto třídu AnimatedGif, založenou na SWT Snippet 141, která spustí nové vlákno, starající
se o animaci obrázku.
Vlákno se ukončí, pokud zjistí, že Shell, pro který byl obrázek určen, byl ukončen
(isDisposed() ). Zároveň je nastaveno jako daemon, takže se ihned ukončí v případě ukončení
celé aplikace.
1
V závislosti na platformě je nastavený obrázek používán nejen v záhlaví okna, ale také na systémové
liště nebo při procházení otevřených oken pomoci Alt+Tab (OS Windows). Lze proto nastavit více obrázků
různých velikostí a SWT knihovna použije v konkrétních případech nejvhodnější velikost. Pro aplikaci jsem
použil 2 ikony o velikosti 16 × 16 a 32 × 32 pixelů
35
4.1. UNIVERZÁLNÍ TŘÍDY
Metoda getImage(String fileName) Většina obrázků je ve třídě ImageHandler uložena
jako samostatný field, který má svůj getter a setter. Někdy je ale potřeba načítat nové
obrázky dynamicky za běhu programu. (např. výběr jazyka, viz 4.2.5.3).
K tomu slouží metoda getImage(String fileName), která vrátí obrázek načtený ze zadaného
souboru, který zároveň uloží do ArrayListu imagesToDispose. Při ukončení aplikace jsou
všechny obrázky z tohoto listu automaticky disposovány.
ImageCodeGen Vytvořil jsem také jednoduchou třídu ImageCodeGen, generující kód
pro ImageHandler. Kód nutný vytvořit pro každý obrázek je obdobný, mění se v zásadě
pouze jméno proměnné a soubor s obrázkem, obrázků je přitom mnoho, je tedy výhodné
použít generátor kódu.
Velikost obrázků Snažil jsem se, aby všechny použité obrázky i ikony zabíraly co nejméně
diskového prostoru. Většina obrázků je proto ve formátu GIF. Při vytváření GIF formátu
jsem zároveň volil nejmenší počet barev, při kterém se subjektivně ještě nesnížila kvalita
obrázku.
4.1.2 Messenger
Existuje jen jedna instance třídy Messenger, která je předávána třídám jako parametr.
Díky tomu v případě, že uživatel změní nastavení vyskakovacích zpráv (případ užití „Zvuky
a upozornění“), je tato změna promítnuta do instance třídy Messenger a změny se ihned
projeví ve všech nových vyskakovacích zprávách.
Messenger zobrazuje 4 základní druhy zpráv:
• message_info – informační zpráva
• message_warning – zpráva obsahující varování
• message_error – zpráva o chybě
• message_waiting – zpráva o probíhající akci, na jejíž dokončení aplikace čeká (např.
pokus o aktualizaci)
Díky tomuto dělení zpráv je možné budoucí rozšíření např. o přehrávání různých zvuků
podle typu zprávy, pro zvýraznění jejího typu (Varování, Chyba ad.).
Metoda message_waiting bývá volána z jiného vlákna, proto na začátku kontroluje,
zda Shell aplikace nebyl mezitím zavřen (tento postup je doporučen v dokumentaci SWT).
Všechny metody pro zobrazování zpráv mají parametr boolean successMessage, udávající, zda se jedná o zprávu o úspěchu hledání některého pluginu. Pokud je successMessage
true, je přehrán zvuk nastavený pro úspěšné hledání (metoda Sound.playSuccessSound() ).
Ikony
Ikony zobrazované u zpráv jsou pro věrnější přizpůsobení vzhledu platformě nastavovány
pomocí SWT konstant (např. display.getSystemImage(SWT.ICON_ERROR), viz kapitola
3.1.2.1).
36
KAPITOLA 4. IMPLEMENTACE
ICON_CANCEL
ne
ICON_ERROR
ano
ICON_INFORMATION
ano
ICON_QUESTION
ano
ICON_SEARCH
ne
ICON_WARNING
ano
ICON_WORKING
ano
Tabulka 4.1: SWT ikony k dispozici na OS Windows 7
Některé ikony definované pomocí SWT.ICON ovšem na některých platformách nejsou
k dispozici (tabulka 4.1 zobrazuje ikony, které jsou k dispozici na OS Windows 7). V takovém
případě je použita odpovídající vlastní ikona, inicializovaná ve třídě ImageHandler.
4.1.3 Sounds
Třída Sounds obsahuje metody pro přehrávání zvuku i pro ukončení přehrávání. Přednastavené zvuky jsou dostatečně krátké aby nebylo nutné jejich přehrávání zastavovat. Uživatel si ale může navolit i vlastní libovolně dlouhé zvuky, jejichž přehrávání musí být možné
programově zastavit. Stejně tak budoucí pluginy mohou vyžadovat funkci zastavení přehrávaného zvuku.
Licence použitých zvuků
Některé použité zvuky jsou ze stránek www.freesound.org od autorů Robinhood76 a
ivanbailey, kteří je zveřejnili pod licencemi CC Attribution 3.0 Unported [16] a AttributionNonCommercial 3.0 Unported [17].
Další zvuky jsou z kolekce Designer Sound FX od firmy Final Image Inc. (webové stránky
videocopilot.net), zakoupené pod licencí Royalty free.
4.1.4 UpdateChecker a UpdateInterface
Třída UpdateChecker spustí vlákno (daemon), které ověří dostupnost nové verze programu.
Implementuje interface UpdateInterface:
UpdateInterface je jednoduchý interface, obsahující metodu setCanceled(). Metoda Messenger.message_waiting() má jako jeden z parametrů tento interface. Tato metoda zobrazí
dialog obsahující zprávu (další z parametrů) a tlačítko Zrušit. Při jeho stisku je dialog ihned
zavřen a je zavolána metoda UpdateInterface.setCanceled(), která nastaví vláknu příznak
značící, že uživatel operaci přerušil.
37
4.2. MENU APLIKACE
Třída UpdateChecker pak pravidelně kontroluje, zda nebyla operace přerušena a případně zastaví svou činnost.
Interface UpdateInterface a metodu Messenger.message_waiting() tak mohou využívat i pluginy, pokud chtějí uživateli oznámit informaci o probíhající akci s možností jejího
přerušení.
Protože UpdateChecker spouští kontrolu nové verze v samostatném vlákně, Messenger,
který zobrazí výsledek kontroly, musí být volán přes dříve zmíněnou konstrukci
D i s p l a y . g e t D e f a u l t ( ) . asyncExec ( new Runnable ( ) { . . . } ) ;
Pro přístup na server při samotné kontrole nové verze je použit objekt URLConnection,
který na rozdíl od jednoduššího URL umí nastavit ConnectTimeout (timeout pokusu o
připojení) a ReadTimeout (timeout čtení z URL).
4.1.5 CommentedProperties a Commons
Veškeré přístupy k objektům CommentedProperties (konfigurační soubory aplikace) jsou
prováděny přes metody ve třídě Commons, popsané v kapitole 3.2.5, které mají jako jeden
ze vstupních parametrů výchozí hodnotu hledaného klíče.
Díky tomu nedojde k chybě, pokud hledaný klíč v CommentedProperties není.
V případě, že uživatel nechtěně změní konfiguraci programu a bude se chtít vrátit k výchozí konfiguraci, postačí smazat konfigurační soubor. Aplikace pak při dalším spuštění
použije výchozí hodnoty nastavení a při ukončení vytvoří nový konfigurační soubor.
4.2
Menu aplikace
4.2.1 Mnemonic
Všechny položky menu všech úrovní používají tzv. Mnemonic – klávesové zkratky, definované ampersandem(&) před písmenem v textu položky. Například na OS Windows lze
položku menu vybrat zkratkou Alt+Mnemonic. Klávesové zkratky pro jednotlivé položky
jsem vybíral podobné těm používaným v OS Windows (např. položku Nápověda – Zobrazit
nápovědu lze stejně jako v programech MS Office vybrat zkratkou Alt+V, N).
U podmenu Nápověda k pluginům, jehož položky jsou generovány při načítání pluginů,
jsou Mnemonic přiřazeny automaticky – program přiřadí první písmeno názvu položky, které
dosud nebylo použito (vynechává mezery).
Nápověda pro konkrétní plugin tedy nebude mít přiřazený Mnemonic jen pokud by už
všechna písmena z jeho názvu byla použita. Výměnou za toto malé riziko nemusí programátor nového pluginu položky v menu vytvářet ručně.
4.2.2 Akcelerátory
Některé položky menu používají tzv. akcelerátory – klávesové zkratky, které na rozdíl od
Mnemonics okamžitě vyberou příslušnou položku v menu (uživatel nemusí nejprve zadávat
zkratku pro menu vyšší úrovně). Na většině platforem je tato zkratka zobrazena vedle názvu
položky, se zarovnáním vpravo.
38
KAPITOLA 4. IMPLEMENTACE
Obrázek 4.1: Menu Nápověda s Mnemonics zvýrazněnými podtržítkem a akcelerátorem F1
pro zobrazení nápovědy
4.2.3 Menu Soubor
Položka menu Soubor obsahuje pouze volbu Zavřít a to pod všemi platformami mimo
MacOS X (SWT používá krycí jméno „cocoa“). Na této platformě není položka Soubor –
Zavřít obvyklá.
Na OS Windows je k položce Zavřít přiřazen i obvyklý akcelerátor Alt+F4.
4.2.4 Menu Nastavení
4.2.4.1
Uložit při ukončení
Při výběru této položky objekt MyMenu_Save změní v menu příslušnou ikonu a nastaví
v CommentedProperties hodnotu saveOnExit. Je-li tato hodnota nastavena na true, při
ukončení aplikace je zavolána metoda PluginInterface.save() všech načtených pluginů a při
opětovném spuštění metoda PluginInterface.load() (podrobnosti viz kapitola 4.4.4.1).
4.2.4.2
Spouštět po startu systému
Tato položka je platná pouze na OS Windows. Na jiných platformách v menu tato volba
zůstane, ale je nastavena jako disabled, uživatel ji tedy nemůže zvolit. Za název položky je
v takovém případě přidán dodatek „Pouze OS Windows“.
Další možností by bylo položku pod jinými OS vůbec nezobrazovat, domnívám se ale,
že tento postup je lepší pro uživatele. Zamezí jeho zmatení pokud by program spouštěl na
dvou různých platformách a na každé viděl jiný obsah menu.
Spouštění po startu je zajištěno přidáním zástupce do složky Po spuštění.
Pro přidání zástupce jsem zamýšlel použít knihovnu java.nio.file, uvedenou v Javě 1.7. Při
jejím použití ale nelze zapisovat do systémových adresářů, včetně složky Po spuštění (pokus
vyvolá výjimku AccessDeniedException). Použil jsem proto externí knihovnu JShortcut.
JShortcut (domovská stránka http://alumnus.caltech.edu/ jimmc/jshortcut/) je
šířen pod licencí GNU LGPL [21] a umožňuje jednoduše vytvořit zástupce na OS Windows.
39
4.2. MENU APLIKACE
Jeho nevýhodou je potřeba správné verze knihovny jshortcut.dll podle architektury,
na které je spuštěna (jsou celkem 3 verze jshortcut.dll: x86, x86_64 a amd64).
K dispozici je verze shortcut-0.4-oberzalek, která sama vybere správnou verzi .dll
knihovny. Tato verze ale při každém spuštění opětovně extrahuje .dll soubor spuštěním
C++ kódu, který správnou verzi pod dočasným názvem uloží do adresáře Temp systému
Windows, kde pak dochází k jejich kupení.
Upravil jsem proto soubor JShellLink knihovny JShortcut tak, aby při načítání .dll
knihovny po spuštění aplikace zkontroloval architekturu a načetl správný soubor ze souborů
jshortcut_x86.dll, jshortcut_ia64.dll a jshortcut_amd64.dll, které jsou pod těmito jmény
distribuovány spolu s aplikací.
4.2.4.3
Minimalizovat do oznamovací oblasti
Obrázek 4.2: Menu nad ikonou v oznamovací oblasti OS Windows
Tato položka menu je povolena pouze pokud platforma podporuje tzn. System tray
(Display.getSystemTray()) – tedy např. OS Windows, Ubuntu GNOME. V opačném případě
položku nelze vybrat a k textu je přidán dodatek „Není k dispozici na této platformě“.
Tuto položku obsluhuje třída MyMenu_Minimize. Ta se stará o změnu chování při minimalizaci, o vytvoření ikony v systémové oblasti a jednoduchého kontextového menu zobrazovaného nad touto ikonou (obr. 4.2).
Při prvním vybrání položky je vytvořen objekt TrayItem, který reprezentuje ikonu
v oznamovací oblasti a ten je při dalším přepínání položky již jen skrýván a zase zobrazován (zároveň je přidáván / odebírán Listener pro skrytí Shellu aplikace z hlavní systémové
lišty při minimalizaci).
Kontextové menu zobrazované nad ikonou v oznamovací oblasti má tyto položky:
• Zobrazit SA Notify – otevře okno aplikace
• Tichý režim – zapne, nebo vypne Tichý režim
• Skrývat při minimalizaci – je-li skryté (minimalizované), zobrazí okno aplikace a
schová ikonu v oznamovací oblasti
• Ukončit – ukončí aplikaci
40
KAPITOLA 4. IMPLEMENTACE
Při implementaci tohoto menu jsem narazil na chybu SWT: Celé menu je považováno
za součást objektu TrayItem. Pokud má TrayItem přiřazený Listener pro kliknutí myší,
který zobrazí menu, tak při kliknutí do libovolné části tohoto menu je opět zavolán Listener
pro TrayItem a dojde k jeho opětovnému vykreslení menu na novém místě (vykresluje se
vždy nad aktuální polohou kursoru myši). V metodě handleEvent(Event event) přiřazeného
Listeneru je proto nutné provést kontrolu, zda menu již není zobrazené.
4.2.5 Menu Nastavení – Možnosti
Obrázek 4.3: Dialog Možnosti, záložka Obecné
Vybrání položky Možnosti zobrazí dialog se všemi možnostmi nastavení aplikace.
Pro položku je použit akcelerátor SWT.MOD1+P. SWT nahradí konstantu SWT.MOD1
kódem tlačítka platformy (na OS Windows Ctrl, na MacOS tlačítko Command Key). Text
akcelerátoru je „CTRL+P“. Dle [26]2 SWT automaticky přetíží text akcelerátoru a např. na
MacOS ho nahradí textem „Command + P“.
Jednotlivé položky nastavení jsou seřazeny tématicky do záložek dialogu Možnosti.
Při rozmýšlení pořadí záložek i pořadí položek v záložkách jsem se snažil o seřazení podle
důležitosti – tak, aby položky, které by uživatel mohl nejspíše chtít změnit, byly co nejvýše.
Položky jsou navíc v rámci záložek řazeny do Group (SWT objekt, který způsobí ohraničení
svých potomků rámečkem).
Na obrázku 4.3 jsou na vybrané kartě Obecné 3 Groupy: Aplikace, Jazyk a Vytvořit
zástupce.
2
Kapitola 2.4: Accelerators
41
4.2. MENU APLIKACE
Při vytváření jednotlivých záložek jsem narazil na SWT bug 16438: Všechny obrázky
v záhlaví záložek mají velikost nastavenou na velikost prvního obrázku. Je proto nutné
používat pro všechny záložky stejně velké obrázky.
4.2.5.1
Preferences.java
Dialog Možnosti je reprezentován třídou Preferences.java. V ní probíhá inicializace dialogu i ukládání navolených hodnot do CommentedProperties.
Této třídě jsou proto předány objekty MyMenu_Safe, MyMenu_Startup
a MyMenu_Minimize – obsahují aktuální hodnoty příslušných nastavení (viz 4.2.4) a také
umožňují okamžité promítnutí změn, které uživatel provede.
4.2.5.2
Tlačítko Uložit
Tlačítko Uložit je při otevření dialogu Možnosti nastaveno jako disabled. Je povoleno
až ve chvíli, kdy uživatel provede změnu nastavení.
Tlačítko je také nastaveno jako enabled, pokud uživatel zvolí vytvořit zástupce na záložce
Obecné. To je teoreticky zbytečné, k vytvoření zástupce dojde ihned po stisknutí tlačítka.
V opačném případě by se ale uživatel mohl domnívat, že k vytvoření zástupce nedošlo
(nic se nezměnilo, protože tlačítko Uložit je stále nefunkční).
4.2.5.3
Záložka Obecné
Na tuto záložku jsem umístil i položky, které lze volit přímo z menu Nastavení. Tento
přístup používají i jiné aplikace a považuji ho za přehlednější pro uživatele, který všechna
nastavení najde na jednom místě. Do hlavního menu jsou pak pro urychlení umístěny pouze
některé často používané volby.
Výběr jazyka SWT widget Combo může obsahovat pouze text. Použil jsem proto třídu
ImageCombo ze serveru www.richclient2.de, poskytovanou pod licencí Eclipse Public License (respektive její vylepšenou verzi ze stránek dev.eclipse.org, zveřejněnou pod stejnou
licencí).
Druhá verze umožňuje zobrazení obrázku i u právě vybrané položky (viz obr. 4.3), zatímco první jen u položek v seznamu, který se rozbalí kliknutím na Combo.
Obě verze používají knihovny org.eclipse.ui.forms a org.eclipse.jface, bylo proto nutné importovat je do IDE NetBeans, ve kterém probíhal vývoj aplikace. Z knihovny org.eclipse.jface
je ale třeba jen třída org.eclipse.jface.util.Geometry.class, v rámci úspory místa (celá knihovna má 1052 kB, samotná třída 62 kB) proto s aplikací z dané knihovny distribuuji pouze
tuto třídu.
ImageCombo pro výběr jazyka je generováno ze souboru available_locales.xml
(načten pomocí knihovny Jsoup), kde jsou uloženy informace o dostupných jazykových
verzích, včetně textu, který se zobrazí v ImageCombu a jména obrázku, který se zobrazí
vedle textu.
42
KAPITOLA 4. IMPLEMENTACE
Jazykové verze Jednotlivé jazykové verze jsou uloženy v .properties souborech, které
mají v názvu příponu identifikující jazykovou verzi, kterou obsahují.
Veškeré texty zobrazované uživateli jsou nahrazeny konstrukcí
ResourceBundle . getBundle ( " Bundle " ) . g e t S t r i n g ( [ S t r i n g −key ] )
Knihovna java.util.ResourceBundle načte soubor odpovídající právě nastavenému
jazykovému prostředí (Locale) a v něm vyhledá text pro zadaný klíč.
Při prvním spuštění se aplikace pokusí nastavit jazyk odpovídající jazykovému prostředí
operačního systému. Pokud tento jazyk není k dispozici, použije výchozí nastavení (v současné
distribuci je výchozím jazykem čeština).
Obrázek 4.4: Dialog Možnosti, záložka Zvuky a upozornění
4.2.5.4
Záložka Zvuky a upozornění
Vyskakovací upozornění Je-li zaškrtnuta položka Vyskakovací upozornění, třída Messenger při zobrazení všech vyskakovacích dialogů zavolá shell.forceActive() pro přenesení
okna aplikace do popředí.
Přesné chování se liší podle platformy. Např. na OS Windows 7 program pouze začne
blikat na systémové liště – operační systém záměrně nedovoluje aplikacím přivlastňovat si
programově focus. Toto chování lze obejít např. programovým stisknutím kláves
Windows + D (zobrazí plochu) a následnou maximalizací okna, rozhodl jsem se ale respektovat standardní chování platformy.
Aplikace má navíc možnost nastavit zvuková upozornění na vyskakovací dialogy, nemělo
by tedy hrozit, že si uživatel nevšimne například upozornění na úspěšné hledání pluginu.
43
4.3. LOGOVÁNÍ CHYB APLIKACE
Zvuky Uživatel může přehrát vybrané zvuky stisknutím tlačítka Test zvuku. Listener
přiřazený tomuto tlačítku se pokusí přehrát zvukový soubor vybraný v sousedícím widgetu
Combo nebo Text.
Tlačítko má dva stavy – Přehrát a Zastavit, měnící se podle toho, zda právě probíhá
přehrávání zvuku.
Ke každému přehrávanému klipu je přidán Listener pro odchycení konce přehrávání a
nastavení tlačítka Test zvuku zpět do stavu Přehrát. Přehrávání zvuku probíhá v samostatném vlákně, změnu stavu tlačítka je proto nutné iniciovat pomocí konstrukce zmíněné
v kapitole 3.1.2.2.
Vlastní zvuk Uživatel může pomocí File dialogu vybrat vlastní zvuk – v současnosti jsou
podporovány formáty .wav a .aif.
4.2.6 Menu Nápověda
4.2.6.1
Nápověda k pluginům
Položka Nápověda k pluginům obsahuje podmenu s odkazy na online nápovědu ke
všem pluginům.
Podmenu je generováno dynamicky při načítání pluginů ve třídě PluginLoader. Každý
plugin má metody getHelpPage() a getHelpToolTip(), definované v interfacu PluginInterface,
které vrátí webovou adresu nápovědy a tooltip zobrazovaný nad položkou v menu.
4.2.6.2
O programu
Položka O programu zobrazí dialog s informacemi o aplikaci.
Na pozadí textu je vykreslen barevný přechod (gradient). Všechny texty v tomto dialogu
jsou vytvořeny pomocí widgetu StyledText, který ovšem neumožňuje nastavit transparentní
pozadí – lze nastavit pouze zděděné pozadí Shellu pomocí konstrukce
s h e l l . setBackgroundMode (SWT.INHERIT_DEFAULT ) ;
V takovém případě ale StyledText bere v úvahu pouze pozadí Shellu, definované obrázkem
nebo jednolitou barvou. Gradient na pozadí Shellu, vykreslený pomocí GC (Graphics Context), se na pozadí StyledTextu nepromítne.
Ve třídě ImageHandler.setGradientImg() je proto vytvořen nový obrázek o velikosti
Shellu dialogu, na něj je nakreslen gradient a tento obrázek je nastaven na pozadí Shellu.
Funkce pro vykreslení gradientu na obrázek byla převzata z [25].
4.3
Logování chyb aplikace
Aplikace využívá pro záznam chyb třídu java.util.logging.Logger. Nastavení je uloženo
v souboru bin/log/logging.properties a je načteno před inicializací GUI aplikace, ve třídě
MainClass.
44
KAPITOLA 4. IMPLEMENTACE
Soubor logging.properties obsahuje nastavení FileHandleru
(java.util.logging.FileHandler), který ukládá logy do souborů.
Jsou nastaveny 2 logovací soubory s maximální velikostí 100 000 bajtů. Jakmile jeden
soubor dosáhne maximální velikosti, pokračuje ukládání chyb do druhého souboru (jeho
minulý obsah je vymazán).
Díky tomu nemůže dojít ke stavu kdy by logovací soubor neobsahoval žádné záznamy
protože nedávno dosáhl maximální velikosti a byl přepsán.
Do logovacích souborů jsou uloženy všechny odchycené výjimky. Při nastavení boolean
proměnné MainClass.debug na true jsou zároveň všechny chyby vypsány do konzole.
Zachycené výjimky, které je vhodné oznámit uživateli, (např. nefunkční internetové
připojení) jsou zároveň předány tříde ErrorHandler.
Celé tělo metody MainClass.main() je v bloku try{}, následovaným catch(Exception e){}
pro zachycení všech neočekávaných chyb aplikace a jejich uložení do .log souborů.
4.4
Pluginy
Všechny pluginy jsou inicializovány ve třídě PluginLoader a uloženy do
ArrayListu <PluginInterface> plugins v této třídě. Odtud se načítají při inicializaci plugin
menu nebo menu Nápověda – Nápověda k pluginům.
PluginLoader také při načítání pluginů zkontroluje, který plugin byl vybrán při posledním zavírání aplikace a opět ho nastaví jako vybraný (hodnota je uložena v CommentedProperties, klíč lastActivePlugin).
4.4.1 Soubory pluginů
Soubory jednotlivých pluginů jsou ukládány v adresáři /plugins/<jmeno_pluginu>.
Jedná se pouze o doporučení, cesta není nikde napevno daná. Každý plugin má svou cestu
uloženou ve fieldu pluginFilesPath své nadtřídy Plugin – díky tomu může být ve třídě Plugin
implementována metoda save() (viz 4.4.4.1).
4.4.2 Plugin menu
Nejjednodušší řešení pro plugin menu by bylo použití widgetu TabFolder. Ten ale není
dostatečně variabilní – menu by například nemohlo obsahovat tlačítka.
Jednotlivé položky menu (záložky konkrétních pluginů) jsou proto tvořeny widgetem
Composite. Obsah Composite pro konkrétní plugin je z velké části dán implementací pluginu:
PluginInterface má definované gettery a settery pro fieldy, které jsou použity při
vykreslování menu pluginu. Některé z těchto fieldů (ty, u kterých se předpokládá, že je
programátor pluginu nebude chtít měnit) jsou inicializovány v abstraktní třídě Plugin.
Jsou to:
• borderActive – barva rámečku menu u aktivního pluginu
• borderIdle – barva rámečku menu u neaktivního pluginu při najetí myší
45
4.4. PLUGINY
• whiteColor – druhá barva gradientu na pozadí menu i těla pluginu
V případě potřeby programátor může definovat vlastní hodnoty přetížením getterů a
setterů pro tyto fieldy.
Další fieldy použité pro menu, inicializované ve třídách konkrétních pluginů, jsou:
• name – název pluginu
• namePaddingTop – odsazení názvu pluginu odshora
• nameColor – barva názvu pluginu
• font – jméno fontu použitého pro vykreslení názvu pluginu
• fontHeight – velikost fontu
• fontHeight2 – velikost fontu při najetí myší na menu neaktivního pluginu
• labelColor – první barva gradientu na pozadí menu i těla pluginu
• labelColor2 – první barva gradientu na pozadí menu pluginu při najetí myší na menu
Programátor si tak může libovolně uzpůsobit vzhled menu svého pluginu při současném
zachování automatického vytvoření menu, včetně změny fontu, rámečku a pozadí při najetí
myší na menu.
4.4.2.1
Tlačítka v menu pluginu
Pro snadnější vytváření tlačítek v menu jsou v abstraktní třídě PluginActiveMenu implementované dvě metody addButton(). Jedna vytvoří tlačítko s minimální šířkou zadanou
v parametru, druhá s rozpínavou šířkou. Tlačítka jsou přidávána do menu vedle sebe, v případě použití druhé metody bude tedy celková šířka tlačítek rovna šířce celého menu.
Všechna tlačítka přidaná pomocí některé z metod addButton() používají vlastnost
MigLayoutu sizegroup, nastavenou u všech na stejnou hodnotu. Všechna tedy mají šířku
rovnou šířce největšího z nich.
4.4.2.2
Vybrání pluginu
Jednotlivá menu jsou potomkem Composite topMenu ve třídě PluginLoader
Při kliknutí myší na menu pluginu je zahozen celý obsah Composite topMenu (nad všemi
potomky topMenu je zavolán dispose() ), vybranému pluginu je nastaven příznak selected a
celé menu se znovu vykreslí voláním metod PluginInterface.drawMenu().
Tento způsob je náročnější na systémové prostředky než pouhé překreslení menu původně
vybraného a nově vybraného pluginu. Je ale přehlednější pro programátora pluginů – při
pouhém překreslování menu by např. bylo nutné ukládat všechny listenery přiřazené k menu
aktivního pluginu a ručně je odebírat při vybrání jiného pluginu.
46
KAPITOLA 4. IMPLEMENTACE
Stav
Aktivní
Neaktivní
0
3
1
1
2
1
2
2
4
3
3
4
4
2
4
Tabulka 4.2: Tabulka přechodů automatu pro přepínání menu
4.4.2.3
Přepínání menu
Menu pluginu je uloženo v proměnné PluginMenuState menu. Při změně menu z aktivního na neaktivní a naopak (tedy při přepnutí na jiný plugin) je původní menu uloženo do
fieldu třídy Plugin: PluginMenuState inactive. Díky tomu se při příštím přepnutí stavu
menu nemusí menu znovu inicializovat.
Za tímto účelem jsem vytvořil jednoduchý automat pro 5 možných stavů menu (viz
tabulka 4.23 ).
Možné stavy menu
(ve formátu <číslo stavu> ... <obsah proměnné menu>/<obsah proměnné inactive>):
• 0 ... — / —
• 1 ... IdleMenu / —
• 2 ... ActiveMenu / IdleMenu
• 3 ... ActiveMenu / —
• 4 ... IdleMenu / ActiveMenu
4.4.3 Tělo pluginu
Tělo pluginu je vykreslováno na widget Composite pluginBody, který je fieldem abstraktní třídy Plugin. PluginInterface definuje metody Composite getPluginBody() a
void setPluginBody().
Díky tomu, že všechny komponenty těla pluginu jsou potomkem Compositu pluginBody,
je možné při přepnutí na jiný plugin celé tělo pluginu jednoduše skrýt skrytím Compositu
pluginBody.
Composite pluginBody všech pluginů má nastavenu vlastnost MigLayout hidemode=3.
Díky tomu se pluginBody při skrytí pomocí pluginBody.setVisible(false) neúčastní layoutu.
3
Nejedná se o konečný automat, nelze proto minimalizovat jeho stavy, přestože stavy 2 a 4 mají totožné
přechody.
47
4.4. PLUGINY
4.4.3.1
Líná inicializace
Pro těla pluginů je použita líná inicializace (lazy loading) – pluginBody je inicializován
v abstraktní třídě Plugin, kde je nastaven jeho layout a zároveň příznak bodyInitialized
na false.
Až při přepnutí na daný plugin je zavolána metoda PluginInterface.setPluginBody(),
která naplní pluginBody vnitřními komponenty pluginu.
Volání setPluginBody() je provedeno ve třídě IdleMenu, kde je Listener pro kliknutí na
menu pluginu.
V těle metody Listeneru handleEvent() je provedena kontrola stavu inicializace pluginBody. Je-li bodyInitialized false, je zavolána metoda setPluginBody() a příznak je nastaven na true.
4.4.3.2
Přepínání pluginů
Při vybrání jiného pluginu je nejprve pluginBody vybraného pluginu nastaven na visible
a až poté je případně volána metoda setPluginBody() (pokud tělo dosud nebylo inicializováno).
Díky tomu lze při vytváření layoutu těla pluginu v metodě setPluginBody() používat
metody vracející velikost komponent, která je nulová, má-li komponenta, nebo její předek
(pluginBody), nastavený příznak visible na false.
Tato vlastnost je využita např. u pluginu SA Notify – velikost obou zde použitých tabulek
je nastavována podle velikosti dalších komponent – viz kapitola 5.
Využití Compositu pluginBody jako předka všech komponent těla pluginu má i další
výhody:
• Lze jednoduše upravit layout rodičovské aplikace, aniž by byl narušen vnitřní layout
pluginu.
• Pluginy mohou používat libovolný layout manager. Vývojář pluginů není vázán na
MigLayout, může nastavit libovolný vnitřní layout Compositu pluginBody.
4.4.4 Položky hledání
Abstraktní třída PluginTableItem reprezentuje jednotlivé položky v tabulce probíhajících hledání. Např. u pluginu SA Notify pro hledání míst v autobusech Student Agency
tedy každá instance podtřídy PluginTableItem reprezentuje jeden konkrétní autobus, v němž
se plugin snaží najít volné místo.
PluginTableItem implementuje interface Serializable.
4.4.4.1
Ukládání probíhajících hledání
Při vypnutí programu jsou uložena všechna probíhající hledání. Za tímto účelem definuje
PluginInterface metodu s generickým návratovým typem:
p u b l i c A r r a y L i s t <? e x t e n d s PluginTableItem > getTableData ( ) ;
48
KAPITOLA 4. IMPLEMENTACE
Tato metoda vrátí ArrayList položek v tabulce hledání. PluginInterface dále definuje
metody save() a load() pro uložení probíhajících hledání a pro jejich opětovné načtení při
spuštění programu.
Metoda save() je implementována v abstraktní třídě Plugin:
V těle metody se zavolá getTableData() a všechny vrácené položky jsou uloženy do
souboru, jehož jméno je ve fieldu třídy Plugin savedSearchesFile. Výchozí jméno souboru
je „savedSearches.san“ a soubor je uložen do složky se soubory pluginu (v kapitole 4.4.1
zmíněný field pluginFilesPath).
Programátor pluginu tak musí jen doplnit tělo metody getTableData() a metody load(),
která načte uložené položky hledání, uložené metodou save() jako objekty PluginTableItem,
a přetíží je na odpovídající podtyp (svou implementaci třídy PluginTableItem).
4.4.5 Kontrola volných míst
Pozn: Nadpis této kapitoly není přesný, plugin může kontrolovat cokoli, ne pouze volná
místa.
Abstraktní třída CheckerThread extends Thread obsahuje metody a fieldy pro usnadnění kontroly volných míst. Obsahuje tyto fieldy:
• INTERVAL – interval, v jakém má probíhat kontrola volných míst na serveru
• DEVIATION – odchylka od intervalu, ve kterém probíhá kontrola
• INTERVAL_DEFAULT – výchozí interval, field má nastaven příznak final
• DEVIATION_DEFAULT – výchozí odchylka, field má nastaven příznak final
Při opakovaném přistupování na servery třetích stran je nutné přístupy opakovat
v dostatečně velkých intervalech, aby při masivnějším použití aplikace nedocházelo k přetížení
těchto serverů.
Zároveň je vhodné zvolený interval náhodně měnit, aby byla ztížena detekce robota ze
strany provozovatelů serveru. K tomu slouží field DEVIATION.
Metody implementované ve třídě CheckerThread slouží k nastavení intervalu kontroly,
výpočtu náhodné odchylky, ukládání aktuálního času a zjišťování, kolik času zbývá do konce
intervalu.
49
4.4. PLUGINY
4.4.5.1
Doporučená struktura metody Run
Doporučená struktura metody Run vlákna pluginu, které je podtřídou CheckerThread a
slouží k periodické kontrole volných míst (uvedené metody jsou implementované ve třídě
CheckerThread):
@Override
p u b l i c v o i d run ( ) {
while ( ! freeSeatFound ){
setInterval ();
setLastCheck ( ) ;
{
/∗ k o n t r o l a m í s t . . . ∗ /
}
s l e e p ( getSleepTime ( ) ) ;
}
}
setInterval() nastaví nový interval pro kontrolu míst. Interval je vypočten podle vzorce
IN T ERV AL + (−DEV IAT ION + newRandom().nextInt(DEV IAT ION × 2 + 1))
Vypočtený interval je tedy náhodné číslo v intervalu INTERVAL ± DEVIATION.
setLastCheck() uloží aktuální čas.
getSleepTime() vrátí čas zbývající do konce intervalu, nebo 0, pokud kontrola volných
míst trvala déle, než je nastavený interval.
4.4.6 Nastavení pluginů
Pro snadnější vytváření dialogu Nastavení pro jednotlivé pluginy byla navrhnuta abstraktní třída PluginPreferences, která obsahuje metody pro vytvoření dialogu podobného
tomu, který se otevře při volbě položky v menu aplikace Nastavení – Možnosti.
PluginPreferences obsahuje metody pro vytvoření příslušného dialogu, záložkového
menu (widget TabFolder), tlačítek Uložit a Storno včetně příslušných Listenerů apod.
Děděním od této třídy lze tedy snadno vytvořit celý dialog, do kterého stačí doplnit
obsah jednotlivých záložek.
Tlačítko Uložit po stisknutí zavolá metodu save(). Na rozdíl od tlačítka Uložit u dialogu
Možnosti – Nastavení jeho stisk kromě zavolání metody save() nezpůsobí zavření dialogu.
Dialog je nutné zavřít v těle metody save() po uložení provedených změn v nastavení.
V těle metody save() tak může být provedena kontrola správnosti nastavení (např.
správně zadaný login a heslo pro přístup k serveru) a v případě chyby (prázdný login,
nebo heslo) se dialog neuzavře a uživatel je na chybu upozorněn.
50
KAPITOLA 4. IMPLEMENTACE
4.4.7 Historie hledání
Abstraktní třída PluginHistory je určená pro zjednodušení tvorby dialogu Historie hledání.
Třída pracuje s instancemi abstraktní třídy PluginTableItem, která je nadtřídou položek
hledání konkrétních pluginů.
Díky tomu bylo možné implementovat některé metody pro práci s historií hledání:
• addToHistory(PluginTableItem item) přidá položku do
ArrayListu <PluginTableItem> historyList, obsahujícího nové položky historie.
• saveHistory(boolean saveHistory) uloží obsah listu historyList do souboru. Jméno
souboru je uloženo ve fieldu historyFile, výchozí jméno je „history.san“.
Je-li parametr saveHistory false, uloží prázdný soubor. Metoda tedy slouží i k vymazání historie.
• createHistoryDialog() vytvoří jednoduchý dialog s názvem „[jméno pluginu]-historie:“,
tabulkou s historií a zavíracím tlačítkem.
Dále třída definuje tyto abstraktní metody:
• ArrayList<? extends PluginTableItem> loadHistory() načte historii uloženou
v souboru.
• ArrayList<? extends PluginTableItem> getHistory() vrátí celou historii, tedy
obsah listu historyList s připojenou historií, která byla uložena do souboru.
4.4.7.1
Tabulka historie
Tabulka s položkami historie je vytvořena v metodě createTable(String[ ] columns,
String[ ] columnsTooltTip, int[ ] columnsWidth).
Její parametry jsou názvy sloupců (columns), tooltipy názvů (columnsToolTip) a
šířky jednotlivých sloupců (columnsWidth).
Tedy pokud tělo pluginu obsahuje tabulku zobrazující probíhající hledání, jejíž parametry Název sloupce, Tooltip sloupce a Šířka sloupce jsou uloženy v polích, stačí tato pole
předat metodě createTable(), která sama vytvoří tabulku historie.
Dialog Historie používá, na rozdíl od zbytku aplikace, GridLayout. Díky tomu je možné
použít kód z SWT Snippetu 77 pro automatický resize sloupců při změně velikosti okna
dialogu – při použití MigLayoutu snippet ani po složitých úpravách nefungoval.
Šířka sloupců tabulky je přepočítána při každé změně velikosti okna dialogu tak, aby
sloupce vyplnily celou šířku dialogu a zároveň byl zachován jejich poměr stran vypočítaný
ze vstupního parametru int[ ] columnsWidth.
51
4.4. PLUGINY
Obrázek 4.5: Třídní diagram pluginu
4.4.8 Přehled tříd pluginu
Na obrázku 4.5 je třídní diagram typického pluginu.
Každý plugin musí obsahovat tyto třídy (respektive implementovat jejich nadtřídy):
• NewPlugin – třída reprezentující daný plugin, implementuje metody interfacu PluginInterface.
• NewPluginMenu – obsahuje implementaci menu aktivního pluginu (tedy podobu
menu, pokud je plugin právě vybrán).
• NewPluginTableItem – reprezentuje jednu hledanou položku.
Implementace této třídy (podtřídy PluginTableItem) povinná není, umožňuje ale využití
metody safe() pro ukládání probíhajících hledání, implementované ve třídě Plugin, a
také metod třídy PluginHistory pro práci s historií hledání.
52
KAPITOLA 4. IMPLEMENTACE
Dále plugin navržený na obrázku obsahuje třídy:
• NewPluginPreferences – otevře dialog Nastavení pluginu.
• NewPluginHistory – zobrazí historii hledání.
• NewPluginChecker – samostatné vlákno, které provádí cyklické hledání volných
míst.
Programátor nového pluginu musí implementovat pouze třídy vyznačené na obrázku 4.5
zeleně. Všechny ostatní jsou již součástí aplikace.
4.5
Různé
Do této kapitoly řadím popisy implementace, které není vhodné zařadit do žádné z předchozích kapitol.
4.5.1 Texty v dialozích
Texty ve vyskakovacích dialozích i v dialozích O programu, Nastavení – Možnosti apod.
jsou vytvořeny pomocí widgetu StyledText. Pro daný účel je možné použít i widget Label,
ten ale neumožňuje text jednoduše formátovat. V případech, kdy je text formátován, je
proto použit StyledText.
StyledText má nastaven setEditable(false) (uživatel text nemůže editovat) a výchozí
kurzor widgetu je přetížen na kurzor šipka.
Obrázek 4.6: Widget StyledText – kurzor myši vedle textu „POZOR:“
I s přetíženým kurzorem myši ale uživatel na text může kliknout a v textu se objeví
kurzor pro psaní (obr. 4.6). Text lze navíc i vybrat (obr. 4.7).
Obrázek 4.7: Widget StyledText – uživatel vybral text myší
U většiny dialogů je proto StyledText nastaven jako disabled pomocí
StyledText.setEnabled(false).
53
4.5. RŮZNÉ
Jako enabled je nastaven pouze v případech, kde může být žádoucí, aby uživatel mohl
text vybrat a zkopírovat - např. dialog O Programu, položky Autor a Kontakt.
Také všechny texty, jejichž součástí je URL odkaz, musí být enabled, jinak na odkaz
nelze kliknout. Enabled v takovém případě musí být celý StyledText obsahující odkaz.
Dalším řešením je vytvořit jeden StyledText obsahující text před odkazem, následovaný
druhým StyledText, který obsahuje pouze URL odkaz.
V takovém řešení ovšem nefunguje správně automatické zalamování řádek, zvolil jsem
proto první možnost, kdy je enabled celý text s URL odkazem.
4.5.2 Jediná instance programu
Ve třídě MainClass je uložen boolean oneInstance. Pokud je nastaven na true (výchozí
nastavení pro distribuci programu), lze spustit pouze jedinou instanci aplikace.
4.5.2.1
Kontrola jediné instance programu
Před inicializací GUI je zkontrolována existence souboru „token“. Pokud soubor neexistuje, aplikace ho vytvoří a nastaví mu příznak deleteOnExit(). Při ukončení aplikace tak
dojde k jeho smazání.
Pokud soubor existuje, aplikace zobrazí dialog informující uživatele, že je již spuštěna
jiná instance programu (obr. 4.8).
Obrázek 4.8: Dialog informující uživatele o již spuštěné instanci aplikace
Uživatel může zvolit spuštění aplikace i přes existenci souboru „token“. Tím je ošetřen
případ, kdy při předchozím spuštění aplikace nebyla řádně ukončena a soubor „token“ nebyl
vymazán.
Zvažoval jsem i další způsoby kontroly již běžící aplikace:
• Uzamykání souboru „token“, např. pomocí java.nio.channels.FileLock. Soubor
je v takovém případě automaticky odemčen při ukončení JVM. Stále ale může dojít
k situaci, kdy z důvodu chyby soubor zůstane uzamčen (např. při pádu operačního
systému).
• Blokování portu – místo souboru je použit libovolný port. V tomto případě ale
může docházet ke kolizi s jinou aplikací, používající daný port, případně k problémům
s firewallem.
Jednoduché řešení pomocí zjištění existence souboru se tedy jeví nejlepší.
54
KAPITOLA 4. IMPLEMENTACE
4.5.3 Přístupnost
Velikost okna aplikace
Velikost okna aplikace může uživatel libovolně měnit.
Výchozí velikost okna je 800×640 px. Toto rozlišení považuji za dostatečné pro přehledný
layout aplikace.
Podle statistik uváděných na webu www.w3schools.com je zároveň dostatečně malé pro
většinu dnes používaných rozlišení monitorů. Podle těchto statistik má pouze 1% uživatelů
rozlišení 800 × 600 px, nebo menší.
Obrázky a texty
Aplikace obsahuje mnoho obrázků u položek menu, tlačítek, záložek dialogu Možnosti
apod.
Obrázky slouží k rychlejší orientaci uživatele, který je již s aplikací seznámen.
Zároveň je ale u všech takto použitých obrázků uveden i text. Ten slouží nejen pro
rychlejší orientaci nového uživatele, ale například i pro větší přístupnost aplikace zrakově
postiženým, využívajícím čtecí zařízení.
Použité ikony
Snažil jsem se volit jednoduché a výrazné ikony, které by uživateli usnadnily zapamatování polohy i funkce různých prvků aplikace.
V případě, že se mi nepodařilo nalézt obrázek, který by vystihoval příslušnou položku
menu nebo tlačítko, snažil jsem se zvolit alespoň výraznou ikonu, kterou si uživatel s danou
položkou může asociovat a nebude si ji plést s jinými ikonami.
V aplikaci jsou použity následující ikony:
• Ikony od Oxygen Team ze stránky
http://iconarchive.com/artist/oxygen-icons.org.html, poskytované pod licencí
GNU LGPL.
• Ikony z kolekce Country flags (http://iconarchive.com). Jsou uvedné jako free
for non-commercial use (autor neuvádí konkrétní licenci).
• Ikony z kolekce Function Icon Set, zmíněné v kapitole 1.2.
• Ikona kávy od uživatele Martin Berube (http://iconarchive.com) – autor uvádí
License: Freeware, Commercial usage: Allowed.
• Ikona autobusu z www.wpclipart.com. Podmínky použití viz pclipart.com/legal.html
– v zásadě je povoleno libovolné použití.
• Ikony autobusu a vlaku ze stránek www.clker.com/.
Z podmínek (clker.com/disclaimer.html) opět vyplývá libovolné použití.
• Obrázek autobusu ze stránek společnosti Student Agency, sekce Pro média
(www.studentagency.cz/pro-media/).
55
4.5. RŮZNÉ
4.5.4 Název aplikace
Zvolil jsem název aplikace SA Notify. Stejně jsem také pojmenoval plugin pro kontrolu
míst ve spojích Student Agency.
Tento název navazuje na původní program SA Notify, popsaný v kapitole 2.1.2. Od
autora programu jsem získal písemné povolení k užití tohoto názvu.
4.5.5 Komentáře
Veškeré zdrojové kódy jsou opatřeny podrobnými komentáři v anglickém jazyce. U rozsáhlejších komentářů jsem použil formátování pomocí HTML tagů pro zpřehlednění dokumentace vygenerované pomocí Javadoc.
56
Kapitola 5
Plugin SA Notify
V této sekci se zabývám implementací pluginu SA Notify pro kontrolu volných míst ve
spojích Student Agency.
5.1
Analýza a návrh řešení pluginu SA Notify
5.1.1 Specifikace požadavků
Analýzou rešerše všech existujících řešení v kapitole 2.1 bylo stanoveno množství funkčních
i nefunkčních požadavků. Plugin by měl umět:
• sledovat více spojů najednou
• aktualizovat seznam stanic
• načítat dostupné spoje pro zvolené datum ze serveru
• poradit si s více spoji v jeden čas
• minimalizovat se do oznamovací oblasti (OS Windows)
• automaticky zarezervovat volná místa
• hledat pouze preferovaná sedadla
• rozlišovat typy spojů (vlak/autobus, autobus Fun & Relax/Posilový spoj bez služeb
apod.)
• přehrát výrazné zvukové upozornění při úspěšném hledání
• zobrazit historii hledání
• měl by mít přehledné grafické rozhraní
5.1. ANALÝZA A NÁVRH ŘEŠENÍ PLUGINU SA NOTIFY
5.1.2 Případy užití
Na základě specifikovaných požadavků byly stanoveny následující případy užití:
5.1.2.1
Hlavní okno pluginu
Obrázek 5.1: Případy užití hlavního okna pluginu SA Notify
Na obrázku 5.1 jsou znázorněny hlavní případy užití pluginu:
• Přidat spoj
Uživatel zvolí tyto parametry požadovaného spojení:
- Výchozí stanice
- Cílová stanice
- Datum
- Konkrétní spoj v daný čas
Po potvrzení výběru aplikace začne s kontrolováním volných míst.
• Odebrat spoj
Uživatel zruší hledání volného místa u vybraného spoje.
58
KAPITOLA 5. PLUGIN SA NOTIFY
• Zapnout automatickou rezervaci
Uživatel zapne automatickou rezervaci.
V případě nalezení volného místa aplikace volné místo ihned zarezervuje.
Uživatel musí předem zadat přihlašovací údaje ke kreditové jízdence v Nastavení pluginu.
• Zvolit preferovaná sedadla
Uživatel může zvolit, jaká sedadla preferuje:
- Jakákoli
- U okna
- V uličce
- Vše kromě prostřední části zadní 5-sedačky (tzn. na sedadla na 5-sedačce u oken program
upozorní)
Za nejdůležitější považuji volbu Vše kromě prostřední části zadní 5-sedačky. Cestovat
na delší vzdálenosti na sedadle uprostřed 5-sedačky, kdy z obou stran sedí další cestující, je velmi nepohodlné. Sedadlo je relativně úzké a mezi sedadly nejsou opěrky pro
ruce, je tedy silně narušen intimní prostor cestujícího.
Tato sedadla bývají proto poslední obsazená a zároveň to jsou často první místa, která
se uvolní v plném spoji. Je proto důležité, aby uživatel mohl vyloučit rezervaci právě
těchto sedadel.
• Zobrazit nastavení
Aplikace zobrazí dialog s možnostmi nastavení pluginu. Více viz kapitola 5.1.2.2.
• Zobrazit historii
Aplikace zobrazí historii všech proběhlých hledání.
1
Každá položka obsahuje:
- Výchozí stanice
- Cílová stanice
- Datum a čas spoje
- Typ spoje (vlak, bus, posilový bus, bus Fun & Relax apod.)
- Preferovaná sedadla
- Stav automatické rezervace (zapnuta/vypnuta)
- Rezervované sedadlo (bylo-li rezervováno)
5.1.2.2
Nastavení pluginu
• Nastavit výchozí preferovaná sedadla
Uživatel zvolí výchozí preferovaná sedadla (jednotlivé možnosti viz předchozí kapitola).
1
Hledání je ukončeno a uloženo do historie okamžikem nalezení volného místa.
59
5.1. ANALÝZA A NÁVRH ŘEŠENÍ PLUGINU SA NOTIFY
Obrázek 5.2: Případy užití v dialogu Nastavení pluginu SA Notify
• Aktualizovat seznam zastávek
Aplikace podle webového rezervačního systému Student Agency aktualizuje seznam
zastávek. Uživatel tuto možnost zvolí pouze pokud se lokální seznam aplikace stane
neaktuálním.
• Zvolit akci pro volné místo
Uživatel zvolí výchozí akci při nalezení volného místa. Systém buď na volné místo
pouze upozorní, nebo ho ihned zarezervuje. Ve druhém případě musí uživatel zadat
přihlašovací údaje ke kreditové jízdence a vybrat cenový tarif.
• Nastavit výchozí trasu
Uživatel zvolí výchozí počáteční a cílovou stanici. Zvolené stanice budou přednastavené
v dialozích pro výběr počáteční a cílové stanice.
• Nezobrazovat stará hledání
Systém z výpisu hledaných spojů odebere spoje, které jsou již neaktuální (proběhl čas
odjezdu). Tyto spoje zůstanou uložené v historii, pokud je ukládání historie zapnuto.
60
KAPITOLA 5. PLUGIN SA NOTIFY
• Ukládat historii
Zvolí-li uživatel tuto možnost, aplikace uloží všechna úspěšná hledání do historie.
5.1.3 Diagram aktivit - přidání spoje
Obrázek 5.3: Diagram aktivit - přidání spoje do vyhledávání
Na obrázku 5.3 je diagram aktivit pro přidání spoje do vyhledávání. Uživatel postupně
navolí všechny potřebné parametry, aplikace průběžně kontroluje jejich správnost.
61
5.1. ANALÝZA A NÁVRH ŘEŠENÍ PLUGINU SA NOTIFY
5.1.4 Analytický model
V této kapitole je popsána struktura tříd pluginu. Základní struktura odpovídá té zobrazené na obrázku 4.5, byly ale přidány některé další, pomocné třídy.
5.1.4.1
Hledání volných míst
Obrázek 5.4: Třídy účastnící se hledání volných míst
Na obrázku 5.4 jsou třídy přímo se účastnící hledání volných míst.
SA je hlavní třída pluginu, implementující interface PluginInterface.
SAChecker obsahuje metody pro parsování HTML stránek a vyhledání požadovaných
dat na stránkách.
SACheckerThread je vlákno provádějící kontrolu volných míst.
SATableItemBean reprezentuje jednu položku hledání.
SALineBean je fieldem SATableItemBean a reprezentuje konkrétní spoj.
V SATableItemBean jsou uloženy obecné informace o hledání (nastavení automatické
rezervace, preferovaných míst apod.), zatímco v SALineBean jsou uloženy detaily spoje čas odjezdu, typ spoje apod.
62
KAPITOLA 5. PLUGIN SA NOTIFY
DateTimeBean je pomocná třída, reprezentující datum a čas a obsahující pomocné
metody např. pro zjištění dne v týdnu. Je navržena pro snadnou interakci s SWT widget
DateTime.
5.1.4.2
Nastavení a historie
Obrázek 5.5: Nastavení pluginu a historie hledání
SAHistory obstarává zobrazování a ukládání historie pluginu.
SAPreferences zobrazí dialog Nastavení.
SAPreferencesBean pro jednodušší použití frameworku JFace Data Binding (viz 3.1.5)
jsou veškeré hodnoty, které může uživatel změnit v dialogu Nastavení, reprezentovány třídou
SAPreferencesBean.
SAStationsUpdate slouží k aktualizování seznamu stanic. Díky implementaci interfacu
UpdateInterface může uživatel aktualizaci v průběhu přerušit.
5.1.4.3
Chyby a obrázky
Plugin má vlastní třídu pro zobrazování chyb uživateli (SAErrorHandler, obrázek 5.6),
která je potomkem třídy ErrorHandler.
63
5.2. IMPLEMENTACE PLUGINU
Obrázek 5.6: Třídy pro správu chyb a obrázků pluginu
Potomek třídy ImageHandler, třída SAImageHandler, slouží k inicializaci a disposingu
obrázků pluginu.
5.1.5 Grafický návrh pluginu
Grafický návrh je na obrázku 3.6.
Při návrhu jsem se snažil, aby všechny důležité komponenty byly ihned přístupné - tedy
aby uživatel nemusel například přepínat mezi dialogem pro výběr stanice a dialogem pro
výběr data.
V současné podobě lze velmi rychle navolit potřebné parametry a spoj přidat do vyhledávání.
5.2
Implementace pluginu
5.2.1 Rezervační systém Student Agency
Společnost Student Agency svůj web pro rezervaci spojů v minulosti několikrát změnila.
K poslední velké změně došlo v roce 2011.
Poslední verze webu ve velké míře využívá Javascript a technologii Ajax. I pro pouhé
zobrazení spojů pro zvolený den je tak nutné na server odeslat několik Ajax požadavků.
Požadavky přitom obsahují i proměnné generované Javascriptem na straně klienta, které se
dynamicky mění např. podle počtu přístupů na stránku. Ani získání požadovaných dat za
použití HTML requestů simulujících Ajax požadavky tedy není zcela triviální.
Stránky rezervačního systému bývaly v minulosti (v době, kdy byly funkční programy
pro kontrolu volných míst zmíněné v kapitole 2.1) často přetížené. Lze proto předpokládat,
že současná dynamická podoba webu je zčásti záměrem za účelem vyřazení robotů, které v
minulosti na stránky přistupovaly.
64
KAPITOLA 5. PLUGIN SA NOTIFY
5.2.1.1
Přístup k rezervačnímu systému
Ať už je domněnka z předchozí kapitoly pravdivá či nikoli, jistě je vhodné přistupovat
na stránky Student Agency tak, aby aplikace server zbytečně nezatěžovala a zároveň aby
byla pokud možno snížena možnost detekce robota ze strany správce serveru.
Všechny přístupy k rezervačnímu systému jsou proto prováděny pomocí knihovny Jsoup,
která umožňuje snadné nastavení všech parametrů HTML requestu a jednoduchou práci
s cookies.
Hlavičky requestu jsou nastaveny tak, aby request simuloval prohlížeč Mozilla Firefox v. 10.
5.2.1.2
Ajax požadavky
Při odpovídání na některé Ajax požadavky vrací server HTML kód s escaped HTML
tagy (vrací pouze kódy tagů).
Před parsováním pomocí Jsoup je proto vrácený kód převeden na validní HTML pomocí
org.apache.commons.lang.StringEscapeUtils - metoda unescape(). Apache Commons
knihovny jsou poskytovány pod licencí Apache License, Version 2.0 [27].
5.2.1.3
Interval kontroly volných míst
Pro interval kontroly volných míst, nastavovaný ve třídě SACheckerThread, jsem zvolil
70 s ± 20 s.
Interval by měl být co největší kvůli zátěží serveru, při intervalu větším než 90 s už ale
roste nebezpečí, že volné místo zarezervuje někdo jiný a to i bez použití této aplikace:
I v době, kdy nebyl funkční žádný z programů pro kontrolu volných míst, byla uvolněná
místa ve špičce během maximálně několika minut opět zarezervována.
5.2.2 Grafické rozhraní
V této kapitole popisuji implementaci grafického rozhraní aplikace a provedené změny
oproti grafickému návrhu.
Na obrázku 5.10 je vidět srovnání GUI původního grafického návrhu a výsledné aplikace.
5.2.2.1
Výchozí a cílová stanice
Oproti návrhu bylo přidáno tlačítko pro prohození výchozí a cílové stanice cesty.
Typický cestující cestuje pravidelně na jediné trase v obou směrech, potřeba tlačítka se
proto objevila již při prvotním testování aplikace.
5.2.2.2
Spoje
V první verzi grafického rozhraní byl výpis dostupných spojů tvořen widgetem List, ten
je i v GUI návrhu aplikace.
List ale neumožňuje formátovat text (jednotlivé položky mohou být jedině typu String)
nebo zobrazovat obrázky, provedl jsem proto refaktoring a použil widget Table (obr. 5.7).
65
5.2. IMPLEMENTACE PLUGINU
Výška tabulky: Tabulka se spoji musí mít pevně nastavenou výšku, jinak se automaticky
nastaví tak, aby byly zobrazeny všechny položky.
Výška by ale zároveň měla být pohyblivá, aby při změně velikosti okna došlo i ke změně
velikosti tabulky. Byl proto přidán Shell Resize Listener, který při změně velikosti okna
programu změní velikost tabulky podle nové velikosti Shellu.
Vhodnější by bylo přiřadit tento Resize Listener ke Compositu pluginBody, jenž obsahuje všechny komponenty těla pluginu, nebo alespoň velikost tabulky podle pluginBody
počítat.
V současné implementaci by totiž při změně okolního layoutu (např. vypnutí stavového
řádku) byla velikost tabulky nastavena špatně.
Při přiřazení Listeneru k pluginBody byla ale odezva na změnu velikosti okna nepřirozeně
pomalá a trhaná - pravděpodobně kvůli řetězení Listenerů, kdy změna velikosti okna inicializuje změnu velikosti Shellu, která teprve inicializuje změnu velikosti pluginBody pomocí
MigLayoutu.
Obrázek 5.7: Tabulka pro výběr konkrétního spoje
Změny oproti návrhu: Jak je patrné z obrázku 5.7, tabulka se spoji obsahuje více informací, než v původním návrhu.
Jsou to:
• Datum - vždy nad skupinou spojů pro daný den, podobně jako na obr. 3.6
• Dopravní prostředek - ikonka vlaku, nebo autobusu
• Čas odjezdu
• Počet volných míst ve spoji
• Typ spoje - ikonka znázorňující typ spoje
Aplikace rozlišuje tyto typy spojů:
- Fun & Relax
66
KAPITOLA 5. PLUGIN SA NOTIFY
- Posila Žlutý standard
- Posila Economy
Názvy typů a ikony odpovídají těm, které jsou použity na webu Student Agency.
5.2.2.3
Tabulka hledání
Tabulka zobrazující probíhající hledání má nastaven parametr MigLayoutu endgroupy
stejný jako tabulka spojů. Tím je zajištěno zarovnání jejich dolního okraje.
Šířku sloupců tabulky může uživatel změnit. Nová šířka bude uložena při ukončení aplikace a použita při opětovném spuštění.
Trasa: V tomto sloupci byla původně mezi výchozí a cílovou stanicí vykreslována šipka
(→), tak jako je tomu v grafickém návrhu.
Ovšem přestože byl použit symbol šipky z Microsoft WGL4 character set
(microsoft.com/typography/otspec150/wgl4d.htm), symbol se nezobrazoval na operačním
systému Windows XP. Použil jsem proto jako oddělovací znak pomlčku (–).
CCombo s výběrem preferovaných míst: Widget CCombo je určen k nahrazení widgetu Combo v případech, kdy Combo nelze použít - např. jako prvek v řádku tabulky.
Některé platformy nepodporují nastavení velikosti SWT.Combo (např. OS Windows), pro
tabulku je proto nutné použít CCombo, které nevyužívá komponenty systému, ale je celé
vykreslováno SWT knihovnou.
Do tabulky je CCombo přidáno pomocí widgetu TableEditor (kapitola 5.2.2.4).
CCombo má bohužel podobná omezení jako Combo: nelze nastavit obrázek (a neexistuje
ImageCCombo alternativa ke třídě ImageCombo, zmíněné v kap. 4.2.5.3) ani zarovnání textu
na střed, tak jako je to v GUI návrhu.
Při implementaci CCombo s výběrem preferovaných míst jsem narazil na bug 358183
(viz bugs.eclipse.org):
• Pokud je text delší než velikost Comba, je useknutý zleva, ne zprava.
U bugu je popsaný i workaround:
combo . a d d L i s t e n e r (SWT. R e s i z e , new L i s t e n e r ( ) {
p u b l i c v o i d handleEvent ( f i n a l Event argEvent ) {
combo . s e t T e x t ( combo . getText ( ) ) ;
}
});
Ten ovšem funguje jen pro widget Combo, ne pro CCombo.
Vytvořil jsem proto pro CCombo Listener pro události SWT.Resize a SWT.Selection.
67
5.2. IMPLEMENTACE PLUGINU
Oba Listenery pomocí SWT třídy GC (Graphics Context) spočítají přesnou šířku CComba
i nezkráceného textu vybrané položky. Následně je spočítána průměrná šířka jednoho znaku
textu a je vytvořen substring o tomto počtu znaků.
Vzhledem k výpočtu pomocí průměrné šířky znaku, který je rychlejší než přesný výpočet
šířky jednotlivých znaků (postačí celkovou šířku textu vydělit počtem znaků) může i vytvořený
substring být stále širší, než je šířka CComba. I šířka větší jen o několik pixelů přitom způsobí
useknutí části prvního písmene textu.
U vytvořeného substringu je proto v cyklu kontrolována šířka a snižován počet znaků,
dokud není šířka textu opravdu menší, než šířka CComba.
Na obrázku 5.8 je vidět CCombo se špatným zarovnáním i CCombo se zarovnáním
opraveným popsanou metodou.
Obrázek 5.8: Vlevo je vidět CCombo chyba – špatné zarovnání textu, vpravo je chyba
opravena
Změny v tabulce hledání oproti návrhu:
• V tabulce je na začátku řádku zobrazena ikona dopravního prostředku. V současné
verzi je zobrazována pouze ikona vlaku (viz obr. 5.9) - většina spojů jsou autobusy,
ikona autobusu je navíc zobrazována v tabulce Spoje, není tedy třeba ji přidávat i do
hlavní tabulky, kde by ubírala na přehlednosti.
• Byl přidán sloupec Typ, který zobrazuje typ spoje (stejně jako v tabulce Spoje). Na
obrázku 5.9 je vidět autobus typu Fun & Relax a autobus Posila Economy.
Obrázek 5.9: Tabulka hledání, probíhá hledání míst ve vlaku a autobusech Fun & Relax a
Posila Economy
5.2.2.4
TableEditor
TableEditor je objekt, určený pro přidávání widgetů do tabulky. Může mu být přiřazen
libovolný widget, který je umístěn nad zvolenou buňku tabulky.
Jeho nevýhodou je nutnost ručního disposingu - při odebrání položky (řádku) tabulky
není přiřazený TableEditor automaticky také odebrán.
68
KAPITOLA 5. PLUGIN SA NOTIFY
Widget TableEditor byl použit pro přidání CComba s výběrem preferovaných míst a
tlačítka pro vypnutí/zapnutí automatické rezervace do tabulky hledání.
5.2.2.5
Barvy
Všechny barvy (SWT Color) používají línou inicializaci. Getter pro danou barvu zkontroluje, zda byla inicializována a případně zavolá setter.
Ne všechny barvy jsou použity při každém spuštění programu, líná inicializace je tedy
hospodárnější.
Obrázek 5.10: Srovnání GUI návrhu s GUI výsledné aplikace
69
5.2. IMPLEMENTACE PLUGINU
5.2.3 Implementace grafického rozhraní
5.2.3.1
Seznam stanic
Seznam stanic je uložen v XML souboru Stations.xml, uloženém ve složce pluginu
(plugins/SA/).
Soubor má následující strukturu:
<s t a t i o n s −czech >
<s t a t i o n >
<t e x t >Český Krumlov , AN</t e x t >
<val ue >CK</valu e >
</ s t a t i o n >
</ s t a t i o n s −czech >
Načtení seznamu stanic ze souboru probíhá ve třídě SAPreferences.
Pokud při načítání dojde k chybě (soubor je prázdný, nebo neexistuje), aplikace se pokusí
připojit k serveru Student Agency a stáhnout nový seznam stanic.
5.2.3.2
Spoje
Dojde-li k chybě při načítání spojů, aplikace upozorní uživatele jen v případě, že seznam
stanic není prázdný – to by znamenalo, že došlo k chybě při načítání seznamu stanic a
uživatel byl již na chybu upozorněn.
Třída SALineBean obsahuje informace o konkrétním spoji – především čas, typ spoje
(vlak/bus), podtyp (Fun & Relax/Posila), počet volných míst, ID spoje apod.
Třída obsahuje i field DateTimeBean date, reprezentující datum spoje.
Díky tomu je jednoduše možné vypisovat v tabulce Spoje více dní:
Server v případě, že na hledaný den je k dispozici méně než 10 spojů, vyhledá spoje i na
den následující.
Je tedy nutné kontrolovat, zda vypisovaný spoj je pro zvolený den, nebo den následující
a případně vypsat nadpis pro další den (viz obr. 5.10).
Existující řešení z kapitoly 2.1 vypisovala spoje pouze pro jeden den. To ale může být
pro uživatele matoucí - například by nepoznal, zda pro zvolený den už nejedou žádné spoje,
nebo došlo k neoznámené chybě při výpisu spojů.
Možnost vypisování navíc umožňuje budoucí rozšíření pluginu o tlačítko Další spoje,
které by vyhledalo spoje následující po posledním nalezeném.
Detail spoje: Aplikace umí ze serveru získat i podrobnější údaje o spoji, které lze na
webu rezervačního systému získat stisknutím tlačítka Detail spoje.
Pro tento účel existuje metoda SAChecker.setLineDetails(SALineBean bean),
která doplní dosud prázdné fieldy objektu SALineBean:
• Čas příjezdu
70
KAPITOLA 5. PLUGIN SA NOTIFY
• Nástupiště
• Spojení (Stanice, ze které spoj vyjíždí a stanice, ve které končí.)
• Cena
• Sedadlo
V první verzi pluginu byly detaily parsovány automaticky pro každý nalezený spoj. Server
má ale velmi pomalou odezvu, získání detailů pro každý spoj trvá přibližně 1 vteřinu.
Zpoždění při vypisování spojů by tedy bylo neúnosně velké. V současné verzi proto plugin
detaily nezjišťuje. V budoucnu lze ale jednoduše implementovat např. rozšíření o tlačítko
Zobrazit detail spoje.
Aktualizace tabulky Spoje proběhne automaticky vždy, když uživatel zvolí jiné datum
nebo změní výběr stanice v Combo boxech Z nebo Do. Okamžitou aktualizaci považuji
za přívětivější a rychlejší než potvrzování výběru tlačítkem, jako je tomu na webu Student
Agency.
5.2.3.3
Přidání spoje do vyhledávání
Všechna nastavení provedená v dialozích pro výběr spoje (stanice, datum, čas) se ukládají
do SATableItemBean bean, která je fieldem třídy SA.
Při stisknutí tlačítka Přidat spoj aplikace zkontroluje:
• Platnost zvolených stanic – Combo boxy s výběrem stanic obsahují i nadpisy zemí
(Česko, Slovensko). Ty mají hodnotu stanice (VALUE) nastavenou na -1.
• Aktuálnost spoje - nelze přidat spoj, který již proběhl. Tato kontrola je spíše dvojím
jištěním - při vyhledávání spojů server vrátí pouze spoje budoucí.
Teoreticky by ale mohlo dojít k situaci, kdy plugin vyhledá spoje na dnešní den a
uživatel výběr provede se zpožděním. Může se tedy stát, že vybere spoj, který mezitím
odjel.
• Platnost zvoleného času – analogicky se zvolenými stanicemi, i tabulka se spoji obsahuje nadpisy.
• Zda vybraný spoj již není v tabulce hledání.
Proběhne-li kontrola v pořádku, SATableItemBean bean je zkopírováno pomocí tzv.
Copy konstruktoru - konstruktor třídy přijímá jako parametr instanci téže třídy a zkopíruje
všechny fieldy. Je-li kopírovaný field objektem (např. SALineBean), musí být také zkopírován
pomocí Copy konstruktoru.
Vytvořená kopie je přidána do ArrayListu<SATableItemBean> tableData, který reprezentuje obsah tabulky hledání.
Poté je nastaven příznak tableDataModified pro vlákno procházející SACheckerThread
(viz 5.2.4).
71
5.2. IMPLEMENTACE PLUGINU
Diagram aktivit z obrázku 5.3 byl mírně pozměněn: Výchozí stanici, cílovou stanici a
datum lze vybírat paralelně, jejich ověření probíhá až při přidávání spoje do vyhledávání.
5.2.3.4
Tabulka hledání
Tabulka hledání je aktualizována na konci každého cyklu ve vlákně SACheckerThread,
kontrolujícího počet volných míst u všech položek tabulky.
Díky tomu uživatel vidí vždy aktuální počet volných míst ve sledovaných spojích.
Při každém naplňování tabulky (tedy i při aktualizaci volných míst) je zároveň provedena kontrola aktuálnosti všech hledaných spojů. Spoje, které nejsou aktuální (uplynul čas
odjezdu), jsou z tabulky vyřazeny, nebo označeny šedou barvou řádku, pokud uživatel zvolil
možnost Zobrazovat stará hledání v nastavení pluginu.
Řazení položek: Kliknutím na záhlaví libovolného sloupce lze řádky tabulky podle tohoto
sloupce seřadit. Opakovaným kliknutím lze měnit směr řazení. Řazení je založeno na SWT
Snippetu 192.
SATableItemBean obsahuje za účelem řazení metody getStringColumn(int index)
a getLongColumn(int index):
Listener přiřazený ke všem sloupcům zavolá metodu
Collections.sort(ArrayList<SATableItemBean> data, Comparator comparator).
Použitý Comparator má přetíženou metodu compare():
Metoda podle indexu (čísla sloupce, na jehož záhlaví uživatel kliknul a který je tedy
řazen) zavolá buď SATableItemBean.getStringColumn(index), nebo
SATableItemBean.getLongColumn(index).
Tyto metody vrací String, nebo Long reprezentaci hodnoty vybraného sloupce, která je
dále porovnávána ve zbytku metody compare().
Tento způsob je výhodný vzhledem k různé reprezentaci dat v jednotlivých sloupcích.
Například sloupec Datum obsahuje datum ve tvaru Ww DD.MM. (Ww je zkratka dne
v týdnu).
Při řazení podle tohoto sloupce je proto v compare() volána metoda SATableItemBean.getLongColumn(1), která vrátí počet milisekund reprezentující dané datum (zaokrouhlené na minuty).
5.2.4 Kontrola volných míst
Kontrola volných míst probíhá ve vlákně SACheckerThread ve while cyklu metody
Run() (dále jen While cyklus), jehož struktura odpovídá té popsané v kapitole 4.4.5.1.
Cyklus běží, dokud jsou v tabulce hledání platné spoje. Protože kontrola běží v samostatném vlákně, bylo nutné ošetřit chyby ConcurrentModificationException, způsobené
paralelním modifikováním Listu tableData, obsahujícího položky tabulky hledání – obsah
tabulky totiž může být kdykoli změněn uživatelem.
Na začátku cyklu je proto obsah tableData zkopírován do lokálního ArrayListu a kontrola
probíhá nad lokálním Listem.
72
KAPITOLA 5. PLUGIN SA NOTIFY
5.2.4.1
Kopírování položek
V průběhu procházení Listu tableData za účelem zkopírování vždy před přístupem k další
položce proběhne kontrola, zda nedošlo ke změně obsahu Listu. K tomu slouží příznak
tableDataModified, nastavovaný při změně obsahu tabulky hledání uživatelem.
Jestliže aplikace zjistí, že byla provedena modifikace Listu, zahodí dosud zkopírovaný
obsah a začne kopírování od začátku.
Tímto způsobem je zajištěno ošetření proti chybám ConcurrentModificationException
a zároveň ArrayList tableData nemusí být pro účely kopírování uzamčen pro modifikaci
uživatelem.
5.2.4.2
Volná místa spoje
Ve While cyklu jsou kontrolována volná místa postupně pro všechny položky tabulky
hledání.
V seznamu spojů pro konkrétní den, který vrací server, je HTML tag <DIV>, obsahující
počet volných míst, identifikován unikátním atributem ID.
Tento atribut je ale generován dynamicky a pokud dojde ke změně v seznamu spojů
(například se jedná o dnešní den a oproti předchozí kontrole je vráceno o jeden spoj méně,
neboť čas odjezdu prvního spoje uplynul), ID se změní.
Je proto nutné nalézt nejprve <DIV> obsahující atribut row:id, jehož hodnotou je
unikátní, neměnící se ID pro konkrétní spoj a následně procházením DOM struktury pomocí
Jsoup nalézt <DIV> obsahující volná místa.
5.2.4.3
Jsoup bug – HTML tag <A>
Při práci s HTML parserem Jsoup jsem objevil následující chybu:
Obsah tagu <A> je považován za text a není brán v úvahu při vytváření Jsoup objektu
Document, který reprezentuje DOM strukturu HTML stránky.
Obsah tagu musí tedy být samostatně parsován do nového objektu Document.
5.2.4.4
Spoje pro stejný den
Obrázek 5.11: Tabulka hledání, probíhá hledání pro více spojů na 1 lince
73
5.2. IMPLEMENTACE PLUGINU
Při kontrole konkrétního spoje ve While cyklu je načtená webová stránka uložena a při
kontrole následujícího spoje aplikace zkontroluje, zda se nejedná o stejnou linku a stejné
datum – pokud ano, není nutné znovu načítat stránku ze serveru.
Při typickém využití aplikace uživatel hledá volné místo pro několik různých spojů ve
stejný den, lišící se jen různými časy odjezdu (obr.5.11).
Je tedy výhodné, pokud program tuto skutečnost kontroluje a zbytečně nezatěžuje server
opakovaným stahováním stránky.
Vyhledání seznamu spojů na serveru navíc podle aktuálního zatížení serveru může trvat
i více než 10 s, dojde tedy i k významnému urychlení kontroly míst.
Proměnná „interface“: Proměnná interface, odesílaná na server jako jeden z parametrů
při každém HTML požadavku, reprezentuje počet kroků, které uživatel udělal ve webovém
rozhraní rezervace. Při prvním přístupu je odesílaná hodnota 0, při odesílání požadavku na
vložení spoje do košíku již musí být hodnota odesílaného parametru nastavena na 1.
Výše popsaný způsob kontroly volných míst pro spoje ve stejný den lze proto použít
pouze pokud při kontrole spojů nedochází k navýšení hodnoty parametru interface. K tomu
dochází při kontrole preferovaných míst a při automatické rezervaci spoje.
V opačném případě by došlo k chybě např. při následujícím scénáři:
• 1. Uživatel přidá 2 spoje Praha - Brno, odjíždějící 25. 6. ve 13:00 a ve 14:00.
• 2. Pro první spoj zapne automatickou rezervaci a nastaví preferovaná sedadla, pro druhý spoj
pouze preferovaná sedadla.
• 3. Aplikace zkontroluje první spoj, nalezne volné místo.
• 4. Aplikace zkontroluje, zda se jedná o preferované místo (dojde k navýšení proměnné interface).
• 5. Aplikace se místo pokusí zarezervovat (dojde k několikerému navýšení proměnné interface – nová hodnota závisí na úspěchu rezervace, případně na kroku rezervace, ve kterém
došlo k chybě např. z důvodu špatného přihlašovacího jména nebo nedostatečného kreditu).
• 6. Aplikace se pokusí zkontrolovat druhý spoj – zjistí, že se jedná o spoj pro stejnou linku a
den jako předchozí, proto znovu nenačte HTML stránku se spoji, použije uloženou předchozí
stránku.
• 7. Analýzou HTML stránky zjistí, že druhý spoj také obsahuje volná místa. Pokusí se odeslat na
server požadavek o rozpis sedadel pro kontrolu, zda se jedná o preferované sedadlo. V této chvíli
dojde k chybě, neboť je odeslána špatná hodnota proměnné interface a server na požadavek
odpoví přesměrováním na hlavní stránku, nebo stránku s informací o chybě.
Jak je vidět z bodu 5, hodnota proměnné interface po provedení rezervace (ale i po ověření
preferovaných míst) není přesně definována – záleží na úspěchu rezervace, případně na místě
výskytu chyby.
Sledovat správnou hodnotu by bylo složité. Aplikace proto raději v případě, že mohlo dojít ke změně hodnoty (předchozí spoj má zapnutou automatickou rezervaci nebo preferovaná
místa) vytvoří novou session a stránku se seznamem spojů stáhne znovu.
74
KAPITOLA 5. PLUGIN SA NOTIFY
5.2.5 Automatická rezervace
Pro fungování automatické rezervace nalezených míst musí uživatel vyplnit v Nastavení
pluginu číslo své kreditové jízdenky, heslo a cenový tarif, který bude použit při koupi jízdenky
(např. Dospělý nebo ISIC).
Aplikace poté může nalezená místa zarezervovat a uhradit z kreditu.
Heslo pro přístup ke kreditové jízdence je ukládáno do konfiguračního souboru šifrovaně
a je dešifrováno před odesíláním na server (server Student Agency nepoužívá žádné šifrování
pro odesílané heslo).
Tarif použitý při rezervaci je ukládán samostatně ke každému spoji. Do budoucna je tak
případně možné rozšířit plugin o možnost nastavit tarif každému spoji zvlášť. V současné
verzi je pro všechny spoje použit tarif zadaný v Nastavení pluginu, zvolená hodnota je ale
zkopírována do SATableItemBean reprezentující daný spoj.
Přihlášení: Při přihlašování přes webové rozhraní je na server odesílán spolu s číslem
kreditové jízdenky a heslem také atribut ID tagu <input type=”hidden”>.
Přihlášení proběhne úspěšně i bez odeslání tohoto parametru. Pro věrnější imitaci webového prohlížeče ho ale plugin odesílá také.
5.2.6 Úspěšné hledání
Obrázek 5.12: Bylo nalezeno volné preferované místo
Obrázek 5.13: Bylo nalezeno volné preferované sedadlo a bylo ihned rezervováno a uhrazeno
z kreditu
V případě úspěšného hledání je zavolána metoda SA.success(), která zobrazí informace
o úspěchu uživateli.
75
5.2. IMPLEMENTACE PLUGINU
Pojem „úspěšné hledání“ zahrnuje tyto stavy:
• Automatická rezervace je vypnutá:
– Nalezeno volné místo, nejsou nastavena preferovaná sedadla.
– Nalezeno volné místo, jedná se o preferované sedadlo.
– Nalezeno volné místo, sedadlo přiděluje steward/ka.
– Nalezeno volné místo, ale nepodařilo se ověřit, zda se jedná o preferované sedadlo.
• Automatická rezervace je zapnutá:
Nejsou nastavena preferovaná místa:
– Nalezeno a rezervováno volné místo.
– Nalezeno volné místo, došlo k chybě při rezervaci – špatné číslo kreditové jízdenky nebo
heslo.
– Nalezeno volné místo, došlo k chybě při rezervaci – nedostatečný kredit.
– Nalezeno volné místo, došlo k chybě při rezervaci (např vypršel timeout spojení, server
je přetížen).
Jsou nastavena preferovaná místa:
– Nalezeno a rezervováno volné preferované sedadlo.
– Nalezeno a rezervováno volné místo, sedadlo přiděluje steward/ka.
– Nalezeno volné preferované sedadlo, došlo k chybě při rezervaci – špatné číslo kreditové
jízdenky nebo heslo.
– Nalezeno volné preferované sedadlo, došlo k chybě při rezervaci – nedostatečný kredit.
– Nalezeno volné preferované sedadlo, došlo k chybě při rezervaci (např vypršel timeout
spojení, server je přetížen).
– Nalezeno volné místo, ale nepodařilo se ověřit, zda se jedná o preferované sedadlo.
Pro každý z těchto stavů je zobrazena zpráva informující uživatele o daném stavu.
Součástí zobrazeného dialogu je buď odkaz na stránku s výpisem spojů (v případě, že
bylo nalezeno volné místo, ale nebylo rezervováno – obr. 5.12) nebo odkaz na stránku se
seznamem rezervací na kreditové jízdence (nalezené místo bylo rezervováno – obr. 5.13).
Aplikace také zobrazí výstražnou zprávu, pokud bylo rezervováno místo ve spoji, který
uživatel mezitím z tabulky hledání odstranil (obr. 5.14), nebo u kterého vypnul automatickou
rezervaci.
Obrázek 5.14: Byl rezervován spoj, který uživatel odstranil z tabulky hledání
76
KAPITOLA 5. PLUGIN SA NOTIFY
5.2.6.1
Rezervované sedadlo
Při úspěšné rezervaci program ve zprávě o úspěchu vypíše i číslo rezervovaného sedadla
(obr. 5.13 a 5.14).
Chyby při zjišťování čísla rezervovaného sedadla (např. v případě rezervace přestupních
spojů – viz kapitola 5.2.7) jsou odchytávány zvlášť a uživatel na ně není upozorněn, pouze
ve zprávě o úspěchu neuvidí rezervované sedadlo.
5.2.7 Přestupní spoje
Hledání míst v přestupních spojích: Původní návrh pluginu počítal s kontrolou, zda
se jedná o přímý spoj. V opačném případě by program nepovolil spoj přidat do vyhledávání
– viz diagram aktivit na obr. 5.3.
Struktura seznamu vyhledaných spojů je ale shodná pro přímé spoje i spoje přestupní –
rezervační systém zobrazuje informace o přestupech až v dalším kroku rezervace.
Plugin proto umožňuje bezproblémové vyhledávání volných míst i v přestupních spojích.
Rezervace přestupních spojů: Automatická rezervace funguje pro přestupní spoje také
bez problémů.
Nefunguje pouze kontrola preferovaných sedadel: U přestupních spojů je vždy minimálně
u jednoho spoje přidělováno sedadlo stewardem/kou. To i v případě, kdy při rezervaci toho
samého spoje jednotlivě lze sedadlo libovolně zvolit – jedná se pravděpodobně o omezení
rezervačního systému Student Agency.
Plugin v současné implementaci u všech přestupních spojů nalezne na stránce s výběrem
sedadla informaci o přidělování sedadla stewardem/kou a nepokusí se proto o kontrolu preferovaných sedadel.
5.2.8 Chyby při hledání volných míst
V době vzniku této práce byl rezervační systém Student Agency v nejvíce exponovaných
časech často přetížen. I při testování programu docházelo k timeoutu spojení (timeout
pokusu o spojení je nastaven na 10 vteřin), případně docházelo k chybě, když server místo
požadované stránky vrátil stránku s informací „Server je přetížen, zkuste to prosím později“.
Bylo proto nutné ošetřit případy dočasné ztráty spojení.
5.2.8.1
Požadavky na ošetření chyb spojení
Stanovil jsem následující požadavky na ošetření chyb spojení:
• Při chybě by nemělo dojít k přerušení hledání – může se jednat pouze o timeout spojení
a příští pokus bude úspěšný.
• Při opakovaných chybách by mělo dojít k prodloužení intervalu kontroly volných míst,
aby nedocházelo ke zbytečně častým pokusům o připojení při dlouhodobém výpadku.
77
5.2. IMPLEMENTACE PLUGINU
• Uživatel by měl být na ztracené spojení jednorázově upozorněn.
• Nemělo by dojít k přerušení hledání ani po mnohonásobném neúspěchu – to by mohlo
být pro uživatele frustrující v případě, kdy by měl server periodické výpadky a uživatel
by musel po každém delším výpadku hledání znovu manuálně spustit.
5.2.8.2
Navrhnuté řešení
Obrázek 5.15: Upozornění uživatele na ztracené spojení
• Všechny metody, které přistupují na server, nebo vyhledávají data na HTML stránkách
vrácených serverem, odhazují výjimky.
• Výjimky jsou zachycené ve While cyklu třídy SACheckerThread.
• Při vyskytnutí výjimky je tato uložena do .log souboru a je o 1 navýšena hodnota
integeru failCounter.
• FailCounter je vynulován, pokud jeden cyklus (kontrola všech spojů z tabulky hledání)
proběhl úspěšně.
• Pokud failCounter dosáhne hodnoty konstanty MAX_FAILS (výchozí nastavení
je na hodnotu 5), je uživateli zobrazena informace o pravděpodobně ztraceném spojení
a informace, že program se dál bude pokoušet o navázání spojení (obr. 5.15).
While cyklus nadále pokračuje a failCounter je při chybě stále navyšován.
• Vždy, když hodnota failCounter dosáhne násobku konstanty MAX_FAILS (včetně
případu kdy je failCounter roven MAX_FAILS), zvýší se interval hledání (uložen ve
fieldu INTERVAL třídy SACheckerThread – viz 4.4.5) o hodnotu INTERVAL_DEFAULT
(původní interval, nastaven na 70 s) a odchylka (field DEVIATION) o hodnotu DEVIATION_DEFAULT.
• Při úspěšném pokusu o připojení jsou interval i odchylka nastaveny zpět na své původní
hodnoty.
5.2.9 Chyby v synchronizaci vláken
Způsob kopírování ArrayListu tableData ve vlákně SACheckerThread, popsaný v kapitole 5.2.4.1, zabraňuje vznikům výjimek ConcurrentModificationException.
Může ale docházet k chybě, která nevyvolá výjimku, ale způsobí nesprávné chování
programu, konkrétně dvojí rezervaci jednoho spoje:
78
KAPITOLA 5. PLUGIN SA NOTIFY
Může dojít k situaci, kdy je spoj rezervován a SACheckerThread zavolá metodu pro
vyhodnocení úspěchu SA.success().
Dříve, než metoda success() doběhne a dojde k odstranění nalezené položky z tabulky
hledání, doběhne While cyklus v SACheckerThread a začne odznovu – tedy zkopíruje si opět
ArrayList tableData, který ovšem stále obsahuje již rezervovaný spoj, který je následně
podruhé zarezervován.
K této chybě docházelo vždy, když kontrola volných míst trvala déle, než byl nastavený
interval kontroly (field INTERVAL třídy SACheckerThread). V takovém případě totiž po
ukončení While cyklu začne ihned cyklus nový (vlákno není na konci cyklu uspáno).
Na tuto chybu by byl uživatel upozorněn dialogem z obr. 5.14, jejímu vzniku lze ale
zamezit použitím jednoduchého zámku:
Na začátku metody success() je field třídy SA, boolean updatingTable nastaven na
true a na konci této metody zpět na výchozí hodnotu, false.
Na konci While cyklu ve třídě SACheckerThread je smyčka
w h i l e ( ! SA . getUpdatingTable ( ) ) { s l e e p (WAITING_INTERVAL ) ; }
Konstanta WAITING_INTERVAL je nastavena na 500 ms. Tato hodnota je zbytečně
vysoká, vzhledem k minimální době trvání jednoho cyklu, nastavené na 70 s ± 20 s, to ale
nevadí.
5.2.10 Nastavení pluginu
Obrázek 5.16: Dialog Nastavení pluginu SA Notify
Dialog Nastavení je vytvořen ve třídě SAPreferences, která je potomkem abstraktní
třídy Preferences.
79
5.2. IMPLEMENTACE PLUGINU
Tato třída realizuje všechny případy užití z kapitoly 5.1.2.2.
Třída SAPreferences vytvoří instanci třídy SAPreferencesBean, obsahující gettery a settery pro všechny fieldy reprezentující jednotlivé možnosti nastavení. Přes třídu SAPreferencesBean jsou pak všechny položky dialogu Nastavení pomocí JFace Data Binding provázány
s příslušnými fieldy.
Všechna nastavení jsou uložena do CommentedProperties a při ukončení aplikace do
souboru plugins/SA/properties-SA.ini.
80
KAPITOLA 6. TESTOVÁNÍ
Kapitola 6
Testování
6.1
Simple Code Metrics
Simple Code Metrics je plugin pro IDE NetBeans, umožňující měření zdrojových kódu
projektu. Kromě obecných informací (počet řádků kódu, objektů, metod) jsou jeho výstupem
i hodnoty Lack Of Cohesion Metrics a Cyclomatic complexity.
6.1.1 Lack of Cohesion in Methods
Lack Of Cohesion Metrics (LCOM) je metoda analýzy zdrojového kódu, jejímž výstupem je informace o počtu nesouvisejících úkolů, které jsou prováděny v jedné třídě. Je-li
tedy hodnota LCOM příliš vysoká, třída provádí navzájem nesouvisející operace, stává se
nepřehlednou a je vhodné rozdělit ji do několika tříd.
Existují 4 metody měření (LCOM1 až LCOM4). Více o Lack of Cohesion in Methods a
metodice měření různých verzí LCOM viz např. [24] nebo [2].
Sledoval jsem hodnotu LCOM3 u všech tříd rodičovské aplikace i pluginu SA Notify.
LCOM3 dosahuje hodnot 0 až 2, hodnoty větší než 1 jsou považovány za signál k refaktoringu – rozdělení třídy do několika menších tříd.
Všechny třídy aplikace mají hodnotu LCOM3 menší než 1.
6.1.2 Cyclomatic complexity
Cyclomatic complexity je další způsob analýzy kódu. Udává počet lineárně nezávislých
cest skrz metodu ([12], [31]). Např. příkazy if tedy zvyšují hodnotu cyclomatic complexity.
Metoda s hodnotou cyclomatic complexity (dále též CC) větší než 15 jsou považovány
za příliš komplexní a doporučuje se jejich refaktoring.
Analýzou pomocí Simple Code Metrics byly odhaleny tyto metody s nejvyšší hodnotou
CC:
• SA.success() ... CC 21
• SA.setPluginBody() ... CC 18
81
6.2. UŽIVATELSKÉ TESTY
• SACheckerThread.run() ... CC 17
• SACheckerThread.checkPreferredSeats() ... CC 16
Metody SACheckerThread.run() a SACheckerThread.checkPreferredSeats()
jsou krátké a považuji je za dostatečně přehledné, rozhodl jsem se proto neměnit je.
Provedl jsem ale refaktoring metod success() a setPluginBody() rozdělením na několik menších.
Po refaktoringu byly naměřeny následující hodnoty:
• SA.success_ReservationOn() ... CC 10
• SA.setPluginBody() ... CC < 8
SA.success_ReservationOn() je nejkomplexnější z metod, na které byla rozdělena
původní metoda success().
Simple Code Metrics uvádí jen 4 nejvyšší hodnoty v rámci testovaného Java Package.
Žádná z metod, vzniklých rozdělením SA.setPluginBody(), mezi 4 nejvyššími hodnotami
nebyla. O CC metod, na které byla metoda setPluginBody() rozdělena, můžeme tedy s jistotou říct jen to, že je menší než 8 (nejnižší hodnota ze 4 nejvyšších, které Simple Code
Metrics zobrazil).
6.2
Uživatelské testy
V průběhu i na konci vývoje rodičovské aplikace a pluginu SA Notify jsem prováděl
testování správného fungování všech funkcionalit programu.
Velkou pozornost jsem věnoval zejména všem možným scénářům průběhu hledání a rezervace volného místa v pluginu SA Notify. Vzhledem k tomu, že tento plugin přistupuje
k účtu uživatele na serveru Student Agency a uskutečňuje platby za rezervované jízdenky,
je správná funkčnost pluginu klíčová.
V průběhu vývoje pluginu SA Notify jsem vývojovou verzi poskytl několika dobrovolníkům, kteří aplikaci používali pro hledání volných míst a později (když byla tato funkce
implementována) i pro automatickou rezervaci míst. Všechny chyby aplikace, které tito uživatelé objevili, byly odstraněny.
V současné době nejsou známy žádné chyby aplikace.
6.3
Testování aplikace na různých platformách
Jak již bylo zmíněno v kapitole 4, testování aplikace probíhalo v průběhu vývoje na OS
Windows 7, Windows XP a Linuxové distribuci Ubuntu v. 10.10, GUI GNOME v. 2.32.
Byla otestována funkčnost aplikace i správné zobrazení všech prvků GUI.
Při testování rodičovské aplikace i pluginu SA Notify byly odhaleny tyto chyby grafického
rozhraní:
82
KAPITOLA 6. TESTOVÁNÍ
• Layout dialogu Možnosti je rozházený na Ubuntu GNOME (dále jen Ubuntu).
Před otevřením Shellu dialogu Možnosti je nutné zavolat metodu shell.pack(). Layout
se poté zobrazí správně.
• Na Ubuntu dojde ke správnému nastavení velikosti tabulky spojů pluginu SA Notify
až při změně velikosti okna. Po otevření aplikace je výška tabulky nastavena špatně.
Velikost této tabulky je nastavována pomocí Shell Resize Listeneru (viz kapitola 5.2.2.2).
Na OS Windows je spuštění aplikace považováno za Resize událost a příslušný Listener tak nastaví správnou velikost hned po spuštění. Na Ubuntu po spuštění Resize
Listenery zavolány nejsou.
Pro opravení chyby proto stačilo před otevřením Shellu hlavního okna aplikace zavolat
shell.layout() a poté zavolat metodu, která nastavuje správnou velikost tabulky.
• Na Ubuntu je špatně pozicován horní banner u pluginu SA Notify – konec obrázku
byl uříznutý.
Obrázek byl pozměněn tak, aby na jeho konci byla prázdná bílá plocha, takže nyní
dojde k odříznutí pouze této plochy.
• Při roztahování okna programu do šířky na OS Windows nedochází k roztahování
sloupců tabulky hledání pluginu SA Notify. Na Ubuntu dojde k roztažení posledního
sloupce, obsahujícího tlačítko pro vypnutí/zapnutí automatické rezervace. Layout pluginu tím není nijak narušen a při ručním roztažení některého z předcházejících sloupců
se šířka posledního sloupce zmenší na přednastavenou velikost.
• Při nastavení minimalizace do oznamovací oblasti nejsou na Ubuntu zobrazovány ikony
v kontextovém menu nad ikonou v oznamovací oblasti.
6.4
Testování použitelnosti aplikace
V této kapitole se zabývám testováním použitelnosti aplikace z pohledu běžného uživatele
metodou kognitivního průchodu.
Test probíhal na šesti osobách, které jsou pro větší přehlednost reprezentovány dvěma
personami. Testované osoby byly vybírány tak, aby se jedné z person podobaly co největším
počtem vlastností.
6.4.1 Metoda kognitivního průchodu
Metoda kognitivního průchodu je založena na postupném plnění předem daných úkolů
uživatelem.
Činnost uživatele je monitorována. Po každém úkolu si klademe následující otázky:
• Je akce vidět?
Každý krok úkolu by měl být vidět, aby nebyla kladena zbytečná zátěž na uživatelovu
paměť. Při opakování úkolu tak může být vzpomínání nahrazeno rozpoznáváním –
uživatel rozpozná např. tlačítko pro hledanou akci.
83
6.4. TESTOVÁNÍ POUŽITELNOSTI APLIKACE
• Zvolil si uživatel správný cíl? Pochopil uživatel správně zadání úkolu a pustil se
správným směrem?
• Zvolil uživatel správnou akci?
Různé akce by měly být dostatečně popsány a odlišeny tak, aby uživatel poznal, že
zvolil správnou akci, vedoucí k cíli.
• Rozumí uživatel zpětné vazbě?
Po provedení akce by měl uživatel poznat, že došlo k jejímu úspěšnému dokončení.
Dále byl sledován čas potřebný pro splnění jednotlivých akcí.
6.4.2 Persony
Persony slouží ke kategorizaci uživatelů, provádějících testy použitelnosti. Každý uživatel
je přiřazen jedné personě.
Uvedené odpovědi na otázky pro personu jsou průměrným výsledkem uživatelů přiřazených
této personě.
V poznámce mohou být uvedeny rozdílné odpovědi uživatelů patřících pod jednu personu, pokud by tyto rozdíly mohly být důležité pro vyhodnocení výsledků testování. Za
jménem persony je v takovém případě uvedeno číslo konkrétního uživatele, který prováděl
testy (např. Karel 2).
• Persona Jitka
Věk: 21 let
Vzdělání: Studuje VŠ technického zaměření
Práce s PC: Pokročilý uživatel.
Jitka používá počítač denně k práci i zábavě. Nedělá jí problémy instalovat a zkoušet
nové programy nebo hry.
Dokáže online vyhledat řešení případných problémů se svým počítačem. Ovládá základy HTML.
• Persona Karel
Věk: 52 let
Vzdělání: VŠ ekonomického zaměření
84
KAPITOLA 6. TESTOVÁNÍ
Práce s PC: Pouze na čistě uživatelské úrovni.
Karel s počítačem pracuje denně v práci. Je zvyklý používat aplikace z rodiny MS
Office a internetový prohlížeč.
Používá stále stejné aplikace a nedokáže si sám bez pomoci osvojit práci s novým
programem.
Nemá žádné zkušenosti s instalací ani údržbou programů – v případě jakéhokoli problému s PC je zvyklý požádat o pomoc technickou podporu. Zásadně nečte jakékoli
vyskakovací dialogy.
Karel 1 uvedl následující odpovědi na otázky:
- Jaký používáte operační systém?
- „Office.“
- Jaký používáte internetový prohlížeč?
- „Seznam nebo Google. Nejraději mám Seznam.“
6.4.3 Zadané úkoly
Před zahájením testování byli všichni testovaní uživatelé pouze slovním popisem krátce
seznámeni s účelem aplikace a pluginu SA Notify. Plnění prvního úkolu tak bylo vůbec první
interakcí těchto uživatelů s aplikací.
Všechny testy probíhaly na OS Windows 7.
6.4.4 Úkol 1 – nastavení rodičovské aplikace
• 1. Spusťte aplikaci.
• 2. Nastavte minimalizaci programu do oznamovací oblasti (tj. do pravého dolního rohu
obrazovky).
• 3. Otevřete dialog Možnosti a nastavte přehrávání libovolného zvuku u všech vyskakovacích dialogů.
• 4. Zkontrolujte, zda je k dispozici novější verze programu.
• 5. Otevřete dialog Možnosti a zkontrolujte, zda je vypnuto přehrávání všech zvuků
v Tichém režimu.
• 6. Zapněte Tichý režim.
6.4.5 Úkol 2 – práce s pluginem SA Notify
• 1. Přepněte na plugin SA Notify.
• 2. Zahajte hledání volných míst v libovolném spoji na trase Praha – Brno.
• 3. V nastavení pluginu vypněte zobrazování starých hledání.
85
6.4. TESTOVÁNÍ POUŽITELNOSTI APLIKACE
• 4. V nastavení pluginu nastavte preferovaná sedadla V uličce.
• 5. V nastavení pluginu nastavte automatickou rezervaci. Použijte libovolné přihlašovací
údaje.
• 6. Zahajte vyhledávání volných míst v libovolném spoji na trase Brno – Praha.
• 7. Zobrazte historii hledaných spojů.
6.4.6 Výsledky testování
Průběh testování a odpovědi na kladené otázky u dílčích úkolů jsou v příloze C. Zde je
uveden pouze rozbor výsledků testování.
Zjištěné nedostatky: Byly zjištěny následující nedostatky rodičovské aplikace nebo pluginu SA Notify:
• Zpočátku je pro uživatele matoucí dvojí dialog s možnostmi nastavení – jeden v menu
Nastavení – Možnosti, druhý zobrazovaný tlačítkem Nastavení pluginu SA Notify.
• Volbu pro změnu stavu Tichého režimu většina uživatelů očekává i v dialogu Možnosti.
• Pro méně zkušené uživatele (persona Karel) jsou nastavení rodičovské aplikace málo
přehledná a trvá jim déle je v menu nalézt.
• Tlačítko Přidat spoj je pro méně zkušené uživatele málo výrazné.
Navržené změny: Na základě zjištěných nedostatků aplikace byly navrženy tyto změny:
• Přidat volbu pro vypnutí/zapnutí Tichého režimu do dialogu Možnosti.
• Zvýraznit tlačítko Přidat spoj.
• Přesunout některé položky z menu Nastavení a Nápověda na novou lištu v horní části
okna aplikace, kde budou přímo přístupné.
Závěr: Testování metodou kognitivního průchodu dopadlo velmi dobře:
I uživatelé s velmi malými zkušenostmi (persona Karel, dále též nezkušení uživatelé) jsou
schopni aplikaci bez větších problémů spustit a používat plugin SA Notify.
Velmi důležitá se ukázala skutečnost, že maximum ovládacích prvků pluginu SA Notify
je vidět v základním okně pluginu. Nezkušení uživatelé měli problémy s nalezením položek
menu, které nejsou viditelné na první pohled. Základní obsluhu pluginu SA Notify ale díky
přehlednosti GUI zvládali většinou bez problémů.
Menu pluginů je dostatečně výrazné, všichni testovaní uživatelé pochopili jeho funkci
a způsob přepínání pluginů.
Je důležité zvolit takové výchozí nastavení programu, které bude vyhovovat co největšímu
procentu uživatelů. Mnoho uživatelů totiž není zvyklých měnit nastavení používaných programů a orientovat se v možnostech nastavení.
86
KAPITOLA 7. PLUGIN DIVADLO JÁRY CIMRMANA
Kapitola 7
Plugin Divadlo Járy Cimrmana
7.1
Analýza a návrh řešení pluginu
Plugin Divadlo Járy Cimrmana (dále jen DJC) slouží ke kontrole volných míst na představení v Žižkovském Divadle Járy Cimrmana.
Představení tohoto divadla bývají vyprodána během několika minut od zveřejnění programu na příští měsíc. Podobně jako v případě pluginu SA Notify ale dochází k nevyzvednutí
rezervací a v následujících dnech jsou některá místa uvolněna.
Plugin DJC umožňuje hlídat vybraná představení a upozornit na volná místa.
7.1.1 Funkční požadavky
Byly stanoveny tyto funkční požadavky:
• upozornění na volná místa na vybrané představení
• možnost volby minimálního počtu míst, na která program upozorní
• ukládání přihlašovacích údajů
Lístky uvolněné z důvodu propadlé rezervace nebývají znovu rezervovány tak rychle jako
v případě lístku Student Agency. Není proto nutné, aby plugin nalezená volná místa ihned
rezervoval. Tato funkcionalita může být případně doplněna s novými verzemi pluginu.
Důležitým funkčním požadavkem je možnost nastavení minimálního počtu volných míst,
na která plugin upozorní. Většina návštěvníků divadla kupuje na představení alespoň 2 lístky,
nemělo by tedy smysl, kdyby plugin upozorňoval na jediné volné místo.
7.2
Implementace pluginu
Plugin byl implementován s využitím postupu a předpřipravených tříd popsaných v programátorské příručce (příloha D).
Implementace pluginu díky tomu trvala relativně krátkou dobu.
87
7.2. IMPLEMENTACE PLUGINU
Oproti doporučené struktuře tříd pluginu (obr. D.2) byla provedena jediná změna: třída
DJCCheckerThread, sloužící pro kontrolu volných míst, není instanciována přímo z hlavní
třídy pluginu (třída DJC), ale z nově přidané třídy DJCChecker. Ta, obdobně jako třída
SAChecker pluginu SA Notify, obsahuje metody pro přístup k rezervačnímu systému a
parsování dat z HTML kódu.
7.2.1 Grafické rozhraní
Implementace pluginu probíhala až po provedení testů použitelnosti, popsaných v kapitole 6.4.
Na základě výsledků těchto testů bylo navrženo co nejjednodušší grafické rozhraní programu, které obsahuje pouze pole pro zadání přihlašovacího jména a hesla pro přístup k rezervačnímu systému (obr. 7.1) a 2 tabulky (obr. 7.2).
V tabulce vlevo je vypsán program všech představení, vpravo jsou představení, u kterých
probíhá kontrola volných míst.
Obrázek 7.1: Údaje pro přihlášení k rezervačnímu systému
Obrázek 7.2: Hlavní část těla pluginu DJC. Vlevo tabulka s programem divadla, vpravo
představení, u nichž jsou hlídána volná místa.
88
KAPITOLA 7. PLUGIN DIVADLO JÁRY CIMRMANA
7.2.2 Tlačítka
Z testů použitelnosti pluginu SA Notify vyplynulo, že tlačítka, použitá pro přidání/odebrání spoje z vyhledávání jsou málo výrazná.
Pro akce zahájení/ukončení hlídání volných míst byla proto navržena vlastní, podstatně
výraznější tlačítka.
Tlačítka jsou vykreslována na SWT widget Composite, u kterého se mění obrázek na
pozadí při najetí nebo kliknutí myší.
Text tlačítek je vykreslován pomocí SWT třídy GC ze zadaného Stringu. Při změně jazyka
v nastavení aplikace se tedy i texty tlačítek změní podle aktuální jazykové verze.
7.2.3 Minimální počet míst
Pro zadání minimálního počtu volných míst, na která má plugin upozornit, jsem použil
rozbalovací seznam s přednastavenými hodnotami.
Seznam obsahuje volby 1 až 10. Rezervační systém divadla neumožňuje rezervovat více
než 10 lístků v rámci jednoho účtu, použitý rozsah hodnot je tedy dostatečný.
Po přidání představení do vyhledávání může uživatel zvolenou hodnotu kdykoli změnit
pomocí rozbalovacího seznamu u každého představení.
7.2.4 Interval kontroly volných míst
Plugin kontroluje volná místa každých 5 minut ± 90 s.
Jak již bylo zmíněno výše, uvolněná místa nebývají opět rezervována příliš rychle (obvykle místo zůstane volné minimálně několik desítek minut), není tedy nutné používat kratší
interval a zbytečně zatěžovat server.
89
7.2. IMPLEMENTACE PLUGINU
90
KAPITOLA 8. DISTRIBUCE
Kapitola 8
Distribuce
8.1
Licence:
Program je šířen pod licencí GNU General Public License v. 3.
8.2
Verze knihovny SWT
Pro úspěšné spuštění aplikace je třeba použít správnou verzi knihovny SWT podle aktuální platformy.
S aplikací jsou distribuovány následující verze SWT:
• Windows 32 b.
• Windows 64 b.
• Linux 32 b.
• Linux 64 b.
• OS X 32 b.
• OS X 64 b.
Po spuštění aplikace je automaticky načtena verze SWT knihovny, odpovídající platformě. Pro výběr správně verze SWT bylo použito řešení popsané v [15].
Díky tomuto řešení lze aplikaci distribuovat v podobě jediného distribučního balíčku,
který lze spustit na všech zmíněných platformách.
Funkčnost tohoto řešení byla ověřena na OS Windows 7 32 b., Windows 7 64 b., Windows
XP 32 b. a Ubuntu 32 b.
91
8.3. SPUŠTĚNÍ APLIKACE
8.3
Spuštění aplikace
8.3.1 Launch4j
Běžní uživatelé, používající OS Windows, často neznají soubory .jar a nevědí, že se
jedná o spouštěcí soubor aplikace. Souborům .jar navíc nelze nastavit libovolnou ikonu, jako
souborům .exe, a zvýraznit tak, že se jedná o spouštěcí soubor.
Součástí kořenového adresáře distribučního balíčku je proto soubor SANotify.exe, kterým
lze aplikaci spustit. Ve stejném adresáři je i soubor SANotify.jar. Je jedno, který ze souborů
uživatel pro spuštění zvolí.
Pro vytvoření souboru SANotify.exe jsem použil jednoduchý program Launch4j.
Launch4j je poskytován zdarma i pro komerční účely a umožňuje rozsáhlá nastavení pro
vytvoření .exe souboru, například:
• Kontrolu verze JRE
• Splash Screen
• Nastavení ikony .exe souboru
• Vlastní jméno procesu – ve správci úloh je zobrazováno zvolené jméno procesu, ne
pouze javaw.exe, jako při spuštění pomocí souboru .jar.
Spuštění aplikace pomocí vytvořeného SANotify.exe probíhá následovně:
• Proběhne kontrola verze JRE. Jestliže není nalezena verze 1.7, program zobrazí upozornění a nabídne otevření webové stránky pro stažení Javy 1.7.
• Je zobrazen Splash Screen, totožný se Splash Screenem samotné aplikace. Spuštění
SANotify.jar pomocí SANotify.exe trvá několik vteřin, je proto vhodné zobrazit Splash
Screen již při spuštění SANotify.exe. Jakmile je spuštěn .jar, první Splash Screen je
zavřen a je nahrazen Splash Screenem z SANotify.jar.
8.3.2 Spouštění přes příkazovou řádku
Při spouštění aplikace přes příkazovou řádku na OS Windows je nutné zadat ručně
použitou verzi Javy pomocí argumentu –version:1.7+. Jedná se o bug JRE 1.7. Celý
příkaz je tedy:
j a v a – v e r s i o n : 1 . 7 + −j a r s a n o t i f y . j a r
8.3.3 Spuštění bez GUI
V současné době lze aplikaci spustit pouze s grafickým rozhraním.
Navržená architektura aplikace ale do budoucna umožní snadné rozšíření o možnost
spuštění bez GUI např. na vzdáleném serveru.
Veškerá nastavení aplikace i pluginu SA Notify jsou uložena v konfiguračních souborech,
možnost konfigurace programu bez grafického rozhraní je tak v zásadě již vyřešena.
92
KAPITOLA 8. DISTRIBUCE
8.3.4 Adresářová struktura
Na obrázku 8.1 je adresářová struktura aplikace. Na obrázku 8.2 je obsah kořenového
adresáře.
Adresářová struktura byla volena tak, aby v kořenovém adresáři bylo co nejméně souborů
a složek. Uživatel se tak může snadno zorientovat a rychle nalezne spouštěcí soubor aplikace.
Obrázek 8.1: Adresářová struktura aplikace
Obrázek 8.2: Obsah kořenového adresáře aplikace
93
8.3. SPUŠTĚNÍ APLIKACE
94
KAPITOLA 9. ZÁVĚR
Kapitola 9
Závěr
V rámci této práce jsem vypracoval rešerši existujících řešení pro rezervaci spojů ve
společnosti Student Agency, s.r.o. (kapitola 2.1) a navrhl vlastní modulární aplikaci.
Při návrhu aplikace (kapitola 3) jsem věnoval velkou pozornost její snadné rozšiřitelnosti
o nové zásuvné moduly. Aplikace byla navržena tak, aby se programátor nového pluginu mohl
soustředit pouze na aplikační logiku svého pluginu. Integrace do zbytku aplikace proběhne
automaticky. Zároveň jsem navrhl množství univerzálních tříd a metod, které mohou být
užitečné při tvorbě typického pluginu.
Plugin SA Notify, určený ke kontrole volných míst ve spojích Student Agency, byl oproti
původnímu zadání práce rozšířen o mnoho nových funkcionalit. V současné verzi disponuje
bohatými možnostmi nastavení a umožňuje automatickou rezervaci nalezených spojů.
Dále byl implementován plugin pro hlídání volných míst v Žižkovském Divadle Járy
Cimrmana. Při jeho vytváření byla v praxi ověřena kvalita návrhu aplikace. Díky snadné
integraci nového pluginu do zbytku aplikace a připravené struktuře tříd pluginu probíhal
vývoj velmi rychle.
Testování použitelnosti aplikace a pluginu SA Notify pro předpokládané cílové uživatele
(kap. 6.4) prokázalo použitelnost i pro méně zkušené uživatele. Zároveň byly analýzou
výsledků testování stanoveny návrhy pro vylepšení aplikace, z nichž některé byly použity
při vývoji pluginu Divadlo Járy Cimrmana.
Vytvořil jsem také programátorskou příručku pro tvorbu nových pluginů (příloha D).
Při její tvorbě jsem se snažil o co největší stručnost a přehlednost, tak aby tvůrce nového
pluginu mohl již po zběžném prostudování příručky začít programovat. Na web aplikace
(http://sanotify.cz) jsem pro zájemce o tvorbu nových pluginů umístil zdrojové kódy,
javadoc dokumentaci, programátorskou příručku i celou tuto práci.
9.1
Přínos práce
Při vývoji aplikace jsem se seznámil s množstvím nových technologií. Za velmi přínosné
považuji zejména seznámení s knihovnou SWT, Java Layout Managerem MigLayout a
výborným HTML parserem Jsoup. Dále jsem si lépe osvojil práci s IDE NetBeans a jeho
nástroji pro správu knihoven, refaktoring projektu a snadnou internacionalizaci projektu.
95
9.1. PŘÍNOS PRÁCE
Zajímavá byla také zkušenost s testy použitelnosti. Dosud jsem jejich význam podceňoval, ukázalo se ale, že mohou být při návrhu GUI aplikace velmi přínosné a nelze je zcela
nahradit návrhem za pomoci pouze vlastní intuice.
96
PŘÍLOHA A. POUŽITÉ ZKRATKY A POJMY
Příloha A
Použité zkratky a pojmy
V této příloze je výpis použitých zkratek a použitých pojmů. V případě zkratek se ve
většině případů jedná o zkratky běžně používané v dané problematice.
A.1
Zkratky
AJAX Asynchronous JavaScript and XML
CC Creative Commons
CSS Cascading Style Sheets
ČVUT České vysoké učení technické v Praze
DPMLJ Dopravní podnik měst Liberce a Jablonce nad Nisou, a. s.
GUI – Graphical user interface – Grafické uživatelské rozhraní.
HTML Hypertext Mark-up Language
JRE Java Runtime Enviroment
JVM Java Virtual Machine
OS Operační systém
PC Personal Computer – osobní počítač
PHP PHP: Hypertext Preprocessor (rekurzivní zkratka)
UML Unified modeling language
97
A.2. POJMY
A.2
Pojmy
API – Application Programming Interface
Rozhraní určené pro komunikaci dalších programů s danou aplikací.
DOM – Document Object Model
Objektová reprezentace HTML nebo XML dokumentu, kde každý HTML tag představuje jeden objekt.
IDE – Integrated Development Environment
Vývojové prostředí, obecně software usnadňující programování.
Java SE – Java Platform, Standard Edition
Označení základního balíčku programovacího jazyka Java, který obsahuje virtuální
stroj, API základních knihoven i knihoven pro vytváření GUI aplikací (AWT, Swing).
PDF – Portable Document Format
Formát pro ukládání dokumentů od společnosti Adobe Systems.
URL – Uniform Resource Locator
Řetězec znaků, sloužící k jednoznačnému určení adresy webové stránky.
98
PŘÍLOHA B. ADRESÁŘOVÁ STRUKTURA PŘILOŽENÉHO CD
Příloha B
Adresářová struktura přiloženého CD
Obrázek B.1: Obsah přiloženého CD
• Adresář program:
– sanotify_v0.65 – obsahuje distribuční verzi aplikace.
– sanotify_v0.65_src – obsahuje zdrojové kódy aplikace:
- SANotify_developers – zdrojové kódy, projekt pro IDE NetBeans
- SANotify_libraries – použité externí knihovny
• Adresář text:
– budajan_thesis.pdf – elektronická verze této práce ve formátu PDF.
– LaTeX – text práce ve zdrojovém formátu LaTeX.
99
100
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
Příloha C
Výsledky testování metodou
kognitivního průchodu
Prerekvizity pro testování jsou uvedeny v kapitole 6.4, zde uvádím pouze výsledky - tedy
odpovědi na otázky, kladené u jednotlivých úkolů.
C.1
Úkol 1 – nastavení rodičovské aplikace
C.1.1 1. Spusťte aplikaci
Obrázek C.1: Adresář se soubory aplikace
Jitka
Je akce vidět?
Karel
Ano, je vidět soubor SANotify.exe i soubor SANotify.jar.
Oba soubory spustí aplikaci.
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
5s
5s
Jitka i Karel bez váhání spustili aplikaci pomocí souboru SANotify.exe.
101
C.1. ÚKOL 1 – NASTAVENÍ RODIČOVSKÉ APLIKACE
C.1.2 2. Nastavte minimalizaci programu do oznamovací oblasti (tj. do
pravého dolního rohu obrazovky)
Obrázek C.2: Menu Nastavení
Jitka
Karel
Ne – tlačítko je v menu Nastavení.
Je akce vidět?
Zvolil správný cíl?
Ano
Ne – Karel neznal pojem „Oznamovací oblast“ ani nevěděl, že některé programy se mohou minimalizovat do pravého dolního rohu.
Zvolil správnou akci?
Ano – Jitka 1 nejprve vyzkoušela
program vypnout stisknutím
křížku v pravém horním rohu.
Je zvyklá, že některé programy
se při této akci do oznamovací
oblasti schovají. Když zjistila,
že program se vypnul, znovu ho
spustila a vzápětí nalezla správné
nastavení v menu.
Ano – Karel našel správnou
položku v menu, ale nechápal, co
daná položka provede za akci.
Rozumí zpětné vazbě?
Ano
Ne
Čas
20 s
30 s
Karel neměl problém s nalezením správné položky v menu. Nechápal ale, k čemu položka
je – s touto funkcí programů se nikdy dříve nesetkal.
102
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.1.3 3. Otevřete dialog Možnosti a nastavte přehrávání libovolného zvuku
u všech vyskakovacích dialogů
Obrázek C.3: Dialog Možnosti, záložka Zvuky a upozornění
Jitka
Karel
Ne – tlačítko Možnosti je v menu Nastavení.
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
25 s
30 s
Tento úkol nedělal Jitce ani Karlovi problémy. Oba správně našli tlačítko Možnosti
v menu Nastavení a v dialogu ihned objevili záložku Zvuky a upozornění.
103
C.1. ÚKOL 1 – NASTAVENÍ RODIČOVSKÉ APLIKACE
C.1.4 4. Zkontrolujte, zda je k dispozici novější verze programu
Obrázek C.4: Menu Nápověda
Jitka
Karel
Ne – tlačítko je v menu Nápověda.
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano – Jitka 2 dlouho nemohla
položku „Zkontrolovat aktualizace“ nalézt, nakonec ale uspěla.
Ano – Karel 2 přehlédl v menu
Nápověda položku „Zkontrolovat
aktualizace“ a místo toho zvolil
možnost „O programu“ a následně
kliknul na domovskou stránku
programu, podle které zjistil, že
používá aktuální verzi.
Rozumí zpětné vazbě?
Ano
Ano
Čas
20 s
40 s
Karel není zvyklý ručně kontrolovat dostupnost aktualizací programů, proto nevěděl,
kde položku hledat. Nakonec ale uspěl.
104
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.1.5 5. Otevřete dialog Možnosti a zkontrolujte, zda je vypnuto přehrávání
všech zvuků v Tichém režimu
Obrázek C.5: Menu Možnosti, záložka Zvuky a upozornění
Jitka
Karel
Ano – po otevření dialogu Možnosti jsou další kroky vidět.
Je akce vidět?
Zvolil správný cíl?
Ano
Ne – Karel ze zadání úkolu
nepochopil, že lze měnit nastavení
vlastností Tichého režimu.
Zvolil správnou akci?
Ano
Ne – Karel pouze zapnul Tichý
režim v menu Nastavení. Až po
upřesnění zadání našel nastavení
Tichého režimu.
Rozumí zpětné vazbě?
Ano
Ano
Čas
15 s
50 s
105
C.1. ÚKOL 1 – NASTAVENÍ RODIČOVSKÉ APLIKACE
C.1.6 6. Zapněte Tichý režim
Obrázek C.6: Vlevo vypnutý Tichý režim, vpravo zapnutý Tichý režim
Jitka
Karel
Ne – tlačítko je v menu Nastavení.
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano
Rozumí zpětné vazbě?
Ano – Jitka 2 nemohla tlačítko
dlouho najít, hledala ho v dialogu
Možnosti.
Ano – Karel hledal možnost zapnutí Tichého režimu v dialogu
Možnosti, který zůstal otevřený
z předchozího úkolu. Následně se
vrátil ke tlačítku v menu Nastavení. Karel 2 byl zmatený dvěma
různými stavy tlačítka, nebyl si
jistý, který stav znamená zapnutý
Tichý režim, a který vypnutý (viz
obr. C.6).
Čas
20 s
30 s
Téměř všichni uživatelé hledali možnost zapnutí Tichého režimu nejprve v dialogu Možnosti.
106
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.2
Úkol 2 – práce s pluginem SA Notify
C.2.1 1. Přepněte na plugin SA Notify
Obrázek C.7: Vybraný plugin Divadlo Járy Cimrmana
Jitka
Karel
Ano
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
3s
5s
Před začátkem testování byl záměrně vybrán plugin Divadlo Járy Cimrmana (který
v době testování neměl implementované GUI). Všichni uživatelé ale ihned správně přepnuli
na plugin SA Notify.
107
C.2. ÚKOL 2 – PRÁCE S PLUGINEM SA NOTIFY
C.2.2 2. Zahajte hledání volných míst v libovolném spoji na trase Praha –
Brno
Obrázek C.8: Plugin SA Notify
Jitka
Karel
Ano – všechna potřebná nastavení jsou vidět.
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano – Karel měl problémy s
nalezením tlačítka Přidat spoj.
Karel 3 se opakovaně pokoušel přidat spoj dvojím kliknutím na vybraný spoj v tabulce Spoje.
Rozumí zpětné vazbě?
Ano
Ano
Čas
20 s
30 s
S vybráním požadovaného spoje neměli Jitka ani Karel problémy. Karel nemohl nalézt
tlačítko Přidat spoj.
Karel 2 také nechápal význam symbolů znázorňujících typ spoje (konkrétně ikony značící
autobus Fun & Relax). Nenapadlo ho vyzkoušet zobrazení tooltipu najetím myši nad ikonu
nebo na záhlaví sloupce.
Karla 1 zaujal červený křížek u tlačítka pro vypnutí/zapnutí automatické rezervace
v posledním sloupci tabulky hledání (viz např. obr. 5.9). Po kliknutí na tlačítko se zobrazilo upozornění „Prosím vyplňte údaje pro automatickou rezervaci v nastavení pluginu“.
Karel 1 ale dialog bez přečtení ihned zavřel a spokojil se se závěrem, že funkci tlačítka nezná
a je lepší na něj neklikat.
108
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.2.3 3. V nastavení pluginu vypněte zobrazování starých hledání
Obrázek C.9: Dialog Nastavení pluginu SA Notify, záložka Obecná nastavení
Jitka
Karel
Ano – tlačítko Nastavení je v menu pluginu (obr. C.8).
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
20 s
15 s
Všichni uživatelé bez problémů nalezli tlačítko Nastavení a následně i položku Zobrazovat stará hledání na záložce Obecná nastavení.
109
C.2. ÚKOL 2 – PRÁCE S PLUGINEM SA NOTIFY
C.2.4 4. V nastavení pluginu nastavte preferovaná sedadla V uličce
Obrázek C.10: Dialog Nastavení pluginu SA Notify, záložka Výchozí hledání
Jitka
Karel
Ano
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano – Jitka 1 nejprve hledala v
dialogu Možnosti. Když položku
nenalezla, napadlo jí vrátit se k
dialogu Nastavení pluginu SA Notify.
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
25 s
20 s
Všichni uživatelé po chvíli nalezli rozbalovací seznam s výběrem preferovaných míst.
Nikdo se ale nenamáhal se čtením textu pod seznamem, popisujícího funkci preferovaných
míst.
110
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.2.5 5. V nastavení pluginu nastavte automatickou rezervaci.
Použijte libovolné přihlašovací údaje.
Obrázek C.11: Dialog Nastavení pluginu SA Notify, záložka Automatická rezervace
Jitka
Karel
Ano
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano – Jitka ihned nalezla nastavení automatické rezervace a vyplnila údaje pro přihlášení náhodnými znaky.
Ano – Karel 2 jako jediný použil
tlačítko Otestovat připojení.
Rozumí zpětné vazbě?
Ano
Ano
Čas
15 s
30 s
111
C.2. ÚKOL 2 – PRÁCE S PLUGINEM SA NOTIFY
C.2.6 6. Zahajte vyhledávání volných míst v libovolném spoji na trase Brno
– Praha
Obrázek C.12: Nepodařilo se rezervovat preferované sedadlo
Jitka
Karel
Ano
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano – Jitka použila tlačítko pro
prohození výchozí a cílové stanice.
Ano – Karel 1 si dlouho nemohl
vzpomenout, že spoj přidával
do vyhledávání tlačítkem Přidat
spoj.
Rozumí zpětné vazbě?
Ano
Ano
Čas
10 s
20 s
Tento úkol byl podobný úkolu C.2.2, Jitka ani Karel proto neměli problém s jeho
splněním.
Plugin vzápětí nalezl volné místo a zobrazil dialog z obr. C.12. Karel 1 bez čtení dialogu
zvolil možnost Přejít k rezervaci a následně byl zmaten otevřením webového prohlížeče.
112
PŘÍLOHA C. VÝSLEDKY TESTOVÁNÍ METODOU
KOGNITIVNÍHO PRŮCHODU
C.2.7 7. Zobrazte historii hledaných spojů
Obrázek C.13: Menu pluginu s tlačítkem Historie
Jitka
Karel
Ano – tlačítko Historie je v menu pluginu (obr. C.13).
Je akce vidět?
Zvolil správný cíl?
Ano
Ano
Zvolil správnou akci?
Ano – Jitka 2 nejprve v nastavení
pluginu opět zapnula zobrazování
starých hledání, které vypnula v
rámci úkolu C.2.3. Když se stará
hledání v tabulce nezobrazila, zvolila správně tlačítko Historie.
Ano
Rozumí zpětné vazbě?
Ano
Ano
Čas
15 s
5s
113
C.2. ÚKOL 2 – PRÁCE S PLUGINEM SA NOTIFY
114
PŘÍLOHA D. PROGRAMÁTORSKÁ PŘÍRUČKA
Příloha D
Programátorská příručka
D.1
Úvod
D.1.1 Technologie
• Program je psaný v jazyce Java 1.7.
• GUI je vytvářeno pomocí knihovny SWT . (http://eclipse.org/swt/)
• Pro layout GUI byl použit MigLayout (http://www.miglayout.com/). Celé tělo
pluginu je ale vykreslováno na SWT widget Composite, kterému lze nastavit libovolný
vnitřní layout manager. Není tedy nutné omezovat se na MigLayout (nicméně ho vřele
doporučuji).
• Jsoup (http://jsoup.org/) je skvělý HTML parser, který byl použit u pluginu SA
Notify a je tedy již součásti aplikace. Jeho využití taktéž doporučuji, umožňuje velmi
jednoduché extrahování informací z HTML stránky, ale i posílání HTML requestů
včetně cookies.
D.1.2 Knihovny
Zde je seznam knihoven, které program používá (a které je tedy nutné přidat do projektu,
aby ho bylo možné zkompilovat). Knihovny jsou přibaleny ke zdrojovým kódům.
• SWT – je potřeba správná verze podle platformy! Viz eclipse.org/swt/.
• MigLayout
• JShortcut_my – upravená verze JShortcut (https://github.com/jimmc/jshortcut), která
načte správnou verzi jshortcut.dll z adresáře lib/.
• Jsoup
• Apache.commons.lang.StringEscapeUtils
• Apache.commons.codec.binary
115
D.1. ÚVOD
A dále tyto knihovny z IDE Eclipse (v případě importu projektu do Eclipse je tedy není
nutné manuálně přidávat ):
• org.eclipse.ui.forms
• org.eclipse.core.databinding
• org.eclipse.core.databinding.beans
• org.eclipse.core.databinding.observable
• org.eclipse.core.databinding.property
• org.eclipse.core.equinox.common
• org.eclipse.core.runtime
• org.eclipse.core.runtime.compatibility
• org.eclipse.jface.databinding
• org.eclipse.jface.util – pouze třída Geometry.class,
D.1.3 Pojmy
• plugin menu – záložka pluginu na horní liště, na které lze přepínat mezi pluginy.
• plugin active-menu – menu aktivní pluginu, může obsahovat tlačítka (viz obr. D.1).
Tvoří ho programátor pluginu.
• plugin idle-menu – menu neaktivního pluginu, je vytvořeno automaticky.
• tělo pluginu – samotný plugin, tedy to, co se zobrazí v hlavním okně při kliknutí na
plugin menu.
• pluginBody – SWT Composite pluginBody je fieldem třídy Plugin.java. Na tomto
Compositu je celé tělo pluginu.
Obrázek D.1: Vlevo active-menu pluginu SA Notify, vpravo idle-menu pluginu Divadlo J.C.
116
PŘÍLOHA D. PROGRAMÁTORSKÁ PŘÍRUČKA
D.2
Struktura aplikace
Zdrojové kódy obsahují 3 základní Java Package:
• sanotify – package obsahující kódy rodičovské aplikace
• plugins – package obsahující (abstraktní) třídy a interfacy související s pluginy
• sandbox – slouží pouze k testování, není součástí distribučního balíčku
Na obrázku D.2 je struktura tříd typického pluginu.
Každý plugin musí obsahovat tyto třídy (respektive implementovat jejich nadtřídy):
• NewPlugin – třída reprezentující daný plugin, implementuje metody interfacu PluginInterface. Klíčová je její metoda setPluginBody(), která vytvoří celé tělo pluginu.
Parent všech komponentů těla pluginu je Composite pluginBody,
• NewPluginMenu – obsahuje implementaci active-menu pluginu. Celé menu je na
Composite menuBG, který je fieldem abstraktní nadtřídy PluginMenu.java.
• NewPluginTableItem – reprezentuje jednu hledanou položku (např. jeden autobus
Student Agency). Implementace této třídy (podtřídy PluginTableItem) povinná není,
umožňuje ale využití metody safe() pro ukládání probíhajících hledání, implementované ve třídě Plugin, a také metod třídy PluginHistory pro práci s historií hledání.
Dále plugin navržený na obrázku D.2 obsahuje třídy:
• NewPluginPreferences – otevře dialog Nastavení pluginu.
• NewPluginHistory – zobrazí historii hledání.
• NewPluginChecker – samostatné vlákno, které provádí cyklické hledání volných
míst.
Abstraktní třídy PluginPreferences.java, PluginHistory.java a CheckerThread.java obsahují podpůrné metody, které se mohou hodit při vytváření dialogu Nastavení (PluginPreferences) dialogu Historie (PluginHistory) nebo vlákna, které se cyklicky připojuje na server
a kontroluje volná místa (CheckerThread).
Tyto třídy tedy není nutné implementovat, ale mohou ušetřit hodně práce.
PluginLoader.java: V této třídě probíhá načítání pluginů. V současnosti je nutné každý
nový plugin ručně přidat v metodě loadPlugins():
p l u g i n s . add ( new NewPlugin ( d i s p l a y , s h e l l , p r o p e r t i e s , me s s en g e r ) ) ;
117
D.3. JAK ZAČÍT
Obrázek D.2: Třídní diagram pluginu
D.3
Jak začít
Všechny třídy nového pluginu by měly být v balíku plugins.NewPlugin. Tedy např.
ve složce src/plugins/NewPlugin/.
Soubory pluginu (tzn. obrázky, konfigurační soubory apod.) zase ve složce
/plugins/NewPlugin/.
Ve zdrojových kódech je již k dispozici adresář src/plugins/NewPlugin/, který obsahuje
základní strukturu nového pluginu, přesně takovou, jako je na obr. D.2.
Stačí tedy doplnit těla metod – především metody NewPlugin.setPluginBody().
Všechny metody, které je třeba implementovat, mají javadoc dokumentaci, popisující, co
mají dělat. Stačí tedy nahlédnout do dokumentace nebo do kódu příslušné nadtřídy.
Není nutné použít všechny připravené třídy (viz výše – povinné jsou jen třídy NewPlugin
a NewPluginMenu).
118
PŘÍLOHA D. PROGRAMÁTORSKÁ PŘÍRUČKA
D.4
Univerzální třídy
Package sanotify obsahuje některé univerzální třídy, které je vhodné použít:
ImageHandler.java – statická třída, určená k načítání všech obrázků. Všechny obrázky
(SWT Image) je nutné ručně disposovat při ukončení aplikace (image.dispose()), hodí se
tedy mít je všechny na jednom místě.
Pro nový plugin doporučuji použít podtřídu NewPluginImageHandler.
CommentedProperties.java – podtřída java.util.Properties, která nevymaže komentáře
z properties souboru při přidávání nových položek.
Messenger.java – zajišťuje zobrazování zpráv uživateli a to jak chybových, tak informačních. Pro zobrazení popup zprávy uživateli stačí zavolat např.:
new Messenger ( ) . message_warning ( " H e l l o world " ) ;
Buttons.java – zjednodušuje vytváření tlačítek. Má několik metod pro vytvoření často
používaných tlačítek.
Sounds.java – přehrává zvuky – metoda public Clip playSound(String fileName).
Commons.java – obsahuje zejména metody pro snadné získání hodnot uložených v CommentedProperties. Např. metoda boolean getBoolProperty() se pokusí nalézt zadaný
klíč v CommentedProperties a převést jeho hodnotu na boolean.
ImageCodeGen.java – jednoduchá třída pro vygenerování kódu pro nový obrázek. Vygeneruje kód pro příslušné fieldy, getter a setter, který stačí zkopírovat do NewPluginImageHandler.java
D.5
Logování chyb
Pro logování chyb je určena metoda MainClass.logException(), která uloží výjimku do
.log souboru ve složce /bin/log/.
Doporučený postup odchytávání chyb:
try { . . .
}
catch ( Exception e ) {
S t r i n g msg="Zpráva co s e u l o ž í s chybou . " ;
MainClass . l o g E x c e p t i o n ( e , NewPlugin . c l a s s . getName ( ) , msg ) ;
}
119
D.6. JAZYKOVÉ VERZE
D.6
Jazykové verze
Různé jazykové verze pluginu jsou uloženy v souborech Bundle.properties.
V balíku NewPlugin jsou připraveny 2 soubory:
• Bundle.properties obsahuje českou jazykovou verzi
• Bundle_en.properties anglickou verzi
Všechny Stringy, jejichž hodnota se má měnit podle jazykové verze, stačí nahradit touto
konstrukcí:
ResourceBundle . getBundle ( " p l u g i n s / NewPlugin / Bundle " ) . g e t S t r i n g ( " K l i c 1 " ) ;
A následně klíč a hodnotu doplnit do souborů – např. do Bundle.properties doplnit řádek
K l i c 1=č e s k ý t e x t
A do Bundle_en.properties doplnit
K l i c 1=E n g l i s h t e x t
Programovací IDE má většinou nástroje pro rychlé nahrazení všech Stringů a přidání
klíčů do Bundle souborů.
V NetBeans je to Tools → Internationalization → Internationalization Wizard.
120
Literatura
[1] BIBLIOGRAFICKÉ CITACE Obsah, forma a struktura. [online],[rev. 1996-12], [cit.
2012-04-27]. Dostupné z: http://web.lib.fce.vutbr.cz/files/20512_0.pdf.
[2] Cohesion metrics. [online], [cit. 2012-05-06]. Dostupné z: http://www.aivosto.com/
project/help/pm-oo-cohesion.html.
[3] Eclipse Public License - v 1.0. [online], [cit. 2012-04-28]. Dostupné z: http://www.
eclipse.org/legal/epl-v10.html.
[4] Java SE 7 Features and Enhancements. [online], [cit. 2012-04-27]. Dostupné z: http:
//www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html.
[5] JGoodies Binding. [online], [rev. 2012], [cit. 2012-04-28]. Dostupné z: http://www.
jgoodies.com/freeware/libraries/binding/.
[6] K336 Info – pokyny pro psaní a zadávání diplomových prací. [online], [rev. 2010-04-26],
[cit. 2012-02-28]. Dostupné z: https://info336.felk.cvut.cz/?clanek=400.
[7] Should you avoid static classes? [online], [rev. 2009-08-22], [cit. 2012-04-29]. Dostupné
z: http://stackoverflow.com/questions/1315086/should-you-avoid-static-classes.
[8] Breuer, J.: Automatická detekce volného místa v autobusech na lince Liberec - Praha.
[online], [rev. 2009-04-19], [cit. 2012-02-28]. Dostupné z: http://jaybee.cz/software/
automaticka-detekce-volneho-mista-v-autobusech-student-agency/.
[9] Green, R.: static: Java Glossary. [online], [rev. 2012], [cit. 2012-04-29]. Dostupné z:
http://mindprod.com/jgloss/static.html.
[10] Grev, M.: GUI Bechmarking with MiG Layout Demo. [online], [rev. 2006-08-30], [cit.
2012-04-28]. Dostupné z: http://www.javalobby.org/java/forums/t78884.html.
[11] Šindelář, J.: Počítačová gramotnost v ČR - unikátní průzkum znalostí populace. [online], [rev. 2005-08-26], [cit. 2012-04-27]. Dostupné z: http://www.zive.
cz/Clanky/Pocitacova-gramotnost-v-CR---unikatni-pruzkum-znalosti-populace/
sc-3-a-126364/default.aspx.
[12] : Code Quality Metrics. [online], [cit. 2012-05-06]. Dostupné z: http://docs.ncover.
com/best-practices/code-quality-metrics/.
LITERATURA
[13] Bc. Vitásek, L.: Frameworky pro tvorbu desktopových aplikací v Javě.
Diplomová práce, České vysoké učení technické v Praze, Fakulta elektrotechnická, 2009, [online], [rev. 2009-01], [cit. 2012-04-27]. Dostupné z
https://dip.felk.cvut.cz/browse/details.php?f¯
F3&d=K13136&y=2009&a=vitasek&t=dipl.
[14] Carolyn MacLeodn a Steve Northover: SWT: The Standard Widget Toolkit, PART 2:
Managing Operating System Resources. [online], [rev. 2001-11-27], [cit. 2012-04-28].
Dostupné z: http://www.eclipse.org/articles/swt-design-2/swt-design-2.html.
[15] Chris Newland: Select correct SWT jar for your OS and JVM at runtime. [online], [rev. 2012-02-10], [cit. 2012-05-06]. Dostupné z: http://www.chrisnewland.com/
select-correct-swt-jar-for-your-os-and-jvm-at-runtime-191.
[16] Creative Commons: Attribution 3.0 Unported. [online], [cit. 2012-04-29]. Dostupné z:
http://creativecommons.org/licenses/by/3.0/.
[17] Creative Commons: Attribution-NonCommercial 3.0 Unported. [online], [cit. 2012-0429]. Dostupné z: http://creativecommons.org/licenses/by-nc/3.0/.
[18] Creative Commons: Attribution-NonCommercial-NoDerivs 3.0 Unported. [online], [cit.
2012-03-02]. Dostupné z: http://creativecommons.org/licenses/by-nc-nd/3.0/.
[19] Free Software Foundation, Inc.: GNU General Public License version 2. [online], [rev.
1991-06], [cit. 2012-04-27]. Dostupné z: http://www.gnu.org/licenses/old-licenses/
gpl-2.0.txt.
[20] Free Software Foundation, Inc.: GNU General Public License version 3. [online], [rev.
2007-06-29], [cit. 2012-04-28]. Dostupné z: http://www.gnu.org/licenses/gpl.html.
[21] Free Software Foundation, Inc.: GNU Lesser General Public License. [online], [rev.
2007-06-29], [cit. 2012-04-29]. Dostupné z: http://www.gnu.org/copyleft/lesser.html.
[22] Janečka P., Chlouba T.: SWT & MigLayout. [online], [rev. 2011-06], [cit. 2012-04-28].
Dostupné z: http://java.cz/dwn/1003/51292_SWT%20MigLayout%20-%20prezentace%20-%
20CZJUG.pdf.
[23] Open Source Initiative OSI: The MIT License. [online], [cit. 2012-04-28]. Dostupné z:
http://www.opensource.org/licenses/mit-license.php/.
[24] Samudra Gupta: Coupling and Cohesion: The Two Cornerstones of OO Programming.
[online], [cit. 2012-05-06]. Dostupné z: http://javaboutique.internet.com/tutorials/
coupcoh/.
[25] Stavros Kounis: Gradient Background to any SWT Control. [online], [rev. 200806-22], [cit. 2012-05-03].
Dostupné z: http://skounis.blogspot.com/2008/06/
gradient-background-to-any-swt-control.html.
[26] Steve Northover a Mike Wilson: SWT: The Standard Widget Toolkit. Addison
Wesley, 2004. ISBN 0-321-25663-8.
Dostupné z: http://book.javanb.com/
swt-the-standard-widget-toolkit/main.html.
122
LITERATURA
[27] The Apache Software Foundation: Apache License, Version 2.0. [online],[rev. 2012], [cit.
2012-05-04]. Dostupné z: http://www.apache.org/licenses/.
[28] The FreeBSD Project: The FreeBSD Copyright. [online], [rev. 2012], [cit. 2012-04-28].
Dostupné z: http://www.freebsd.org/copyright/freebsd-license.html.
[29] Muller, M.: SWT Binding. [online], [rev. 2009-07-17], [cit. 2012-04-28]. Dostupné z:
http://sourceforge.net/projects/swtbinding/.
[30] Wikipedia: Royalty-free — Wikipedia, The Free Encyclopedia. [online], [rev. 201202-18], [cit. 2012-02-28]. Dostupné z: http://en.wikipedia.org/w/index.php?title=
Royalty-free&oldid=477476145.
[31] Wikipedia: Royalty-free — Wikipedia, The Free Encyclopedia. [online], [rev. 201203-22], [cit. 2012-05-06]. Dostupné z: http://en.wikipedia.org/wiki/Cyclomatic_
complexity.
123
Download

Automatický rezerva£ní systém