Compare commits

...

131 Commits
055 ... master

Author SHA1 Message Date
5728ea4f4d „README.md“ ändern 2020-12-17 17:44:38 +01:00
13dd0a0150 Merge branch 'develop' of Seil0/cemu_UI into master 2019-06-28 17:35:22 +02:00
f584eef9b7
update to 0.3.0
* updated jfoenix 9.0.8 -> 9.0.9
2019-06-28 17:32:25 +02:00
a6b1ce7f72
some new css styling 2019-06-23 15:39:58 +02:00
0fecb8bb16
more lambda code 2019-06-15 11:11:18 +02:00
2689b03c16
minor clean up
* CloudController is now a singleton
2019-05-18 13:19:34 +02:00
bc36630ef2
removed unneeded methode 2019-05-18 01:28:21 +02:00
07ded89069
Major code clean up
* DBController doesn't need mwc anymore
* no dialogs anymore, only alerts
2019-05-18 01:25:54 +02:00
a4c8eb2efe
the license dialog is now a alert & reduced main usage in mwc 2019-05-17 00:22:51 +02:00
7d376535ae
nicer dialog on first startup 2019-05-16 15:09:01 +02:00
3f69169a6a
new constructor for UIROMDataType 2019-05-15 16:39:00 +02:00
922c5197da
update to JavaFX 12.0.1 2019-05-15 16:25:08 +02:00
0599945036
clean up some mwc code + UIROMDataType
it should be now much better to understand the generatePosition() method
2019-05-15 16:19:31 +02:00
df33c21826 some code clean up
* library updates
* dialog -> alert
2019-04-09 00:42:39 +02:00
e59b14074e added a few new games, updated some Japanese titles 2019-03-17 00:35:54 +01:00
648d101c8e updated year 2019-03-01 19:03:30 +01:00
4222101b68 Update 'README.md' 2019-02-16 17:03:29 +01:00
db8fcd4bdc major code clean up 2019-01-22 19:21:38 +01:00
7434d0be25 minor clean up 2019-01-14 20:16:19 +01:00
360badb841 removed travis.yml 2019-01-04 23:35:50 +01:00
38421599a3 the updater now uses gitea 2018-12-03 00:09:02 +01:00
3f6eeece7d updated some libs, code clean up
* openjfx 11 -> 11.0.1
* jfoenix 9.0.6 -> 9.0.8
* sqlite-jdbc 3.23.2 -> 3.25.2
* google-api-services-drive rev129 -> rev136
* jackson-core 2.9.6 -> 2.9.7
2018-12-02 23:51:14 +01:00
36fd86d15c Merge branch 'develop' 2018-11-19 23:21:53 +01:00
87eaec31ee „README.md“ ändern 2018-11-19 23:18:29 +01:00
a2f35de1c7 „README.md“ ändern 2018-11-19 23:18:07 +01:00
b879e22fcf deleted unused images 2018-11-19 23:17:13 +01:00
960bec5283 „README.md“ ändern 2018-11-19 23:02:26 +01:00
ffb7bc971c removed eclipse specific files 2018-10-25 16:42:45 +02:00
50088e0130 „.project“ löschen 2018-10-25 16:35:20 +02:00
a3fc8ba463 „.classpath“ löschen 2018-10-25 16:35:14 +02:00
ada6bec325 updated gitignore 2018-10-25 16:34:56 +02:00
bbfc9521a0 target java11/javafx11 2018-10-01 21:20:35 +02:00
2ac66978ba updated some libraries
* jfoenix 9.0.4 -> 9.0.6
* log4j 2.11.0 -> 2.11.1
* google apis 1.23.0 -> 1.25.0
* jackson-core 2.9.5 -> 2.9.6
* javax.servlet 4.0.0 -> 4.0.1
* maven-compiler-plugin 3.7.0 -> 3.8.0
2018-09-08 12:50:34 +02:00
ed99e45115 cleaned up games.csv
* use https now
* added a few covers
* added a few japanese titles
2018-08-16 13:27:31 +02:00
dcd928096a updated a few games in games.csv 2018-08-16 00:01:54 +02:00
1df6a91f41 Merge branch 'develop' of Seil0/cemu_UI into master 2018-08-14 21:35:57 +02:00
Jannik
d46eace9d5 updated readme 2018-06-18 15:19:47 +02:00
Jannik
9e58a30390 updated readme 2018-06-18 15:14:34 +02:00
Jannik
010f109597 updated readme 2018-06-18 15:13:09 +02:00
Jannik
d082482844 updated readme 2018-06-18 13:54:46 +02:00
fb1fd442f7 'README.md' ändern 2018-06-16 12:04:43 +02:00
Jannik
9839c303da download the games.db from gitea 2018-06-16 00:03:23 +02:00
b610dc337b 'README.md' ändern 2018-06-14 15:24:33 +02:00
Jannik
f195addea8 version 0.3.1 (81) 2018-06-13 18:29:16 +02:00
Jannik
e371859987 test commit 2 2018-06-13 15:14:34 +02:00
Jannik
8b62a732cd test commit 2018-06-13 15:08:34 +02:00
Jannik
41a0becd4f typo 2018-06-13 13:49:47 +02:00
Jannik
9b7a85cabe code clean up 2018-06-12 16:24:12 +02:00
Jannik
cc4e73c45d InfoAlert & ProcessBuilder
* we use an Alert now to display Info Messages
* use ProcessBuilder instead of Runtime.exec()
2018-06-12 16:01:21 +02:00
Jannik
c6a40f8937 updated some libs
* jfoenix 9.0.3 -> 9.0.4
* sqlite-jdbc 3.21.0.1 -> 3.23.1
* google-api-services-drive v3-rev99-1.23.0 -> v3-rev120-1.23.0
* jackson-core 2.9.4 -> 2.9.5
* maven-shade-plugin 3.1.0 -> 3.1.1
2018-06-06 17:54:22 +02:00
Jannik
e13c84382f biuld against java 10 2018-05-30 19:41:49 +02:00
Jannik
ea34f10c09 fixed Hamburger icon has wrong color after color change 2018-04-28 12:53:01 +02:00
Jannik
4e4d32dc97
Update README.md 2018-04-28 12:24:40 +02:00
Jannik
f1bb0607f7
Merge pull request #18 from Seil0/develop
release 0.3.0
2018-04-28 12:23:14 +02:00
Jannik
5758b23bff
Merge branch 'master' into develop 2018-04-28 12:21:37 +02:00
Jannik
1e7cea86ad code cleanup
* log4j 2.10.0 -> 2.11.0
2018-04-28 12:17:12 +02:00
Jannik
433767f81c Merge remote-tracking branch 'origin/develop' into develop 2018-04-05 09:55:09 +02:00
Jannik
f9f63c0f3c code cleanup 2018-04-05 09:54:45 +02:00
Jannik
fcaffecabf text fix 2018-03-22 18:54:56 +01:00
Jannik
7813778502 small cleanup 2018-03-22 11:54:30 +01:00
Jannik
662188813b removed workaround for xPosHelper Bug 2018-02-24 17:00:43 +01:00
Jannik
b915cf7ad9 removed last unnecessary reboot
* needs more testing, especialy under Windows
* test on a completly fresh setup
2018-02-20 21:22:10 +01:00
Jannik
b4fc36621a code cleanup
removed some unnecessary save calls
* removed some unnecessary things after opening a directorychooser
* typo fixes
2018-02-18 18:27:36 +01:00
Jannik
061f58105a documentation cleanups, code cleanup
* removed one unnecessary restart
* added warning if the ROM directory could not be opened
2018-02-18 13:57:30 +01:00
Jannik
3a6a7b7cce * jfoenix 9.0.1 -> 9.0.2
* code clean up
* last time played and playtime button are now large enough
2018-02-17 17:49:12 +01:00
Jannik
f7675cf277
Update README.md 2018-02-14 22:55:27 +01:00
Jannik
4932731987
Update README.md 2018-02-14 22:53:14 +01:00
Jannik
2e3395caea minor fixes
* fixed a few typos
* fixed window is resiable to 0x0
* * formating work work
2018-02-04 15:19:36 +01:00
Jannik
e9d033f121
Update README.md 2018-02-03 18:05:09 +01:00
Jannik
54078eb99f clean up 2018-02-03 17:51:38 +01:00
Jannik
79cb1c2476 fixed games are not loaded to mwc
* fixed games are not loaded to mwc
* fixed processbuilder
2018-02-03 15:39:35 +01:00
Jannik
b88c530ac2 use a ProcessBuilder instead of Runtime.exec 2018-02-03 14:22:41 +01:00
Jannik
88e31468d4 made choicebox matreial styled
* made choicebox matreial styled
* little code clean up
2018-02-03 12:04:14 +01:00
Jannik
84b5eaedcd reworked startup process
* cemu is showing a loading screen while loading the roms
* jackson core 2.9.3 -> 2.9.4
2018-01-31 17:01:47 +01:00
Jannik
f331fb57a4 added ability to edit launch command, WIP
WARNING THIS IS NOT TESTED
2018-01-19 01:14:01 +01:00
Jannik
a9f675ee5e
Update README.md 2018-01-13 23:35:33 +01:00
Jannik
fe4fcb45d7 travis fix, first try 2018-01-13 00:13:34 +01:00
Jannik
52c2912ba2 maven compile plugin 3.7.0 2018-01-13 00:09:13 +01:00
Jannik
46455e9e9d Java 9, updated a few libs
* cemu_UI targets now Java 9
* jfoenix 1.11.1 -> 9.0.1
* minimal-json 0.9.4 -> 0.9.5
* log4j 2.9.1 -> 2.10.0
* commons-io 2.5 -> 2.6
* jackson-core 2.9.2 -> 2.9.3
* javax.servlet-api 4.0.0-b01 -> 4.0.0
2018-01-12 23:52:44 +01:00
Jannik
1e2d4088e9
Merge pull request #15 from Seil0/develop
release 0.2.3
2018-01-12 20:08:03 +01:00
Jannik
d3acf387d9 code clean up 2017-12-26 17:33:14 +01:00
Jannik
de2c8d76ea
Update CONTRIBUTING.md 2017-12-21 17:33:54 +01:00
Jannik
9be124a5f3
Update CONTRIBUTING.md 2017-12-21 17:33:22 +01:00
Jannik
a020992cc2 release 0.3.2 build 071
* added missing translation
2017-12-21 11:02:54 +01:00
Jannik
8c5d511dfb removed log.txt 2017-12-19 22:18:58 +01:00
Jannik
c73d02c433 added german local 2017-12-19 22:18:22 +01:00
Jannik
34bed89b40 language work part 2
* dialogs support different languages now too
* finished english language pack
2017-12-19 21:35:49 +01:00
Jannik
ce52628554 language work part 1
* added support for different languages
* added english locals
2017-12-19 19:08:12 +01:00
Jannik
fc0be39455 code clean up
* cleaned up the playBtn code
* added language section in settings
2017-12-18 09:58:32 +01:00
Jannik
595bfbe07d bummped buildnumber to 065 2017-12-16 23:05:26 +01:00
Jannik
599669f0f2 fixed a bug that prefent the cloud controller from geting the latest cloud sync 2017-12-13 00:07:20 +01:00
Jannik
42b8434a58 Cloud sync rework
* reworked the hole cloud sync controller
this will make it more save to use the cloud sync
THIS IS WORK IN PROGRESS, NOT READY FOR DAILY USE!
2017-12-12 23:52:54 +01:00
Jannik
9b443dfeae small DBController code clean up 2017-12-12 19:19:01 +01:00
Jannik
c70786cdf4 minor ui improvements 2017-12-12 19:01:17 +01:00
Jannik
a3a7d415c7 fixed a few bugs
* games.db -> reference_games.db
* fix picture cache path under linux
2017-12-12 12:02:28 +01:00
Jannik
9ccb7e6b42 better coding style
* used gettersand setter for accessing the mainparts of the UI elements, uch aus primarStage
* dbController -> DBController
2017-12-12 11:19:33 +01:00
Jannik
1aab6fdeb5
Merge pull request #12 from Seil0/develop
updat version to 0.2.2 build 061
2017-12-11 17:17:53 +01:00
Jannik
45c36aa09c
Merge branch 'master' into develop 2017-12-11 17:16:30 +01:00
Jannik
99574ce6ef updated version to 0.2.2 build 061
* updated version to 0.2.2 build 061
* the license text textarea is not editable anymore
2017-12-11 17:07:20 +01:00
Jannik
3289bb4aed smmdb course images are now correctly scaled
* added a scaling function for smm course images
* smm course images are scrollable now
2017-12-11 16:44:47 +01:00
Jannik
a1bab241b6 log contains some infos about the currect system now
such as os version java re version
2017-12-11 15:51:04 +01:00
Jannik
02d7cb6a3e smmdb image is now in a scrollpane
* smmdb image is now in a scrollpane, now we can resize the image to the correct height
2017-12-11 11:31:39 +01:00
Jannik
e92a43a37e added a search bar for smmdb courses
* added a search bar for the smmdbcourse table
* fixed some wrong Anschors at the smmdb Anchorpane
2017-12-11 10:31:23 +01:00
Jannik
75d8e6b525 smmdb api auery is now in it's own thread
* smmdb api auery is now in it's own thread
* fixed a issue where cemu_UI freezed on a 502 http error of the smmdb api
* jfoenix 1.10 -> 1.11
* sqlite 3.20.0. -> sqlite 3.20.0.1
2017-12-09 13:10:19 +01:00
Jannik
548629eeaf TestArea -> TextArea 2017-12-09 10:19:52 +01:00
Jannik
37d55abe9a fiexd a typo 2017-12-09 10:16:03 +01:00
Jannik
68d3445afe Merge remote-tracking branch 'origin/develop' into develop 2017-12-09 10:14:45 +01:00
Jannik
4851f0c3a4 Revert "fixed s typo"
This reverts commit c4a0a5d5f9.
2017-12-09 10:14:36 +01:00
Jannik
c4a0a5d5f9 fixed s typo 2017-12-09 10:14:17 +01:00
Jannik
95df2b9359 fixed a few cloud sync bugs
* fixed a bug where cemu_UI faild to set the correct text to the playBtn
* fixed cemu_UI crashing when activationg cloud sync under linux
2017-12-07 22:52:32 +01:00
Jannik
e4bf16e7a1 added a dialog to sow all licenses
* added a dialog to sow all licenses of all programms and libraries used int cemu_UI
2017-12-06 13:39:00 +01:00
Jannik
0cfbd2b125 code clean up 2017-11-28 23:07:20 +01:00
Jannik
2e200e5a88 ui fixes
* the spinner backgri´ound is not clear anymore
* code clean up
* added a better description of issue #10
2017-11-28 13:55:07 +01:00
Jannik
b9b7b143e5
Update README.md 2017-11-28 10:32:35 +01:00
Jannik
46c57ef330 code clean up
* removed old reloadRomBtn code
* fixed an issue where the saveSettings after successfully syncing to the cloud failed
2017-11-27 21:57:59 +01:00
Jannik
e0a73a1fbe code clean up
* the mwc init process is now only one call in main
* renamed a few methodes for better clearance
* added a few TODOs
2017-11-27 10:57:16 +01:00
Jannik
0f7d262bcb License dialog update 2017-11-26 11:35:02 +01:00
Jannik
b975a6300c
Update README.md 2017-11-25 11:09:32 +01:00
Jannik
c6737fc387
Update README.md 2017-11-25 11:08:46 +01:00
Jannik
f5e16d2f58 travis ci test 2017-11-25 10:57:11 +01:00
Jannik
73bb433d03 clean up 2017-11-24 21:40:55 +01:00
Jannik
5f756f613f formating work 2017-11-24 21:40:02 +01:00
Jannik
fe6ddedab9 code clean up 2017-11-24 21:36:03 +01:00
Jannik
922b1443e1 clean up
* fixed a few typos
* code clean up
2017-11-24 17:07:53 +01:00
Jannik
ba9fd1bb32 dialog rework and mor license shipping work
* update/add DLC are now JFXDilaog styled
* added MIT license
2017-11-22 23:30:20 +01:00
Jannik
15196718c5 added license lable action 2017-11-22 22:53:15 +01:00
Jannik
890830b84e added gpl3 and apache 2
* added gpl3
* added apache 2
* code clean up
2017-11-20 11:32:14 +01:00
Jannik
2b17d34841 code clean up 2017-11-15 22:00:28 +01:00
Jannik
0a208f5a6b add and edit dialog is now material styled
* added material add/edit dialog
* lots of code clean up
2017-11-15 21:21:52 +01:00
Jannik
88a83e5f0d maen fixes, clean up and add/edit dialog work
* maven uses now apache shaped as build plugin
* begun reworking the addGame Dialog
2017-11-15 15:58:23 +01:00
Jannik
1268ab9cf8 maven fix 2017-11-15 00:29:03 +01:00
63 changed files with 7814 additions and 5390 deletions

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.fx.ide.jdt.core.JAVAFX_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

3
.gitignore vendored
View File

@ -50,3 +50,6 @@ client_secret.json
.directory .directory
target/ target/
cemu_UI.jar cemu_UI.jar
.classpath
.project
.settings/*

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>cemu_UI</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,5 +0,0 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -1,13 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,4 +0,0 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -1,7 +1,13 @@
# Contributing to cemu_UI # Contributing to cemu_UI
The following is a set of guidelines for contributing to cemu_UI. The following is a set of guidelines for contributing to cemu_UI.
## Java Sytleguide ## Translating
If you don't want to contibute any code you can support this project by translating it! The translation files are stored in "src/main/resources/locals".
# Contributing code
If you want to contibute code please read the java code styleguide.
## Java code sytleguide
If your willing to contribute to cemu_UI please us the following example as guide and rules to design your code. If your willing to contribute to cemu_UI please us the following example as guide and rules to design your code.
* Use names for methods and variables that clarify their purpose. (This will help a lot to understand the code) * Use names for methods and variables that clarify their purpose. (This will help a lot to understand the code)
* Use as many spaces as necessary to make the code clear, but as little as possible. * Use as many spaces as necessary to make the code clear, but as little as possible.

View File

@ -1,41 +1,37 @@
# cemu_UI # cemu_UI
![Total Downloads](https://img.shields.io/github/downloads/Seil0/cemu_UI/total.svg?style=flat-square) ![Total Downloads](https://img.shields.io/github/downloads/Seil0/cemu_UI/total.svg?style=flat-square)
[![Latest](https://img.shields.io/github/release/Seil0/cemu_UI/all.svg?style=flat-square)](https://github.com/Seil0/cemu_UI/releases) [![Latest](https://img.shields.io/badge/release-085-blue.svg?style=flat-square)](https://git.mosad.xyz/Seil0/cemu_UI/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0)
cemu_UI is a simple, material design graphical frontend for [cemu](http://cemu.info/), a Wii U emulator. Downloads can be found [here](https://github.com/Seil0/cemu_UI/releases). cemu_UI is a simple, material design graphical frontend for [cemu](http://cemu.info/), a Wii U emulator. Downloads can be found [here](https://git.mosad.xyz/Seil0/cemu_UI/releases).
## Installation ## Installation
Simply download the cemu_UI.jar from [releases](https://github.com/Seil0/cemu_UI/releases), make sure you have the latest version of java 8 oracle jre/jdk installed and open the file. cemu_UI creats a new directory "C:\Users\USERNAME\Documents\cemu_UI", where the database, settings and covers are stored. **first start can take while!** Simply download the cemu_UI.jar from [Releases](https://git.mosad.xyz/Seil0/cemu_UI/releases), make sure you have the latest version of java 8 oracle jre/jdk installed and open the file. cemu_UI creats a new directory "C:\Users\USERNAME\Documents\cemu_UI", where the database, settings and covers are stored. **first start can take while!**
If you want to use the cloud sync function read the [wiki](https://github.com/Seil0/cemu_UI/wiki#cloud-savegame-syncronisation) carefully! If you want to use the cloud sync function read the [wiki](https://git.mosad.xyz/Seil0/cemu_UI/wiki#cloud-savegame-syncronisation) carefully!
### [FAQ](https://git.mosad.xyz/Seil0/cemu_UI/wiki#faq)
## Features ## Features
* launch Games * launch Games
* Time played in total * Time played in total
* last time played * last time played
* easyer way to add updates & DLCs (only adding not downloading!) * add updates and dlcs easier (only adding not downloading!)
* automatic rom detection (only .rpx files with a app.xml) * automatic rom detection (only .rpx files with a app.xml)
* customisable UI * customisable UI
* [sync savegames via google drive](https://github.com/Seil0/cemu_UI/wiki) * [sync savegames via google drive](https://git.mosad.xyz/Seil0/cemu_UI/wiki)
* [smmdb api](https://github.com/Tarnadas/smmdb) integration * [smmdb api](https://github.com/Tarnadas/smmdb) integration
## [planed Features](https://github.com/Seil0/cemu_UI/projects/1) (no ETA) ## [planed Features](https://git.mosad.xyz/Seil0/cemu_UI/milestones)
* Controller support * Controller support
* more UI improvements
* support more rom file formats in automatic detection
### If you have another idea, make a "new issue" with the ![#f03c15](https://placehold.it/15/fbca04/000000?text=+)`idea` lable ### If you have another idea, make a new issue!
## [FAQ](https://github.com/Seil0/cemu_UI/wiki#faq) ### [building from source](https://git.mosad.xyz/Seil0/cemu_UI/wiki/Documentation)
### [building from source](https://github.com/Seil0/cemu_UI/wiki/Documantation)
## Screenshots ## Screenshots
![Screenshot](/downloadContent/cemu_UI4.png) ![Screenshot](https://www.mosad.xyz/images/cemu_UI_MainWindow.webp)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

File diff suppressed because it is too large Load Diff

373
pom.xml
View File

@ -1,222 +1,211 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<modelVersion>4.0.0</modelVersion> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId> <groupId>com</groupId>
<artifactId>cemu_UI</artifactId> <artifactId>cemu_UI</artifactId>
<version>0.2.1-SNAPSHOT</version> <version>0.3.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>cemu_UI</name>
<description>cemu_UI is a simple, material design graphical frontend for cemu, a Wii U emulator</description>
<url>https://www.mosad.xyz</url>
<name>cemu_UI</name> <properties>
<url>http://www.kellerkinder.xyz</url> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<properties> <dependencies>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>org.openjfx</groupId>
<artifactId>junit</artifactId> <artifactId>javafx-controls</artifactId>
<version>3.8.1</version> <version>12.0.1</version>
<scope>test</scope> </dependency>
</dependency>
<dependency> <dependency>
<groupId>com.jfoenix</groupId> <groupId>org.openjfx</groupId>
<artifactId>jfoenix</artifactId> <artifactId>javafx-fxml</artifactId>
<version>1.9.0</version> <version>12.0.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.eclipsesource.minimal-json</groupId> <groupId>org.openjfx</groupId>
<artifactId>minimal-json</artifactId> <artifactId>javafx-media</artifactId>
<version>0.9.4</version> <version>12.0.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.xerial</groupId> <groupId>com.jfoenix</groupId>
<artifactId>sqlite-jdbc</artifactId> <artifactId>jfoenix</artifactId>
<version>3.20.0</version> <version>9.0.9</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>com.eclipsesource.minimal-json</groupId>
<artifactId>log4j-api</artifactId> <artifactId>minimal-json</artifactId>
<version>2.9.0</version> <version>0.9.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.xerial</groupId>
<artifactId>log4j-core</artifactId> <artifactId>sqlite-jdbc</artifactId>
<version>2.9.0</version> <version>3.27.2.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>commons-io</artifactId> <artifactId>log4j-api</artifactId>
<version>2.5</version> <version>2.11.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-vfs2 --> <dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId>
<groupId>org.apache.commons</groupId> <artifactId>log4j-core</artifactId>
<artifactId>commons-vfs2</artifactId> <version>2.11.2</version>
<version>2.2</version> </dependency>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency>
<dependency> <groupId>commons-io</groupId>
<groupId>commons-codec</groupId> <artifactId>commons-io</artifactId>
<artifactId>commons-codec</artifactId> <version>2.6</version>
<version>1.11</version> </dependency>
</dependency>
<!-- https://mvnrepository.com/artifact/io.datafx/flow --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-vfs2 -->
<dependency> <dependency>
<groupId>io.datafx</groupId> <groupId>org.apache.commons</groupId>
<artifactId>flow</artifactId> <artifactId>commons-vfs2</artifactId>
<version>8.0.1</version> <version>2.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j --> <!-- https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j -->
<dependency> <dependency>
<groupId>net.lingala.zip4j</groupId> <groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId> <artifactId>zip4j</artifactId>
<version>1.3.2</version> <version>1.3.2</version>
</dependency> </dependency>
<!-- Google Drive-API libraries--> <!-- Google Drive-API libraries -->
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency> <dependency>
<groupId>commons-logging</groupId> <groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId> <artifactId>commons-logging</artifactId>
<version>1.1.1</version> <version>1.1.1</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.api-client/google-api-client --> <!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-drive -->
<dependency> <dependency>
<groupId>com.google.api-client</groupId> <groupId>com.google.apis</groupId>
<artifactId>google-api-client</artifactId> <artifactId>google-api-services-drive</artifactId>
<version>1.23.0</version> <version>v3-rev136-1.25.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-drive --> <!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client -->
<dependency> <dependency>
<groupId>com.google.apis</groupId> <groupId>com.google.http-client</groupId>
<artifactId>google-api-services-drive</artifactId> <artifactId>google-http-client</artifactId>
<version>v3-rev87-1.23.0</version> <version>1.25.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client --> <!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client-jackson2 -->
<dependency> <dependency>
<groupId>com.google.http-client</groupId> <groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId> <artifactId>google-http-client-jackson2</artifactId>
<version>1.23.0</version> <version>1.25.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client-jackson2 --> <!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty -->
<dependency> <dependency>
<groupId>com.google.http-client</groupId> <groupId>com.google.oauth-client</groupId>
<artifactId>google-http-client-jackson2</artifactId> <artifactId>google-oauth-client-jetty</artifactId>
<version>1.23.0</version> <version>1.25.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client --> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency> <dependency>
<groupId>com.google.oauth-client</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>google-oauth-client</artifactId> <artifactId>jackson-core</artifactId>
<version>1.23.0</version> <version>2.9.7</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.mortbay.jetty/jetty -->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-java6 --> </dependencies>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-java6</artifactId>
<version>1.23.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty --> <build>
<dependency> <plugins>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.23.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <plugin>
<dependency> <groupId>org.apache.maven.plugins</groupId>
<groupId>com.fasterxml.jackson.core</groupId> <artifactId>maven-compiler-plugin</artifactId>
<artifactId>jackson-core</artifactId> <version>3.8.0</version>
<version>2.9.2</version> <configuration>
</dependency> <source>11</source>
<target>11</target>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <plugin>
<dependency> <groupId>org.codehaus.mojo</groupId>
<groupId>javax.servlet</groupId> <artifactId>exec-maven-plugin</artifactId>
<artifactId>javax.servlet-api</artifactId> <version>1.6.0</version>
<version>4.0.0-b01</version> <executions>
<scope>provided</scope> <execution>
</dependency> <goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.cemu_UI.application.Main</mainClass>
</configuration>
</plugin>
<!-- https://mvnrepository.com/artifact/org.mortbay.jetty/jetty --> <plugin>
<dependency> <groupId>org.apache.maven.plugins</groupId>
<groupId>org.mortbay.jetty</groupId> <artifactId>maven-shade-plugin</artifactId>
<artifactId>jetty</artifactId> <version>3.2.1</version>
<version>6.1.26</version> <executions>
</dependency> <execution>
<phase>package</phase>
<!-- https://mvnrepository.com/artifact/org.mortbay.jetty/jetty-util --> <goals>
<dependency> <goal>shade</goal>
<groupId>org.mortbay.jetty</groupId> </goals>
<artifactId>jetty-util</artifactId> <configuration>
<version>6.1.26</version> <finalName>cemu_UI</finalName>
</dependency> <shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
</dependencies> <transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<build> <mainClass>com.cemu_UI.application.JavaFX11Main</mainClass>
<plugins> </transformer>
<plugin> </transformers>
<groupId>org.apache.maven.plugins</groupId> </configuration>
<artifactId>maven-jar-plugin</artifactId> </execution>
<version>3.0.2</version> </executions>
<configuration> </plugin>
<archive> </plugins>
<manifest> </build>
<addClasspath>true</addClasspath>
<classpathPrefix>libraries/</classpathPrefix>
<mainClass>com.cemu_UI.application.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libraries</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -0,0 +1,8 @@
package com.cemu_UI.application;
public class JavaFX11Main {
public static void main(String[] args) {
Main.main(args);
}
}

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -27,7 +27,6 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.Optional;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -35,43 +34,45 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.cemu_UI.controller.CloudController; import com.cemu_UI.controller.CloudController;
import com.cemu_UI.controller.XMLController;
import com.cemu_UI.uiElements.JFXInfoAlert;
import com.cemu_UI.uiElements.JFXOkayCancelAlert;
import javafx.application.Application; import javafx.application.Application;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class Main extends Application { public class Main extends Application {
Stage primaryStage; private final String gamesDBdownloadURL = "https://git.mosad.xyz/Seil0/cemu_UI/raw/branch/master/downloadContent/games.db";
public MainWindowController mainWindowController; //TODO find a better way private static Main main;
CloudController cloudController; private static XMLController xmlController;
AnchorPane pane; private MainWindowController mainWindowController;
private CloudController cloudController;
private Stage primaryStage;
private AnchorPane pane;
private Scene scene; private Scene scene;
private String dirWin = System.getProperty("user.home") + "/Documents/cemu_UI"; //Windows: C:/Users/"User"/Documents/cemu_UI
private String dirLinux = System.getProperty("user.home") + "/cemu_UI"; //Linux: /home/"User"/cemu_UI
private String gamesDBdownloadURL = "https://github.com/Seil0/cemu_UI/raw/master/downloadContent/games.db";
private File directory;
private File configFile;
private File gamesDBFile;
@SuppressWarnings("unused")
private File localDB;
private File pictureCache;
private static Logger LOGGER; private static Logger LOGGER;
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
LOGGER.info("OS: " + XMLController.getOsName() + " " + XMLController.getOsVers() + " " + XMLController.getOsVers());
LOGGER.info("Java: " + XMLController.getJavaVend() + " " + XMLController.getJavaVers());
LOGGER.info("User: " + XMLController.getUserName() + " " + XMLController.getUserHome());
this.primaryStage = primaryStage; this.primaryStage = primaryStage;
cloudController = new CloudController(mainWindowController); mainWindowController = new MainWindowController();
main = this;
mainWindow(); mainWindow();
initActions(); initActions();
} catch (Exception e) { } catch (Exception e) {
@ -83,71 +84,61 @@ public class Main extends Application {
private void mainWindow(){ private void mainWindow(){
try { try {
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
loader.setLocation(ClassLoader.getSystemResource("fxml/MainWindow.fxml")); loader.setLocation(getClass().getResource("/fxml/MainWindow.fxml"));
loader.setController(mainWindowController);
pane = (AnchorPane) loader.load(); pane = (AnchorPane) loader.load();
// primaryStage.setResizable(false); primaryStage.setMinWidth(1130);
primaryStage.setMinHeight(600 + 34);
primaryStage.setTitle("cemu_UI"); primaryStage.setTitle("cemu_UI");
// primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream("/resources/Homeflix_Icon_64x64.png"))); //adds application icon // primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream(""))); //adds application icon
primaryStage.setOnCloseRequest(event -> System.exit(0));
mainWindowController = loader.getController(); //Link of FXMLController and controller class // generate window
mainWindowController.setMain(this); //call setMain scene = new Scene(pane); // create new scene, append pane to scene
scene.getStylesheets().add(Main.class.getResource("/css/MainWindows.css").toExternalForm());
primaryStage.setScene(scene); // append scene to stage
primaryStage.show(); // show stage
//get os and the right paths cloudController = CloudController.getInstance(mainWindowController); // call cloudController constructor
if (System.getProperty("os.name").equals("Linux")) {
directory = new File(dirLinux);
configFile = new File(dirLinux + "/config.xml");
gamesDBFile = new File(dirLinux + "/games.db");
localDB = new File(dirLinux+"/localRoms.db");
pictureCache= new File(dirLinux+"/picture_cache");
} else {
directory = new File(dirWin);
configFile = new File(dirWin + "/config.xml");
gamesDBFile = new File(dirWin + "/games.db");
localDB = new File(dirWin+"/localRoms.db");
pictureCache= new File(dirWin+"/picture_cache");
}
//startup checks // startup checks
//check if client_secret.jason is present // check if client_secret.json is present
if (Main.class.getResourceAsStream("/client_secret.json") == null) { if (Main.class.getResourceAsStream("/client_secret.json") == null) {
LOGGER.error("client_secret is missing!!!!!"); LOGGER.error("client_secret is missing!!!!!");
Alert alert = new Alert(AlertType.ERROR); JFXInfoAlert noCSAlert = new JFXInfoAlert("Error",
alert.setTitle("cemu_UI"); "client_secret is missing! Please contact the maintainer. \n"
alert.setHeaderText("Error"); + "If you compiled cemu_UI by yourself see: \n"
alert.setContentText("client_secret is missing! Please contact the maintainer. \nIf you compiled cemu_UI by yourself see: \nhttps://github.com/Seil0/cemu_UI/wiki/Documantation"); + "https://git.mosad.xyz/Seil0/cemu_UI/wiki/Documantation",
alert.showAndWait(); "-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
noCSAlert.showAndWait();
} }
LOGGER.info("Directory: " + directory.exists()); if (!XMLController.getDirCemuUI().exists()) {
LOGGER.info("Configfile: " + configFile.exists());
if (!directory.exists()) {
LOGGER.info("creating cemu_UI directory"); LOGGER.info("creating cemu_UI directory");
directory.mkdir(); XMLController.getDirCemuUI().mkdir();
pictureCache.mkdir(); XMLController.getPictureCache().mkdir();
} }
if (!configFile.exists()) { if (!XMLController.getConfigFile().exists()) {
LOGGER.info("firststart, setting default values"); LOGGER.info("firststart, setting default values");
firstStart(); firstStart();
mainWindowController.setColor("00a8cc"); xmlController.saveSettings();
mainWindowController.setAutoUpdate(false);
mainWindowController.setxPosHelper(0);
mainWindowController.saveSettings();
Runtime.getRuntime().exec("java -jar cemu_UI.jar"); //start again (preventing Bugs)
System.exit(0); //finishes itself
} }
if (pictureCache.exists() != true) { if (!XMLController.getPictureCache().exists()) {
pictureCache.mkdir(); XMLController.getPictureCache().mkdir();
} }
if (gamesDBFile.exists() != true) { if (!XMLController.getRference_gamesFile().exists()) {
if (XMLController.getGamesDBFile().exists()) {
XMLController.getGamesDBFile().delete();
}
try { try {
LOGGER.info("downloading games.db... "); LOGGER.info("downloading ReferenceGameList.db... ");
URL website = new URL(gamesDBdownloadURL); URL website = new URL(gamesDBdownloadURL);
ReadableByteChannel rbc = Channels.newChannel(website.openStream()); ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(gamesDBFile); FileOutputStream fos = new FileOutputStream(XMLController.getRference_gamesFile());
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close(); fos.close();
LOGGER.info("finished downloading games.db"); LOGGER.info("finished downloading games.db");
@ -156,84 +147,88 @@ public class Main extends Application {
} }
} }
//loading settings and initialize UI, dbController.main() loads all databases // init here as it loads the games to the mwc and the gui, therefore the window must exist
mainWindowController.loadSettings(); mainWindowController.init();
mainWindowController.checkAutoUpdate();
mainWindowController.initActions();
mainWindowController.initUI();
mainWindowController.dbController.main();
if(mainWindowController.isCloudSync()) {
cloudController.initializeConnection(mainWindowController.getCloudService(), mainWindowController.getCemuPath());
cloudController.stratupCheck(mainWindowController.getCloudService(), mainWindowController.getCemuPath());
}
mainWindowController.addUIData();
scene = new Scene(pane); //create new scene, append pane to scene // if cloud sync is activated start sync
scene.getStylesheets().add(Main.class.getResource("/css/MainWindows.css").toExternalForm()); if (XMLController.isCloudSync()) {
primaryStage.setScene(scene); //append scene to stage cloudController.initializeConnection(XMLController.getCloudService(), XMLController.getCemuPath());
primaryStage.show(); //show stage cloudController.sync(XMLController.getCloudService(), XMLController.getCemuPath(), XMLController.getDirCemuUIPath());
} catch (IOException e) {
e.printStackTrace();
} }
} catch (IOException e) {
e.printStackTrace();
}
} }
private void firstStart(){ public static void main(String[] args) {
Alert alert = new Alert(AlertType.CONFIRMATION); //new alert with file-chooser String logPath = "";
alert.setTitle("cemu_UI");
alert.setHeaderText("cemu installation");
alert.setContentText("please select your cemu installation");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDirectory = directoryChooser.showDialog(primaryStage);
mainWindowController.setCemuPath(selectedDirectory.getAbsolutePath());
if (System.getProperty("os.name").contains("Windows")) {
logPath = System.getProperty("user.home") + "/Documents/cemu_UI/app.log";
} else { } else {
mainWindowController.setCemuPath(null); logPath = System.getProperty("user.home") + "/cemu_UI/app.log";
} }
Alert alert2 = new Alert(AlertType.CONFIRMATION); //new alert with file-chooser System.setProperty("logFilename", logPath);
alert2.setTitle("cemu_UI"); File logFile = new File(logPath);
alert2.setHeaderText("rom directory"); logFile.delete();
alert2.setContentText("please select your rom directory"); LOGGER = LogManager.getLogger(Main.class.getName());
Optional<ButtonType> result2 = alert2.showAndWait(); xmlController = new XMLController();
if (result2.get() == ButtonType.OK) { launch(args);
}
private void firstStart() {
JFXOkayCancelAlert cemuInstallAlert = new JFXOkayCancelAlert("cemu installation",
"please select your cemu installation",
"-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
cemuInstallAlert.setOkayAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser(); DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDirectory = directoryChooser.showDialog(primaryStage); File selectedDirectory = directoryChooser.showDialog(primaryStage);
mainWindowController.setRomPath(selectedDirectory.getAbsolutePath()); XMLController.setCemuPath(selectedDirectory.getAbsolutePath());
});
cemuInstallAlert.setCancelAction(e -> {
XMLController.setCemuPath(null);
LOGGER.info("Action canceld by user!");
});
cemuInstallAlert.showAndWait();
JFXOkayCancelAlert romDirectoryAlert = new JFXOkayCancelAlert("rom directory",
"please select your rom directory",
"-fx-button-type: RAISED; -fx-background-color: #00a8cc; -fx-text-fill: BLACK;", primaryStage);
romDirectoryAlert.setOkayAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDirectory = directoryChooser.showDialog(primaryStage);
XMLController.setRomDirectoryPath(selectedDirectory.getAbsolutePath());
});
romDirectoryAlert.setCancelAction(e -> {
XMLController.setRomDirectoryPath(null);
LOGGER.info("Action canceld by user!");
});
romDirectoryAlert.showAndWait();
} else {
mainWindowController.setRomPath(null);
}
} }
private void initActions() { private void initActions() {
final ChangeListener<Number> widthListener = new ChangeListener<Number>() { final ChangeListener<Number> widthListener = new ChangeListener<Number>() {
final Timer timer = new Timer(); final Timer timer = new Timer();
TimerTask saveTask = null; //task to execute save operation TimerTask saveTask = null; // task to execute save operation
final long delayTime = 500; //delay until the window size is saved, if the window is resized earlier it will be killed, default is 500ms final long delayTime = 500; // delay until the window size is saved, if the window is resized earlier it will be killed, default is 500ms
@Override @Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue) { public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue) {
int xPosHelperMax = (int) Math.floor((mainWindowController.getMainAnchorPane().getWidth() - 36) / 217);
mainWindowController.refreshplayBtnPosition(); // if saveTask is already running kill it
//call only if there is enough space for a new row
if (mainWindowController.getOldXPosHelper() != xPosHelperMax) {
mainWindowController.refreshUIData();
}
//if saveTask is already running kill it
if (saveTask != null) saveTask.cancel(); if (saveTask != null) saveTask.cancel();
saveTask = new TimerTask() { saveTask = new TimerTask() {
@Override @Override
public void run() { public void run() {
mainWindowController.saveSettings(); XMLController.setWindowWidth(mainWindowController.getMainAnchorPane().getWidth());
xmlController.saveSettings();
} }
}; };
timer.schedule(saveTask, delayTime); timer.schedule(saveTask, delayTime);
@ -243,8 +238,8 @@ public class Main extends Application {
final ChangeListener<Number> heightListener = new ChangeListener<Number>() { final ChangeListener<Number> heightListener = new ChangeListener<Number>() {
final Timer timer = new Timer(); final Timer timer = new Timer();
TimerTask saveTask = null; //task to execute save operation TimerTask saveTask = null; // task to execute save operation
final long delayTime = 500; //delay until the window size is saved, if the window is resized earlier it will be killed, default is 500ms final long delayTime = 500; // delay until the window size is saved, if the window is resized earlier it will be killed, default is 500ms
@Override @Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue) { public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue) {
@ -254,7 +249,8 @@ public class Main extends Application {
saveTask = new TimerTask() { saveTask = new TimerTask() {
@Override @Override
public void run() { public void run() {
mainWindowController.saveSettings(); XMLController.setWindowHeight(mainWindowController.getMainAnchorPane().getHeight());
xmlController.saveSettings();
} }
}; };
timer.schedule(saveTask, delayTime); timer.schedule(saveTask, delayTime);
@ -278,29 +274,21 @@ public class Main extends Application {
} }
}; };
//add listener to primaryStage // add listener to primaryStage
primaryStage.widthProperty().addListener(widthListener); primaryStage.widthProperty().addListener(widthListener);
primaryStage.heightProperty().addListener(heightListener); primaryStage.heightProperty().addListener(heightListener);
primaryStage.maximizedProperty().addListener(maximizeListener); primaryStage.maximizedProperty().addListener(maximizeListener);
} }
public static void main(String[] args) { public static Main getMain() {
//delete old log file and create new return main;
if(System.getProperty("os.name").equals("Linux")){
System.setProperty("logFilename", System.getProperty("user.home") + "/cemu_UI/app.log");
File logFile = new File(System.getProperty("user.home") + "/cemu_UI/app.log");
logFile.delete();
}else{
System.setProperty("logFilename", System.getProperty("user.home") + "/Documents/cemu_UI/app.log");
File logFile = new File(System.getProperty("user.home") + "/Documents/cemu_UI/app.log");
logFile.delete();
}
LOGGER = LogManager.getLogger(Main.class.getName());
launch(args);
} }
@Override public CloudController getCloudController() {
public void stop() { return cloudController;
System.exit(0); }
public AnchorPane getPane() {
return pane;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,29 +22,33 @@
package com.cemu_UI.application; package com.cemu_UI.application;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.cemu_UI.controller.dbController; import com.cemu_UI.controller.CloudController;
import com.cemu_UI.controller.DBController;
import com.cemu_UI.controller.XMLController;
import javafx.application.Platform; import javafx.application.Platform;
public class playGame extends Thread{ public class playGame extends Thread {
MainWindowController mainWindowController; private MainWindowController mainWindowController;
dbController dbController; private DBController dbController;
private static final Logger LOGGER = LogManager.getLogger(playGame.class.getName()); private static final Logger LOGGER = LogManager.getLogger(playGame.class.getName());
public playGame(MainWindowController m, com.cemu_UI.controller.dbController db){ public playGame(MainWindowController m, com.cemu_UI.controller.DBController db) {
mainWindowController = m; mainWindowController = m;
dbController = db; dbController = db;
} }
@Override @Override
public void run(){ public void run() {
String selectedGameTitleID = mainWindowController.getSelectedGameTitleID(); String selectedGameTitleID = mainWindowController.getSelectedGameTitleID();
String executeComand; String cemuBin = XMLController.getCemuPath() + "/Cemu.exe";
String gameExec = "\"" + mainWindowController.getGameExecutePath() + "\"";
long startTime; long startTime;
long endTime; long endTime;
int timePlayedNow; int timePlayedNow;
@ -52,51 +56,50 @@ public class playGame extends Thread{
Process p; Process p;
Platform.runLater(() -> { Platform.runLater(() -> {
mainWindowController.main.primaryStage.setIconified(true); mainWindowController.getPrimaryStage().setIconified(true); // minimize cemu_UI
}); });
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
try{ try {
if(mainWindowController.isFullscreen()){ if (System.getProperty("os.name").equals("Linux")) {
if(System.getProperty("os.name").equals("Linux")){ if(XMLController.isFullscreen()){
executeComand = "wine "+mainWindowController.getCemuPath()+"/Cemu.exe -f -g \""+mainWindowController.getGameExecutePath()+"\""; p = new ProcessBuilder("wine", cemuBin, "-f", "-g", gameExec).start();
} else { } else {
executeComand = mainWindowController.getCemuPath()+"\\Cemu.exe -f -g \""+mainWindowController.getGameExecutePath()+"\""; p = new ProcessBuilder("wine", cemuBin, "-g", gameExec).start();
} }
}else{ } else {
if(System.getProperty("os.name").equals("Linux")){ if(XMLController.isFullscreen()){
executeComand = "wine "+mainWindowController.getCemuPath()+"/Cemu.exe -g \""+mainWindowController.getGameExecutePath()+"\""; p = new ProcessBuilder(cemuBin, "-f", "-g", gameExec).start();
} else { } else {
executeComand = mainWindowController.getCemuPath()+"\\Cemu.exe -g \""+mainWindowController.getGameExecutePath()+"\""; p = new ProcessBuilder(cemuBin, "-g", gameExec).start();
} }
} }
LOGGER.info(executeComand);
p = Runtime.getRuntime().exec(executeComand); p.waitFor(); // wait until cemu is closed so we can calculate the played time
p.waitFor();
endTime = System.currentTimeMillis(); endTime = System.currentTimeMillis();
timePlayedNow = (int) Math.floor(((endTime - startTime)/1000/60)); timePlayedNow = (int) Math.floor(((endTime - startTime)/1000/60));
timePlayed = Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID))+timePlayedNow; timePlayed = Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID))+timePlayedNow;
dbController.setTotalPlaytime(Integer.toString(timePlayed), selectedGameTitleID); dbController.setTotalPlaytime(Integer.toString(timePlayed), selectedGameTitleID);
Platform.runLater(() -> { Platform.runLater(() -> {
if(Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID)) > 60){ if (Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID)) > 60) {
int hoursPlayed = (int) Math.floor(Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID))/60); int hoursPlayed = (int) Math.floor(Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID)) / 60);
int minutesPlayed = Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID))-60*hoursPlayed; int minutesPlayed = Integer.parseInt(dbController.getTotalPlaytime(selectedGameTitleID)) - 60 * hoursPlayed;
mainWindowController.totalPlaytimeBtn.setText(hoursPlayed+"h "+minutesPlayed+"min"); mainWindowController.totalPlaytimeBtn.setText(hoursPlayed + "h " + minutesPlayed + "min");
}else{ } else {
mainWindowController.totalPlaytimeBtn.setText(dbController.getTotalPlaytime(selectedGameTitleID)+ " min"); mainWindowController.totalPlaytimeBtn.setText(dbController.getTotalPlaytime(selectedGameTitleID) + " min");
} }
mainWindowController.main.primaryStage.setIconified(false); mainWindowController.getPrimaryStage().setIconified(false); // maximize cemu_UI
}); });
// System.out.println(mainWindowController.getCemuPath()+"/mlc01/emulatorSave/"+);
//sync savegame with cloud service //sync savegame with cloud service
if(mainWindowController.isCloudSync()) { if (XMLController.isCloudSync()) {
mainWindowController.main.cloudController.sync(mainWindowController.getCloudService(), mainWindowController.getCemuPath()); XMLController.setLastLocalSync(Instant.now().getEpochSecond());
} CloudController.getInstance(mainWindowController).sync(XMLController.getCloudService(),
XMLController.getCemuPath(), XMLController.getDirCemuUIPath());
}
}catch (IOException | InterruptedException e){ } catch (IOException | InterruptedException e) {
e.printStackTrace(); LOGGER.error(e);
} }
} }

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,31 +22,51 @@
package com.cemu_UI.controller; package com.cemu_UI.controller;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.cemu_UI.application.MainWindowController; import com.cemu_UI.application.MainWindowController;
import com.cemu_UI.datatypes.GlobalDataTypes.CloudService;
import com.cemu_UI.vendorCloudController.GoogleDriveController; import com.cemu_UI.vendorCloudController.GoogleDriveController;
import javafx.application.Platform; import javafx.application.Platform;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
public class CloudController { public class CloudController {
// TODO make singleton
private MainWindowController mwc;
private static CloudController instance = null;
private XMLController xmlController = new XMLController();
private GoogleDriveController googleDriveController = new GoogleDriveController();
private static final Logger LOGGER = LogManager.getLogger(CloudController.class.getName());
public CloudController(MainWindowController mwc) { public CloudController(MainWindowController mwc) {
this.mwc = mwc; this.mwc = mwc;
} }
private MainWindowController mwc; public static CloudController getInstance(MainWindowController mwc) {
private GoogleDriveController googleDriveController = new GoogleDriveController(); if (instance == null) {
private static final Logger LOGGER = LogManager.getLogger(CloudController.class.getName()); instance = new CloudController(mwc);
}
public boolean initializeConnection(String cloudService, String cemuDirectory) { return instance;
}
public boolean initializeConnection(CloudService cloudService, String cemuDirectory) {
boolean success = false; boolean success = false;
LOGGER.info("sartting cloud initialisation ..."); LOGGER.info("sartting cloud initialisation ...");
if(cloudService.equals("GoogleDrive")) { if(cloudService == CloudService.GoogleDrive) {
LOGGER.info("selected service is Google Drive"); LOGGER.info("selected service is Google Drive");
try { try {
googleDriveController.main(cemuDirectory); googleDriveController.main(cemuDirectory);
@ -57,124 +77,151 @@ public class CloudController {
success = true; success = true;
} }
if(cloudService.equals("Dropbox")) { if(cloudService == CloudService.Dropbox) {
LOGGER.info("selected service is Dropbox"); LOGGER.info("selected service is Dropbox");
} }
LOGGER.info("cloud initialisation done!"); LOGGER.info("cloud initialisation done!");
return success; return success;
} }
public void stratupCheck(String cloudService, String cemuDirectory) { /**
if(cloudService.equals("GoogleDrive")) { * to trigger a new sync set the mwc LastLocalSync to the actual time and call the sync method
LOGGER.info("starting startup check google drive ..."); * @param cloudService
try { * @param cemuDirectory
if (!googleDriveController.checkFolder()) { * @param cemu_UIDirectory
googleDriveController.creatFolder(); */
mwc.saveSettings(); public void sync(CloudService cloudService, String cemuDirectory, String cemu_UIDirectory) {
Thread thread = new Thread(new Runnable() { // running sync in a new thread, instead of blocking the main thread
@Override
public void run() {
Platform.runLater(() -> {
mwc.getPlayBtn().setText("syncing...");
});
googleDriveController.uploadAllFiles();
Platform.runLater(() -> {
mwc.getPlayBtn().setText("play");
});
}
});
thread.start();
} else {
sync(cloudService, cemuDirectory);
}
} catch (IOException e) {
LOGGER.error("google drive startup check failed", e);
}
}
if(cloudService.equals("Dropbox")) {
}
}
public void sync(String cloudService, String cemuDirectory) {
//running sync in a new thread, instead of blocking the main thread
Thread thread = new Thread(new Runnable() { Thread thread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Platform.runLater(() -> { try {
mwc.getPlayBtn().setText("syncing..."); Platform.runLater(() -> {
}); mwc.getPlayBtn().setDisable(true);
LOGGER.info("starting synchronization in new thread ..."); mwc.getPlayBtn().setText("syncing...");
});
LOGGER.info("starting synchronization in new thread ...");
if(cloudService.equals("GoogleDrive")) { // zip the saves folder
try { File zipFile = zipSavegames(cemu_UIDirectory, cemuDirectory);
googleDriveController.sync(cemuDirectory);
} catch (IOException e) {
LOGGER.error("google drive synchronization failed", e);
}
}
if(cloudService.equals("Dropbox")) {
} // upload the zip
Platform.runLater(() -> { switch (cloudService) {
mwc.getPlayBtn().setText("play");
}); // use GoogleDriveController
mwc.saveSettings(); case GoogleDrive:
LOGGER.info("synchronization successful!"); LOGGER.info("using GoogleDriveController");
} long lastCloudSync = googleDriveController.getLastCloudSync();
});
if (!googleDriveController.checkFolder()) {
LOGGER.info("cloud sync folder dosen't exist, creating one!");
googleDriveController.creatFolder();
googleDriveController.uploadZipFile(zipFile);
} else if (XMLController.getLastLocalSync() > lastCloudSync) {
LOGGER.info("local is new, going to upload zip");
googleDriveController.uploadZipFile(zipFile);
} else if (XMLController.getLastLocalSync() < lastCloudSync) {
LOGGER.info("cloud is new, going to download zip");
unzipSavegames(cemuDirectory, googleDriveController.downloadZipFile(cemu_UIDirectory));
XMLController.setLastLocalSync(lastCloudSync);
break;
} else {
LOGGER.info("nothing to do");
break;
}
XMLController.setLastLocalSync(Long.parseLong(zipFile.getName().substring(0, zipFile.getName().length() - 4))); // set time of last sucessfull sync
break;
case Dropbox:
// do the thing
break;
default:
LOGGER.warn("no cloud vendor found!");
break;
}
zipFile.delete(); // delete zipfile in cem_UI directory
Platform.runLater(() -> {
mwc.getPlayBtn().setText("play");
mwc.getPlayBtn().setDisable(false);
xmlController.saveSettings();
});
LOGGER.info("synchronization successful!");
} catch (Exception e) {
LOGGER.error(
"There was an error during syncronisation! Please open a new issue on the cemu_UI github page:",
e);
}
}
});
thread.start(); thread.start();
} }
void uploadFile(String cloudService, File file) { private File zipSavegames(String cemu_UIDirectory, String cemuDirectory) throws Exception {
long unixTimestamp = Instant.now().getEpochSecond();
//running uploadFile in a new thread, instead of blocking the main thread FileOutputStream fos = new FileOutputStream(cemu_UIDirectory + "/" + unixTimestamp + ".zip");
new Thread() { ZipOutputStream zos = new ZipOutputStream(fos);
@Override addDirToZipArchive(zos, new File(cemuDirectory + "/mlc01/usr/save"), null);
public void run() { zos.flush();
LOGGER.info("starting uploadFile in new thread ..."); fos.flush();
zos.close();
if(cloudService.equals("GoogleDrive")) { fos.close();
try { return new File(cemu_UIDirectory + "/" + unixTimestamp + ".zip");
googleDriveController.uploadFile(file);
} catch (IOException e) {
LOGGER.error("google drive uploadFile failed" ,e);
}
}
if(cloudService.equals("Dropbox")) {
}
}
}.start();
} }
public String getFolderID(String cloudService) { private static void addDirToZipArchive(ZipOutputStream zos, File fileToZip, String parrentDirectoryName) throws Exception {
if (fileToZip == null || !fileToZip.exists()) {
return;
}
String zipEntryName = fileToZip.getName();
if (parrentDirectoryName!=null && !parrentDirectoryName.isEmpty()) {
zipEntryName = parrentDirectoryName + "/" + fileToZip.getName();
}
if (fileToZip.isDirectory()) {
for (File file : fileToZip.listFiles()) {
addDirToZipArchive(zos, file, zipEntryName);
}
} else {
byte[] buffer = new byte[1024];
FileInputStream fis = new FileInputStream(fileToZip);
zos.putNextEntry(new ZipEntry(zipEntryName));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
}
private void unzipSavegames(String cemuDirectory, File outputFile) {
try {
ZipFile zipFile = new ZipFile(outputFile);
zipFile.extractAll(cemuDirectory + "/mlc01/usr");
outputFile.delete();
LOGGER.info("unzip successfull");
} catch (ZipException e) {
LOGGER.error("an error occurred during unziping the file!", e);
}
}
public String getFolderID(CloudService cloudService) {
String folderID = ""; String folderID = "";
if (cloudService != null) { if (cloudService != null) {
if(cloudService.equals("GoogleDrive")) { if (cloudService == CloudService.GoogleDrive) {
folderID = googleDriveController.getFolderID(); folderID = googleDriveController.getFolderID();
} }
if(cloudService.equals("Dropbox")) { if (cloudService == CloudService.Dropbox) {
} }
} }
return folderID; return folderID;
} }
public void setFolderID(String folderID, String cloudService) {
if (cloudService != null) {
if (cloudService.equals("GoogleDrive")) {
googleDriveController.setFolderID(folderID);
}
if (cloudService.equals("Dropbox")) {
}
}
}
} }

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,6 +28,7 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
@ -45,205 +46,237 @@ import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import com.cemu_UI.application.MainWindowController; import com.cemu_UI.datatypes.UIROMDataType;
public class dbController { import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public dbController(MainWindowController m) { public class DBController {
mainWindowController = m;
}
private MainWindowController mainWindowController; private static DBController instance = null;
private ArrayList<String> entries = new ArrayList<>(); private ArrayList<String> entries = new ArrayList<>();
private String DB_PATH; private String DB_PATH_LocalGames;
private String DB_PATH_games; private String DB_PATH_ReverenceGames;
private Connection connection = null; private Connection connectionLocal = null;
private Connection connectionGames = null; private Connection connectionReverence = null;
private static final Logger LOGGER = LogManager.getLogger(dbController.class.getName()); private static final Logger LOGGER = LogManager.getLogger(DBController.class.getName());
public DBController() {
public void main(){
LOGGER.info("<==========starting loading sql==========>");
loadRomDatabase();
loadGamesDatabase();
createRomDatabase();
loadAllRoms();
checkRemoveEntry();
LOGGER.info("<==========finished loading sql==========>");
} }
private void loadRomDatabase(){ public static DBController getInstance() {
if (System.getProperty("os.name").equals("Linux")) { if (instance == null) {
DB_PATH = System.getProperty("user.home") + "/cemu_UI/localRoms.db"; instance = new DBController();
}else{
DB_PATH = System.getProperty("user.home") + "\\Documents\\cemu_UI" + "\\" + "localRoms.db";
} }
try {
// create a database connection return instance;
connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
connection.setAutoCommit(false); //AutoCommit to false -> manual commit is active
} catch (SQLException e) {
// if the error message is "out of memory", it probably means no database file is found
LOGGER.error("error while loading the ROM database", e);
}
LOGGER.info("ROM database loaded successfull");
} }
/** /**
* this method is used to load the games database with additional informations about a game * initialize the {@link DBController} with the database connection check if
* it is used if a new game is added (automatic or manual) * there is a need to create a new database refresh the database
*/ */
private void loadGamesDatabase(){ public void init() {
if (System.getProperty("os.name").equals("Linux")) { initDatabaseConnection();
DB_PATH_games = System.getProperty("user.home") + "/cemu_UI/games.db"; createRomDatabase();
}else{
DB_PATH_games = System.getProperty("user.home") + "\\Documents\\cemu_UI" + "\\" + "games.db";
}
try {
// create a database connection
connectionGames = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH_games);
connectionGames.setAutoCommit(false); //AutoCommit to false -> manual commit is active
} catch (SQLException e) {
// if the error message is "out of memory", it probably means no database file is found
LOGGER.error("error while loading the games database", e);
}
LOGGER.info("games database loaded successfull");
} }
//creating database, if database has 0 entries search for all .rpx files in the roms directory and add them /**
void createRomDatabase() { * create a new connection to the HomeFlix.db database
try { * AutoCommit is set to false to prevent some issues, so manual commit is active!
Statement stmt = connection.createStatement(); *
stmt.executeUpdate("create table if not exists local_roms (title, coverPath, romPath, titleID, productCode, region, lastPlayed, timePlayed)"); * TODO this should be called LocalGames
stmt.close(); */
connection.commit(); private void initDatabaseConnection() {
} catch (SQLException e) { DB_PATH_LocalGames = XMLController.getDirCemuUI() + "/localRoms.db";
LOGGER.error("error while creating ROM database", e); DB_PATH_ReverenceGames = XMLController.getRference_gamesFile().getAbsolutePath();
}
try { try {
Statement stmt = connection.createStatement(); // create a database connection
connectionLocal = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH_LocalGames);
connectionLocal.setAutoCommit(false);
connectionReverence = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH_ReverenceGames);
connectionReverence.setAutoCommit(false);
} catch (SQLException e) {
// if the error message is "out of memory", it probably means no database file is found
LOGGER.error("error while loading the Local- or ReverenceGames database", e);
}
LOGGER.info("Local- and ReverenceGames database loaded successfull");
}
/**
* creating the local_roms table in localRoms.db
* if the table has no entries, call loadRomDirectory
*
* TODO the local_roms table should be called LocalGames
*/
void createRomDatabase() {
try {
Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("create table if not exists local_roms (title, coverPath, romPath, titleID, productCode, region, lastPlayed, timePlayed)");
connectionLocal.commit();
stmt.close();
} catch (SQLException e) {
LOGGER.error("error while creating local-games database", e);
}
}
/**
* refresh database to contain all (new added) games
*/
public void refreshDataBase() {
LOGGER.info("<========== starting refreshing database ==========>");
entries.clear();
try {
Statement stmt = connectionLocal.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms"); ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms");
while (rs.next()) { while (rs.next()) {
entries.add(rs.getString(2)); entries.add(rs.getString(2));
} }
stmt.close(); stmt.close();
rs.close(); rs.close();
}catch (SQLException e){ } catch (SQLException e) {
LOGGER.error("error while loading ROMs from ROM database, local_roms table", e); LOGGER.error("error while loading ROMs from ROM database, local_roms table", e);
} }
if(entries.size() == 0){
loadRomDirectory(mainWindowController.getRomPath()); if (entries.size() == 0) {
loadAllGames();
} }
LOGGER.info("<========== finished refreshing database ==========>");
} }
public void addRom(String title, String coverPath, String romPath, String titleID, String productCode, String region, String lastPlayed, String timePlayed) throws SQLException{ // add a game to the database
Statement stmt = connection.createStatement(); public void addGame(String title, String coverPath, String romPath, String titleID, String productCode, String region, String lastPlayed, String timePlayed) throws SQLException{
Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("insert into local_roms values ('"+title+"','"+coverPath+"','"+romPath+"','"+titleID+"'," stmt.executeUpdate("insert into local_roms values ('"+title+"','"+coverPath+"','"+romPath+"','"+titleID+"',"
+ "'"+productCode+"','"+region+"','"+lastPlayed+"','"+timePlayed+"')"); + "'"+productCode+"','"+region+"','"+lastPlayed+"','"+timePlayed+"')");
connection.commit(); connectionLocal.commit();
stmt.close(); stmt.close();
LOGGER.info("added \""+title+"\" to ROM database"); LOGGER.info("added \""+title+"\" to ROM database");
} }
public void removeRom(String titleID) throws SQLException{ // remove a game from the database
Statement stmt = connection.createStatement(); public void removeGame(String titleID) throws SQLException{
Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("delete from local_roms where titleID = '"+titleID+"'"); stmt.executeUpdate("delete from local_roms where titleID = '"+titleID+"'");
connection.commit(); connectionLocal.commit();
stmt.close(); stmt.close();
LOGGER.info("removed \""+titleID+"\" from ROM database"); LOGGER.info("removed \""+titleID+"\" from ROM database");
} }
//load all ROMs on startup to the mainWindowController /**
void loadAllRoms(){ * load all games from the database to a ObservableList, order entries by title
LOGGER.info("loading all rom's on startup into the mainWindowController ..."); * @return a ObservableList that contains all local games from the database
*/
public ObservableList<UIROMDataType> loadAllGames() {
ObservableList<UIROMDataType> games = FXCollections.observableArrayList();
LOGGER.info("loading all local games from the database ...");
try { try {
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms"); ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms");
while (rs.next()) { while (rs.next()) {
mainWindowController.addGame(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4)); games.add(new UIROMDataType(rs.getString("romPath"), rs.getString("titleID"), rs.getString("title"),
rs.getString("coverPath")));
} }
stmt.close(); stmt.close();
rs.close(); rs.close();
}catch (Exception e){ } catch (Exception e) {
LOGGER.error("error while loading all ROMs into the mainWindowController", e); LOGGER.error("error while loading all local games from the database", e);
} }
return games;
} }
//load one single ROM after manual adding into the mainWindowController /**
public void loadSingleRom(String titleID){ * load one game from the database
LOGGER.info("loading a single ROM (ID: "+titleID+") into the mainWindowController ..."); * @param titleID the titleID of the game you wish to get
* @return the game you asked for
*/
public UIROMDataType loadSingleGame(String titleID) {
UIROMDataType game = null;
LOGGER.info("loading a single game (ID: {}) from the database ...", titleID);
try { try {
Statement stmt = connection.createStatement(); PreparedStatement ps = connectionLocal.prepareStatement("SELECT * FROM local_roms where titleID = ?");
ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms where titleID = '"+titleID+"'"); ps.setString(1, titleID);
ResultSet rs = ps.executeQuery();
while (rs.next()) { while (rs.next()) {
mainWindowController.addGame(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4)); game = new UIROMDataType(rs.getString("romPath"), rs.getString("titleID"), rs.getString("title"),
rs.getString("coverPath"));
} }
stmt.close();
rs.close(); rs.close();
ps.close();
}catch (Exception e){ }catch (Exception e){
LOGGER.error("error while loading a single ROM into the mainWindowController", e); LOGGER.error("error while loading a single game into the mainWindowController", e);
} }
return game;
} }
//get all files with .rpx TODO add other formats /**
* get all .rpx files from a given directory and add them to the games database if they don't exist there
* @param directory where to search for the .rpx files
*/
public void loadRomDirectory(String directory){ public void loadRomDirectory(String directory){
File dir = new File(directory); File dir = new File(directory);
File appFile; File appFile;
String[] extensions = new String[] { "rpx", "jsp" }; String[] extensions = new String[] { "rpx", "jsp" };
File pictureCache; File pictureCache = XMLController.getPictureCache();
String coverPath; String coverPath;
if(System.getProperty("os.name").equals("Linux")){
pictureCache = mainWindowController.getPictureCacheLinux();
}else{
pictureCache = mainWindowController.getPictureCacheWin();
}
try { try {
Statement stmt = connectionGames.createStatement(); Statement stmt = connectionReverence.createStatement();
List<File> files = (List<File>) FileUtils.listFiles(dir, extensions, true); List<File> files = (List<File>) FileUtils.listFiles(dir, extensions, true);
LOGGER.info("<============================== start loading ROM Directory ==============================>");
LOGGER.info("Getting all .rpx files in " + dir.getCanonicalPath()+" including those in subdirectories"); LOGGER.info("Getting all .rpx files in " + dir.getCanonicalPath()+" including those in subdirectories");
// for all files in dir get the app.xml
for (File file : files) { for (File file : files) {
if(System.getProperty("os.name").equals("Linux")){ appFile = new File(file.getParent() + "/app.xml");
appFile = new File(file.getParent()+"/app.xml");
} else {
appFile = new File(file.getParent()+"\\app.xml");
}
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(appFile); Document document = documentBuilder.parse(appFile);
String title_ID = document.getElementsByTagName("title_id").item(0).getTextContent(); String title_ID = document.getElementsByTagName("title_id").item(0).getTextContent(); // get titile_ID from app.xml
title_ID = title_ID.substring(0, 8) + "-" + title_ID.substring(8, title_ID.length()); title_ID = title_ID.substring(0, 8) + "-" + title_ID.substring(8, title_ID.length());
LOGGER.info("Name: "+file.getName()+"; Title ID: "+title_ID); LOGGER.info("Name: " + file.getName() + "; Title ID: " + title_ID);
ResultSet rs = stmt.executeQuery("SELECT * FROM games WHERE TitleID = '"+title_ID+"';"); ResultSet rs = stmt.executeQuery("SELECT * FROM games WHERE TitleID = '" + title_ID + "';");
while (rs.next()) {
if (checkEntry(rs.getString(2))) {
LOGGER.info(rs.getString(2) + ": game already in database");
}else{
LOGGER.info("adding cover to cache ...");
BufferedImage originalImage = ImageIO.read(new URL(rs.getString(6)));//change path to where file is located
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImagePNG = resizeImage(originalImage, type, 400, 600);
if(System.getProperty("os.name").equals("Linux")) {
ImageIO.write(resizeImagePNG, "png", new File(pictureCache+"/"+rs.getString(3)+".png")); //change path where you want it saved
coverPath = pictureCache+"/"+rs.getString(3)+".png";
} else {
ImageIO.write(resizeImagePNG, "png", new File(pictureCache+"\\"+rs.getString(3)+".png")); //change path where you want it saved
coverPath = pictureCache+"\\"+rs.getString(3)+".png";
}
// for all elements in the games table check if it's already present, else add it
while (rs.next()) {
if (checkAddEntry(rs.getString(2))) {
LOGGER.info(rs.getString(2) + ": game already in database");
} else {
LOGGER.info("adding cover to cache ...");
BufferedImage originalImage = ImageIO.read(new URL(rs.getString(6)));// change path to where file is located
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImagePNG = resizeImage(originalImage, type, 400, 600);
ImageIO.write(resizeImagePNG, "png", new File(pictureCache + "/" + rs.getString(3) + ".png"));
coverPath = pictureCache + "/" + rs.getString(3) + ".png";
LOGGER.info(rs.getString(2) + ": adding ROM"); LOGGER.info(rs.getString(2) + ": adding ROM");
addRom(rs.getString(2), coverPath, file.getCanonicalPath(), rs.getString(1), rs.getString(3), rs.getString(5),"","0"); addGame(rs.getString(2), coverPath, file.getCanonicalPath(), rs.getString(1), rs.getString(3),
rs.getString(5), "", "0");
} }
} }
} }
LOGGER.info("<============================= finished loading ROM Directory ============================>");
} catch (IOException | SQLException | ParserConfigurationException | SAXException e) { } catch (IOException | SQLException | ParserConfigurationException | SAXException e) {
LOGGER.error("error while loading ROMs from directory", e); LOGGER.error("error while loading ROMs from directory", e);
} }
} }
private boolean checkEntry(String title) throws SQLException{ /**
Statement stmt = connection.createStatement(); * check if there is a game with the given name already in the database
* @param title game title
* @return true if the game exists, false if not
* @throws SQLException
*/
private boolean checkAddEntry(String title) throws SQLException{
Statement stmt = connectionLocal.createStatement();
boolean check = false; boolean check = false;
ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms WHERE title = '"+title+"';"); ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms WHERE title = '"+title+"';");
while (rs.next()) { while (rs.next()) {
@ -252,6 +285,7 @@ public class dbController {
return check; return check;
} }
@SuppressWarnings("unused")
private void checkRemoveEntry() { private void checkRemoveEntry() {
/** /**
* TODO needs to be implemented! * TODO needs to be implemented!
@ -260,15 +294,6 @@ public class dbController {
//LOGGER.info("check if entry removed not done yet!"); //LOGGER.info("check if entry removed not done yet!");
} }
private static BufferedImage resizeImage(BufferedImage originalImage, int type, int IMG_WIDTH, int IMG_HEIGHT) {
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
return resizedImage;
}
/** /**
* getting info for a game with titleID * getting info for a game with titleID
* @param titleID Title-ID of the Game * @param titleID Title-ID of the Game
@ -278,7 +303,7 @@ public class dbController {
String[] gameInfo = new String[4]; String[] gameInfo = new String[4];
LOGGER.info("getting game info for titleID: "+titleID+" ..."); LOGGER.info("getting game info for titleID: "+titleID+" ...");
try { try {
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms where titleID = '"+titleID+"'"); ResultSet rs = stmt.executeQuery("SELECT * FROM local_roms where titleID = '"+titleID+"'");
while (rs.next()) { while (rs.next()) {
gameInfo[0] = rs.getString(1);// title gameInfo[0] = rs.getString(1);// title
@ -294,13 +319,13 @@ public class dbController {
return gameInfo; return gameInfo;
} }
public void setGameInfo(String title, String titleID, String romPath, String coverPath){ public void setGameInfo(String title, String coverPath, String romPath, String titleID){
LOGGER.info("setting game info for titleID: "+titleID+" ..."); LOGGER.info("setting game info for titleID: "+titleID+" ...");
try { try {
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("UPDATE local_roms SET title = '" + title + "', coverPath = '" + coverPath + "'," stmt.executeUpdate("UPDATE local_roms SET title = '" + title + "', coverPath = '" + coverPath + "',"
+ " romPath = '" + romPath + "' WHERE titleID = '"+titleID+"';"); + " romPath = '" + romPath + "' WHERE titleID = '"+titleID+"';");
connection.commit(); connectionLocal.commit();
stmt.close(); stmt.close();
}catch (Exception e){ }catch (Exception e){
LOGGER.error("error while setting game info", e); LOGGER.error("error while setting game info", e);
@ -309,9 +334,9 @@ public class dbController {
public void setLastPlayed(String titleID){ public void setLastPlayed(String titleID){
try{ try{
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("UPDATE local_roms SET lastPlayed=date('now') WHERE titleID = '"+titleID+"';"); stmt.executeUpdate("UPDATE local_roms SET lastPlayed=date('now') WHERE titleID = '"+titleID+"';");
connection.commit(); connectionLocal.commit();
stmt.close(); stmt.close();
}catch(SQLException e){ }catch(SQLException e){
LOGGER.error("failed to set the last played", e); LOGGER.error("failed to set the last played", e);
@ -321,7 +346,7 @@ public class dbController {
public String getLastPlayed(String titleID){ public String getLastPlayed(String titleID){
String lastPlayed = null; String lastPlayed = null;
try{ try{
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
ResultSet rs = stmt.executeQuery("SELECT lastPlayed FROM local_roms WHERE titleID = '"+titleID+"';" ); ResultSet rs = stmt.executeQuery("SELECT lastPlayed FROM local_roms WHERE titleID = '"+titleID+"';" );
lastPlayed = rs.getString(1); lastPlayed = rs.getString(1);
stmt.close(); stmt.close();
@ -334,9 +359,9 @@ public class dbController {
public void setTotalPlaytime(String timePlayed, String titleID){ public void setTotalPlaytime(String timePlayed, String titleID){
try{ try{
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
stmt.executeUpdate("UPDATE local_roms SET timePlayed='"+timePlayed+"' WHERE titleID = '"+titleID+"';"); stmt.executeUpdate("UPDATE local_roms SET timePlayed='"+timePlayed+"' WHERE titleID = '"+titleID+"';");
connection.commit(); connectionLocal.commit();
stmt.close(); stmt.close();
}catch(SQLException e){ }catch(SQLException e){
LOGGER.error("failed to set total play time", e); LOGGER.error("failed to set total play time", e);
@ -347,7 +372,7 @@ public class dbController {
public String getTotalPlaytime(String titleID){ public String getTotalPlaytime(String titleID){
String timePlayed = null; String timePlayed = null;
try{ try{
Statement stmt = connection.createStatement(); Statement stmt = connectionLocal.createStatement();
ResultSet rs = stmt.executeQuery("SELECT timePlayed FROM local_roms WHERE titleID = '"+titleID+"';" ); ResultSet rs = stmt.executeQuery("SELECT timePlayed FROM local_roms WHERE titleID = '"+titleID+"';" );
timePlayed = rs.getString(1); timePlayed = rs.getString(1);
stmt.close(); stmt.close();
@ -358,5 +383,13 @@ public class dbController {
return timePlayed; return timePlayed;
} }
private static BufferedImage resizeImage(BufferedImage originalImage, int type, int IMG_WIDTH, int IMG_HEIGHT) {
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
return resizedImage;
}
} }

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -63,6 +63,7 @@ public class SmmdbAPIController {
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("error while making api request or reading response"); LOGGER.error("error while making api request or reading response");
LOGGER.error("response from " + URL + " was: " + output, e); LOGGER.error("response from " + URL + " was: " + output, e);
return course;
} }
String apiOutput = "{ \"courses\": " + output + "}"; String apiOutput = "{ \"courses\": " + output + "}";

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -43,110 +43,100 @@ import com.eclipsesource.json.JsonValue;
import javafx.application.Platform; import javafx.application.Platform;
public class UpdateController implements Runnable{ public class UpdateController implements Runnable {
private MainWindowController mainWindowController; private MainWindowController mainWindowController;
private String buildNumber; private int buildNumber;
private int updateBuildNumber; // tag_name from gitea
private String apiOutput; private String apiOutput;
private String updateBuildNumber; //tag_name from Github @SuppressWarnings("unused")
private String browserDownloadUrl; //update download link private String updateName;
private String githubApiRelease = "https://api.github.com/repos/Seil0/cemu_UI/releases/latest"; @SuppressWarnings("unused")
private String githubApiBeta = "https://api.github.com/repos/Seil0/cemu_UI/releases"; private String updateChanges;
private URL githubApiUrl; private String browserDownloadUrl; // update download link
private String giteaApiRelease = "https://git.mosad.xyz/api/v1/repos/Seil0/cemu_UI/releases";
private URL giteaApiUrl;
private boolean useBeta; private boolean useBeta;
private static final Logger LOGGER = LogManager.getLogger(UpdateController.class.getName()); private static final Logger LOGGER = LogManager.getLogger(UpdateController.class.getName());
/** /**
* updater for cemu_UI based on Project HomeFlix * updater for cemu_UI, checks for Updates and download it
* checks for Updates and download it in case there is one
*/ */
public UpdateController(MainWindowController mwc, String buildNumber, boolean useBeta){ public UpdateController(MainWindowController mwc, String buildNumber, boolean useBeta) {
mainWindowController = mwc; mainWindowController = mwc;
this.buildNumber = buildNumber; this.buildNumber = Integer.parseInt(buildNumber);
this.useBeta = useBeta; this.useBeta = useBeta;
} }
public void run(){ @Override
System.out.println("checking for updates ..."); public void run() {
LOGGER.info("beta:" + useBeta + "; checking for updates ...");
Platform.runLater(() -> { Platform.runLater(() -> {
mainWindowController.getUpdateBtn().setText("checking for updates ..."); mainWindowController.getUpdateBtn().setText(XMLController.getLocalBundle().getString("updateBtnChecking"));
}); });
try { try {
giteaApiUrl = new URL(giteaApiRelease);
if (useBeta) { BufferedReader ina = new BufferedReader(new InputStreamReader(giteaApiUrl.openStream()));
githubApiUrl = new URL(githubApiBeta);
} else {
githubApiUrl = new URL(githubApiRelease);
}
// URL githubApiUrl = new URL(githubApiRelease);
BufferedReader ina = new BufferedReader(new InputStreamReader(githubApiUrl.openStream()));
apiOutput = ina.readLine(); apiOutput = ina.readLine();
ina.close(); ina.close();
} catch (IOException e) { } catch (IOException e) {
Platform.runLater(() -> { Platform.runLater(() -> {
LOGGER.error("could not check update version", e); LOGGER.error("could not check update version", e);
}); });
} }
if (useBeta) { JsonArray objectArray = Json.parse("{\"items\": " + apiOutput + "}").asObject().get("items").asArray();
JsonArray objectArray = Json.parse("{\"items\": " + apiOutput + "}").asObject().get("items").asArray(); JsonValue object = objectArray.get(0).asObject(); // set to the latest release as default
JsonValue object = objectArray.get(0); JsonObject objectAsset = object.asObject().get("assets").asArray().get(0).asObject();
JsonArray objectAssets = object.asObject().get("assets").asArray();
updateBuildNumber = object.asObject().getString("tag_name", ""); for(JsonValue objectIt : objectArray) {
// updateName = object.asObject().getString("name", ""); // TODO note this will download still the pre-release if there's a more recent stable version
// updateChanges = object.asObject().getString("body", ""); if(objectIt.asObject().getBoolean("prerelease", false) == useBeta) {
// we found the needed release either beta or not
for (JsonValue asset : objectAssets) { object = objectIt;
browserDownloadUrl = asset.asObject().getString("browser_download_url", ""); objectAsset = objectIt.asObject().get("assets").asArray().get(0).asObject();
} break;
}
} else {
JsonObject object = Json.parse(apiOutput).asObject();
JsonArray objectAssets = Json.parse(apiOutput).asObject().get("assets").asArray();
updateBuildNumber = object.getString("tag_name", "");
// updateName = object.getString("name", "");
// updateChanges = object.getString("body", "");
for (JsonValue asset : objectAssets) {
browserDownloadUrl = asset.asObject().getString("browser_download_url", "");
}
} }
LOGGER.info("Build: "+buildNumber+", Update: "+updateBuildNumber); updateBuildNumber = Integer.parseInt(object.asObject().getString("tag_name", ""));
updateName = object.asObject().getString("name", "");
updateChanges = object.asObject().getString("body", "");
//Compares the program BuildNumber with the current BuildNumber if program BuildNumber < current BuildNumber then perform a update LOGGER.info("Build: " + buildNumber + ", Update: " + updateBuildNumber);
int iversion = Integer.parseInt(buildNumber);
int iaktVersion = Integer.parseInt(updateBuildNumber.replace(".", ""));
if(iversion >= iaktVersion){ /**
* Compare the program BuildNumber with the current BuildNumber
* if buildNumber < updateBuildNumber then perform a update
*/
if (buildNumber >= updateBuildNumber) {
Platform.runLater(() -> { Platform.runLater(() -> {
mainWindowController.getUpdateBtn().setText("no update available"); mainWindowController.getUpdateBtn().setText(XMLController.getLocalBundle().getString("updateBtnNoUpdateAvailable"));
}); });
LOGGER.info("no update available"); LOGGER.info("no update available");
}else{ } else {
Platform.runLater(() -> { Platform.runLater(() -> {
mainWindowController.getUpdateBtn().setText("update available"); mainWindowController.getUpdateBtn().setText(XMLController.getLocalBundle().getString("updateBtnUpdateAvailable"));
}); });
LOGGER.info("update available"); LOGGER.info("update available");
browserDownloadUrl = objectAsset.getString("browser_download_url", "");
LOGGER.info("download link: " + browserDownloadUrl); LOGGER.info("download link: " + browserDownloadUrl);
try { try {
//open new Http connection, ProgressMonitorInputStream for downloading the data // open new Http connection, ProgressMonitorInputStream for downloading the data
HttpURLConnection conn = (HttpURLConnection) new URL(browserDownloadUrl).openConnection(); HttpURLConnection connection = (HttpURLConnection) new URL(browserDownloadUrl).openConnection();
ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, "Downloading...", conn.getInputStream()); ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, "Downloading...", connection.getInputStream());
ProgressMonitor pm = pmis.getProgressMonitor(); ProgressMonitor pm = pmis.getProgressMonitor();
pm.setMillisToDecideToPopup(0); pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0); pm.setMillisToPopup(0);
pm.setMinimum(0);// tell the progress bar that we start at the beginning of the stream pm.setMinimum(0);// set beginning of the progress bar to 0
pm.setMaximum(conn.getContentLength());// tell the progress bar the total number of bytes we are going to read. pm.setMaximum(connection.getContentLength());// set the end to the file length
FileUtils.copyInputStreamToFile(pmis, new File("cemu_UI_update.jar")); //download update FileUtils.copyInputStreamToFile(pmis, new File("cemu_UI_update.jar")); // download update
org.apache.commons.io.FileUtils.copyFile(new File("cemu_UI_update.jar"), new File("cemu_UI.jar")); //TODO rename update to old name org.apache.commons.io.FileUtils.copyFile(new File("cemu_UI_update.jar"), new File("cemu_UI.jar"));
org.apache.commons.io.FileUtils.deleteQuietly(new File("cemu_UI_update.jar")); //delete update org.apache.commons.io.FileUtils.deleteQuietly(new File("cemu_UI_update.jar")); // delete update
Runtime.getRuntime().exec("java -jar cemu_UI.jar"); //start again new ProcessBuilder("java", "-jar", "cemu_UI.jar").start(); // start the new application
System.exit(0); //finishes itself System.exit(0); // close the current application
} catch (IOException e) { } catch (IOException e) {
Platform.runLater(() -> { Platform.runLater(() -> {
LOGGER.info("could not download update files", e); LOGGER.info("could not download update files", e);
@ -155,4 +145,3 @@ public class UpdateController implements Runnable{
} }
} }
} }

View File

@ -0,0 +1,419 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.cemu_UI.datatypes.GlobalDataTypes.CloudService;
public class XMLController {
private static final String userHome = System.getProperty("user.home");
private static final String userName = System.getProperty("user.name");
private static final String osName = System.getProperty("os.name");
private static final String osArch = System.getProperty("os.arch");
private static final String osVers = System.getProperty("os.version");
private static final String javaVers = System.getProperty("java.version");
private static final String javaVend = System.getProperty("java.vendor");
private static final String sysLocal = System.getProperty("user.language") + "_" + System.getProperty("user.country");
private static String dirCemuUIPath;
private static File dirCemuUI;
private static File configFile;
private static File gamesDBFile;
private static File reference_gamesFile;
private static File pictureCache;
// user settings
private static String color = "00a8cc";
private static String usrLocal = sysLocal;
private static boolean autoUpdate = false;
private static boolean useBeta = false;
private static boolean fullscreen = false;
private static boolean cloudSync = false;
private static ResourceBundle localBundle = ResourceBundle.getBundle("locals.cemu_UI-Local", Locale.US);
private static String cemuPath;
private static String romDirectoryPath;
private static String folderID;
private static CloudService cloudService;
private static long lastLocalSync;
private static double windowWidth;
private static double windowHeight;
private static final Logger LOGGER = LogManager.getLogger(XMLController.class.getName());
private Properties props = new Properties();
public XMLController() {
if (osName.contains("Windows")) {
dirCemuUIPath = userHome + "/Documents/cemu_UI";
} else {
dirCemuUIPath = userHome + "/cemu_UI";
}
// set the concrete files
dirCemuUI = new File(dirCemuUIPath);
configFile = new File(dirCemuUI + "/config.xml");
gamesDBFile = new File(dirCemuUI + "/games.db");
reference_gamesFile = new File(dirCemuUI + "/reference_games.db");
pictureCache= new File(dirCemuUI+"/picture_cache");
}
/**
* save settings to the config.xml file
*/
public void saveSettings() {
LOGGER.info("saving Settings ...");
try {
props.setProperty("cemuPath", getCemuPath());
props.setProperty("romPath", getRomDirectoryPath());
props.setProperty("color", getColor());
props.setProperty("language", getUsrLocal());
props.setProperty("fullscreen", String.valueOf(isFullscreen()));
props.setProperty("cloudSync", String.valueOf(isCloudSync()));
props.setProperty("autoUpdate", String.valueOf(isAutoUpdate()));
props.setProperty("useBeta", String.valueOf(isUseBeta()));
if (getCloudService() == null) {
props.setProperty("cloudService", "");
props.setProperty("folderID", "");
props.setProperty("lastLocalSync", "");
} else {
props.setProperty("cloudService", getCloudService().toString());
props.setProperty("folderID", getFolderID());
props.setProperty("lastLocalSync", Long.toString(getLastLocalSync()));
}
props.setProperty("windowWidth", Double.toString(getWindowWidth()));
props.setProperty("windowHeight", Double.toString(getWindowHeight()));
OutputStream outputStream = new FileOutputStream(XMLController.getConfigFile()); // new output-stream
props.storeToXML(outputStream, "cemu_UI settings"); // write new .xml
outputStream.close();
LOGGER.info("saving Settings done!");
} catch (IOException e) {
LOGGER.error("an error occured", e);
}
}
/**
* loading saved settings from the config.xml file
* if a value is not present, default is used instead
*/
public void loadSettings() {
LOGGER.info("loading settings ...");
try {
InputStream inputStream = new FileInputStream(XMLController.getConfigFile());
props.loadFromXML(inputStream); // new input-stream from .xml
try {
setCemuPath(props.getProperty("cemuPath"));
} catch (Exception e) {
LOGGER.error("cloud not load cemuPath", e);
setCemuPath("");
}
try {
setRomDirectoryPath(props.getProperty("romPath"));
} catch (Exception e) {
LOGGER.error("could not load romPath", e);
setRomDirectoryPath("");
}
try {
setColor(props.getProperty("color"));
} catch (Exception e) {
LOGGER.error("could not load color value, setting default instead", e);
setColor("00a8cc");
}
if (props.getProperty("language") == null) {
LOGGER.error("cloud not load language, setting default instead");
setUsrLocal("en_US");
} else {
setUsrLocal(props.getProperty("language"));
}
try {
setFullscreen(Boolean.parseBoolean(props.getProperty("fullscreen")));
} catch (Exception e) {
LOGGER.error("could not load fullscreen, setting default instead", e);
setFullscreen(false);
}
try {
setCloudSync(Boolean.parseBoolean(props.getProperty("cloudSync")));
} catch (Exception e) {
LOGGER.error("could not load cloudSync, setting default instead", e);
setCloudSync(false);
}
try {
setAutoUpdate(Boolean.parseBoolean(props.getProperty("autoUpdate")));
} catch (Exception e) {
LOGGER.error("cloud not load autoUpdate", e);
setAutoUpdate(false);
}
try {
setUseBeta(Boolean.parseBoolean(props.getProperty("useBeta")));
} catch (Exception e) {
LOGGER.error("cloud not load autoUpdate", e);
setUseBeta(false);
}
try {
switch (props.getProperty("cloudService")) {
case "GoogleDrive":
setCloudService(CloudService.GoogleDrive);
break;
case "Dropbox":
setCloudService(CloudService.Dropbox);
break;
default:
break;
}
} catch (Exception e) {
LOGGER.error("could not load cloudSync", e);
setCloudService(null);
}
try {
setFolderID(props.getProperty("folderID"));
} catch (Exception e) {
LOGGER.error("could not load folderID, disable cloud sync. Please contact an developer", e);
setCloudSync(false);
}
try {
setLastLocalSync(Long.parseLong(props.getProperty("lastLocalSync")));
} catch (Exception e) {
LOGGER.error("could not load lastSuccessSync, setting default instead", e);
setLastLocalSync(0);
}
try {
setWindowWidth(Double.parseDouble(props.getProperty("windowWidth")));
} catch (Exception e) {
LOGGER.error("could not load windowWidth, setting default instead", e);
setWindowWidth(904);
}
try {
setWindowHeight(Double.parseDouble(props.getProperty("windowHeight")));
} catch (Exception e) {
LOGGER.error("could not load windowHeight, setting default instead", e);
setWindowHeight(600);
}
inputStream.close();
LOGGER.info("loading settings done!");
} catch (IOException e) {
LOGGER.error("an error occured", e);
}
}
// getters for application variables
public static String getUserHome() {
return userHome;
}
public static String getUserName() {
return userName;
}
public static String getOsName() {
return osName;
}
public static String getOsArch() {
return osArch;
}
public static String getOsVers() {
return osVers;
}
public static String getJavaVers() {
return javaVers;
}
public static String getJavaVend() {
return javaVend;
}
public static String getSysLocal() {
return sysLocal;
}
public static String getDirCemuUIPath() {
return dirCemuUIPath;
}
public static File getDirCemuUI() {
return dirCemuUI;
}
public static File getConfigFile() {
return configFile;
}
public static File getGamesDBFile() {
return gamesDBFile;
}
public static File getRference_gamesFile() {
return reference_gamesFile;
}
public static File getPictureCache() {
return pictureCache;
}
// getters & setters for user settings
public static String getColor() {
return color;
}
public static void setColor(String color) {
XMLController.color = color;
}
public static String getUsrLocal() {
return usrLocal;
}
public static void setUsrLocal(String usrLocal) {
XMLController.usrLocal = usrLocal;
}
public static boolean isAutoUpdate() {
return autoUpdate;
}
public static void setAutoUpdate(boolean autoUpdate) {
XMLController.autoUpdate = autoUpdate;
}
public static boolean isUseBeta() {
return useBeta;
}
public static void setUseBeta(boolean useBeta) {
XMLController.useBeta = useBeta;
}
public static boolean isFullscreen() {
return fullscreen;
}
public static void setFullscreen(boolean fullscreen) {
XMLController.fullscreen = fullscreen;
}
public static boolean isCloudSync() {
return cloudSync;
}
public static void setCloudSync(boolean cloudSync) {
XMLController.cloudSync = cloudSync;
}
public static ResourceBundle getLocalBundle() {
return localBundle;
}
public static void setLocalBundle(ResourceBundle localBundle) {
XMLController.localBundle = localBundle;
}
public static String getCemuPath() {
return cemuPath;
}
public static void setCemuPath(String cemuPath) {
XMLController.cemuPath = cemuPath;
}
public static String getRomDirectoryPath() {
return romDirectoryPath;
}
public static void setRomDirectoryPath(String romDirectoryPath) {
XMLController.romDirectoryPath = romDirectoryPath;
}
public static String getFolderID() {
return folderID;
}
public static void setFolderID(String folderID) {
XMLController.folderID = folderID;
}
public static CloudService getCloudService() {
return cloudService;
}
public static void setCloudService(CloudService cloudService) {
XMLController.cloudService = cloudService;
}
public static long getLastLocalSync() {
return lastLocalSync;
}
public static void setLastLocalSync(long lastLocalSync) {
XMLController.lastLocalSync = lastLocalSync;
}
public static double getWindowWidth() {
return windowWidth;
}
public static void setWindowWidth(double windowWidth) {
XMLController.windowWidth = windowWidth;
}
public static double getWindowHeight() {
return windowHeight;
}
public static void setWindowHeight(double windowHeight) {
XMLController.windowHeight = windowHeight;
}
}

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -0,0 +1,29 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.datatypes;
public class GlobalDataTypes {
public enum CloudService {
GoogleDrive, Dropbox
}
}

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,107 +21,111 @@
package com.cemu_UI.datatypes; package com.cemu_UI.datatypes;
import java.io.File;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import javafx.beans.property.SimpleObjectProperty; import javafx.geometry.Insets;
import javafx.beans.property.SimpleStringProperty; import javafx.scene.control.ContextMenu;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
public class UIROMDataType { public class UIROMDataType extends VBox {
private final SimpleObjectProperty<VBox> vBox = new SimpleObjectProperty<>(); private String romPath;
private final SimpleObjectProperty<Label> label = new SimpleObjectProperty<>(); private String titleID;
private final SimpleObjectProperty<JFXButton> button = new SimpleObjectProperty<>(); private String name;
private final SimpleObjectProperty<ImageView> imageView = new SimpleObjectProperty<>(); private Label label = new Label();
private final StringProperty titleID = new SimpleStringProperty(); private JFXButton button = new JFXButton();
private final StringProperty romPath = new SimpleStringProperty(); private ImageView imageView = new ImageView();
/** public UIROMDataType(String romPath, String titleID, String name, String coverPath) {
* Data type used for UI ROM elements all uiROMElemts are of this data type this();
*/
public UIROMDataType (final VBox vBox, final Label label, final JFXButton button, final ImageView imageView, final String titleID, final String romPath){ this.romPath = romPath;
this.vBox.set(vBox); this.titleID = titleID;
this.label.set(label); this.name = name;
this.button.set(button);
this.imageView.set(imageView); label.setText(name);
this.titleID.set(titleID); imageView.setImage(new Image(new File(coverPath).toURI().toString()));
this.romPath.set(romPath);
} }
public SimpleObjectProperty<VBox> vBoxProperty(){ public UIROMDataType(String romPath, String titleID, String name, String coverPath, ContextMenu contextMenu) {
return vBox; this();
this.romPath = romPath;
this.titleID = titleID;
this.name = name;
label.setText(name);
imageView.setImage(new Image(new File(coverPath).toURI().toString()));
button.setContextMenu(contextMenu);
} }
public SimpleObjectProperty<Label> labelProperty(){ public UIROMDataType() {
return label; super.getChildren().addAll(label, button);
label.setMaxWidth(200);
label.setPadding(new Insets(0,0,0,8));
label.setFont(Font.font("System", FontWeight.BOLD, 14));
imageView.setFitHeight(300);
imageView.setFitWidth(200);
button.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 3); ");
button.setGraphic(imageView);
} }
public SimpleObjectProperty<JFXButton> buttonProperty(){ public String getRomPath() {
return button;
}
public SimpleObjectProperty<ImageView> imageViewProperty(){
return imageView;
}
public StringProperty titleIDProperty(){
return titleID;
}
public StringProperty romPathProperty(){
return romPath; return romPath;
} }
public String getTitleID() {
public final VBox getVBox() { return titleID;
return vBoxProperty().get();
} }
public final Label getLabel() { public String getName() {
return labelProperty().get(); return name;
} }
public final JFXButton getButton() { public Label getLabel() {
return buttonProperty().get(); return label;
} }
public final ImageView getImageView() { public JFXButton getButton() {
return imageViewProperty().get(); return button;
} }
public final String getTitleID(){ public ImageView getImageView() {
return titleIDProperty().get(); return imageView;
} }
public final String getRomPath(){ public void setRomPath(String romPath) {
return romPathProperty().get(); this.romPath = romPath;
} }
public void setTitleID(String titleID) {
public final void setVBox(VBox vBox) { this.titleID = titleID;
vBoxProperty().set(vBox);
} }
public final void setLabel(Label label) { public void setName(String name) {
labelProperty().set(label); this.name = name;
} }
public final void setButton(JFXButton button) { public void setLabel(Label label) {
buttonProperty().set(button); this.label = label;
} }
public final void setImageView(ImageView imageView) { public void setButton(JFXButton button) {
imageViewProperty().set(imageView); this.button = button;
} }
public final void setTitleID(String titleID){ public void setImageView(ImageView imageView) {
titleIDProperty().set(titleID); this.imageView = imageView;
} }
public final void setRomPath(String romPath){
romPathProperty().set(romPath);
}
} }

View File

@ -0,0 +1,250 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import java.io.File;
import com.cemu_UI.application.MainWindowController;
import com.cemu_UI.controller.XMLController;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class JFXEditGameAlert {
private String headingText;
private String bodyText;
private String title = "";
private String coverPath = "";
private String romPath = "";
private String titleID = "";
private String btnStyle;
private int mode;
private Stage stage;
private MainWindowController mwc; // TODO remove this!
/**
* Creates a new JFoenix Alert to show some information with okay and cancel option
* @param headingText Heading text of the alert
* @param bodyText Content text of the alert
* @param btnStyle Style of the buttons
* @param mode Set to 0 for add and 1 for edit mode
* @param stage Stage to which the Alert belongs
* @param mwc a mwc dep, it's horrible i know
*/
public JFXEditGameAlert(String headingText, String bodyText, String btnStyle, int mode, Stage stage, MainWindowController mwc) {
this.headingText = headingText;
this.bodyText = bodyText;
this.btnStyle = btnStyle;
this.mode = mode;
this.stage = stage;
this.mwc = mwc;
}
public void showAndWait( ) {
JFXAlert<Void> alert = new JFXAlert<>(stage);
TextField gameTitleTF = new TextField();
gameTitleTF.setPromptText(XMLController.getLocalBundle().getString("gameTitle"));
TextField gameTitleIDTF = new TextField();
gameTitleIDTF.setPromptText(XMLController.getLocalBundle().getString("titleID"));
TextField romPathTF = new TextField();
romPathTF.setPromptText(XMLController.getLocalBundle().getString("romPath"));
TextField gameCoverTF = new TextField();
gameCoverTF.setPromptText(XMLController.getLocalBundle().getString("coverPath"));
if (mode == 1) {
gameTitleTF.setText(title);
gameTitleIDTF.setText(titleID);
romPathTF.setText(romPath);
gameCoverTF.setText(coverPath);
gameTitleIDTF.setEditable(false);
}
JFXButton okayBtn = new JFXButton(XMLController.getLocalBundle().getString("okayBtnText"));
okayBtn.setOnAction(event -> {
if (romPathTF.getText().toString().length() == 0 || gameCoverTF.getText().toString().length() == 0
|| gameTitleTF.getText().toString().length() == 0
|| gameTitleIDTF.getText().toString().length() == 0) {
// addGame error dialog
JFXInfoAlert errorDialog = new JFXInfoAlert(
XMLController.getLocalBundle().getString("editGameDialogHeadingTextError"),
XMLController.getLocalBundle().getString("editGameDialogBodyTextError"), btnStyle, stage);
errorDialog.showAndWait();
} else {
switch (mode) {
case 0:
// add-mode title, coverPath, romPath, titleID
mwc.addBtnReturn(gameTitleTF.getText().toString(), gameCoverTF.getText().toString(),
romPathTF.getText().toString(), gameTitleIDTF.getText().toString());
break;
case 1:
// edit mode
mwc.editBtnReturn(gameTitleTF.getText().toString(), gameCoverTF.getText().toString(),
romPathTF.getText().toString(), gameTitleIDTF.getText().toString());
break;
default:
break;
}
alert.close();
}
});
okayBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
okayBtn.setPrefHeight(32);
okayBtn.setStyle(btnStyle);
JFXButton cancelBtn = new JFXButton(XMLController.getLocalBundle().getString("cancelBtnText"));
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> alert.close());
cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
cancelBtn.setPrefHeight(32);
cancelBtn.setStyle(btnStyle);
JFXButton selectPathBtn = new JFXButton(XMLController.getLocalBundle().getString("editGameDialogSelectPathBtn"));
selectPathBtn.setPrefWidth(110);
selectPathBtn.setStyle(btnStyle);
selectPathBtn.setOnAction(event -> {
FileChooser romDirectoryChooser = new FileChooser();
File romDirectory = romDirectoryChooser.showOpenDialog(stage);
romPathTF.setText(romDirectory.getAbsolutePath());
});
JFXButton selectCoverBtn = new JFXButton(XMLController.getLocalBundle().getString("editGameDialogSelectCoverBtn"));
selectCoverBtn.setPrefWidth(110);
selectCoverBtn.setStyle(btnStyle);
selectCoverBtn.setOnAction(event -> {
FileChooser coverDirectoryChooser = new FileChooser();
File coverDirectory = coverDirectoryChooser.showOpenDialog(stage);
gameCoverTF.setText(coverDirectory.getAbsolutePath());
});
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(15, 10, 10, 10));
grid.add(new Label(XMLController.getLocalBundle().getString("gameTitle") + ":"), 0, 0);
grid.add(gameTitleTF, 1, 0);
grid.add(new Label(XMLController.getLocalBundle().getString("titleID") + ":"), 0, 1);
grid.add(gameTitleIDTF, 1, 1);
grid.add(new Label(XMLController.getLocalBundle().getString("romPath") + ":"), 0, 2);
grid.add(romPathTF, 1, 2);
grid.add(selectPathBtn, 2, 2);
grid.add(new Label(XMLController.getLocalBundle().getString("coverPath") + ":"), 0, 3);
grid.add(gameCoverTF, 1, 3);
grid.add(selectCoverBtn, 2, 3);
VBox vbox = new VBox();
vbox.getChildren().addAll(new Text(bodyText), grid);
JFXDialogLayout content = new JFXDialogLayout();
content.setActions(cancelBtn, okayBtn);
content.setHeading(new Text(headingText));
content.setBody(vbox);
alert.setContent(content);
alert.showAndWait();
}
public String getHeadingText() {
return headingText;
}
public String getBodyText() {
return bodyText;
}
public String getTitle() {
return title;
}
public String getCoverPath() {
return coverPath;
}
public String getRomPath() {
return romPath;
}
public String getTitleID() {
return titleID;
}
public String getBtnStyle() {
return btnStyle;
}
public int getMode() {
return mode;
}
public Stage getStage() {
return stage;
}
public void setHeadingText(String headingText) {
this.headingText = headingText;
}
public void setBodyText(String bodyText) {
this.bodyText = bodyText;
}
public void setTitle(String title) {
this.title = title;
}
public void setCoverPath(String coverPath) {
this.coverPath = coverPath;
}
public void setRomPath(String romPath) {
this.romPath = romPath;
}
public void setTitleID(String titleID) {
this.titleID = titleID;
}
public void setBtnStyle(String btnStyle) {
this.btnStyle = btnStyle;
}
public void setMode(int mode) {
this.mode = mode;
}
public void setStage(Stage stage) {
this.stage = stage;
}
}

View File

@ -0,0 +1,106 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.event.ActionEvent;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class JFXInfoAlert {
private String headingText;
private String bodyText;
private String btnStyle;
private Stage stage;
/**
* Creates a new JFoenix Alert to show some information
* @param headerText Heading text of the alert
* @param bodyText Content text of the alert
* @param btnStyle Style of the okay button
* @param stage Stage to which the Alert belongs
*/
public JFXInfoAlert(String headingText, String bodyText, String btnStyle, Stage stage) {
setHeadingText(headingText);
setBodyText(bodyText);
setBtnStyle(btnStyle);
setStage(stage);
}
public JFXInfoAlert() {
// Auto-generated constructor stub
}
public void showAndWait( ) {
JFXAlert<Void> alert = new JFXAlert<>(stage);
JFXButton button = new JFXButton("Okay");
button.addEventHandler(ActionEvent.ACTION, (e)-> alert.close());
button.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
button.setPrefHeight(32);
button.setStyle(btnStyle);
JFXDialogLayout content = new JFXDialogLayout();
content.setActions(button);
content.setHeading(new Text(headingText));
content.setBody(new Text(bodyText));
alert.setContent(content);
alert.showAndWait();
}
public String getHeadingText() {
return headingText;
}
public void setHeadingText(String headingText) {
this.headingText = headingText;
}
public String getBodyText() {
return bodyText;
}
public void setBodyText(String bodyText) {
this.bodyText = bodyText;
}
public String getBtnStyle() {
return btnStyle;
}
public void setBtnStyle(String btnStyle) {
this.btnStyle = btnStyle;
}
public Stage getStage() {
return stage;
}
public void setStage(Stage stage) {
this.stage = stage;
}
}

View File

@ -1,86 +0,0 @@
/**
* cemu_UI
*
* Copyright 2017 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
public class JFXInfoDialog {
private String headingText;
private String bodyText;
private String dialogBtnStyle;
private int dialogWidth;
private int dialogHeight;
private Pane pane;
/**
* Creates a new JFoenix Dialog to show some information
* @param headingText Heading Text, just the heading
* @param bodyText body Text, all other text belongs here
* @param dialogBtnStyle Style of the okay button
* @param dialogWidth dialog width
* @param dialogHeight dialog height
* @param pane pane to which the dialog belongs
*/
public JFXInfoDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth, int dialogHeight, Pane pane) {
this.headingText = headingText;
this.bodyText = bodyText;
this.dialogBtnStyle = dialogBtnStyle;
this.dialogWidth = dialogWidth;
this.dialogHeight = dialogHeight;
this.pane = pane;
}
public void show() {
JFXDialogLayout content = new JFXDialogLayout();
content.setHeading(new Text(headingText));
content.setBody(new Text(bodyText));
content.setPrefSize(dialogWidth, dialogHeight);
StackPane stackPane = new StackPane();
stackPane.autosize();
JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true);
JFXButton button = new JFXButton("Okay");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
dialog.close();
}
});
button.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
button.setPrefHeight(32);
button.setStyle(dialogBtnStyle);
content.setActions(button);
pane.getChildren().add(stackPane);
AnchorPane.setTopAnchor(stackPane, (pane.getHeight() - content.getPrefHeight()) / 2);
AnchorPane.setLeftAnchor(stackPane, (pane.getWidth() - content.getPrefWidth()) / 2);
dialog.show();
}
}

View File

@ -0,0 +1,151 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import com.cemu_UI.controller.XMLController;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class JFXOkayCancelAlert {
private String headingText;
private String bodyText;
private String btnStyle;
private Stage stage;
private EventHandler<ActionEvent> okayAction;
private EventHandler<ActionEvent> cancelAction;
private String okayText = XMLController.getLocalBundle().getString("okayBtnText");
private String cancelText = XMLController.getLocalBundle().getString("cancelBtnText");
/**
*
* @param headingText Heading text of the alert
* @param bodyText Content text of the alert
* @param btnStyle Style of the buttons
* @param stage Stage to which the Alert belongs
*/
public JFXOkayCancelAlert(String headingText, String bodyText, String btnStyle, Stage stage) {
setHeadingText(headingText);
setBodyText(bodyText);
setBtnStyle(btnStyle);
setStage(stage);
}
public void showAndWait( ) {
JFXAlert<Void> alert = new JFXAlert<>(stage);
JFXButton okayBtn = new JFXButton(okayText);
okayBtn.addEventHandler(ActionEvent.ACTION, (e)-> alert.close());
okayBtn.addEventHandler(ActionEvent.ACTION, okayAction);
okayBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
okayBtn.setPrefHeight(32);
okayBtn.setStyle(btnStyle);
JFXButton cancelBtn = new JFXButton(cancelText);
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> alert.close());
cancelBtn.addEventHandler(ActionEvent.ACTION, cancelAction);
cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
cancelBtn.setPrefHeight(32);
cancelBtn.setStyle(btnStyle);
JFXDialogLayout content = new JFXDialogLayout();
content.setActions(cancelBtn, okayBtn);
content.setHeading(new Text(headingText));
content.setBody(new Text(bodyText));
alert.setContent(content);
alert.showAndWait();
}
public String getHeadingText() {
return headingText;
}
public void setHeadingText(String headingText) {
this.headingText = headingText;
}
public String getBodyText() {
return bodyText;
}
public void setBodyText(String bodyText) {
this.bodyText = bodyText;
}
public String getBtnStyle() {
return btnStyle;
}
public void setBtnStyle(String btnStyle) {
this.btnStyle = btnStyle;
}
public String getOkayText() {
return okayText;
}
public void setOkayText(String okayText) {
this.okayText = okayText;
}
public String getCancelText() {
return cancelText;
}
public void setCancelText(String cancelText) {
this.cancelText = cancelText;
}
public Stage getStage() {
return stage;
}
public void setStage(Stage stage) {
this.stage = stage;
}
public EventHandler<ActionEvent> getOkayAction() {
return okayAction;
}
public void setOkayAction(EventHandler<ActionEvent> okayAction) {
this.okayAction = okayAction;
}
public EventHandler<ActionEvent> getCancelAction() {
return cancelAction;
}
public void setCancelAction(EventHandler<ActionEvent> cancelAction) {
this.cancelAction = cancelAction;
}
}

View File

@ -1,105 +0,0 @@
/**
* cemu_UI
*
* Copyright 2017 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
public class JFXOkayCancelDialog {
private String headingText;
private String bodyText;
private String dialogBtnStyle;
private int dialogWidth;
private int dialogHeight;
private EventHandler<ActionEvent> okayAction;
private EventHandler<ActionEvent> cancelAction;
private Pane pane;
/**
* Creates a new JFoenix Dialog to show some information with okay and cancel option
* @param headingText Heading Text, just the heading
* @param bodyText body Text, all other text belongs here
* @param dialogBtnStyle Style of the okay button
* @param dialogWidth dialog width
* @param dialogHeight dialog height
* @param okayAction action which is performed if the okay button is clicked
* @param cancelAction action which is performed if the cancel button is clicked
* @param pane pane to which the dialog belongs
*/
public JFXOkayCancelDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth,
int dialogHeight, EventHandler<ActionEvent> okayAction, EventHandler<ActionEvent> cancelAction, Pane pane) {
this.headingText = headingText;
this.bodyText = bodyText;
this.dialogBtnStyle = dialogBtnStyle;
this.dialogWidth = dialogWidth;
this.dialogHeight = dialogHeight;
this.okayAction = okayAction;
this.cancelAction = cancelAction;
this.pane = pane;
}
public void show() {
JFXDialogLayout content= new JFXDialogLayout();
content.setHeading(new Text(headingText));
content.setBody(new Text(bodyText));
StackPane stackPane = new StackPane();
stackPane.autosize();
JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true);
JFXButton okayBtn = new JFXButton("Okay");
okayBtn.addEventHandler(ActionEvent.ACTION, okayAction);
okayBtn.addEventHandler(ActionEvent.ACTION, (e)-> {
dialog.close();
});
okayBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
okayBtn.setPrefHeight(32);
okayBtn.setStyle(dialogBtnStyle);
JFXButton cancelBtn = new JFXButton("Cancel");
cancelBtn.addEventHandler(ActionEvent.ACTION, cancelAction);
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> {
dialog.close();
});
cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
cancelBtn.setPrefHeight(32);
cancelBtn.setStyle(dialogBtnStyle);
Label placeholder = new Label();
placeholder.setPrefSize(15, 10);
content.setActions(cancelBtn, placeholder, okayBtn);
content.setPrefSize(dialogWidth, dialogHeight);
pane.getChildren().add(stackPane);
AnchorPane.setTopAnchor(stackPane, (pane.getHeight()-content.getPrefHeight())/2);
AnchorPane.setLeftAnchor(stackPane, (pane.getWidth()-content.getPrefWidth())/2);
dialog.show();
}
}

View File

@ -0,0 +1,104 @@
/**
* cemu_UI
*
* Copyright 2017-2019 <@Seil0>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.cemu_UI.uiElements;
import com.jfoenix.controls.JFXAlert;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXTextArea;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class JFXTextAreaAlert {
private String headingText;
private String textAreaText;
private String btnStyle;
private Stage stage;
/**
* Creates a new JFoenix Alert to show some information on a TextArea
* @param headingText Heading text of the alert
* @param textAreaText Content text of the alert
* @param btnStyle Style of the okay button
* @param stage Stage to which the Alert belongs
*/
public JFXTextAreaAlert(String headingText, String textAreaText, String btnStyle, Stage stage) {
setHeadingText(headingText);
setTextAreaText(textAreaText);
setBtnStyle(btnStyle);
setStage(stage);
}
public void showAndWait( ) {
JFXAlert<Void> alert = new JFXAlert<>(stage);
JFXTextArea textArea = new JFXTextArea(textAreaText);
textArea.setMinWidth(450);
JFXButton button = new JFXButton("Okay");
button.setOnAction(event -> alert.close());
button.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
button.setPrefHeight(32);
button.setStyle(btnStyle);
JFXDialogLayout content = new JFXDialogLayout();
content.setActions(button);
content.setHeading(new Text(headingText));
content.setBody(textArea);
alert.setContent(content);
alert.showAndWait();
}
public String getHeadingText() {
return headingText;
}
public String getTextAreaText() {
return textAreaText;
}
public String getBtnStyle() {
return btnStyle;
}
public Stage getStage() {
return stage;
}
public void setHeadingText(String headingText) {
this.headingText = headingText;
}
public void setTextAreaText(String textAreaText) {
this.textAreaText = textAreaText;
}
public void setBtnStyle(String btnStyle) {
this.btnStyle = btnStyle;
}
public void setStage(Stage stage) {
this.stage = stage;
}
}

View File

@ -1,7 +1,7 @@
/** /**
* cemu_UI * cemu_UI
* *
* Copyright 2017 <@Seil0> * Copyright 2017-2019 <@Seil0>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,20 +21,16 @@
package com.cemu_UI.vendorCloudController; package com.cemu_UI.vendorCloudController;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.cemu_UI.controller.XMLController;
import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
@ -56,15 +52,11 @@ import com.google.api.services.drive.model.FileList;
public class GoogleDriveController { public class GoogleDriveController {
Drive service; Drive service;
private String saveDirectory; private String folderID = XMLController.getFolderID();
private String folderID; private File downloadFile;
private ArrayList<java.io.File> localSavegames = new ArrayList<>();
private ArrayList<File> cloudSavegames = new ArrayList<>();
private ArrayList<String> localSavegamesName = new ArrayList<>();
private ArrayList<String> cloudSavegamesName = new ArrayList<>();
private static final Logger LOGGER = LogManager.getLogger(GoogleDriveController.class.getName()); private static final Logger LOGGER = LogManager.getLogger(GoogleDriveController.class.getName());
private final String APPLICATION_NAME ="cemu_Ui Drive API Controller"; //TODO add Google private final String APPLICATION_NAME ="cemu_Ui Google Drive API Controller";
//Directory to store user credentials for this application //Directory to store user credentials for this application
private final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".credentials/cemu_UI_credential"); private final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".credentials/cemu_UI_credential");
@ -87,109 +79,51 @@ public class GoogleDriveController {
try { try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
folderID = ""; folderID = ""; // TODO why do we do this?
} catch (Throwable t) { } catch (Throwable t) {
LOGGER.error("error", t); LOGGER.error("error", t);
System.exit(1); System.exit(1);
} }
} }
/** /**
* Creates an authorized Credential object. * Creates an authorized Credential object.
* @return an authorized Credential object. *
* @throws IOException * @return an authorized Credential object.
*/ * @throws IOException
public Credential authorize() throws IOException { */
// Load client secrets. public Credential authorize() throws IOException {
InputStream in = getClass().getClassLoader().getResourceAsStream("client_secret.json"); // Load client secrets.
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in)); InputStream in = getClass().getClassLoader().getResourceAsStream("client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").build();
//FIXME Linux fails to open a new browser window, application crashes, maybe a kde only bug Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
// Build flow and trigger user authorization request. LOGGER.info("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) return credential;
.setDataStoreFactory(DATA_STORE_FACTORY) }
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
LOGGER.info("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/** /**
* Build and return an authorized Drive client service. * Build and return an authorized Drive client service.
*
* @return an authorized Drive client service * @return an authorized Drive client service
* @throws IOException * @throws IOException
*/ */
public Drive getDriveService() throws IOException { public Drive getDriveService() throws IOException {
Credential credential = authorize(); Credential credential = authorize();
return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
.setApplicationName(APPLICATION_NAME) }
.build();
}
public void main(String cemuDirectory) throws IOException {
service = getDriveService();
public void main(String cemuDirectory) throws IOException {
java.io.File dir = new java.io.File(cemuDirectory + "/mlc01/usr/save");
service = getDriveService();
// cemu >= 1.11 uses /mlc01/usr/save/... instead of /mlc01/emulatorSave/...
if (dir.exists()) {
LOGGER.info("using new save path");
saveDirectory = cemuDirectory + "/mlc01/usr/save";
} else {
LOGGER.info("using old save path");
saveDirectory = cemuDirectory + "/mlc01/emulatorSave";
}
}
public void sync(String cemuDirectory) throws IOException {
//in case there is no folderID saved, look it up first
if (getFolderID() == "" || getFolderID() == null) { if (getFolderID() == "" || getFolderID() == null) {
getSavegamesFolderID(); getSavegamesFolderID();
} }
getLocalSavegames();
getCloudSavegames();
// download files from cloud which don't exist locally
for (int i = 0; i < cloudSavegames.size(); i++) {
// if the file exists locally, check which one is newer
if (localSavegamesName.contains(cloudSavegames.get(i).getName())) {
int localSavegamesNumber = localSavegamesName.indexOf(cloudSavegames.get(i).getName());
long localModified = new DateTime(localSavegames.get(localSavegamesNumber).lastModified()).getValue();
long cloudModified = cloudSavegames.get(i).getModifiedTime().getValue();
FileInputStream fis = new FileInputStream(localSavegames.get(localSavegamesNumber));
if (cloudSavegames.get(i).getMd5Checksum().equals(org.apache.commons.codec.digest.DigestUtils.md5Hex(fis))) {
LOGGER.info("both files are the same, nothing to do");
} else {
if (localModified >= cloudModified) {
LOGGER.info("local is newer");
updateFile(cloudSavegames.get(i), localSavegames.get(localSavegamesNumber));
} else {
LOGGER.info("cloud is newer");
downloadFile(cloudSavegames.get(i));
}
}
} else {
LOGGER.info("file doesn't exist locally");
downloadFile(cloudSavegames.get(i));
}
}
// upload file to cloud which don't exist in the cloud
for (int j = 0; j < localSavegames.size(); j++) {
if (!cloudSavegamesName.contains(localSavegamesName.get(j))) {
LOGGER.info("file doesn't exist in the cloud");
uploadFile(localSavegames.get(j));
}
}
} }
//create a folder in google drive // create a folder in google drive
public void creatFolder() throws IOException { public void creatFolder() throws IOException {
LOGGER.info("creating new folder"); LOGGER.info("creating new folder");
File fileMetadata = new File(); File fileMetadata = new File();
@ -201,7 +135,7 @@ public class GoogleDriveController {
folderID = file.getId(); folderID = file.getId();
} }
//check if folder already exist // check if folder already exist
public boolean checkFolder() { public boolean checkFolder() {
try { try {
Files.List request = service.files().list().setQ("mimeType = 'application/vnd.google-apps.folder' and name = 'cemu_savegames'"); Files.List request = service.files().list().setQ("mimeType = 'application/vnd.google-apps.folder' and name = 'cemu_savegames'");
@ -217,32 +151,58 @@ public class GoogleDriveController {
} }
} }
//reading all local savegames // FIXME it seams like there is a bug in this method
private void getLocalSavegames() throws IOException { // get the name of the zip in the semu_savegames folder, which is the last upload Unix time
java.io.File dir = new java.io.File(saveDirectory); public long getLastCloudSync() throws IOException {
String[] extensions = new String[] { "dat","sav","bin" }; LOGGER.info("getting last cloud sync");
localSavegames.removeAll(localSavegames); long lastCloudSync = 0;
localSavegamesName.removeAll(localSavegamesName);
LOGGER.info("Getting all dat,sav,bin files in " + dir.getCanonicalPath()+" including those in subdirectories");
List<java.io.File> files = (List<java.io.File>) FileUtils.listFiles(dir, extensions, true);
for (java.io.File file : files) {
localSavegamesName.add(file.getParentFile().getName()+"_"+file.getName());
localSavegames.add(file);
}
}
//reading all cloud savegames
private void getCloudSavegames() throws IOException {
LOGGER.info("getting all cloud savegames");
cloudSavegames.removeAll(cloudSavegames);
cloudSavegamesName.removeAll(cloudSavegamesName);
Files.List request = service.files().list().setQ("'"+folderID+"' in parents").setFields("nextPageToken, files(id, name, size, modifiedTime, createdTime, md5Checksum)"); Files.List request = service.files().list().setQ("'"+folderID+"' in parents").setFields("nextPageToken, files(id, name, size, modifiedTime, createdTime, md5Checksum)");
FileList files = request.execute(); FileList files = request.execute();
for (File file : files.getFiles()) { for (File file : files.getFiles()) {
cloudSavegamesName.add(file.getName()); downloadFile = file;
cloudSavegames.add(file); lastCloudSync = Long.parseLong(file.getName().substring(0, file.getName().length()-4));
} }
return lastCloudSync;
}
/**
* delete all existing files in cemu_savegames at first
* upload the new savegames zip file
* @param uploadFile savegames zip file
* @throws IOException
*/
public void uploadZipFile(java.io.File uploadFile) throws IOException{
LOGGER.info("deleting old savegames ...");
Files.List request = service.files().list().setQ("'"+folderID+"' in parents").setFields("nextPageToken, files(id, name, size, modifiedTime, createdTime, md5Checksum)");
FileList files = request.execute();
for (File file : files.getFiles()) {
service.files().delete(file.getId()).execute(); // deleting old file
}
LOGGER.info("uploading " + uploadFile.getName() + " ...");
File fileMetadata = new File();
fileMetadata.setName(uploadFile.getName());
fileMetadata.setParents(Collections.singletonList(folderID));
fileMetadata.setModifiedTime(new DateTime(uploadFile.lastModified()));
FileContent mediaContent = new FileContent("", uploadFile);
File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute();
LOGGER.info("upload successfull, File ID: " + file.getId());
}
// download zip file from the cloud and unzip it
public java.io.File downloadZipFile(String cemu_UIDirectory) throws IOException{
LOGGER.info("downloading "+downloadFile.getName()+" ...");
java.io.File outputFile = new java.io.File(cemu_UIDirectory + "/" + downloadFile.getName());
OutputStream outputStream = new FileOutputStream(outputFile);
service.files().get(downloadFile.getId()).executeMediaAndDownloadTo(outputStream);
outputStream.close();
LOGGER.info("download successfull: " + downloadFile.getName());
return outputFile;
} }
private void getSavegamesFolderID() throws IOException { private void getSavegamesFolderID() throws IOException {
@ -251,76 +211,14 @@ public class GoogleDriveController {
try { try {
LOGGER.info("FolderID: " + files.getFiles().get(0).getId()); LOGGER.info("FolderID: " + files.getFiles().get(0).getId());
setFolderID(files.getFiles().get(0).getId()); folderID = files.getFiles().get(0).getId();
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("Oops, something went wrong! It seems that you have more than one folder called 'cemu_savegames'!", e); LOGGER.error("Oops, something went wrong! It seems that you have more than one folder called 'cemu_savegames'!", e);
} }
} }
//upload a file to the cloud from the local savegames folder
public void uploadFile(java.io.File uploadFile) throws IOException{
LOGGER.info("uploading " + uploadFile.getName() + " ...");
File fileMetadata = new File();
fileMetadata.setName(uploadFile.getParentFile().getName()+"_"+uploadFile.getName());
fileMetadata.setParents(Collections.singletonList(folderID));
fileMetadata.setModifiedTime(new DateTime(uploadFile.lastModified()));
FileContent mediaContent = new FileContent("", uploadFile);
File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute();
LOGGER.info("upload successfull, File ID: " + file.getId());
}
//download a file from the cloud to the local savegames folder
private void downloadFile(File downloadFile) throws IOException{
LOGGER.info("downloading "+downloadFile.getName()+" ...");
java.io.File directory = new java.io.File(saveDirectory + "/" + downloadFile.getName().substring(0,8));
String file = downloadFile.getName().substring(9,downloadFile.getName().length());
if(!directory.exists()) {
LOGGER.info("dir dosent exist");
directory.mkdir();
}
OutputStream outputStream = new FileOutputStream(directory +"/"+ file);
service.files().get(downloadFile.getId()).executeMediaAndDownloadTo(outputStream);
outputStream.close();
LOGGER.info("download successfull, File ID: " + file); //TODO add FileID
}
//update a file in the cloud, by deleting the old one and uploading an new with the same id
private void updateFile(File oldFile, java.io.File newFile) throws IOException {
LOGGER.info("updating " +oldFile.getName()+" ...");
service.files().delete(oldFile.getId()).execute(); //deleting old file
//uploading new file
File fileMetadata = new File();
fileMetadata.setName(newFile.getParentFile().getName()+"_"+newFile.getName());
fileMetadata.setParents(Collections.singletonList(folderID));
fileMetadata.setModifiedTime(new DateTime(newFile.lastModified()));
FileContent mediaContent = new FileContent("", newFile);
File file = service.files().create(fileMetadata, mediaContent).setFields("id, parents").execute();
LOGGER.info("update successfull, File ID: " + file.getId());
}
public void uploadAllFiles() {
try {
getLocalSavegames();
LOGGER.info("uploading " + localSavegames.size() + " files ...");
for (int i = 0; i < localSavegames.size(); i++) {
uploadFile(localSavegames.get(i));
}
LOGGER.info("finished uploading all files");
} catch (IOException e) {
LOGGER.error("error while uploading all files", e);
}
}
public String getFolderID() { public String getFolderID() {
return folderID; return folderID;
} }
public void setFolderID(String folderID) {
this.folderID = folderID;
}
} }

View File

@ -1,6 +1,8 @@
/* /*******************************************************************************
* HAMBURGER CSS * *
*/ * Hamburger Menu *
* *
******************************************************************************/
.jfx-hamburgerW StackPane { .jfx-hamburgerW StackPane {
-fx-background-color: white; -fx-background-color: white;
@ -12,9 +14,11 @@
-fx-background-radius: 5px; -fx-background-radius: 5px;
} }
/* /*******************************************************************************
* TREE TABLE CSS * *
*/ * TreeTable *
* *
******************************************************************************/
.tree-table-view { .tree-table-view {
-fx-tree-table-color: rgba(0, 168, 204, 0.2); -fx-tree-table-color: rgba(0, 168, 204, 0.2);
@ -81,6 +85,138 @@
-fx-background-color: -fx-tree-table-color, -fx-box-border, -fx-control-inner-background; -fx-background-color: -fx-tree-table-color, -fx-box-border, -fx-control-inner-background;
-fx-background-insets: -1.4, 0, 1; -fx-background-insets: -1.4, 0, 1;
-fx-background-radius: 1.4, 0, 0; -fx-background-radius: 1.4, 0, 0;
/*....*/
-fx-padding: 1; /* 0.083333em; */ -fx-padding: 1; /* 0.083333em; */
} }
/*******************************************************************************
* *
* ChoiceBox *
* *
******************************************************************************/
.choice-box {
-fx-background-color: transparent;
-fx-border-color: #000000;
-fx-border-width: 0 0 1 0;
-fx-background-radius: 0;
-fx-border-radius: 0;
}
.choice-box:focused {
-fx-border-color: #9E9E9E;
}
.choice-box>.open-button>.arrow {
-fx-background-color: #757575;
}
.menu-item:focused {
-fx-background-color: #00A8CC;
}
/*******************************************************************************
* *
* Spinner *
* *
******************************************************************************/
.spinner {
-fx-background-color: #f4f4f4;
}
/*******************************************************************************
* *
* ScrollBar *
* *
******************************************************************************/
.scroll-bar:vertical, .scroll-bar:horizontal {
-fx-background-color: transparent;
}
.scroll-bar:vertical > .track-background, .scroll-bar:horizontal > .track-background {
-fx-background-color: transparent;
-fx-background-insets: 0.0;
}
.scroll-bar:vertical > .thumb {
-fx-background-color: #BCBCBC;
-fx-background-insets: 0.0;
-fx-background-radius: 15.0;
}
.scroll-bar:horizontal > .thumb {
-fx-background-color: #FFFFFF;
-fx-background-insets: 0.0;
-fx-background-radius: 15.0;
}
/* Up- and Down-Button Padding */
.scroll-bar:vertical > .increment-button, .scroll-bar:vertical > .decrement-button {
-fx-padding: 5 2 5 2;
}
/* Left- and Right-Button Padding */
.scroll-bar:horizontal > .increment-button, .scroll-bar:horizontal > .decrement-button {
-fx-background-color: transparent;
-fx-padding: 5 2 5 2;
}
.scroll-bar > .increment-button, .scroll-bar > .decrement-button, .scroll-bar:hover > .increment-button, .scroll-bar:hover > .decrement-button {
-fx-background-color: transparent;
}
.scroll-bar > .increment-button > .increment-arrow, .scroll-bar > .decrement-button > .decrement-arrow {
-fx-background-color: rgb(150.0, 150.0, 150.0);
}
/* Up Arrow */
.scroll-bar:vertical > .increment-button > .increment-arrow {
-fx-shape: "M298 426h428l-214 214z";
}
/* Down Arrow */
.scroll-bar:vertical > .decrement-button > .decrement-arrow {
-fx-shape: "M298 598l214-214 214 214h-428z";
}
/* Right Arrow */
.scroll-bar:horizontal > .increment-button > .increment-arrow {
/* -fx-shape: "M0 428l0 -428l214 214l-214 214z"; */
-fx-background-color:transparent;
-fx-shape: " ";
-fx-padding: 0;
}
/* Left Arrow */
.scroll-bar:horizontal > .decrement-button > .decrement-arrow {
/* -fx-shape: "M214 0l0 428l-214 -214l214 -214z"; */
-fx-background-color:transparent;
-fx-shape: " ";
-fx-padding: 0;
}
/*******************************************************************************
* *
* ScrollPane *
* *
******************************************************************************/
.scroll-pane {
-fx-background-insets: 0;
-fx-padding: 0;
}
.scroll-pane:focused {
-fx-background-insets: 0;
}
.scroll-pane .corner {
-fx-background-insets: 0;
}
.scroll-pane > .viewport {
-fx-background-color: transparent;
}

View File

@ -10,23 +10,187 @@
<?import javafx.scene.control.ChoiceBox?> <?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?> <?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.text.TextFlow?> <?import javafx.scene.text.TextFlow?>
<AnchorPane fx:id="mainAnchorPane" prefHeight="600.0" prefWidth="904.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.cemu_UI.application.MainWindowController"> <AnchorPane fx:id="mainAnchorPane" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1130.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<ScrollPane fx:id="mainScrollPane" fitToWidth="true" layoutY="38.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0"> <ScrollPane fx:id="mainScrollPane" fitToWidth="true" layoutY="38.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<content> <content>
<AnchorPane fx:id="gamesAnchorPane"> <FlowPane fx:id="gamesFlowPane" hgap="3.0" vgap="7.0">
<padding> <padding>
<Insets bottom="17.0" /> <Insets bottom="17.0" />
</padding></AnchorPane> </padding>
</FlowPane>
</content> </content>
</ScrollPane> </ScrollPane>
<ScrollPane fx:id="settingsScrollPane" fitToHeight="true" fitToWidth="true" prefHeight="562.0" prefWidth="729.0" style="-fx-background: white;" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="175.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<content>
<!-- space between settings sections 35px, between sections elements (label + element) 20px, between label and element 3px(or more) -->
<AnchorPane fx:id="settingsAnchorPane" prefHeight="686.0" prefWidth="711.0" style="-fx-background-color: white;">
<children>
<VBox spacing="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<VBox prefHeight="485.0" prefWidth="710.0" spacing="25.0">
<children>
<VBox>
<children>
<Label fx:id="cemu_UISettingsLbl" text="cemu_UI Settings">
<font>
<Font name="System Bold" size="14.0" />
</font>
<VBox.margin>
<Insets />
</VBox.margin>
</Label>
<Separator prefWidth="200.0">
<padding>
<Insets right="5.0" />
</padding>
</Separator>
</children>
<padding>
<Insets left="-14.0" />
</padding>
</VBox>
<VBox spacing="7.0">
<children>
<Label fx:id="cemuDirectoryLbl" text="Cemu Directory" />
<HBox spacing="10.0">
<children>
<JFXTextField fx:id="cemuTextField" maxWidth="305.0" minWidth="305.0" prefHeight="32.0" prefWidth="305.0" promptText="cemu directory" />
<JFXButton fx:id="cemuTFBtn" onAction="#cemuTFBtnAction" prefHeight="32.0" text="choose directory" />
</children>
</HBox>
</children>
<padding>
<Insets right="5.0" />
</padding>
</VBox>
<VBox spacing="7.0">
<children>
<Label fx:id="romDirectoryLbl" text="Rom Directory" />
<HBox spacing="10.0">
<children>
<JFXTextField fx:id="romTextField" maxWidth="305.0" minWidth="305.0" prefHeight="32.0" prefWidth="305.0" promptText="rom directory" />
<JFXButton fx:id="romTFBtn" onAction="#romTFBtnAction" prefHeight="32.0" text="choose directory" />
</children>
</HBox>
</children>
</VBox>
<HBox spacing="10.0">
<children>
<Label fx:id="mainColorLbl" minHeight="25.0" text="main Color" />
<JFXColorPicker fx:id="colorPicker" onAction="#colorPickerAction" />
</children>
</HBox>
<HBox prefHeight="100.0" prefWidth="200.0" spacing="10.0">
<children>
<Label fx:id="languageLbl" prefHeight="25.0" text="language" />
<ChoiceBox fx:id="languageChoisBox" prefWidth="150.0" />
</children>
</HBox>
<JFXToggleButton fx:id="cloudSyncToggleBtn" onAction="#cloudSyncToggleBtnAction" text="cloud savegames (Google Drive)" />
<VBox spacing="10.0">
<children>
<Label fx:id="updateLbl" text="Updates" />
<HBox spacing="10.0">
<children>
<JFXButton fx:id="updateBtn" onAction="#updateBtnAction" prefHeight="32.0" text="check now!" />
<Label fx:id="branchLbl" prefHeight="32.0" text="Branch" />
<ChoiceBox fx:id="branchChoisBox" prefWidth="150.0" />
</children>
</HBox>
<JFXToggleButton fx:id="autoUpdateToggleBtn" onAction="#autoUpdateToggleBtnAction" text="check for updates on startup" />
</children>
</VBox>
</children>
<padding>
<Insets left="24.0" />
</padding>
</VBox>
<VBox spacing="25.0">
<children>
<VBox>
<children>
<Label fx:id="cemuSettingsLbl" text="Cemu Settings">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<Separator prefWidth="200.0">
<padding>
<Insets right="5.0" />
</padding>
</Separator>
</children>
<padding>
<Insets left="-14.0" />
</padding>
</VBox>
<JFXToggleButton fx:id="fullscreenToggleBtn" onAction="#fullscreenToggleBtnAction" text="start game in fullscreen">
<VBox.margin>
<Insets top="-10.0" />
</VBox.margin></JFXToggleButton>
<Label fx:id="licensesLbl" text="Licenses" />
</children>
<padding>
<Insets left="24.0" />
</padding>
</VBox>
</children>
<padding>
<Insets bottom="14.0" top="14.0" />
</padding>
</VBox>
</children>
</AnchorPane>
</content>
</ScrollPane>
<AnchorPane fx:id="smmdbAnchorPane" style="-fx-background-color: white;" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="175.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<children>
<JFXTextField fx:id="courseSearchTextFiled" layoutX="14.0" layoutY="14.0" onAction="#courseSearchTextFiledAction" prefHeight="25.0" prefWidth="405.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="14.0" />
<JFXTreeTableView fx:id="courseTreeTable" layoutX="14.0" layoutY="53.0" prefHeight="494.0" prefWidth="405.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="53.0" />
<ScrollPane fx:id="smmdbScrollPane" layoutX="436.0" layoutY="190.0" prefHeight="281.0" prefWidth="279.0" AnchorPane.bottomAnchor="91.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="190.0">
<content>
<TextFlow fx:id="smmdbTextFlow" maxWidth="265.0" prefWidth="265.0" />
</content>
</ScrollPane>
<JFXButton fx:id="smmdbDownloadBtn" buttonType="RAISED" layoutX="436.0" layoutY="479.0" onAction="#smmdbDownloadBtnAction" prefHeight="38.0" prefWidth="267.0" text="download" AnchorPane.bottomAnchor="45.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</JFXButton>
<Label fx:id="helpLbl" layoutX="436.0" layoutY="538.0" prefHeight="17.0" prefWidth="267.0" text="please help me improving this! click me!" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0">
<font>
<Font size="14.0" />
</font>
</Label>
<ScrollPane fx:id="smmdbImageViewScrollPane" layoutX="436.0" layoutY="14.0" prefHeight="160.0" prefWidth="279.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<content>
<ImageView fx:id="smmdbImageView" fitHeight="158.0" fitWidth="277.0" pickOnBounds="true" preserveRatio="true" />
</content>
</ScrollPane>
</children>
</AnchorPane>
<HBox fx:id="bottomHBox" alignment="CENTER" layoutX="326.0" layoutY="602.0" prefHeight="48.0" prefWidth="200.0" spacing="10.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<JFXButton fx:id="totalPlaytimeBtn" buttonType="RAISED" maxHeight="32.0" maxWidth="156.0" minHeight="32.0" minWidth="156.0" onAction="#totalPlaytimeBtnAction" style="-fx-background-color: #ffffff; -fx-button-type: RAISED; -fx-text-fill: BLACK;" text="0 h 0 min">
</JFXButton>
<JFXButton fx:id="playBtn" buttonType="RAISED" maxHeight="28.0" minWidth="100.0" onAction="#playBtnAction" ripplerFill="#00aacc" text="play" textAlignment="CENTER">
<font>
<Font name="System Bold" size="14.0" />
</font>
</JFXButton>
<JFXButton fx:id="lastTimePlayedBtn" buttonType="RAISED" maxHeight="32.0" maxWidth="156.0" minHeight="32.0" minWidth="156.0" onAction="#lastTimePlayedBtnAction" style="-fx-background-color: #ffffff; -fx-button-type: RAISED; -fx-text-fill: BLACK;" text="Last played, never" />
</children>
</HBox>
<HBox fx:id="topHBox" prefHeight="38.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <HBox fx:id="topHBox" prefHeight="38.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children> <children>
<JFXHamburger fx:id="menuHam" prefHeight="38.0" prefWidth="38.0" stylesheets="@../css/MainWindows.css" /> <JFXHamburger fx:id="menuHam" prefHeight="38.0" prefWidth="38.0" stylesheets="@../css/MainWindows.css" />
@ -61,67 +225,5 @@
</JFXButton> </JFXButton>
</children> </children>
</VBox> </VBox>
<ScrollPane fx:id="settingsScrollPane" style="-fx-background: white;" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="175.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<content>
<!-- space between settings sections 35px, between sections elements (label + element) 20px, between label and element 3px(or more) -->
<AnchorPane fx:id="settingsAnchorPane" prefHeight="562.0" prefWidth="511.0" style="-fx-background-color: white;">
<children>
<Label fx:id="cemuDirectoryLbl" layoutX="10.0" layoutY="39.0" text="Cemu Directory" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="39.0" />
<JFXTextField fx:id="cemuTextField" layoutX="10.0" layoutY="59.0" maxWidth="305.0" minWidth="305.0" onAction="#cemuTextFieldAction" prefHeight="32.0" prefWidth="305.0" promptText="cemu directory" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="59.0" />
<JFXTextField fx:id="romTextField" layoutX="10.0" layoutY="131.0" maxWidth="305.0" minWidth="305.0" onAction="#romTextFieldAction" prefHeight="32.0" prefWidth="305.0" promptText="rom directory" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="131.0" />
<JFXButton fx:id="romTFBtn" layoutX="329.0" layoutY="131.0" onAction="#romTFBtnAction" prefHeight="32.0" text="choose directory" AnchorPane.leftAnchor="329.0" AnchorPane.topAnchor="131.0" />
<JFXButton fx:id="cemuTFBtn" layoutX="329.0" layoutY="59.0" onAction="#cemuTFBtnAction" prefHeight="32.0" text="choose directory" AnchorPane.leftAnchor="329.0" AnchorPane.topAnchor="59.0" />
<JFXColorPicker fx:id="colorPicker" layoutX="12.0" layoutY="207.0" onAction="#colorPickerAction" AnchorPane.leftAnchor="12.0" AnchorPane.topAnchor="207.0" />
<JFXToggleButton fx:id="fullscreenToggleBtn" layoutX="16.0" layoutY="488.0" onAction="#fullscreenToggleBtnAction" text="start game in fullscreen" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="488.0" />
<Label fx:id="romDirectoryLbl" layoutX="10.0" layoutY="111.0" text="Rom Directory" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="111.0" />
<Label fx:id="mainColorLbl" layoutX="10.0" layoutY="183.0" text="main Color" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="183.0" />
<Label fx:id="cemuSettingsLbl" layoutX="16.0" layoutY="450.0" text="Cemu Settings" AnchorPane.leftAnchor="16.0" AnchorPane.topAnchor="465.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<Label fx:id="cemu_UISettingsLbl" layoutX="22.0" layoutY="14.0" text="cemu_UI Settings" AnchorPane.leftAnchor="18.0" AnchorPane.topAnchor="14.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<JFXToggleButton fx:id="cloudSyncToggleBtn" layoutX="10.0" layoutY="247.0" onAction="#cloudSyncToggleBtnAction" text="cloud savegames (Google Drive)" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="247.0" />
<Label fx:id="updateLbl" layoutX="10.0" layoutY="315.0" text="Updates" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="315.0" />
<JFXButton fx:id="updateBtn" layoutX="14.0" layoutY="335.0" onAction="#updateBtnAction" prefHeight="32.0" text="check now!" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="335.0" />
<JFXToggleButton fx:id="autoUpdateToggleBtn" layoutX="10.0" layoutY="372.0" onAction="#autoUpdateToggleBtnAction" text="check for updates on startup" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="372.0" />
<ChoiceBox fx:id="branchChoisBox" layoutX="270.0" layoutY="339.0" prefWidth="150.0" AnchorPane.leftAnchor="270.0" AnchorPane.topAnchor="339.0" />
<Label fx:id="branchLbl" layoutX="204.0" layoutY="337.0" prefHeight="32.0" text="Branch" AnchorPane.leftAnchor="204.0" AnchorPane.topAnchor="335.0" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<AnchorPane fx:id="smmdbAnchorPane" style="-fx-background-color: white;" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="175.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0">
<children>
<JFXTreeTableView fx:id="courseTreeTable" layoutX="14.0" layoutY="14.0" prefHeight="537.0" prefWidth="405.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="14.0" />
<ImageView fx:id="smmdbImageView" fitHeight="150.0" fitWidth="267.0" layoutX="436.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0" />
<ScrollPane fx:id="smmdbScrollPane" layoutX="436.0" layoutY="181.0" prefHeight="290.0" prefWidth="267.0" AnchorPane.bottomAnchor="91.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="181.0">
<content>
<TextFlow fx:id="smmdbTextFlow" maxWidth="265.0" prefWidth="265.0" />
</content>
</ScrollPane>
<JFXButton fx:id="smmdbDownloadBtn" buttonType="RAISED" layoutX="436.0" layoutY="479.0" onAction="#smmdbDownloadBtnAction" prefHeight="38.0" prefWidth="267.0" text="download" AnchorPane.bottomAnchor="45.0" AnchorPane.leftAnchor="436.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="479.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</JFXButton>
<Label fx:id="helpLabel" layoutX="436.0" layoutY="538.0" prefHeight="17.0" prefWidth="267.0" text="please help me improving this! click me!">
<font>
<Font size="14.0" />
</font>
</Label>
</children></AnchorPane>
<JFXButton fx:id="playBtn" buttonType="RAISED" layoutX="396.0" maxHeight="28.0" minWidth="100.0" onAction="#playBtnAction" ripplerFill="#00aacc" text="play" textAlignment="CENTER" visible="false" AnchorPane.bottomAnchor="12.0">
<font>
<Font name="System Bold" size="14.0" />
</font>
</JFXButton>
<JFXButton fx:id="totalPlaytimeBtn" buttonType="RAISED" layoutX="275.5" maxHeight="32.0" minWidth="100.0" onAction="#totalPlaytimeBtnAction" prefHeight="32.0" style="-fx-background-color: #ffffff; -fx-button-type: RAISED; -fx-text-fill: BLACK;" text="0 h 0 min" visible="false" AnchorPane.bottomAnchor="10.0">
</JFXButton>
<JFXButton fx:id="lastTimePlayedBtn" buttonType="RAISED" layoutX="516.5" maxHeight="32.0" minWidth="100.0" onAction="#lastTimePlayedBtnAction" prefHeight="32.0" style="-fx-background-color: #ffffff; -fx-button-type: RAISED; -fx-text-fill: BLACK;" text="Last played, never" visible="false" AnchorPane.bottomAnchor="10.0" />
</children> </children>
</AnchorPane> </AnchorPane>

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 JFoenix.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,675 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,822 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
Copyright (c) 2013, 2014 EclipseSource
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,19 @@
Copyright (c) 2013, 2014 EclipseSource
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,87 @@
#HomeFlix-Local_de_DE.properties DE-Deutsch Local
# Buttons
aboutBtn = \u00dcber
settingsBtn = Einstellungen
addBtn = Spiel hinzuf\u00fcgen
reloadRomsBtn = ROMs neu laden
smmdbBtn = smmdb
cemuTFBtn = Ordner \u00F6ffnen
romTFBtn = Ordner \u00F6ffnen
smmdbDownloadBtn = Download
playBtn = spielen
cloudSyncToggleBtn = Spielst\u00e4nde \u00fcber die Cloud syncronisieren (Google Drive)
autoUpdateToggleBtn = beim Start nach Updates suchen
fullscreenToggleBtn = Spiel im Vollbildmodus starten
# Labels
cemu_UISettingsLbl = cemu_UI Einstellungen
cemuDirectoryLbl = cemu directory
romDirectoryLbl = ROM directory
mainColorLbl = Hauptfarbe
languageLbl = Sprache
updateLbl = updates
branchLbl = Updatezweig
cemuSettingsLbl = cemu Einstellungen
licensesLbl = Lizenzen
# Columns
titleColumn = Titel
idColumn = ID
starsColumn = Sterne
timeColumn = Zeit
# Strings
editHeadingText = bearbeiten
editBodyText = Du kannst den Title und den ROM-/Coverpfad bearbeiten.
removeHeadingText = löschen
removeBodyText = Bist du sicher dass du flgendes Spiel l\u00f6schen m\u00f6chtest
addUpdateHeadingText = update
addUpdateBodyText = Bitte w\u00e4hle das Update-Verzeichniss aus.
addDLCHeadingText = ein DLC hinzufügen
addDLCBodyText = Bitte w\u00e4hle das DLC-Verzeichniss aus.
licensesLblHeadingText = cemu_UI
licensesLblBodyText = cemu_UI ist lizensiert unter der GNU GPL 3.\n\nJFoenix, Apache License 2.0\nminimal-json, MIT License\nsqlite-jdbc, Apache License 2.0\nApache Commons IO, Apache License 2.0\nApache Commons Logging, Apache License 2.0\nApache Commons Codec, Apache License 2.0\nApache Log4j 2, Apache License 2.0\n
showLicenses = Lizenzen \u00f6ffnen
aboutBtnHeadingText = cemu_UI
aboutBtnBodyText = Diese Programm wurde mit freier Software erstellt\nund ist lizensiert unter der GNU GPL 3.\n\nwww.mosad.xyz
cloudSyncWaringHeadingText = Spielst\u00e4nde über die Cloud syncronisieren (beta)
cloudSyncWaringBodyText = WARNING this is a completly WIP cloud save integration,\nit's NOT recomended to use this!!\n\nUse it on your own risk and backup everthing before!
cloudSyncErrorHeadingText = Fehler beim initialisieren der Cloud-Verbindung!
cloudSyncErrorBodyText = Fehler beim initialisieren der Cloud-Verbindung.\nBitte lade die app.log (welceh du im cemu_UI Verzeichniss findest)\nauf \"https://github.com/Seil0/cemu_UI/issues\" hoch.
addGameBtnHeadingText = eine neues Spiel zu cemu_Ui hinzuf\u00fcgen
addGameBtnBodyText =
addBtnReturnErrorHeadingText = Fehler beim hinzuf\u00fcgen des Spiels!
addBtnReturnErrorBodyText = Fehler beim hinzuf\u00fcgen des Spiels.\nEiner der benötigten Werte war leer, bitte versuche es erneut.
lastPlayed = zuletzt gespielt,
today = heute
yesterday = gestern
never = nie
# button strings
playBtnPlay = spieles
playBtnUpdating = updating...
playBtnCopyingFiles = kopiere Dateien...
smmdbDownloadBtnLoading = laden
smmdbDownloadBtnDownload = Download
okayBtnText = okay
cancelBtnText = abbruch
updateBtnCheckNow = Auf Update pr\u00FCfen
updateBtnChecking = Es wird nach Updates gesucht...
updateBtnNoUpdateAvailable = Kein Update verf\u00FCgbar
updateBtnUpdateAvailable = Update verf\u00FCgbar
#EditGameDialog
gameTitle = Spiel Titel
titleID = Titel ID
romPath = ROM Pfad
coverPath = Cover-Pfad
editGameDialogHeadingTextError = Fehler beim hinzuf\u00fcgen des Spiels!
editGameDialogBodyTextError = Fehler beim hinzuf\u00fcgen des Spiels.\nEiner der benötigten Werte war leer, bitte versuche es erneut.
editGameDialogSelectPathBtn = .rpx Datei ausw\u00E4hlen
editGameDialogSelectCoverBtn = cover Datei ausw\u00E4hlen

View File

@ -0,0 +1,87 @@
#HomeFlix-Local_en_US.properties US-English Local and default
# Buttons
aboutBtn = About
settingsBtn = Settings
addBtn = Add new Game
reloadRomsBtn = reload ROMs
smmdbBtn = smmdb
cemuTFBtn = choose directory
romTFBtn = choose directory
smmdbDownloadBtn = Download
playBtn = play
cloudSyncToggleBtn = cloud savegames (Google Drive)
autoUpdateToggleBtn = check for updates on startup
fullscreenToggleBtn = start game in fullscreen
# Labels
cemu_UISettingsLbl = cemu_UI Settings
cemuDirectoryLbl = cemu directory
romDirectoryLbl = ROM directory
mainColorLbl = primary color
languageLbl = Language
updateLbl = Updates
branchLbl = Branch
cemuSettingsLbl = cemu Settings
licensesLbl = Licenses
# Columns
titleColumn = title
idColumn = ID
starsColumn = stars
timeColumn = time
# Strings
editHeadingText = edit
editBodyText = You can edit the tile and ROM/cover path.
removeHeadingText = remove
removeBodyText = Are you sure you want to delete
addUpdateHeadingText = update
addUpdateBodyText = Please select the update root directory.
addDLCHeadingText = add a DLC to
addDLCBodyText = Please select the DLC root directory.
licensesLblHeadingText = cemu_UI
licensesLblBodyText = cemu_UI is licensed under the terms of GNU GPL 3.\n\nJFoenix, Apache License 2.0\nminimal-json, MIT License\nsqlite-jdbc, Apache License 2.0\nApache Commons IO, Apache License 2.0\nApache Commons Logging, Apache License 2.0\nApache Commons Codec, Apache License 2.0\nApache Log4j 2, Apache License 2.0\n
showLicenses = show licenses
aboutBtnHeadingText = cemu_UI
aboutBtnBodyText = This Application is made with free Software\nand licensed under the terms of GNU GPL 3.\n\nwww.mosad.xyz
cloudSyncWaringHeadingText = activate cloud savegame sync (beta)
cloudSyncWaringBodyText = WARNING this is a completely WIP cloud save integration,\nit's NOT recommended to use this!!\n\nUse it on your own risk and backup everything before!
cloudSyncErrorHeadingText = Error while initializing cloud sync!
cloudSyncErrorBodyText = There was some trouble while initializing cloud sync.\nPlease upload the app.log (which can be found in the cemu_UI directory)\nto \"https://github.com/Seil0/cemu_UI/issues\" so we can fix this.
addGameBtnHeadingText = add a new game to cemu_UI
addGameBtnBodyText =
addBtnReturnErrorHeadingText = Error while adding a new Game!
addBtnReturnErrorBodyText = There was some trouble adding your game.\nOne of the needed values was empty, please try again to add your game.
lastPlayed = Last played,
today = today
yesterday = yesterday
never = never
# button strings
playBtnPlay = play
playBtnUpdating = updating...
playBtnCopyingFiles = copying files...
smmdbDownloadBtnLoading = loading
smmdbDownloadBtnDownload = Download
okayBtnText = okay
cancelBtnText = cancel
updateBtnCheckNow = check now!
updateBtnChecking = checking for updates ...
updateBtnNoUpdateAvailable = no update available
updateBtnUpdateAvailable = update available
#EditGameDialog
gameTitle = game title
titleID = title ID
romPath = ROM path
coverPath = cover path
editGameDialogHeadingTextError = Error while adding a new Game!
editGameDialogBodyTextError = There was some trouble adding your game.\nOne of the needed values was empty, please try again to add your game.
editGameDialogSelectPathBtn = select .rpx file
editGameDialogSelectCoverBtn = select cover file

View File

@ -0,0 +1,40 @@
package com.cemu_UI.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest extends TestCase {
/**
* Create the test case
*
* @param testName
* name of the test case
*/
public AppTest(String testName) {
super(testName);
}
@SuppressWarnings("unused")
private void testClientsSecret() {
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(AppTest.class);
}
/**
* Rigourous Test :-)
*/
public void testApp() {
assertTrue(true);
}
}