├── system_configs
└── raspbian_buster
│ ├── home
│ ├── app
│ │ ├── ffbbg.jpg
│ │ ├── .fluxbox
│ │ │ ├── menu
│ │ │ ├── menu-backup
│ │ │ ├── lastwallpaper
│ │ │ └── init
│ │ ├── ffbbg-h.jpg
│ │ ├── ffbbg-v.jpg
│ │ ├── onboard_reset.sh
│ │ └── rotate_desktop.sh
│ └── app-data
│ │ ├── MUSIC
│ │ └── yahVlcWasAdded
│ │ ├── fbb.sh
│ │ ├── ffb.sh
│ │ └── FlashFreeBoardDesktop-1.0-SNAPSHOT-jar-with-dependencies
│ └── etc
│ └── systemd
│ └── system
│ ├── vlc.service
│ ├── fbb.service
│ ├── ffb.service
│ ├── xhosthack.service
│ ├── dconfUserReload.service
│ ├── rotate.service
│ └── keyboard.service
├── .travis.yml
├── docs
└── imgs
│ ├── box.png
│ ├── dev.png
│ ├── new.png
│ ├── two.png
│ ├── ball.png
│ ├── campus.png
│ ├── clock.png
│ ├── date.png
│ ├── hBar.png
│ ├── menu.png
│ ├── quick.png
│ ├── readme.png
│ ├── search.png
│ ├── select.png
│ ├── slow1.png
│ ├── slow2.png
│ ├── slow3.png
│ ├── stats.png
│ ├── vBar.png
│ ├── whole.png
│ ├── addClimb.png
│ ├── navFull.png
│ ├── timered.png
│ ├── wholeCz.png
│ ├── directJump.png
│ ├── manual.cz.png
│ ├── selectMulti.png
│ └── wholeMarked.png
├── manifest.mf
├── tesBoards
├── bad.wall
├── test20.wall
├── moonboard.wall
└── img.jpeg_Thu_Feb_21_16_30_05_CET_2019.wall
├── src
└── main
│ ├── resources
│ └── org
│ │ └── fbb
│ │ └── board
│ │ ├── tutorial
│ │ ├── imgs
│ │ │ ├── 01_1.png
│ │ │ ├── 02_2.png
│ │ │ ├── 03_3.png
│ │ │ ├── 00_0-4.png
│ │ │ ├── 04_noTop.png
│ │ │ ├── 05__top.png
│ │ │ ├── 06_filled.png
│ │ │ └── 07_sfinx.png
│ │ └── show
│ │ ├── latest-release
│ │ └── internals
│ │ └── grades
│ │ └── tabulka
│ └── java
│ └── org
│ └── fbb
│ └── board
│ ├── internals
│ ├── grid
│ │ ├── Meassurable.java
│ │ ├── HoldMarkerProvider.java
│ │ ├── PhotoGrider.java
│ │ ├── RelativePoint.java
│ │ └── Line.java
│ ├── training
│ │ ├── ListSetter.java
│ │ ├── TrainingWithBackends.java
│ │ ├── TrainingPlaylist.java
│ │ ├── BoulderCalc.java
│ │ ├── Training.java
│ │ └── TimeredTraining.java
│ ├── FUtils.java
│ ├── comm
│ │ ├── ByteEater.java
│ │ ├── ListAndWrite.java
│ │ ├── ConnectionID.java
│ │ └── wired
│ │ │ └── PortWork.java
│ ├── db
│ │ ├── GuiExceptionHandler.java
│ │ ├── ExceptionHandler.java
│ │ └── Puller.java
│ ├── ContentReaderListener.java
│ ├── GuiLogHelper.java
│ ├── ProcessResult.java
│ ├── HistoryManager.java
│ ├── TeeOutputStream.java
│ ├── grades
│ │ └── Grade.java
│ ├── ContentReader.java
│ └── ProcessWrapper.java
│ ├── desktop
│ ├── tutorial
│ │ ├── StoryPart.java
│ │ ├── SingleText.java
│ │ ├── ImgProvider.java
│ │ ├── StoryProvider.java
│ │ └── awt
│ │ │ ├── ImageWithTitles.java
│ │ │ └── HelpWindow.java
│ ├── gui
│ │ ├── awtimpl
│ │ │ ├── TipsListener.java
│ │ │ ├── IconifierThread.java
│ │ │ └── WinUtils.java
│ │ ├── dialogs
│ │ │ ├── parts
│ │ │ │ ├── DefaultSnoozeAction.java
│ │ │ │ ├── Snoozer.java
│ │ │ │ └── TimeAndSnooze.java
│ │ │ ├── LogView.java
│ │ │ ├── SlowBoulder.java
│ │ │ ├── BoxesWindow.java
│ │ │ ├── ClockWindow.java
│ │ │ └── CampusLikeDialog.java
│ │ ├── GitAuthenticator.java
│ │ ├── Authenticator.java
│ │ ├── MainWindow.java
│ │ ├── ArduinoWindow.java
│ │ └── LoadBackgroundOrImportOrLoadWall.java
│ ├── TextToSpeech.java
│ └── ScreenFinder.java
│ ├── Utils.java
│ └── Translator.java
├── .gitignore
├── LICENSE
├── README.md
└── pom.xml
/system_configs/raspbian_buster/home/app/ffbbg.jpg:
--------------------------------------------------------------------------------
1 | ffbbg-h.jpg
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app-data/MUSIC/yahVlcWasAdded:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk8
4 | sudo: false
5 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/.fluxbox/menu:
--------------------------------------------------------------------------------
1 | [begin] (fluxbox)
2 | [end]
3 |
--------------------------------------------------------------------------------
/docs/imgs/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/box.png
--------------------------------------------------------------------------------
/docs/imgs/dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/dev.png
--------------------------------------------------------------------------------
/docs/imgs/new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/new.png
--------------------------------------------------------------------------------
/docs/imgs/two.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/two.png
--------------------------------------------------------------------------------
/docs/imgs/ball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/ball.png
--------------------------------------------------------------------------------
/docs/imgs/campus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/campus.png
--------------------------------------------------------------------------------
/docs/imgs/clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/clock.png
--------------------------------------------------------------------------------
/docs/imgs/date.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/date.png
--------------------------------------------------------------------------------
/docs/imgs/hBar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/hBar.png
--------------------------------------------------------------------------------
/docs/imgs/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/menu.png
--------------------------------------------------------------------------------
/docs/imgs/quick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/quick.png
--------------------------------------------------------------------------------
/docs/imgs/readme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/readme.png
--------------------------------------------------------------------------------
/docs/imgs/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/search.png
--------------------------------------------------------------------------------
/docs/imgs/select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/select.png
--------------------------------------------------------------------------------
/docs/imgs/slow1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/slow1.png
--------------------------------------------------------------------------------
/docs/imgs/slow2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/slow2.png
--------------------------------------------------------------------------------
/docs/imgs/slow3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/slow3.png
--------------------------------------------------------------------------------
/docs/imgs/stats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/stats.png
--------------------------------------------------------------------------------
/docs/imgs/vBar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/vBar.png
--------------------------------------------------------------------------------
/docs/imgs/whole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/whole.png
--------------------------------------------------------------------------------
/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | X-COMMENT: Main-Class will be added automatically by build
3 |
4 |
--------------------------------------------------------------------------------
/tesBoards/bad.wall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/tesBoards/bad.wall
--------------------------------------------------------------------------------
/docs/imgs/addClimb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/addClimb.png
--------------------------------------------------------------------------------
/docs/imgs/navFull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/navFull.png
--------------------------------------------------------------------------------
/docs/imgs/timered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/timered.png
--------------------------------------------------------------------------------
/docs/imgs/wholeCz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/wholeCz.png
--------------------------------------------------------------------------------
/tesBoards/test20.wall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/tesBoards/test20.wall
--------------------------------------------------------------------------------
/docs/imgs/directJump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/directJump.png
--------------------------------------------------------------------------------
/docs/imgs/manual.cz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/manual.cz.png
--------------------------------------------------------------------------------
/docs/imgs/selectMulti.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/selectMulti.png
--------------------------------------------------------------------------------
/docs/imgs/wholeMarked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/docs/imgs/wholeMarked.png
--------------------------------------------------------------------------------
/tesBoards/moonboard.wall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/tesBoards/moonboard.wall
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/.fluxbox/menu-backup:
--------------------------------------------------------------------------------
1 | [begin] (fluxbox)
2 | [include] (/etc/X11/fluxbox/fluxbox-menu)
3 | [end]
4 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app-data/fbb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | java -Xmx512m -jar /home/app-data/FlashBalknaSwing*.jar iconifyWindow
3 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app-data/ffb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | java -Xmx2g -jar /home/app-data/FlashFreeBoardDesktop-*-jar-with-dependencies.jar
3 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/ffbbg-h.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/system_configs/raspbian_buster/home/app/ffbbg-h.jpg
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/ffbbg-v.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/system_configs/raspbian_buster/home/app/ffbbg-v.jpg
--------------------------------------------------------------------------------
/tesBoards/img.jpeg_Thu_Feb_21_16_30_05_CET_2019.wall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/tesBoards/img.jpeg_Thu_Feb_21_16_30_05_CET_2019.wall
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/01_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/01_1.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/02_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/02_2.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/03_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/03_3.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/00_0-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/00_0-4.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/04_noTop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/04_noTop.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/05__top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/05__top.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/06_filled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/06_filled.png
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/imgs/07_sfinx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/src/main/resources/org/fbb/board/tutorial/imgs/07_sfinx.png
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/.fluxbox/lastwallpaper:
--------------------------------------------------------------------------------
1 | fbsetroot|-foreground rgb:10/18/20 -background rgb:30/38/40 -mod 4 4|style|:0.0
2 | $full $full|/home/app/ffbbg.jpg||:0
3 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/vlc.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Start VLC
3 | After=rotate.service
4 |
5 | [Service]
6 | User=app-data
7 | Group=app-data
8 | Environment="DISPLAY=:0"
9 | Environment="LANG=cs_CZ.UTF-8"
10 | ExecStart=vlc /home/app-data/MUSIC
11 | Restart=always
12 | RestartSec=3
13 |
14 | [Install]
15 | WantedBy=graphical.target
16 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/fbb.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Start FBB
3 | After=rotate.service
4 |
5 | [Service]
6 | User=app-data
7 | Group=app-data
8 | Environment="DISPLAY=:0"
9 | Environment="LANG=cs_CZ.UTF-8"
10 | ExecStart=bash /home/app-data/fbb.sh
11 | Restart=always
12 | RestartSec=3
13 |
14 | [Install]
15 | WantedBy=graphical.target
16 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/ffb.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Start FFB
3 | After=rotate.service
4 |
5 | [Service]
6 | User=app-data
7 | Group=app-data
8 | Environment="DISPLAY=:0"
9 | Environment="LANG=cs_CZ.UTF-8"
10 | ExecStart=/bin/bash /home/app-data/ffb.sh
11 | Restart=always
12 | RestartSec=3
13 |
14 | [Install]
15 | WantedBy=graphical.target
16 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/xhosthack.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=enable app data
3 | After=rotate.service
4 |
5 | [Service]
6 | User=app
7 | Group=app
8 | Environment="DISPLAY=:0"
9 | Environment="LANG=cs_CZ.UTF-8"
10 | ExecStart=xhost +SI:localuser:app-data
11 | Restart=always
12 | RestartSec=3
13 |
14 | [Install]
15 | WantedBy=graphical.target
16 |
17 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/dconfUserReload.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=reload onboard conf and the app every N secnds, to prevent misconfigurations
3 | After=ffb.service
4 |
5 | [Service]
6 | User=app
7 | Group=app
8 | Restart=always
9 | # every 10 minues
10 | RestartSec=600
11 | ExecStart=bash /home/app/onboard_reset.sh
12 |
13 | [Install]
14 | WantedBy=graphical.target
15 |
16 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/rotate.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Rotate desktop to portrait, including touch coordinates
3 |
4 | [Service]
5 | User=app
6 | Group=app
7 | Restart=on-failure
8 | RestartSec=5
9 | Environment="DISPLAY=:0"
10 | #ExecStart=bash /home/app/rotate_desktop.sh left
11 | ExecStart=bash /home/app/rotate_desktop.sh normal
12 |
13 | [Install]
14 | WantedBy=graphical.target
15 |
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/latest-release:
--------------------------------------------------------------------------------
1 | https://github.com/judovana/FlashFreeBoardDesktop/releases/download/FlashFreeBoardDesktop-1.8/FlashFreeBoardDesktop-1.8-jar-with-dependencies.jar
2 | https://raw.githubusercontent.com/judovana/arduino/ee1feba8e3b7fe315f94554bfe9854965d2ad5bd/FreeBoard/WS2812blinks/WS2812blinks.ino
3 | https://github.com/judovana/FlashBalknaSwing/releases/download/FlashBalknaSwing-2.4/FlashBalknaSwing_2.4.jar
4 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grid/Meassurable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grid;
7 |
8 | /**
9 | *
10 | * @author jvanek
11 | */
12 | interface Meassurable {
13 | public int getWidth();
14 | public int getHeight();
15 | }
16 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/onboard_reset.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ex
3 | # have or dont have services all vars?
4 | HOME=/home/app/
5 | orig="$HOME/onboard.default"
6 | current="$HOME/.config/dconf/user"
7 | if [ -f $orig ] ; then
8 | killall onboard || true
9 | sleep 1 #wait for dconf to save ; see keyboard.service RestartSec
10 | cp -v $orig $current
11 | exit 133
12 | else
13 | echo "$orig do not exists, creating new"
14 | cp -v $current $orig
15 | exit 122
16 | fi
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 | *.so
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 | /build/
25 | /dist/
26 | /target/
27 |
28 | /nbproject/
29 | .idea/
30 | FlashFreeBoardDesktop.iml
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/ListSetter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import org.fbb.board.internals.Filter;
9 |
10 | /**
11 | *
12 | * @author jvanek
13 | */
14 | public abstract class ListSetter {
15 |
16 | public abstract void setUpBoulderWall(Filter f, String selected, String title);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/FUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals;
7 |
8 | import javax.swing.JLabel;
9 | import javax.swing.JPanel;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | public class FUtils {
16 |
17 | public static void align(int from, int to, JPanel p) {
18 | for (int i = from; i < to; i++) {
19 | p.add(new JLabel());
20 | p.add(new JLabel());
21 | };
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/etc/systemd/system/keyboard.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Start virtual keyboards
3 | After=ffb.service
4 |
5 | [Service]
6 | User=app
7 | Group=app
8 | Restart=always
9 | RestartSec=3
10 | Environment="DISPLAY=:0"
11 | # see the onboard_reset.sh
12 | ExecStartPre=sleep 1
13 | #ExecStart=matchbox-keyboard
14 | # onboard is the only keyboard with ctrl in selections working
15 | # onboard must have docking enabled and show floating icon when hideen
16 | # onboard must have long click set to key repeat (special chars were crashing the system)
17 | # onboard must have
18 | ExecStart=onboard
19 |
20 | [Install]
21 | WantedBy=graphical.target
22 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/comm/ByteEater.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.comm;
7 |
8 | import org.fbb.board.internals.grid.Grid;
9 |
10 | /**
11 | *
12 | * @author jvanek
13 | */
14 | public interface ByteEater {
15 |
16 | public void sendBytes(int[] b, Grid id);
17 | public void deregisterProvider(Grid id);
18 | public void reset();
19 | public int getNumberOfRegisteredProviders();
20 | public int getMaxOfRegisteredProviders();
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/comm/ListAndWrite.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.comm;
7 |
8 | /**
9 | *
10 | * @author jvanek
11 | */
12 | public interface ListAndWrite {
13 |
14 | public static interface LogConsole {
15 |
16 | public void print(Exception ex);
17 | }
18 |
19 | public ConnectionID[] listDevices();
20 |
21 | public void writeToDevice(String id, byte[]... b);
22 |
23 | // public void setLogConsole(LogConsole l);
24 | //need tee stream, and as the BT and Wire are static, different architecture
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This program is offered under a commercial and under the AGPL license.
2 | For commercial licensing, contact us at via the issue tracker on this github page. For AGPL licensing, see below.
3 |
4 | AGPL licensing:
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU Affero General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU Affero General Public License for more details.
14 |
15 | You should have received a copy of the GNU Affero General Public License
16 | along with this program. If not, see .
17 |
18 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/StoryPart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | public class StoryPart {
16 |
17 | private final String img;
18 | private final List lines;
19 |
20 | public StoryPart(String img) {
21 | this.img = img;
22 | this.lines = new ArrayList<>();
23 | }
24 |
25 | public void addLine(SingleText l) {
26 | lines.add(l);
27 | }
28 |
29 | public String getImg() {
30 | return img;
31 | }
32 |
33 | public List getLines() {
34 | return lines;
35 | }
36 |
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/SingleText.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial;
7 |
8 | /**
9 | *
10 | * @author jvanek
11 | */
12 | public class SingleText {
13 |
14 | private final int x;
15 | private final int y;
16 | private final String key;
17 |
18 | public SingleText(int x, int y, String key) {
19 | this.x = x;
20 | this.y = y;
21 | this.key = key;
22 | }
23 |
24 | public int getX(double d) {
25 | return (int)((double)x*d);
26 | }
27 |
28 | public int getY(double d) {
29 | return (int)((double)y*d);
30 | }
31 |
32 | public String getKey() {
33 | return key;
34 | }
35 |
36 |
37 |
38 |
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/comm/ConnectionID.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.comm;
7 |
8 | /**
9 | *
10 | * @author jvanek
11 | */
12 | public class ConnectionID {
13 |
14 | /**
15 | * id to use to be used to communicate
16 | */
17 | private final String id;
18 | /**
19 | * human nice name for listing
20 | */
21 | private final String name;
22 |
23 | public ConnectionID(String id, String name) {
24 | this.id = id;
25 | this.name = name;
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return name + " [" + id + "]";
31 | }
32 |
33 | public String getId() {
34 | return id;
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/ImgProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial;
7 |
8 | import java.awt.image.BufferedImage;
9 | import java.io.IOException;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 | import javax.imageio.ImageIO;
13 |
14 | /**
15 | *
16 | * @author jvanek
17 | */
18 | public class ImgProvider {
19 |
20 | private final Map cache = new HashMap<>(15);
21 |
22 | public ImgProvider() {
23 |
24 | }
25 |
26 | public BufferedImage get(String name) throws IOException {
27 | BufferedImage bi = cache.get(name);
28 | if (bi == null) {
29 | bi = ImageIO.read((this.getClass().getClassLoader().getResourceAsStream("org/fbb/board/tutorial/imgs/" + name)));
30 | cache.put(name, bi);
31 | }
32 | return bi;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/tutorial/show:
--------------------------------------------------------------------------------
1 | 00_0-4.png
2 | 00_0-4.png
3 | 485 629 FIRST_CLICK
4 | 01_1.png
5 | 01_1.png
6 | 485 629 SECOND_CLICK
7 | 02_2.png
8 | 02_2.png
9 | 485 629 THIRD_CLICK
10 | 03_3.png
11 | 03_3.png
12 | 485 629 FOURTH_CLICK
13 | 00_0-4.png
14 | 00_0-4.png
15 | 485 629 AGAIN_NOTHING
16 | 00_0-4.png
17 | 04_noTop.png
18 | 04_noTop.png
19 | 485 629 CREATE_BOULDER
20 | 04_noTop.png
21 | 485 629 NO_TOP
22 | 04_noTop.png
23 | 05__top.png
24 | 05__top.png
25 | 485 629 ADD_TOP
26 | 05__top.png
27 | 05__top.png
28 | 99 150 MUST_FILL
29 | 05__top.png
30 | 207 123 GRADE
31 | 05__top.png
32 | 341 96 NAME
33 | 05__top.png
34 | 204 72 AUTHOR
35 | 05__top.png
36 | 06_filled.png
37 | 06_filled.png
38 | 99 150 FILLED
39 | 06_filled.png
40 | 99 150 FILLED
41 | 207 123 GRADE
42 | 06_filled.png
43 | 99 150 FILLED
44 | 207 123 GRADE
45 | 341 96 NAME
46 | 06_filled.png
47 | 99 150 FILLED
48 | 207 123 GRADE
49 | 341 96 NAME
50 | 204 72 AUTHOR
51 | 06_filled.png
52 | 165 921 PRESS_DONE
53 | 07_sfinx.png
54 | 07_sfinx.png
55 | 215 294 SFINX_Q
56 | 07_sfinx.png
57 | 215 294 SFINX_A
58 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/db/GuiExceptionHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.db;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import javax.swing.JOptionPane;
11 | import org.fbb.board.Translator;
12 | import org.fbb.board.internals.GuiLogHelper;
13 |
14 | public class GuiExceptionHandler implements ExceptionHandler {
15 |
16 | private static final List remebered = new ArrayList<>();
17 |
18 | @Override
19 | public void handleWithIssue(Throwable t) throws Throwable {
20 | throw new UnsupportedOperationException("Should not occure");
21 | }
22 |
23 | @Override
24 | public void handleCleanly(Throwable t) {
25 | GuiLogHelper.guiLogger.loge(t);
26 | if (remebered.contains(t.getClass())) {
27 | return;
28 | }
29 | int r = JOptionPane.showConfirmDialog(null, t + "\n\n" + Translator.R("gitIssueQuestion"), Translator.R("gitIssue"), JOptionPane.YES_NO_OPTION);
30 | if (r == JOptionPane.NO_OPTION) {
31 | remebered.add(t.getClass());
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/awtimpl/TipsListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.awtimpl;
7 |
8 | import java.awt.event.ActionEvent;
9 | import java.awt.event.ActionListener;
10 | import javax.swing.JOptionPane;
11 | import org.fbb.board.Translator;
12 |
13 | /**
14 | *
15 | * @author jvanek
16 | */
17 | public class TipsListener implements ActionListener {
18 |
19 | public TipsListener() {
20 | }
21 |
22 | @Override
23 | public void actionPerformed(ActionEvent e) {
24 | JOptionPane.showMessageDialog(null, "" + "" + Translator.R("tip1") + "" + "- " + escape(Translator.R("tip2")) + "
- " + escape(Translator.R("tip3")) + "
" + "" + "- " + escape(Translator.R("tip4")) + "
- " + escape(Translator.R("tip5")) + "
- " + escape(Translator.R("tip6")) + "
" + "" + escape(Translator.R("tips7")) + "" + "- " + escape(Translator.R("tips8")) + "
- " + escape(Translator.R("tips9")) + "
- " + escape(Translator.R("tips10")) + "
");
25 | }
26 |
27 | private String escape(String R) {
28 | return R.replace("<", "<").replace(">", ">");
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/awtimpl/IconifierThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.awtimpl;
7 |
8 | import javax.swing.JFrame;
9 | import org.fbb.board.desktop.gui.MainWindow;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | class IconifierThread extends Thread {
16 | JFrame target;
17 | private static final int WINDOW_COMFOR_ZONE = 5 * 60 * 1000;
18 |
19 | public IconifierThread() {
20 | super();
21 | this.target = null;
22 | this.setDaemon(true);
23 | this.setName("iconifier");
24 | this.start();
25 | }
26 |
27 | public void setTarget(JFrame target) {
28 | this.target = target;
29 | }
30 |
31 | @Override
32 | public void run() {
33 | while (true) {
34 | try {
35 | Thread.sleep(WINDOW_COMFOR_ZONE);
36 | if (target != null && MainWindow.gs.isPopUpping()) {
37 | if (target.getState() == JFrame.ICONIFIED) {
38 | target.setState(JFrame.NORMAL);
39 | }
40 | }
41 | } catch (InterruptedException ex) {
42 | }
43 | ;
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/db/ExceptionHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.db;
7 |
8 | import org.fbb.board.internals.GuiLogHelper;
9 |
10 | /**
11 | *
12 | * @author jvanek
13 | * @param
14 | */
15 | public interface ExceptionHandler {
16 |
17 | public void handleWithIssue(T t) throws T;
18 |
19 | public void handleCleanly(T t);
20 |
21 | class LoggingEater implements ExceptionHandler {
22 |
23 | @Override
24 | public void handleWithIssue(Throwable t) throws Throwable {
25 | throw new UnsupportedOperationException("Should not occure");
26 | }
27 |
28 | @Override
29 | public void handleCleanly(Throwable t) {
30 | GuiLogHelper.guiLogger.loge(t);
31 | }
32 | }
33 |
34 | class Resender implements ExceptionHandler {
35 |
36 | @Override
37 | public void handleWithIssue(Throwable t) throws Throwable {
38 | throw new UnsupportedOperationException("Should not occure");
39 | }
40 |
41 | @Override
42 | public void handleCleanly(Throwable t) {
43 | throw new RuntimeException(t);
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/parts/DefaultSnoozeAction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs.parts;
7 |
8 | import org.fbb.board.desktop.gui.dialogs.CampusLikeDialog;
9 | import org.fbb.board.internals.grid.GridPane;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | public class DefaultSnoozeAction implements Runnable {
16 |
17 | private final GridPane gp;
18 |
19 | public DefaultSnoozeAction(GridPane gp) {
20 | this.gp = gp;
21 | }
22 |
23 | @Override
24 | public void run() {
25 | try {
26 | for (int x = 0; x < gp.getGrid().getWidth(); x++) {
27 | gp.getGrid().clean();
28 | CampusLikeDialog.drawColumn(x, 1, gp.getGrid());
29 | gp.repaintAndSendToKnown();
30 | Thread.sleep(100);
31 | }
32 | for (int x = gp.getGrid().getWidth() - 1; x >= 0; x--) {
33 | gp.getGrid().clean();
34 | CampusLikeDialog.drawColumn(x, 1, gp.getGrid());
35 | gp.repaintAndSendToKnown();
36 | Thread.sleep(100);
37 | }
38 | } catch (InterruptedException ex) {
39 | //unimportant
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grid/HoldMarkerProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grid;
7 |
8 | import java.awt.Color;
9 |
10 | /**
11 | *
12 | * @author jvanek
13 | */
14 | public interface HoldMarkerProvider {
15 |
16 | //known styles
17 | public static final int FILL = 0;
18 | public static final int C_BIG = 1;
19 | public static final int C_SMALL = 2;
20 | public static final int C_BOTH = 3;
21 | public static final int E_BIG = 4;
22 | public static final int E_SMALL = 5;
23 | public static final int E_BOTH = 6;
24 | public static final int RECT = 7;
25 | //there is 8 of them
26 | public static int COUNT_OF_STYLES = 8;
27 |
28 | public float getStartRed();
29 |
30 | public float getStartGreen();
31 |
32 | public float getStartBlue();
33 |
34 | public float getPathRed();
35 |
36 | public float getPathGreen();
37 |
38 | public float getPathBlue();
39 |
40 | public float getTopRed();
41 |
42 | public float getTopGreen();
43 |
44 | public float getTopBlue();
45 |
46 | public float getHoldMarkerOapcity();
47 |
48 | public Color getGridColor();
49 |
50 | public int getDefaultStyle();
51 |
52 | public void setDefaultStyle(int a);
53 |
54 | public int getCurrentStyle();
55 |
56 | public void setCurrentStyle(int a);
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/StoryProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.List;
14 |
15 | /**
16 | *
17 | * @author jvanek
18 | */
19 | public class StoryProvider {
20 |
21 | private final List story = new ArrayList(50);
22 |
23 | public StoryProvider() throws IOException {
24 |
25 |
26 | try(BufferedReader br = new BufferedReader(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("org/fbb/board/tutorial/show"), "utf-8"))) {
27 | while (true) {
28 | String s = br.readLine();
29 | if (s == null) {
30 | break;
31 | }
32 | if (s.startsWith(" ")||s.startsWith("\t")){
33 | String[] parts = s.trim().split("\\s");
34 | story.get(story.size()-1).addLine(new SingleText(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]), parts[2]));
35 | }else{
36 | story.add(new StoryPart(s.trim()));
37 | }
38 | }
39 | }
40 | }
41 |
42 | public List getStory(){
43 | return Collections.unmodifiableList(story);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | public class Utils {
16 |
17 | public static List bresenhamLine(int x1, int y1, int x2, int y2) {
18 | List l = new ArrayList<>();
19 | if ((x1 == x2) && (y1 == y2)) {
20 | l.add(new int[]{x1, y1});
21 | } else {
22 | int dx = Math.abs(x2 - x1);
23 | int dy = Math.abs(y2 - y1);
24 | int diff = dx - dy;
25 |
26 | int moveX, moveY;
27 |
28 | if (x1 < x2) {
29 | moveX = 1;
30 | } else {
31 | moveX = -1;
32 | }
33 | if (y1 < y2) {
34 | moveY = 1;
35 | } else {
36 | moveY = -1;
37 | }
38 |
39 | while ((x1 != x2) || (y1 != y2)) {
40 |
41 | int p = 2 * diff;
42 |
43 | if (p > -dy) {
44 | diff = diff - dy;
45 | x1 = x1 + moveX;
46 | }
47 | if (p < dx) {
48 | diff = diff + dx;
49 | y1 = y1 + moveY;
50 | }
51 | l.add(new int[]{x1, y1});
52 | }
53 | }
54 | return l;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/parts/Snoozer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs.parts;
7 |
8 | import javax.swing.JLabel;
9 | import javax.swing.JTextField;
10 | import org.fbb.board.internals.training.BoulderCalc;
11 |
12 | /**
13 | *
14 | * @author jvanek
15 | */
16 | public class Snoozer {
17 |
18 | private final Runnable close;
19 | private long snoozeCounter;
20 |
21 | Snoozer(Runnable close) {
22 | this.close = close;
23 | }
24 |
25 | void adjustSnoozeCounter(long by) {
26 | this.snoozeCounter += by;
27 | }
28 |
29 | void setSnoozeCounter(long snoozeCounter) {
30 | this.snoozeCounter = snoozeCounter;
31 | }
32 |
33 | boolean isOnZero(double delay) {
34 | return (double) snoozeCounter / 1000d < delay && (double) snoozeCounter / 1000d > -delay;
35 | }
36 |
37 | String getTime() {
38 | return BoulderCalc.code(snoozeCounter / 1000l);
39 | }
40 |
41 | void snooze() {
42 | close.run();
43 | }
44 |
45 | void checkAndDo(long delay, JLabel time, JTextField origin) {
46 | this.adjustSnoozeCounter(-delay);
47 | time.setText(this.getTime());
48 | time.repaint();
49 | if (this.isOnZero((double) delay / 1000d)
50 | && BoulderCalc.decode(origin.getText()) > 0) {
51 | this.snooze();
52 | }
53 | time.repaint();
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grid/PhotoGrider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grid;
7 |
8 | import java.awt.image.BufferedImage;
9 | import java.io.IOException;
10 | import javax.imageio.ImageIO;
11 | import javax.swing.JFrame;
12 | import javax.swing.SwingUtilities;
13 | import org.fbb.board.internals.GuiLogHelper;
14 |
15 | /**
16 | *
17 | * @author jvanek
18 | */
19 | public class PhotoGrider {
20 |
21 | /**
22 | * @param args the command line arguments
23 | */
24 | public static void main(String[] args) {
25 | SwingUtilities.invokeLater(new Runnable() {
26 |
27 | @Override
28 | public void run() {
29 | JFrame f = new JFrame("Flash Free Board");
30 | f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
31 | f.pack();
32 | f.setSize(800, 600);
33 | BufferedImage img;
34 | try {
35 | img = ImageIO.read(PhotoGrider.class.getResourceAsStream("mnbr.png"));
36 | //img = ImageIO.read(PhotoGrider.class.getResourceAsStream("bgr.jpg"));
37 | } catch (IOException ex) {
38 | GuiLogHelper.guiLogger.loge(ex);
39 | img = new BufferedImage(800, 600, BufferedImage.TYPE_3BYTE_BGR);
40 | }
41 | f.add(new GridPane(img, null, null));
42 | f.setVisible(true);
43 | }
44 | });
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/db/Puller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.db;
7 |
8 | import org.fbb.board.internals.GuiLogHelper;
9 |
10 | public class Puller implements Runnable {
11 |
12 | private boolean alive = true;
13 | private int delay = 60;//1 minute
14 | private final DB db;
15 |
16 | private Puller(int seconds, DB db) {
17 | this.delay = seconds;
18 | this.db = db;
19 | }
20 |
21 | public void cancel() {
22 | alive = false;
23 | }
24 |
25 | public void setDelay(int seconds) {
26 | delay = seconds;
27 | }
28 |
29 | @Override
30 | public void run() {
31 | while (alive) {
32 | try {
33 | if (delay <= 0) {
34 | Thread.sleep(60l * 1000l);
35 | //GuiLogHelper.guiLogger.logo("Puller doing nothing...");
36 | } else {
37 | Thread.sleep((long) delay * 1000l);
38 | pull();
39 | }
40 | } catch (Exception ex) {
41 | GuiLogHelper.guiLogger.loge(ex);
42 | }
43 | }
44 | GuiLogHelper.guiLogger.logo("Puller ended");
45 | }
46 |
47 | public void pull() {
48 | //GuiLogHelper.guiLogger.logo("Auto pull!!!");
49 | db.pullCatched(new ExceptionHandler.LoggingEater());
50 | }
51 |
52 | public static Puller create(int seconds, DB db) {
53 | Puller p = new Puller(seconds, db);
54 | Thread t = new Thread(p);
55 | t.setDaemon(true);
56 | t.start();
57 | return p;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/ContentReaderListener.java:
--------------------------------------------------------------------------------
1 | /* ContentReaderListener.java
2 | Copyright (C) 2011,2012 Red Hat, Inc.
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or
7 | modify it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, version 2.
9 |
10 | IcedTea is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with IcedTea; see the file COPYING. If not, write to
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 | 02110-1301 USA.
19 |
20 | Linking this library statically or dynamically with other modules is
21 | making a combined work based on this library. Thus, the terms and
22 | conditions of the GNU General Public License cover the whole
23 | combination.
24 |
25 | As a special exception, the copyright holders of this library give you
26 | permission to link this library with independent modules to produce an
27 | executable, regardless of the license terms of these independent
28 | modules, and to copy and distribute the resulting executable under
29 | terms of your choice, provided that you also meet, for each linked
30 | independent module, the terms and conditions of the license of that
31 | module. An independent module is a module which is not derived from
32 | or based on this library. If you modify this library, you may extend
33 | this exception to your version of the library, but you are not
34 | obligated to do so. If you do not wish to do so, delete this
35 | exception statement from your version.
36 | */
37 |
38 | package org.fbb.board.internals;
39 |
40 | public interface ContentReaderListener {
41 |
42 | public void charReaded(char ch);
43 | public void lineReaded(String s);
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FlashFreeBoardDesktop
2 | Implementation of moonboard-like approach, on custom indoor climbing walls - PC client. See [video](http://www.facebook.com/1403584339870419/videos/562209057939918/), from this [zip](https://github.com/FlashFreeBoard/FreeBoard/raw/Olomouc20191113/walls/Olomouc20191116.wall)
3 |
4 | User manuals: [cz](https://htmlpreview.github.io/?https://github.com/judovana/FlashFreeBoardDesktop/blob/master/docs/cs_CZ.utf8.html)
5 |
6 | This is fully moonbaord-leds compatible client, however, due to no-limits on leds shining, I strongly recomends to set up own power.
7 |
8 | Except HW, you have no limitations on wall you build. Any holds, any size, any angle. Just mak a picture of it and import it as new wall, and start doing boulders on it. The client of yours can be connected to any git repository to store boulders also on remote
9 | - backup
10 | - remote maintance
11 | - several walls with same holds
12 | - several different walls on same repo
13 | However, there do not - intentionaly - exists shared world as on moonboard. well everybody is about to have custom layout :)
14 |
15 | You can set it up also as helper on campus like devices, to highlight some parts of it.
16 |
17 | As written above, there is no limitation on number of leds or even on number of lightened-on leds, however you powersource is limited, and leds eat - a bit only, but we have a lot of them. So there is built in protection to under-power. The leds will get dimmer from some point. Set upthis protection carefully!
18 |
19 | **Although the code is open, this is not entirely free stuff! Contact us by rising issue her, or by contacting http://www.flashbb.cz/**. **You are allowed to use this for non-comercial usage, to the size of moonboaard - 11x18 max.** Any commercial or any bigger array of leds in any dimesnion, must be consulted. Wall around 20x20 leds, delivered out of the box, with holds set for your difficulty, is priced aprox 20000eur, without transfer fees.
20 |
21 | Long live great moonboard, but from some time it starts to get boring, and without posibility to set up custom holds (which kills its meaning) it is doomed.
22 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/GuiLogHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | *
12 | * @author jvanek
13 | */
14 | public class GuiLogHelper {
15 |
16 | public GuiLogHelper() {
17 | //add middleware, which catches client's application stdout/err
18 | //and will submit it into console
19 | System.setErr(new TeeOutputStream(System.err, true));
20 | System.setOut(new TeeOutputStream(System.out, false));
21 | //internal stdOut/Err are going throughs outLog/errLog
22 | //when console is off, those tees are not installed
23 | }
24 |
25 | public static final GuiLogHelper guiLogger = new GuiLogHelper();
26 |
27 | StringBuffer sout = new StringBuffer();
28 | StringBuffer serr = new StringBuffer();
29 |
30 | public synchronized String getSerr() {
31 | return serr.toString();
32 | }
33 |
34 | public String getSout() {
35 | return sout.toString();
36 | }
37 |
38 | public void logo(String s) {
39 | System.out.println(s);
40 | }
41 |
42 | int limit = 1000000;
43 |
44 | public synchronized void appendInternal(String s, boolean err) {
45 | StringBuffer a = sout;
46 | if (err) {
47 | a = serr;
48 | }
49 | if (s.startsWith(" ") | s.startsWith("\t")) {
50 | a.append(s);
51 | } else {
52 | a.append(new Date().toString()).append(": ").append(s);
53 | }
54 | if (a.length() > limit) {
55 | a.delete(0, a.length() - (limit - 1));
56 | }
57 | }
58 |
59 | public void loge(String s) {
60 | System.err.println(s);
61 | }
62 |
63 | public void loge(Throwable e) {
64 | e.printStackTrace(System.err);
65 |
66 | }
67 |
68 | public static void main(String... ar) {
69 | StringBuffer a = new StringBuffer("123456789");
70 | System.out.println(a.delete(0, a.length() - 5));
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/TrainingWithBackends.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import javax.swing.JCheckBox;
9 | import org.fbb.board.internals.Filter;
10 |
11 | /**
12 | *
13 | * @author jvanek
14 | */
15 | public class TrainingWithBackends {
16 |
17 | private final BoulderCalc boulderCalc;
18 | final JCheckBox allowRandom;
19 | final JCheckBox allowRegular;
20 | final JCheckBox allowJumps;
21 | private final Training training;
22 | private final int initialDelay;
23 | private final ListSetter listSetter;
24 | private final String title;
25 |
26 | public TrainingWithBackends(BoulderCalc bc, JCheckBox random, JCheckBox regular, JCheckBox skipping, Training training, int initialDelay, String title, ListSetter ls) {
27 | this.boulderCalc = bc;
28 | this.allowRandom = random;
29 | this.allowRegular = regular;
30 | this.allowJumps = skipping;
31 | this.training = training;
32 | this.initialDelay = initialDelay;
33 | this.title = title;
34 | this.listSetter = ls;
35 | }
36 |
37 | public void setBoulderCalc() {
38 | boulderCalc.setTimeOfBoulder(training.innerSettings.tOfBoulder);
39 | boulderCalc.setTimeOfTraining(training.innerSettings.tOfTraining);
40 | boulderCalc.setNumBoulders(training.innerSettings.numOfBoulders);
41 | }
42 |
43 | public void setChecks() {
44 | allowRandom.setSelected(training.innerSettings.random);
45 | allowRegular.setSelected(training.innerSettings.regular);
46 | allowJumps.setSelected(training.innerSettings.jumps);
47 | }
48 |
49 | public void init() {
50 | listSetter.setUpBoulderWall(training.filter, training.currentName, title);
51 | }
52 |
53 | int getTotalTime() {
54 | return boulderCalc.getTotalTime();
55 | }
56 |
57 | int getTimeOfBoulder() {
58 | return boulderCalc.getTimeOfBoulder();
59 | }
60 |
61 | public int getInitialDelay() {
62 | return initialDelay;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/resources/org/fbb/board/internals/grades/tabulka:
--------------------------------------------------------------------------------
1 | id: UIAA france usa-boulder fountainbleu usa sasko britain austral
2 | #######################################################################################################
3 | 0: I 1 v0--------- fb_0 5.2 I moderate 11-
4 | 1: II 2 v0-------- fb_0+ 5.3 II dificult 11
5 | 2: III 3 v0------- fb_1- 5.4 III very dificult 11+
6 | 3: IV- 4- v0------ fb_1 5.4+ IV- 4a- 12
7 | 4: IV 4 v0----- fb_1+ 5.5 IV 4a 12+
8 | 5: IV+ 4+ v0---- fb_2- 5.5+ IV+ 4a+ 13-
9 | 6: V- 5- v0--- fb_2 5.6 V 4b- 13
10 | 7: V 5 v0-- fb_2+ 5.7 VI 4b+ 14
11 | 8: V+ 5+ v0- fb_3 5.8 VII 4c 15
12 | 9: VI- 6a- v0 fb_4 5.9- VIIb 5a 16
13 | 10: VI 6a v0+ fb_5A 5.9 VIIb/c 5a+ 17
14 | 11: VI+ 6a+ v1 fb_5B 5.10a VIIc 5b 18
15 | 12: VII- 6b v1+ fb_5C 5.10b VIII 5b/5b+ 19
16 | 13: VII-/VII 6b/6b+ v2- fb_6A 5.10c VIIIb 5b+ 20
17 | 14: VII 6b+ v2 fb_6A+ 5.10d VIIIb/c 5b+/6a- 21
18 | 15: VII+ 6c v2/v3 fb_6B 5.11a VIIIc 6a- 22
19 | 16: VIII- 6c+ v3 fb_6B+ 5.11b IX 6a+ 23
20 | 17: VIII 7a v3/v4 fb_6C 5.11c IXb 6a+/6b- 23+
21 | 18: VIII/VIII+ 7a+/7b v4 fb_6C+ 5.11d IXc- 6b- 24
22 | 19: VIII+ 7b v5 fb_7A 5.12a IXc+ 6b/6b+ 25
23 | 20: VIII+/IX- 7b+ v6 fb_7A+ 5.12b X 6b+ 26
24 | 21: IX- 7c v6/v7 fb_7B- 5.12c Xb- 6b+/6c 27
25 | 22: IX 7c+ v7 fb_7B 5.12d Xb+ 6c 28
26 | 23: IX+ 8a v8 fb_7B+ 5.13a Xc 6c+ 29
27 | 24: X- 8a+ v9 fb_7C 5.13c XI 7a- 30
28 | 25: X 8b v10 fb_7C+ 5.13d XIb- 7a 31
29 | 26: X+ 8c v11 fb_8A 5.14a XIb+ 7a/7b 32
30 | 27: XI- 8c+ v12 fb_8A+ 5.14b+ XIc- 7b 33
31 | 28: XI-/XI 8c+/9a- v13 fb_8B 5.14c XIc-/XIc+ 7b+ 34
32 | 29: XI 9a v14 fb_8B+ 5.14d XIc+ 7c 35
33 | 30: XI+ 9a+ v15 fb_8C 5.15a XII 8a 36
34 | 31: XII- 9b- v16 fb_9A 5.15b XII+ 8a+ 37
35 | 32: XII 9b v17 fb_9A+ 5.15c XIIb 8a+/8a- 38
36 | 33: XII+ 9b+ v16 fb_9B 5.15d XIIc 8b- 39
37 | 34: XIII- 9c- v19 fb_9B+ 5.16a XIII 8b 40
38 | 35: XIII 9c v20 fb_9C 5.16b XIIIb 8b+ 40+
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grid/RelativePoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grid;
7 |
8 | import java.awt.Color;
9 | import java.awt.Graphics;
10 | import java.awt.geom.Rectangle2D;
11 |
12 | /**
13 | *
14 | * @author jvanek
15 | */
16 | public class RelativePoint {
17 |
18 | private double x;
19 | private double y;
20 | private final Meassurable parent;
21 | private final Rectangle2D.Double bounds;
22 |
23 | public RelativePoint(double x, double y, Meassurable parent) {
24 | this(x, y, parent, new Rectangle2D.Double(0, 0, 1, 1));
25 | }
26 |
27 | public RelativePoint(double x, double y, Meassurable parent, Rectangle2D.Double relativeBounds) {
28 | this.x = x;
29 | this.y = y;
30 | this.parent = parent;
31 | this.bounds = relativeBounds;
32 | }
33 |
34 | public double getX() {
35 | return x;
36 | }
37 |
38 | public double getY() {
39 | return y;
40 | }
41 |
42 | public int getRealX() {
43 | return (int) (x * (double) parent.getWidth());
44 | }
45 |
46 | public int getRealY() {
47 | return (int) (y * (double) parent.getHeight());
48 | }
49 |
50 | public boolean setX(double x) {
51 | if (x >= bounds.x && x <= bounds.x + bounds.width) {
52 | this.x = x;
53 | return true;
54 | } else {
55 | return false;
56 | }
57 | }
58 |
59 | public boolean setY(double y) {
60 | if (y >= bounds.y && y <= bounds.y + bounds.height) {
61 | this.y = y;
62 | return true;
63 | } else {
64 | return false;
65 | }
66 | }
67 |
68 | public void draw(Graphics g) {
69 | int r = 50;
70 | Color c = g.getColor();
71 | g.setColor(new Color(this.hashCode()));
72 | g.drawOval(getRealX() - r, getRealY() - r, 2 * r, 2 * r);
73 | g.setColor(c);
74 | }
75 |
76 | public boolean isInAreaOfControl(double x, double y) {
77 | return x >= bounds.x && x <= bounds.x + bounds.width
78 | && y >= bounds.y && y <= bounds.y + bounds.height;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grid/Line.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grid;
7 |
8 | import java.awt.Graphics;
9 | import java.awt.Point;
10 | import java.awt.geom.Point2D;
11 |
12 | /**
13 | *
14 | * @author jvanek
15 | */
16 | public class Line {
17 |
18 | private final Point from;
19 | private final Point to;
20 |
21 | public Line(Point from, Point to) {
22 | this.from = from;
23 | this.to = to;
24 | }
25 |
26 | public Line(int x1, int y1, int x2, int y2) {
27 | this.from = new Point(x1, y1);
28 | this.to = new Point(x2, y2);
29 | }
30 |
31 | void draw(Graphics g) {
32 | g.drawLine(from.x, from.y, to.x, to.y);
33 | }
34 |
35 | void draw(Graphics g, int xShift, int yShift) {
36 | g.drawLine(from.x+xShift, from.y+yShift, to.x+xShift, to.y+yShift);
37 | }
38 |
39 | Point cross(Line l) {
40 | //not playing with paralel or identicals - they cant be form nature of grid
41 | Point.Double p1 = new Point2D.Double(from.x, from.y);
42 | Point2D.Double v1 = new Point2D.Double(to.x - from.x, to.y - from.y);
43 | Point.Double p2 = new Point2D.Double(l.from.x, l.from.y);
44 | Point2D.Double v2 = new Point2D.Double(l.to.x - l.from.x, l.to.y - l.from.y);
45 | Point2D.Double r = calculateInterceptionPoint(p1, v1, p2, v2);
46 | if (r == null) {
47 | return null;
48 | }
49 | return new Point((int) r.x, (int) r.y);
50 | }
51 |
52 | public static Point.Double calculateInterceptionPoint(Point2D.Double p1, Point2D.Double v1, Point2D.Double p2, Point2D.Double v2) {
53 |
54 | double sNumerator = p1.y * v1.x + p2.x * v1.y - p1.x * v1.y - p2.y * v1.x;
55 | double sDenominator = v2.y * v1.x - v2.x * v1.y;
56 |
57 | // parallel ... 0 or infinite points, or one of the vectors is 0|0
58 | if (sDenominator == 0) {
59 | return null;
60 | }
61 |
62 | double s = sNumerator / sDenominator;
63 |
64 | double t;
65 | if (v1.x != 0) {
66 | t = (p2.x + s * v2.x - p1.x) / v1.x;
67 | } else {
68 | t = (p2.y + s * v2.y - p1.y) / v1.y;
69 | }
70 |
71 | Point.Double i1 = new Point.Double(p1.x + t * v1.x, p1.y + t * v1.y);
72 |
73 | return i1;
74 |
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/awt/ImageWithTitles.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial.awt;
7 |
8 | import java.awt.Color;
9 | import java.awt.Font;
10 | import java.awt.Graphics;
11 | import java.awt.Graphics2D;
12 | import java.awt.geom.Rectangle2D;
13 | import java.awt.image.BufferedImage;
14 | import java.util.Date;
15 | import java.util.List;
16 | import javax.swing.JPanel;
17 | import org.fbb.board.Translator;
18 | import org.fbb.board.desktop.gui.BoulderCreationGui;
19 | import org.fbb.board.desktop.tutorial.SingleText;
20 | import org.fbb.board.internals.Filter;
21 |
22 | /**
23 | *
24 | * @author jvanek
25 | */
26 | public class ImageWithTitles extends JPanel {
27 |
28 | private final List titles;
29 | private final BufferedImage bi;
30 |
31 | public ImageWithTitles(List titles, BufferedImage bi) {
32 | this.titles = titles;
33 | this.bi = bi;
34 | }
35 |
36 | @Override
37 | public void paint(Graphics g) {
38 | g.drawImage(bi, 0, 0, this.getWidth(), this.getHeight(), null);
39 | double w = (double) this.getWidth() / (double) bi.getWidth();
40 | double h = (double) this.getHeight() / (double) bi.getHeight();
41 | g.setFont(g.getFont().deriveFont(g.getFont().getSize2D() * 1.5f));
42 | for (int i = 0; i < titles.size(); i++) {
43 | SingleText get = titles.get(i);
44 | String s = Translator.R(get.getKey(), BoulderCreationGui.antiChild.format(new Date()));
45 | g.setFont(g.getFont().deriveFont(Font.BOLD));
46 | Rectangle2D rect = g.getFontMetrics().getStringBounds(s, g);//java.awt.geom.Rectangle2D$Float[x=0.0,y=-11.138672,w=71.0,h=13.96875]
47 | int fh = g.getFontMetrics().getHeight();//15
48 | g.setColor(new Color(250, 250, 250, 200));
49 | if (get.getX(w) + rect.getWidth() > getWidth()) {
50 | g.fillRect(getWidth() - (int) rect.getWidth(), get.getY(h), (int) rect.getWidth(), fh);
51 | g.setColor(Color.black);
52 | g.drawString(s, getWidth() - (int) rect.getWidth(), get.getY(h) + fh);
53 | } else {
54 | g.fillRect(get.getX(w), get.getY(h), (int) rect.getWidth(), fh);
55 | g.setColor(Color.black);
56 | g.drawString(s, get.getX(w), get.getY(h) + fh);
57 | }
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/rotate_desktop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # many thanks: https://gist.github.com/mildmojo/48e9025070a2ba40795c
3 | # set -eo added against original to work fine as service
4 | set -e
5 | set -o pipefail
6 | #
7 | # rotate_desktop.sh
8 | #
9 | # Rotates modern Linux desktop screen and input devices to match. Handy for
10 | # convertible notebooks. Call this script from panel launchers, keyboard
11 | # shortcuts, or touch gesture bindings (xSwipe, touchegg, etc.).
12 | #
13 | # Using transformation matrix bits taken from:
14 | # https://wiki.ubuntu.com/X/InputCoordinateTransformation
15 | #
16 |
17 | # Configure these to match your hardware (names taken from `xinput` output).
18 | #TOUCHPAD='SynPS/2 Synaptics TouchPad'
19 | #TOUCHSCREEN='Atmel Atmel maXTouch Digitizer'
20 |
21 | # adapted against original
22 | TOUCHPAD='ELAN Touchscreen'
23 | TOUCHSCREEN='Virtual core XTEST pointer'
24 |
25 | if [ -z "$1" ]; then
26 | echo "Missing orientation."
27 | echo "Usage: $0 [normal|inverted|left|right] [revert_seconds]"
28 | echo
29 | exit 1
30 | fi
31 |
32 | function do_rotate
33 | {
34 | xrandr --output $1 --rotate $2
35 |
36 | TRANSFORM='Coordinate Transformation Matrix'
37 |
38 | case "$2" in
39 | normal)
40 | [ ! -z "$TOUCHPAD" ] && xinput set-prop "$TOUCHPAD" "$TRANSFORM" 1 0 0 0 1 0 0 0 1
41 | [ ! -z "$TOUCHSCREEN" ] && xinput set-prop "$TOUCHSCREEN" "$TRANSFORM" 1 0 0 0 1 0 0 0 1
42 | ;;
43 | inverted)
44 | [ ! -z "$TOUCHPAD" ] && xinput set-prop "$TOUCHPAD" "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
45 | [ ! -z "$TOUCHSCREEN" ] && xinput set-prop "$TOUCHSCREEN" "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
46 | ;;
47 | left)
48 | [ ! -z "$TOUCHPAD" ] && xinput set-prop "$TOUCHPAD" "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
49 | [ ! -z "$TOUCHSCREEN" ] && xinput set-prop "$TOUCHSCREEN" "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
50 | ;;
51 | right)
52 | [ ! -z "$TOUCHPAD" ] && xinput set-prop "$TOUCHPAD" "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
53 | [ ! -z "$TOUCHSCREEN" ] && xinput set-prop "$TOUCHSCREEN" "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
54 | ;;
55 | esac
56 | }
57 |
58 | XDISPLAY=`xrandr --current | grep primary | sed -e 's/ .*//g'`
59 | XROT=`xrandr --current --verbose | grep primary | egrep -o ' (normal|left|inverted|right) '`
60 |
61 | do_rotate $XDISPLAY $1
62 | sleep 2
63 | fbsetbg /home/app/ffbbg.jpg
64 | sleep 2
65 | rm /home/app/.fluxbox/lastwallpaper
66 | sleep 2
67 | fbsetbg /home/app/ffbbg.jpg
68 |
69 |
70 | # not disabled in original, as this is service, handled rather by forced restart; maybe bad idea
71 | # but the sleep may not be enough
72 | #if [ ! -z "$2" ]; then
73 | #sleep $2
74 | # do_rotate $XDISPLAY $XROT
75 | # exit 0
76 | #fi
77 |
78 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/GitAuthenticator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui;
7 |
8 | import java.awt.GridLayout;
9 | import java.nio.charset.Charset;
10 | import javax.swing.JCheckBox;
11 | import javax.swing.JLabel;
12 | import javax.swing.JOptionPane;
13 | import javax.swing.JPanel;
14 | import javax.swing.JPasswordField;
15 | import org.fbb.board.Translator;
16 | import org.fbb.board.desktop.Files;
17 | import org.fbb.board.internals.GuiLogHelper;
18 |
19 | /**
20 | *
21 | * @author jvanek
22 | */
23 | public class GitAuthenticator {
24 |
25 | private static char[] pernament = null;
26 |
27 | public boolean isPernament() {
28 | return pernament != null;
29 | }
30 |
31 | public static void revoke() {
32 | pernament = null;
33 | }
34 |
35 | public char[] authenticate(String message) {
36 | char[] r = authenticateImpl(message);
37 | return r;
38 |
39 | }
40 |
41 | private char[] authenticateImpl(String message) {
42 | if (pernament != null) {
43 | return pernament;
44 | }
45 | if (Files.remotePass.exists()) {
46 | try {
47 | String zzz = java.nio.file.Files.readAllLines(Files.remotePass.toPath(), Charset.forName("utf-8")).get(0);
48 | String plainText = SettingsListener.textEncryptor.decrypt(zzz);
49 | return plainText.toCharArray();
50 | } catch (Exception ex) {
51 | GuiLogHelper.guiLogger.loge(ex);
52 | }
53 | }
54 | Object[] r = new AuthoriseDialog().show(message);
55 | if (r == null || r.length != 2) {
56 | return null;
57 | }
58 | char[] s = (char[]) (r[0]);
59 | if (s == null || new String(s).trim().isEmpty()) {
60 | return null;
61 | }
62 | if ((boolean) r[1]) {
63 | pernament = s;
64 | }
65 | return s;
66 | }
67 |
68 | private static class AuthoriseDialog {
69 |
70 | public Object[] show(String message) {
71 | JPasswordField pass = new JPasswordField(5);
72 | JCheckBox save = new JCheckBox(Translator.R("keepLoged"), false);
73 |
74 | JPanel myPanel = new JPanel(new GridLayout(3, 1));
75 | myPanel.add(new JLabel(message));
76 | myPanel.add(pass);
77 | myPanel.add(save);
78 | int result = JOptionPane.showConfirmDialog(null, myPanel, Translator.R("autenticateGit"), JOptionPane.OK_CANCEL_OPTION);
79 | if (result == JOptionPane.OK_OPTION) {
80 | return new Object[]{pass.getPassword(), save.isSelected()};
81 | }
82 | return null;
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/ProcessResult.java:
--------------------------------------------------------------------------------
1 | /* ProcessResult.java
2 | Copyright (C) 2011,2012 Red Hat, Inc.
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or
7 | modify it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, version 2.
9 |
10 | IcedTea is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with IcedTea; see the file COPYING. If not, write to
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 | 02110-1301 USA.
19 |
20 | Linking this library statically or dynamically with other modules is
21 | making a combined work based on this library. Thus, the terms and
22 | conditions of the GNU General Public License cover the whole
23 | combination.
24 |
25 | As a special exception, the copyright holders of this library give you
26 | permission to link this library with independent modules to produce an
27 | executable, regardless of the license terms of these independent
28 | modules, and to copy and distribute the resulting executable under
29 | terms of your choice, provided that you also meet, for each linked
30 | independent module, the terms and conditions of the license of that
31 | module. An independent module is a module which is not derived from
32 | or based on this library. If you modify this library, you may extend
33 | this exception to your version of the library, but you are not
34 | obligated to do so. If you do not wish to do so, delete this
35 | exception statement from your version.
36 | */
37 |
38 | package org.fbb.board.internals;
39 |
40 | /**
41 | * artefacts what are left by finished process
42 | */
43 | public class ProcessResult {
44 |
45 | public final String stdout;
46 | public final String notFilteredStdout;
47 | public final String stderr;
48 | public final Process process;
49 | public final Integer returnValue;
50 | public final boolean wasTerminated;
51 | /*
52 | * possible exception which caused Process not to be launched
53 | */
54 | public final Throwable deadlyException;
55 |
56 | public ProcessResult(String stdout, String stderr, Process process, boolean wasTerminated, Integer r, Throwable deadlyException) {
57 | this.notFilteredStdout = stdout;
58 | if (stdout == null) {
59 | this.stdout = null;
60 | } else {
61 | this.stdout = stdout.replaceAll("EMMA:.*\n?", "");
62 | }
63 | this.stderr = stderr;
64 | this.process = process;
65 | this.wasTerminated = wasTerminated;
66 | this.returnValue = r;
67 | this.deadlyException = deadlyException;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app/.fluxbox/init:
--------------------------------------------------------------------------------
1 | session.screen0.iconbar.usePixmap: true
2 | session.screen0.iconbar.iconWidth: 128
3 | session.screen0.iconbar.mode: {static groups} (workspace)
4 | session.screen0.iconbar.iconTextPadding: 10
5 | session.screen0.iconbar.alignment: Relative
6 | session.screen0.toolbar.autoHide: false
7 | session.screen0.toolbar.alpha: 255
8 | session.screen0.toolbar.widthPercent: 100
9 | session.screen0.toolbar.height: 0
10 | session.screen0.toolbar.tools: prevworkspace, workspacename, nextworkspace, clock, prevwindow, nextwindow, iconbar, systemtray
11 | session.screen0.toolbar.onhead: 1
12 | session.screen0.toolbar.visible: true
13 | session.screen0.toolbar.maxOver: false
14 | session.screen0.toolbar.layer: Dock
15 | session.screen0.toolbar.placement: BottomCenter
16 | session.screen0.clientMenu.usePixmap: true
17 | session.screen0.titlebar.left: Stick
18 | session.screen0.titlebar.right: Minimize Maximize Close
19 | session.screen0.menu.alpha: 255
20 | session.screen0.tabs.usePixmap: true
21 | session.screen0.tabs.maxOver: false
22 | session.screen0.tabs.intitlebar: true
23 | session.screen0.slit.onhead: 0
24 | session.screen0.slit.alpha: 255
25 | session.screen0.slit.autoHide: false
26 | session.screen0.slit.maxOver: false
27 | session.screen0.slit.acceptKdeDockapps: true
28 | session.screen0.slit.placement: RightBottom
29 | session.screen0.slit.layer: Dock
30 | session.screen0.window.focus.alpha: 255
31 | session.screen0.window.unfocus.alpha: 255
32 | session.screen0.tab.placement: TopLeft
33 | session.screen0.tab.width: 64
34 | session.screen0.focusNewWindows: true
35 | session.screen0.fullMaximization: false
36 | session.screen0.colPlacementDirection: TopToBottom
37 | session.screen0.defaultDeco: NORMAL
38 | session.screen0.tabFocusModel: ClickToTabFocus
39 | session.screen0.opaqueMove: true
40 | session.screen0.edgeSnapThreshold: 10
41 | session.screen0.noFocusWhileTypingDelay: 0
42 | session.screen0.allowRemoteActions: false
43 | session.screen0.clickRaises: true
44 | session.screen0.rowPlacementDirection: LeftToRight
45 | session.screen0.tooltipDelay: 500
46 | session.screen0.maxDisableResize: false
47 | session.screen0.focusModel: ClickFocus
48 | session.screen0.focusSameHead: false
49 | session.screen0.autoRaise: true
50 | session.screen0.showwindowposition: false
51 | session.screen0.menuDelay: 200
52 | session.screen0.maxDisableMove: false
53 | session.screen0.windowMenu: /home/app/.fluxbox/windowmenu
54 | session.screen0.maxIgnoreIncrement: true
55 | session.screen0.workspaceNames: Workspace 1,Workspace 2,
56 | session.screen0.workspaces: 1
57 | session.screen0.strftimeFormat: %d %b, %a %02k:%M:%S
58 | session.screen0.workspacewarping: true
59 | session.screen0.windowPlacement: RowMinOverlapPlacement
60 | session.keyFile: ~/.fluxbox/keys
61 | session.appsFile: /home/app/.fluxbox/apps
62 | session.forcePseudoTransparency: false
63 | session.colorsPerChannel: 4
64 | session.configVersion: 13
65 | session.styleOverlay: /home/app/.fluxbox/overlay
66 | session.ignoreBorder: false
67 | session.cacheMax: 200
68 | session.tabsAttachArea: Window
69 | session.autoRaiseDelay: 250
70 | session.menuFile: ~/.fluxbox/menu
71 | session.styleFile: /usr/share/fluxbox/styles/Artwiz
72 | session.doubleClickInterval: 250
73 | session.cacheLife: 5
74 | session.slitlistFile: /home/app/.fluxbox/slitlist
75 | session.tabPadding: 0
76 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/TextToSpeech.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop;
7 |
8 | import java.io.IOException;
9 | import org.fbb.board.Translator;
10 | import org.fbb.board.internals.GuiLogHelper;
11 |
12 | /**
13 | *
14 | * @author jvanek
15 | */
16 | public class TextToSpeech {
17 |
18 | public static class TextId {
19 |
20 | final private String name;
21 | final private String code;
22 |
23 | public TextId(String name, String code) {
24 | this.name = name;
25 | this.code = code;
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return name;
31 | }
32 |
33 | }
34 | private static final TextId[] avail = new TextId[]{
35 | new TextId(Translator.R("silent"), null),
36 | new TextId(("čeština"), "cs"),
37 | new TextId(("english"), "en")
38 |
39 | };
40 |
41 | public static void change(TextId id) {
42 | try {
43 | if (id != null && id.code != null) {
44 | if (id.code.equalsIgnoreCase("cs")) {
45 | tellImpl("Změna v tréniku", id);
46 | }
47 | if (id.code.equalsIgnoreCase("en")) {
48 | tellImpl("Change in training", id);
49 | }
50 | }
51 | } catch (Exception ex) {
52 | GuiLogHelper.guiLogger.loge(ex);
53 | }
54 | }
55 |
56 | public static void pause(TextId id) {
57 | try {
58 | if (id.code.equalsIgnoreCase("cs")) {
59 | tellImpl("Pauza", id);
60 | }
61 | if (id.code.equalsIgnoreCase("en")) {
62 | tellImpl("Break", id);
63 | }
64 | } catch (Exception ex) {
65 | GuiLogHelper.guiLogger.loge(ex);
66 | }
67 | }
68 |
69 | public void tell(String s, TextId id) {
70 | try {
71 | tellImpl(s, id);
72 | } catch (Exception ex) {
73 | GuiLogHelper.guiLogger.loge(ex);
74 | }
75 | }
76 |
77 | public static void tellImpl(String s, TextId id) throws IOException {
78 | if (id.code != null) {
79 | Process p = Runtime.getRuntime().exec(new String[]{"espeak", "-v", id.code, s});
80 | }
81 | }
82 |
83 | public static boolean isAvail() throws IOException, InterruptedException {
84 | Process p = Runtime.getRuntime().exec("espeak --version");
85 | p.waitFor();
86 | return (p.exitValue() == 0);
87 | }
88 |
89 | public static TextId[] getLangs() {
90 | try {
91 | if (isAvail()) {
92 | return avail;
93 | } else {
94 | return new TextId[]{
95 | new TextId(Translator.R("noEspeak"), null)
96 | };
97 | }
98 | } catch (Exception ex) {
99 | GuiLogHelper.guiLogger.loge(ex);
100 | return new TextId[]{
101 | new TextId(Translator.R("noEspeak"), null)
102 | };
103 |
104 | }
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/HistoryManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals;
7 |
8 | import org.fbb.board.internals.grid.Boulder;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.Vector;
12 |
13 | /**
14 | *
15 | * @author jvanek
16 | */
17 | public class HistoryManager {
18 |
19 | protected final List history = new ArrayList<>();
20 | protected int historyIndex = -1;
21 | protected final int llimit;
22 |
23 | public HistoryManager(int limit) {
24 | llimit = limit;
25 | }
26 |
27 | public HistoryManager() {
28 | llimit = -1;
29 | }
30 |
31 | //returns whether we are at end or not;
32 | //return true, if index is NOT last (and thus forward button can be enabld)
33 | public Boulder getCurrentInHistory() {
34 | if (history.isEmpty() || historyIndex < 0 || historyIndex > history.size()) {
35 | return null;
36 | }
37 | return history.get(historyIndex);
38 | }
39 |
40 | public int getHistoryIndex() {
41 | return historyIndex;
42 | }
43 |
44 |
45 |
46 | public void addToBoulderHistory(Boulder b) {
47 | if (history.isEmpty()) {
48 | history.add(b);
49 | historyIndex = 0;
50 | return;
51 | }
52 | if (historyIndex >= history.size() - 1) {
53 | historyIndex++;
54 | history.add(b);
55 | limit();
56 | return;
57 | }
58 | historyIndex++;
59 | history.add(historyIndex, b);
60 | limit();
61 | return;
62 | }
63 |
64 | public boolean canBack() {
65 | return historyIndex > 0;
66 | }
67 |
68 | public Vector getHistory() {
69 | return new Vector(history);
70 | }
71 |
72 | public void setIndex(int index) {
73 | this.historyIndex = index;
74 | }
75 |
76 | public void setIndex(String id) {
77 | for (int i = 0; i < history.size(); i++) {
78 | Boulder get = history.get(i);
79 | if (get.getFile().getName().equals(id)) {
80 | this.historyIndex = i;
81 | break;
82 | }
83 | }
84 |
85 | }
86 |
87 | public Boulder forward() {
88 | if (history.isEmpty()) {
89 | return null;
90 | }
91 | if (canFwd()) {
92 | historyIndex++;
93 | return history.get(historyIndex);
94 | }
95 | return history.get(historyIndex);
96 | }
97 |
98 | public Boulder back() {
99 | if (history.isEmpty()) {
100 | return null;
101 | }
102 | if (canBack()) {
103 | historyIndex--;
104 | return history.get(historyIndex);
105 | }
106 | return history.get(historyIndex);
107 | }
108 |
109 | public boolean canFwd() {
110 | return historyIndex < history.size() - 1;
111 | }
112 |
113 | public void clearHistory() {
114 | historyIndex = -1;
115 | history.clear();
116 | }
117 |
118 | protected void limit() {
119 | if (llimit > 0 && history.size() > llimit) {
120 | history.remove(0);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/parts/TimeAndSnooze.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs.parts;
7 |
8 | import java.awt.Container;
9 | import javax.swing.JLabel;
10 | import javax.swing.JSpinner;
11 | import javax.swing.JTextField;
12 | import javax.swing.SpinnerNumberModel;
13 | import javax.swing.event.DocumentEvent;
14 | import javax.swing.event.DocumentListener;
15 | import org.fbb.board.Translator;
16 | import org.fbb.board.internals.training.BoulderCalc;
17 |
18 | /**
19 | *
20 | * @author jvanek
21 | */
22 | public class TimeAndSnooze {
23 |
24 | private final JSpinner delay;
25 | private final JTextField snooze;
26 | private final JLabel time;
27 | private final Changer ch;
28 | private final Snoozer snoozer;
29 | private final Runnable reset;
30 | private final Runnable mainPaint;
31 | private final Thread runner;
32 |
33 | private volatile boolean alive = true;
34 |
35 | public TimeAndSnooze(Container parent, Runnable snoozAction, Runnable resetAction, Runnable paint) {
36 | parent.add(new JLabel(Translator.R("delay")));
37 | delay = new JSpinner(new SpinnerNumberModel(1.5, 0.2, 10, 0.2));
38 | parent.add(delay);
39 | parent.add(new JLabel(Translator.R("snooze")));
40 | snooze = new JTextField("00:00");
41 | ch = new Changer();
42 | snooze.getDocument().addDocumentListener(ch);
43 | parent.add(snooze);
44 | parent.add(new JLabel(" mm:ss :"));
45 | time = new JLabel("0:0");
46 | time.setFont(time.getFont().deriveFont(time.getFont().getSize() * 3f));
47 | parent.add(time);
48 | snoozer = new Snoozer(new Runnable() {
49 | @Override
50 | public void run() {
51 | snoozer.setSnoozeCounter(-2000/*very aprox time of rendering below*/);
52 | snoozAction.run();
53 | }
54 | });
55 | reset = resetAction;
56 | mainPaint = paint;
57 | runner = new Thread(new Runnable() {
58 | @Override
59 | public void run() {
60 | reset.run();
61 | while (alive) {
62 | try {
63 | Thread.sleep(getDelay());
64 | snoozer.checkAndDo(getDelay(), time, snooze);
65 | mainPaint.run();
66 | } catch (InterruptedException ex) {
67 | //nooo!
68 | }
69 | }
70 | }
71 | });
72 | ch.work();
73 | }
74 |
75 | public void start() {
76 | runner.start();
77 | }
78 |
79 | public void stop() {
80 | alive = false;
81 | }
82 |
83 | private class Changer implements DocumentListener {
84 |
85 | @Override
86 | public void insertUpdate(DocumentEvent e) {
87 | work();
88 | }
89 |
90 | @Override
91 | public void removeUpdate(DocumentEvent e) {
92 | work();
93 | }
94 |
95 | @Override
96 | public void changedUpdate(DocumentEvent e) {
97 | work();
98 | }
99 |
100 | private void work() {
101 | snoozer.setSnoozeCounter((long) BoulderCalc.decode(snooze.getText()) * 1000l);
102 | reset.run();
103 | }
104 |
105 | }
106 |
107 | public void doAsOnChange() {
108 | ch.work();
109 | }
110 |
111 | private long getDelay() {
112 | return (long) (((Double) delay.getValue()) * 1000d);
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/TrainingPlaylist.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.File;
10 | import java.io.FileInputStream;
11 | import java.io.IOException;
12 | import java.io.InputStreamReader;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import org.fbb.board.desktop.Files;
16 |
17 | /**
18 | *
19 | * @author jvanek
20 | */
21 | public class TrainingPlaylist {
22 |
23 | private final List data;
24 |
25 | private TrainingPlaylist(List r) {
26 | data = r;
27 | }
28 |
29 | private static class TrainingWithStartTime {
30 |
31 | private final Training t;
32 | private final int seconds;
33 | private final String name;
34 |
35 | public TrainingWithStartTime(Training t, int seconds, String name) {
36 | this.t = t;
37 | this.seconds = seconds;
38 | this.name = name;
39 | }
40 | }
41 |
42 | public List toTrainings() {
43 | List r = new ArrayList<>(data.size());
44 | for (TrainingWithStartTime t : data) {
45 | Training tt = new Training(t.t.innerSettings.random, t.t.innerSettings.regular, t.t.innerSettings.jumps, t.t.innerSettings.tOfBoulder, t.t.innerSettings.tOfTraining, t.t.innerSettings.numOfBoulders, t.t.filter, t.t.currentName);
46 | r.add(tt);
47 | }
48 | return r;
49 | }
50 |
51 | public int getPauseForTraing(int i) {
52 | return data.get(i).seconds;
53 | }
54 |
55 | public String getTitleForTraing(int i) {
56 | return data.get(i).name;
57 | }
58 |
59 | @Override
60 | public String toString() {
61 | StringBuilder sb = new StringBuilder("Trainings in list: " + data.size() + "\n");
62 | int i = 0;
63 | for (TrainingWithStartTime t : data) {
64 | i++;
65 | sb.append(i).append(")").append(t.name).append(", init delay: ").append(BoulderCalc.code(t.seconds)).append("\n");
66 |
67 | }
68 | sb.append("\n*** Details *** \n");
69 | i = 0;
70 | int total1 = 0;
71 | int total2 = 0;
72 | for (TrainingWithStartTime t : data) {
73 | i++;
74 | sb.append(i).append(") pause: ").append(BoulderCalc.code(t.seconds)).append(", ");
75 | sb.append(t.name).append("/").append(t.t.toString());
76 | sb.append("\n-----------\n");
77 | total1 += t.seconds + BoulderCalc.decode(t.t.innerSettings.tOfTraining);
78 | total2 += BoulderCalc.decode(t.t.innerSettings.tOfTraining);
79 | }
80 | sb.append("total: ").append(BoulderCalc.code(total1)).append("(").append(BoulderCalc.code(total2)).append(" of pure workload)" + "\n");
81 | return sb.toString();
82 | }
83 |
84 | public static TrainingPlaylist loadSavedTraining(File selectedFile) throws IOException {
85 | List r = new ArrayList<>();
86 | try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(selectedFile), "utf-8"))) {
87 | while (true) {
88 | String s = br.readLine();
89 | if (s == null) {
90 | break;
91 | }
92 | String[] src = s.split("/");
93 | if (src.length == 1) {
94 | r.add(new TrainingWithStartTime(Training.loadSavedTraining(Files.getTraining(src[0])), 0, src[0]));
95 | } else {
96 | int ts = BoulderCalc.decode(src[0]);
97 | r.add(new TrainingWithStartTime(Training.loadSavedTraining(Files.getTraining(src[1])), ts, src[1]));
98 | }
99 | }
100 | }
101 | return new TrainingPlaylist(r);
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/comm/wired/PortWork.java:
--------------------------------------------------------------------------------
1 | /*
2 | sudo usermod -aG dialout jvanek
3 | sudo usermod -aG uucp jvanek
4 | sudo usermod -aG lock jvanek
5 | sudo chown root:uucp /run/lock
6 | sudo chmod 775 /run/lock
7 |
8 | */
9 | package org.fbb.board.internals.comm.wired;
10 |
11 | import com.fazecast.jSerialComm.SerialPort;
12 | import java.util.HashSet;
13 | import java.util.Set;
14 | import org.fbb.board.internals.GuiLogHelper;
15 | import org.fbb.board.internals.comm.ConnectionID;
16 | import org.fbb.board.internals.comm.ListAndWrite;
17 |
18 | /**
19 | *
20 | * @author jvanek
21 | */
22 | public class PortWork implements ListAndWrite {
23 |
24 | @Override
25 | public void writeToDevice(String id, byte[]... b) {
26 | writeTo(id, b);
27 | }
28 |
29 | @Override
30 | public ConnectionID[] listDevices() {
31 | return list();
32 | }
33 |
34 | //9600 is super safe
35 | private static final int BAUD_RATE = 38400;
36 |
37 | public static void main(String... s) throws Exception {
38 | ConnectionID[] a = list();
39 | for (ConnectionID a1 : a) {
40 | GuiLogHelper.guiLogger.logo(a1.toString());
41 |
42 | }
43 | byte[] testData = new byte[]{
44 | (byte) 5, 0, 0,
45 | (byte) 5, 0, 0,
46 | (byte) 0, 5, 0,
47 | (byte) 0, 5, 0,
48 | (byte) 0, 0, 5,
49 | (byte) 0, 0, 5,
50 | (byte) 5, 5, 0,
51 | (byte) 5, 5, 0,
52 | (byte) 5, 0, 5,
53 | (byte) 5, 0, 5,
54 | (byte) 0, 5, 5,
55 | (byte) 0, 5, 5,
56 | (byte) 5, 5, 5
57 | };
58 | writeTo("ttyUSB0", testData);
59 |
60 | }
61 |
62 | private static void writeTo(String port, byte[]... bytes) {
63 | int u = getUsage(port);
64 | for (int i = 0; i < u; i++) {
65 | writeToImpl(SerialPort.getCommPort(port), bytes);
66 | }
67 | }
68 |
69 | private static void writeTo(SerialPort port, byte[]... bytes) {
70 | int u = getUsage(port.getSystemPortName());
71 | for (int i = 0; i < u; i++) {
72 | writeToImpl(port, bytes);
73 | }
74 | }
75 |
76 | private static void writeToImpl(SerialPort comPort, byte[]... b) {
77 |
78 | comPort.setBaudRate(BAUD_RATE);
79 | try {
80 | comPort.openPort();
81 | Thread.sleep(100);
82 | for (byte[] byteArray : b) {
83 | writeByteByByte(byteArray, comPort);
84 | GuiLogHelper.guiLogger.logo("[wired]written - " + byteArray.length);
85 | }
86 | GuiLogHelper.guiLogger.logo("[wired]written - end - " + b.length);
87 | } catch (Exception e) {
88 | GuiLogHelper.guiLogger.loge(e);
89 | }
90 | comPort.closePort();
91 | }
92 |
93 | public static void writeByteByByte(byte[] byteArray, SerialPort comPort) throws InterruptedException {
94 | for (int i = 0; i < byteArray.length; i++) {
95 | byte c = byteArray[i]; //arduino have very small buffer (so no need to send byte by byte until 64bytes, but this should serve for some 400
96 | comPort.writeBytes(new byte[]{c}, 1);
97 | Thread.sleep(2);//we sleep 1 in arduino
98 | }
99 | }
100 |
101 | private static Set usages = new HashSet<>();
102 |
103 | //First usage of each port is lost
104 | private static int getUsage(String port) {
105 | if (usages.contains(port)) {
106 | return 1;
107 | } else {
108 | usages.add(port);
109 | return 2;
110 | }
111 | }
112 |
113 | private static ConnectionID[] list() {
114 | SerialPort[] ports = SerialPort.getCommPorts();
115 | ConnectionID[] a = new ConnectionID[ports.length];
116 | for (int i = 0; i < ports.length; i++) {
117 | SerialPort port = ports[i];
118 | a[i] = new ConnectionID(port.getSystemPortName(), port.getDescriptivePortName());
119 | }
120 | return a;
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/TeeOutputStream.java:
--------------------------------------------------------------------------------
1 | /* TeeOutputStream.java
2 | Copyright (C) 2010 Red Hat
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2, or (at your option)
9 | any later version.
10 |
11 | IcedTea is distributed in the hope that it will be useful, but
12 | WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with IcedTea; see the file COPYING. If not, write to the
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 | 02110-1301 USA.
20 |
21 | Linking this library statically or dynamically with other modules is
22 | making a combined work based on this library. Thus, the terms and
23 | conditions of the GNU General Public License cover the whole
24 | combination.
25 |
26 | As a special exception, the copyright holders of this library give you
27 | permission to link this library with independent modules to produce an
28 | executable, regardless of the license terms of these independent
29 | modules, and to copy and distribute the resulting executable under
30 | terms of your choice, provided that you also meet, for each linked
31 | independent module, the terms and conditions of the license of that
32 | module. An independent module is a module which is not derived from
33 | or based on this library. If you modify this library, you may extend
34 | this exception to your version of the library, but you are not
35 | obligated to do so. If you do not wish to do so, delete this
36 | exception statement from your version. */
37 | package org.fbb.board.internals;
38 |
39 | import java.io.ByteArrayOutputStream;
40 | import java.io.File;
41 | import java.io.PrintStream;
42 |
43 | /**
44 | * Behaves like the 'tee' command, sends output to both actual std stream and a
45 | * log
46 | */
47 | public final class TeeOutputStream extends PrintStream {
48 |
49 | // Everthing written to TeeOutputStream is written to our log too
50 | private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
51 | private final boolean isError;
52 |
53 | public TeeOutputStream(PrintStream stdStream, boolean isError) {
54 | super(stdStream);
55 | this.isError = isError;
56 | }
57 |
58 | @Override
59 | public void close() {
60 | flushLog();
61 | super.close();
62 | }
63 |
64 | @Override
65 | public void flush() {
66 | flushLog();
67 | super.flush();
68 | }
69 |
70 | /*
71 | * The big ones: these do the actual writing
72 | */
73 | @Override
74 | public synchronized void write(byte[] b, int off, int len) {
75 | if (len == 0) {
76 | return;
77 | }
78 | appendByteArray(b, off, len);
79 | super.write(b, off, len);
80 | }
81 |
82 | @Override
83 | public synchronized void write(int b) {
84 | appendByte(b);
85 | super.write(b);
86 | }
87 |
88 | private void flushLog() {
89 | String s = byteArrayOutputStream.toString();
90 | if (s.length() > 0) {
91 | log(s);
92 | byteArrayOutputStream.reset();
93 | }
94 | }
95 |
96 | public void log(String s) {
97 | GuiLogHelper.guiLogger.appendInternal(s, isError);
98 | }
99 |
100 | public boolean isError() {
101 | return isError;
102 | }
103 |
104 | private void appendByte(int b) {
105 | byteArrayOutputStream.write(b);
106 | String s = byteArrayOutputStream.toString();
107 | if (s.endsWith(getLineSeparator())) {
108 | flushLog();
109 | }
110 | }
111 |
112 | private void appendByteArray(byte[] b, int off, int len) {
113 | byteArrayOutputStream.write(b, off, len);
114 | String s = new String(b, off, len);
115 | if (s.endsWith(getLineSeparator())) {
116 | flushLog();
117 | }
118 | }
119 |
120 | public static String getLineSeparator() {
121 | return File.separator;
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/system_configs/raspbian_buster/home/app-data/FlashFreeBoardDesktop-1.0-SNAPSHOT-jar-with-dependencies:
--------------------------------------------------------------------------------
1 | sudo apt install vim
2 | sudo apt install avahi
3 | sudo apt install avahi-utils
4 | apt-get install xorg
5 | sudo apt-get install xorg
6 | sudo apt-get install fluxbox onboard
7 | sudo mv /usr/bin/xterm /usr/bin/xterm-backup #as xterm is in default menu
8 |
9 | sudo apt install dconf #onbaords depndence
10 | sudo apt-get install matchbox-keyboard # good one
11 | sudo apt-get install espeak
12 | sudo apt-get install pulseaudio
13 | sudo apt-get install alza
14 | sudo apt-get install alsa-mixer #audio enablment
15 | sudo apt install sox # to enable fallback if application, run as systemd service fails to play directly form jdk
16 | # maybe also ad duser to audio and other groups?
17 |
18 | sudo apt install openjdk-8-jdk
19 | sudo apt install xinput #rotation depndence
20 | sudo apt install espeak
21 | sudo apt install florence #buggy
22 | sudo apt install dconf-gsettings-backend #onboard depndence
23 | sudo apt install dconf-gsettings-backend #onboard depndence
24 | sudo apt install dconf-tools #onboard depndence
25 | sudo apt install dconf-editor #onboard depndence
26 | sudo apt install dbus-x11 #onboard depndence
27 |
28 | NOPE!: sudo usermod -aG dialout app
29 | NOPE!: sudo usermod -aG uucp app
30 | NOPE!: sudo su: echo -n pass | sha256sum > /etc/FBB.auth
31 |
32 | .fluxbox/init: session.screen0.workspaces: 1
33 | /etc/lightdm/lightdm.conf: autologin-user=app
34 | in raspi-config add cs_CZ locale
35 |
36 | sudo vim /boot/cmdline.txt to add consoleblank=0 to prevent screen dimm
37 |
38 | usermod -s //usr/sbin/nologin app
39 |
40 | # add user to run the app - it is different user then the one logged into system
41 | useradd app-data
42 | mkdir /home/app-data
43 | chown app-data:app-data /home/app-data
44 |
45 | # undo:
46 | #sudo usermod -aG dialout app
47 | #sudo usermod -aG uucp app
48 | #sudo su: echo -n pass | sha256sum > /etc/FBB.auth
49 | deluser app dialout
50 | deluser app uucp
51 | rm /etc/FBB.auth
52 | # use as app-data
53 | echo -n pass | sha256sum > /home/app-data/.config/FlashBoard/FFB.auth # as here it do not need to be world readable
54 | chmod 600 /home/app-data/.config/FlashBoard/FFB.auth
55 |
56 | sudo usermod -aG dialout app-data
57 | sudo usermod -aG uucp app-data
58 |
59 | uucp:x:10:app,app-data
60 | dialout:x:20:pi,app,app-data
61 | audio:x:29:pi,pulse,app,app-data
62 | video:x:44:pi,app,app-data
63 | users:x:100:pi,app,app-data
64 | input:x:105:pi,app,app-data
65 | netdev:x:109:pi,app,app-data
66 | spi:x:999:pi,app,app-data
67 | i2c:x:998:pi,app,app-data
68 | gpio:x:997:pi,app,app-data
69 | app:x:1004:
70 | app-data:x:1005:
71 |
72 | # at the end...
73 | # usermod -s //usr/sbin/nologin app-data
74 | # usermod -s //usr/sbin/nologin app
75 | usermod -s /bin/bash app-data
76 | usermod -s /bin/bash app
77 |
78 | sudo apt install arduino # to get autoupdate for hw too
79 |
80 |
81 | # tune onboard to not mess with system
82 | #keyboard->advanced->long press action == key repeat
83 | #keyboard->advanced->touch inmpu == single touch ##ps do not set this to none!!! wills top to work on touchscreen! How did they did it?
84 |
85 | # making dconf read only led to reseting onboard aprox every three seconds :(
86 | # -r--r--r-- 1 jvanek mock 32906 Dec 16 16:57 ~/.config/dconf/user
87 | # dr-sr-sr-x. 2 jvanek mock 4096 Dec 16 16:57 ~/.config/dconf/
88 |
89 | #so better to use the services, with timing aroun 10 minutes, or desktop icon
90 |
91 | #--------last image
92 |
93 | apt install x11vnc
94 | #? apt remove x11vnc
95 | su app
96 | x11app
97 | vncviewer freeboard.local:0 SecurityTypes=None
98 |
99 | # usbmount pkg is broken on rpi3
100 | apt install usbmount # to fetch deps
101 | # based on https://www.linuxuprising.com/2019/04/automatically-mount-usb-drives-on.html
102 | sudo apt install git
103 | git clone https://github.com/rbrito/usbmount
104 | sudo apt install debhelper build-essential
105 | cd usbmount
106 | dpkg-buildpackage -us -uc -b
107 | apt install ./*usbmount*.deb
108 | # https://raspberrypi.stackexchange.com/questions/100312/raspberry-4-usbmount-not-working
109 | vim /lib/systemd/system/systemd-udevd.service
110 | change:
111 | PrivateMounts=yes
112 | to
113 | PrivateMounts=no
114 |
115 |
116 | # no X afer raspbian update? Set manually resolution via raspi-config
117 | usermod -s //usr/sbin/nologin app-data
118 | usermod -s //usr/sbin/nologin app
119 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/Translator.java:
--------------------------------------------------------------------------------
1 | package org.fbb.board;
2 |
3 | import java.text.MessageFormat;
4 | import java.util.Locale;
5 | import java.util.MissingResourceException;
6 | import java.util.ResourceBundle;
7 | import org.fbb.board.internals.GuiLogHelper;
8 |
9 | /**
10 | * Utility class to provide simple methods to help localize messages
11 | */
12 | public class Translator {
13 |
14 | public String getLocale() {
15 | String s = this.resources.getLocale().toString();
16 | //GuiLogHelper.guiLogger.logo(s);
17 | return s;
18 | }
19 |
20 | private void reload(String locale) {
21 | try {
22 | if (locale == null || locale.trim().isEmpty()) {
23 | resources = ResourceBundle.getBundle(defaultBundle);
24 | } else {
25 | resources = ResourceBundle.getBundle(defaultBundle, new Locale(locale));
26 | }
27 | } catch (Exception ex) {
28 | throw new IllegalStateException("No bundles found for Locale: " + Locale.getDefault().toString()
29 | + "and missing base resource bundle in jar:\\" + defaultBundle + "/Messages.properties");
30 | }
31 | }
32 |
33 | private static class TranslatorHolder {
34 |
35 | //https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
36 | //https://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
37 | private static final Translator INSTANCE = new Translator();
38 |
39 | private static Translator getTransaltor() {
40 | return TranslatorHolder.INSTANCE;
41 | }
42 | }
43 |
44 | /**
45 | * the localized resource strings
46 | */
47 | private ResourceBundle resources;
48 | private static final String defaultBundle = "org.fbb.board.locales.bundles.Messages";
49 |
50 | Translator() {
51 | this(defaultBundle);
52 | }
53 |
54 | Translator(String s) {
55 | try {
56 | resources = ResourceBundle.getBundle(s);
57 | this.reload(getLocale());
58 | } catch (Exception ex) {
59 | GuiLogHelper.guiLogger.loge(ex);
60 | throw new IllegalStateException("No bundles found for Locale: " + Locale.getDefault().toString()
61 | + "and missing base resource bundle in jar:\\" + s + "/Messages.properties");
62 | }
63 | }
64 |
65 | public static Translator getInstance() {
66 | return TranslatorHolder.getTransaltor();
67 | }
68 |
69 | public static void load(String locale) {
70 | TranslatorHolder.getTransaltor().reload(locale);
71 | }
72 |
73 | /**
74 | * Return a translated (localized) version of the message
75 | *
76 | * @param message the message to translate
77 | * @return a string representing the localized message
78 | */
79 | public static String R(String message) {
80 | return R(message, new Object[0]);
81 | }
82 |
83 | /**
84 | * @param message key to be found in properties
85 | * @param params params to be expanded to message
86 | * @return the localized string for the message
87 | */
88 | public static String R(String message, Object... params) {
89 | return getInstance().getMessage(message, params);
90 | }
91 |
92 | /**
93 | * @return the localized resource string using the specified arguments.
94 | * @param key key to be found in properties
95 | * @param args params to be expanded to message
96 | */
97 | protected String getMessage(String key, Object... args) {
98 | return MessageFormat.format(getMessage(key), args);
99 | }
100 |
101 | /**
102 | * Returns the localized resource string identified by the specified key. If
103 | * the message is empty, a null is returned.
104 | */
105 | private String getMessage(String key) {
106 | try {
107 | String result = resources.getString(key);
108 | if (result.length() == 0) {
109 | return "";
110 | } else {
111 | return result;
112 | }
113 | } catch (NullPointerException e) {
114 | return getMessage("RNoResource", new Object[]{key});
115 | } catch (MissingResourceException e) {
116 | return multiCatchTool(key);
117 | } catch (ClassCastException ee) {
118 | return multiCatchTool(key);
119 | }
120 | }
121 |
122 | private String multiCatchTool(String key) {
123 | if ("RNoResource".equals(key)) {
124 | return "No localized text found";
125 | } else {
126 | return getMessage("RNoResource", new Object[]{key});
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/awtimpl/WinUtils.java:
--------------------------------------------------------------------------------
1 | package org.fbb.board.desktop.gui.awtimpl;
2 |
3 | import org.fbb.board.desktop.gui.*;
4 | import java.awt.Rectangle;
5 | import java.awt.Toolkit;
6 | import java.awt.Window;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 | import java.awt.image.BufferedImage;
10 | import java.net.URL;
11 | import javax.swing.JDialog;
12 | import javax.swing.JEditorPane;
13 | import javax.swing.JFrame;
14 | import javax.swing.JOptionPane;
15 | import org.fbb.board.Translator;
16 | import org.fbb.board.desktop.ScreenFinder;
17 | import org.fbb.board.internals.GlobalSettings;
18 | import org.fbb.board.internals.GuiLogHelper;
19 |
20 | /**
21 | *
22 | * @author jvanek
23 | */
24 | public class WinUtils {
25 |
26 | public static double getIdealWindowSizw(BufferedImage bis) {
27 | Rectangle size = ScreenFinder.getCurrentScreenSizeWithoutBounds();
28 | double dw = (double) size.width / (double) bis.getWidth();
29 | double dh = (double) size.height / (double) bis.getHeight();
30 | double ratio = Math.min(dw, dh);
31 | ratio = ratio * MainWindow.gs.getRatio();
32 | return ratio;
33 | }
34 |
35 | public static void setIdealWindowLocation(Window w) {
36 | GlobalSettings gs = MainWindow.gs;
37 | int he = gs.getHardcodedEdge();
38 | if (gs.getLocation().equalsIgnoreCase("TR")) {
39 | w.setLocation(
40 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth() - he),
41 | (int) (he));
42 | } else if (gs.getLocation().equalsIgnoreCase("TL")) {
43 | w.setLocation(
44 | (int) (he),
45 | (int) (he));
46 | } else if (gs.getLocation().equalsIgnoreCase("BR")) {
47 | w.setLocation(
48 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth() - he),
49 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) - he);
50 | } else if (gs.getLocation().equalsIgnoreCase("BL")) {
51 | w.setLocation(
52 | (int) (he),
53 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) - he);
54 |
55 | } else if (gs.getLocation().equalsIgnoreCase("T")) {
56 | w.setLocation(
57 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth()) / 2,
58 | (int) (he));
59 | } else if (gs.getLocation().equalsIgnoreCase("B")) {
60 | w.setLocation(
61 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth()) / 2,
62 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) - he);
63 | } else if (gs.getLocation().equalsIgnoreCase("R")) {
64 | w.setLocation(
65 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth() - he),
66 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) / 2);
67 | } else if (gs.getLocation().equalsIgnoreCase("L")) {
68 | w.setLocation(
69 | (int) (he),
70 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) / 2);
71 | } else {
72 | w.setLocation(
73 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - w.getWidth()) / 2,
74 | (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - w.getHeight()) / 2);
75 | }
76 | }
77 |
78 | public static String addCtrLine(String string) {
79 | return "" + string + "
" + Translator.R("tryCtrl");
80 | }
81 |
82 | public static class ShowWebHelp implements ActionListener {
83 |
84 | @Override
85 | public void actionPerformed(ActionEvent ae) {
86 | try {
87 | JDialog jd = new JDialog();
88 | jd.setModal(true);
89 | jd.setSize(ScreenFinder.getCurrentScreenSizeWithoutBounds().getSize());
90 | JEditorPane text = new JEditorPane(new URL("https://raw.githubusercontent.com/judovana/FlashFreeBoardDesktop/master/README.md"));
91 | jd.add(text);
92 | jd.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
93 | jd.setVisible(true);
94 | } catch (Exception ex) {
95 | GuiLogHelper.guiLogger.loge(ex);
96 | JOptionPane.showMessageDialog(null, ex);
97 | }
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/LogView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.GridLayout;
10 | import java.awt.HeadlessException;
11 | import java.awt.event.ActionEvent;
12 | import java.awt.event.ActionListener;
13 | import java.awt.event.WindowAdapter;
14 | import java.awt.event.WindowEvent;
15 | import javax.swing.JButton;
16 | import javax.swing.JCheckBox;
17 | import javax.swing.JDialog;
18 | import javax.swing.JFrame;
19 | import javax.swing.JPanel;
20 | import javax.swing.JScrollPane;
21 | import javax.swing.JSplitPane;
22 | import javax.swing.JTextArea;
23 | import org.fbb.board.internals.db.DB;
24 | import org.fbb.board.internals.GuiLogHelper;
25 |
26 | /**
27 | *
28 | * @author jvanek
29 | */
30 | public class LogView extends JDialog {
31 |
32 | private final DB db;
33 |
34 | private class Autorefrsh extends Thread {
35 |
36 | private boolean alive = true;
37 | private final JTextArea o;
38 | private final JTextArea e;
39 | private final JCheckBox r;
40 |
41 | private Autorefrsh(JTextArea o, JTextArea e, JCheckBox r) {
42 | this.o = o;
43 | this.e = e;
44 | this.r = r;
45 | }
46 |
47 | @Override
48 | public void run() {
49 | while (alive) {
50 | try {
51 | if (r.isSelected()) {
52 | e.setText(GuiLogHelper.guiLogger.getSerr());
53 | e.setCaretPosition(e.getDocument().getLength());
54 | o.setText(GuiLogHelper.guiLogger.getSout());
55 | o.setCaretPosition(o.getDocument().getLength());
56 | }
57 | Thread.sleep(500);
58 | } catch (Exception ex) {
59 | GuiLogHelper.guiLogger.loge(ex);
60 | }
61 | }
62 | }
63 |
64 | }
65 |
66 | public LogView(DB ddb) throws HeadlessException {
67 | this(ddb, false);
68 | }
69 | public LogView(DB ddb, boolean modal) throws HeadlessException {
70 | this.db = ddb;
71 | this.setModal(modal);
72 | this.setLayout(new BorderLayout());
73 | JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
74 | JTextArea e = new JTextArea();
75 | e.setText(GuiLogHelper.guiLogger.getSerr());
76 | JTextArea o = new JTextArea();
77 | o.setText(GuiLogHelper.guiLogger.getSout());
78 | split.add(new JScrollPane(o));
79 | split.add(new JScrollPane(e));
80 | this.add(split);
81 | JPanel tools = new JPanel(new GridLayout(1, 3));
82 | JButton or = new JButton("refresh");
83 | or.addActionListener(new ActionListener() {
84 |
85 | @Override
86 | public void actionPerformed(ActionEvent x) {
87 | o.setText(GuiLogHelper.guiLogger.getSout());
88 | }
89 | });
90 | tools.add(or);
91 | final JCheckBox autor = new JCheckBox("autorefresh", true);
92 | tools.add(autor);
93 | JButton log = new JButton("db log");
94 | tools.add(log);
95 | log.addActionListener(new ActionListener() {
96 |
97 | @Override
98 | public void actionPerformed(ActionEvent e) {
99 | autor.setSelected(false);
100 | o.setText(o.getText() + "\n" + db.logCatched());
101 | }
102 | });
103 | JButton er = new JButton("refresh");
104 | er.addActionListener(new ActionListener() {
105 |
106 | @Override
107 | public void actionPerformed(ActionEvent x) {
108 | e.setText(GuiLogHelper.guiLogger.getSerr());
109 | }
110 | });
111 | tools.add(er);
112 | this.add(tools, BorderLayout.SOUTH);
113 | this.pack();
114 | split.setDividerLocation(400);
115 | this.setSize(800, 800);
116 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
117 | final Autorefrsh autorefresh = new Autorefrsh(o, e, autor);
118 | this.addWindowListener(new WindowAdapter() {
119 |
120 | @Override
121 | public void windowClosed(WindowEvent e) {
122 | try {
123 | super.windowClosed(e);
124 | } finally {
125 | autorefresh.alive = false;
126 | }
127 |
128 | }
129 |
130 | });
131 | autorefresh.start();
132 |
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/Authenticator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui;
7 |
8 | import java.awt.GridLayout;
9 | import java.nio.charset.StandardCharsets;
10 | import java.security.MessageDigest;
11 | import java.security.NoSuchAlgorithmException;
12 | import javax.swing.JCheckBox;
13 | import javax.swing.JLabel;
14 | import javax.swing.JOptionPane;
15 | import javax.swing.JPanel;
16 | import javax.swing.JPasswordField;
17 | import org.fbb.board.Translator;
18 | import org.fbb.board.desktop.Files;
19 |
20 | /**
21 | *
22 | * @author jvanek
23 | */
24 | public class Authenticator {
25 |
26 | private boolean pernament = false;
27 | public static final Authenticator auth = new Authenticator();
28 |
29 | public boolean isPernament() {
30 | return pernament || Files.getAuthFileHash() == null;
31 | }
32 |
33 | public void authenticate(String message) throws AuthoriseException {
34 | try {
35 | if (!authenticateImpl(message)) {
36 | throw new AuthoriseException();
37 | }
38 | } catch (Exception ex) {
39 | throw new AuthoriseException(ex);
40 | }
41 | }
42 |
43 | private boolean authenticateImpl(String message) throws NoSuchAlgorithmException {
44 | String hash = Files.getAuthFileHash();
45 | if (hash == null) {
46 | //warning security by obscurity!
47 | //if the file do not exists, app is not "secured" at all
48 | //note, that all the config files are plain an readable in ~/.config anyway
49 | //to secure them, encrypt them with locekd pass
50 | //if app is run as limited user, then the security should be ok
51 | return true;
52 | }
53 | if (pernament) {
54 | return true;
55 | }
56 | Object[] r = new AuthoriseDialog().show(message);
57 | if (r == null || r.length != 2) {
58 | return false;
59 | }
60 | String s = new String((char[]) (r[0]));
61 | if (s == null || s.trim().isEmpty()) {
62 | return false;
63 | }
64 |
65 | MessageDigest md = MessageDigest.getInstance("SHA-256");
66 | md.update(s.getBytes(StandardCharsets.UTF_8));
67 | byte[] passHash = md.digest();
68 | //to nice (correct) string
69 | StringBuilder sb = new StringBuilder();
70 | for (byte b : passHash) {
71 | sb.append(String.format("%02x", b));
72 | }
73 | if (hash.equals(sb.toString())) {
74 | if ((boolean) r[1]) {
75 | pernament = true;
76 | }
77 | return true;
78 | }
79 | return false;
80 | }
81 |
82 | public void revoke() {
83 | pernament = false;
84 | }
85 |
86 | public String[] getStatus() {
87 | if (Files.getAuthFileHash() == null) {
88 | return new String[]{
89 | Translator.R("secNone"),
90 | "use `su " + System.getProperty("user.name") + "; echo -n your_pass | sha256sum > " + Files.localAuth,
91 | " or `su ; echo -n your_pass | sha256sum > " + Files.masterAuth+ " && chmod 600 it"};
92 | }
93 | if (isPernament()) {
94 | return new String[]{
95 | Translator.R("secUnlocked"),
96 | "To lock, again, use: ",
97 | Translator.R("revokePP")};
98 | }
99 | return new String[]{Translator.R("secOk"), "", ""};
100 | }
101 |
102 | private static class AuthoriseDialog {
103 |
104 | public static Object[] show(String message) {
105 | JPasswordField pass = new JPasswordField(5);
106 | JCheckBox save = new JCheckBox(Translator.R("keepLoged"), false);
107 |
108 | JPanel myPanel = new JPanel(new GridLayout(3, 1));
109 | myPanel.add(new JLabel(message));
110 | myPanel.add(pass);
111 | myPanel.add(save);
112 | int result = JOptionPane.showConfirmDialog(null, myPanel, Translator.R("autenticate"), JOptionPane.OK_CANCEL_OPTION);
113 | if (result == JOptionPane.OK_OPTION) {
114 | return new Object[]{pass.getPassword(), save.isSelected()};
115 | }
116 | return null;
117 | }
118 | }
119 |
120 | public static class AuthoriseException extends Exception {
121 |
122 | public AuthoriseException(String s) {
123 | super(s);
124 | }
125 |
126 | public AuthoriseException() {
127 | this(Translator.R("authFail"));
128 | }
129 |
130 | private AuthoriseException(Exception ex) {
131 | super(ex);
132 | }
133 |
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/ScreenFinder.java:
--------------------------------------------------------------------------------
1 | /* ScreenFinder.java
2 | Copyright (C) 2012 Red Hat, Inc.
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2, or (at your option)
9 | any later version.
10 |
11 | IcedTea is distributed in the hope that it will be useful, but
12 | WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with IcedTea; see the file COPYING. If not, write to the
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 | 02110-1301 USA.
20 |
21 | Linking this library statically or dynamically with other modules is
22 | making a combined work based on this library. Thus, the terms and
23 | conditions of the GNU General Public License cover the whole
24 | combination.
25 |
26 | As a special exception, the copyright holders of this library give you
27 | permission to link this library with independent modules to produce an
28 | executable, regardless of the license terms of these independent
29 | modules, and to copy and distribute the resulting executable under
30 | terms of your choice, provided that you also meet, for each linked
31 | independent module, the terms and conditions of the license of that
32 | module. An independent module is a module which is not derived from
33 | or based on this library. If you modify this library, you may extend
34 | this exception to your version of the library, but you are not
35 | obligated to do so. If you do not wish to do so, delete this
36 | exception statement from your version. */
37 | package org.fbb.board.desktop;
38 |
39 | import java.awt.GraphicsConfiguration;
40 | import java.awt.GraphicsDevice;
41 | import java.awt.GraphicsEnvironment;
42 | import java.awt.HeadlessException;
43 | import java.awt.Insets;
44 | import java.awt.MouseInfo;
45 | import java.awt.Point;
46 | import java.awt.Rectangle;
47 | import java.awt.Toolkit;
48 | import java.awt.Window;
49 | import org.fbb.board.internals.GuiLogHelper;
50 |
51 | public class ScreenFinder {
52 |
53 | public static GraphicsDevice getCurrentScreen() {
54 | Point p = MouseInfo.getPointerInfo().getLocation();
55 | return getScreenOnCoords(p);
56 |
57 | }
58 |
59 | public static Rectangle getCurrentScreenSizeWithoutBounds() {
60 | try {
61 | Point p = MouseInfo.getPointerInfo().getLocation();
62 | return getScreenOnCoordsWithoutBounds(p);
63 | } catch (HeadlessException ex) {
64 | GuiLogHelper.guiLogger.loge(ex);
65 | return new Rectangle(800, 600);
66 | }
67 |
68 | }
69 |
70 | public static void centerWindowsToCurrentScreen(Window w) {
71 | Rectangle bounds = getCurrentScreenSizeWithoutBounds();
72 | w.setLocation(bounds.x + (bounds.width - w.getWidth()) / 2,
73 | bounds.y + (bounds.height - w.getHeight()) / 2);
74 |
75 | }
76 |
77 | public static GraphicsDevice getScreenOnCoords(Point point) {
78 | GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
79 | GraphicsDevice[] devices = e.getScreenDevices();
80 | GraphicsDevice result = null;
81 | //now get the configuration(s) for each device
82 | for (GraphicsDevice device : devices) {
83 | //GraphicsConfiguration[] configurations = device.getConfigurations();
84 | //or?
85 | GraphicsConfiguration[] configurations = new GraphicsConfiguration[]{device.getDefaultConfiguration()};
86 | for (GraphicsConfiguration config : configurations) {
87 | Rectangle gcBounds = config.getBounds();
88 | if (gcBounds.contains(point)) {
89 | result = device;
90 | }
91 | }
92 | }
93 | if (result == null) {
94 | //not found, get the default display
95 | result = e.getDefaultScreenDevice();
96 | }
97 | return result;
98 | }
99 |
100 | public static Rectangle getScreenOnCoordsWithoutBounds(Point p) {
101 | try {
102 | GraphicsDevice device = getScreenOnCoords(p);
103 | Rectangle screenSize = device.getDefaultConfiguration().getBounds();
104 | Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(device.getDefaultConfiguration());
105 | return new Rectangle((int) screenSize.getX() + insets.left, (int) screenSize.getY() + insets.top, (int) screenSize.getWidth() - insets.left, (int) screenSize.getHeight() - insets.bottom);
106 | } catch (HeadlessException | IllegalArgumentException ex) {
107 | GuiLogHelper.guiLogger.loge(ex);
108 | return new Rectangle(800, 600);
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/SlowBoulder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs;
7 |
8 | import org.fbb.board.Translator;
9 | import org.fbb.board.desktop.gui.awtimpl.MainWindowImpl;
10 | import org.fbb.board.desktop.gui.dialogs.parts.DefaultSnoozeAction;
11 | import org.fbb.board.desktop.gui.dialogs.parts.TimeAndSnooze;
12 | import org.fbb.board.internals.GuiLogHelper;
13 | import org.fbb.board.internals.grid.Boulder;
14 | import org.fbb.board.internals.grid.GridPane;
15 |
16 | import javax.swing.*;
17 | import java.awt.*;
18 | import java.awt.event.WindowAdapter;
19 | import java.awt.event.WindowEvent;
20 |
21 | /**
22 | * @author jvanek
23 | */
24 | public class SlowBoulder extends JDialog implements Runnable {
25 |
26 | private final GridPane gp;
27 | private final TimeAndSnooze tas;
28 | private final MainWindowImpl boulders;
29 |
30 | public SlowBoulder(MainWindowImpl parent, GridPane gp) {
31 | super(parent);
32 | this.boulders = parent;
33 | this.gp = gp;
34 | this.setTitle(Translator.R("slowBoulder"));
35 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
36 | this.setModalityType(ModalityType.DOCUMENT_MODAL);
37 | this.setSize(500, 400);
38 | this.setLocationRelativeTo(parent);
39 | this.add(new JTextField(Translator.R("slowBoulderHelp")), BorderLayout.SOUTH);
40 | JPanel panel = new JPanel();
41 | this.add(panel);
42 | panel.setLayout(new GridLayout(5, 2));
43 | tas = new TimeAndSnooze(panel, new DefaultSnoozeAction(gp), new Runnable() {
44 | @Override
45 | public void run() {
46 | SlowBoulder.this.reset();
47 | }
48 | }, this);
49 | tas.doAsOnChange();
50 | this.pack();
51 | this.setSize(this.getWidth(), 350);
52 | this.setLocationRelativeTo(parent);
53 | this.addWindowListener(new WindowAdapter() {
54 |
55 | @Override
56 | public void windowClosed(WindowEvent e) {
57 | tas.stop();
58 | }
59 |
60 | });
61 | tas.start();
62 | }
63 |
64 | private Boulder currentBoulder;
65 | int finalBlinks = -6;
66 | volatile int row = finalBlinks;
67 | int[] currentBoulderGrid;
68 |
69 | @Override
70 | public void run() {
71 | try {
72 | if (row <= finalBlinks) {
73 | reset();
74 | }
75 | row--;
76 | int[] r = findRow();
77 | if (r == null) {
78 | if (row % 2 == 0) {
79 | gp.getGrid().clean();
80 | } else {
81 | gp.getGrid().setBouler(currentBoulder);
82 | }
83 | } else {
84 | for (int x = 0; x < r.length; x++) {
85 | gp.getGrid().set(x, row, (byte) r[x]);
86 | }
87 | }
88 | gp.repaintAndSendToKnown();
89 | } catch (Exception ex) {
90 | GuiLogHelper.guiLogger.loge(ex);
91 | JOptionPane.showMessageDialog(SlowBoulder.this, ex);
92 | }
93 | }
94 |
95 | private int[] findRow() {
96 | int[] currentRow = new int[gp.getGrid().getWidth()];
97 | for (int x = 0; x < currentRow.length; x++) {
98 | currentRow[x] = 0;
99 | }
100 | while (true) {
101 | if (row < 0) {
102 | return null;
103 | }
104 | for (int x = row; x < currentBoulderGrid.length; x += gp.getGrid().getHeight()) {
105 | currentRow[x / gp.getGrid().getHeight()] = currentBoulderGrid[x];
106 | }
107 | if (isEmpty(currentRow)) {
108 | row--;
109 | } else {
110 | return currentRow;
111 | }
112 | }
113 |
114 | }
115 |
116 | private boolean isEmpty(int[] currentRow) {
117 | for (int x = 0; x < currentRow.length; x++) {
118 | if (currentRow[x] != 0) {
119 | return false;
120 | }
121 | }
122 | return true;
123 | }
124 |
125 |
126 | private void reset() {
127 | gp.getGrid().clean();
128 | currentBoulder = boulders.list.getRandom();
129 | currentBoulderGrid = new int[gp.getGrid().getWidth() * gp.getGrid().getHeight()];
130 | for (int x = 0; x < currentBoulderGrid.length; x++) {
131 | currentBoulderGrid[x] = 0;
132 | }
133 | currentBoulder.apply(currentBoulderGrid, gp.getGrid().getHeight());
134 | boulders.setNameTextAndGrade(boulders.name, currentBoulder);
135 | boulders.hm.addToBoulderHistory(currentBoulder);
136 | boulders.next.setEnabled(boulders.hm.canFwd());
137 | boulders.previous.setEnabled(boulders.hm.canBack());
138 | row = gp.getGrid().getHeight();
139 | }
140 |
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | org.judovana.flash
5 | FlashFreeBoardDesktop
6 | jar
7 | 1.9-SNAPSHOT
8 | FlashFreeBoardDesktop
9 | http://maven.apache.org
10 |
11 | 1.8
12 | UTF-8
13 | ${basedir}/../
14 | org.fbb.board.desktop.gui.MainWindow
15 |
16 |
17 |
18 | junit
19 | junit
20 | 4.13.1
21 | test
22 |
23 |
24 |
25 | commons-cli
26 | commons-cli
27 | 1.4
28 |
29 |
30 | net.sf.bluecove
31 | bluecove
32 | 2.1.0
33 |
34 |
35 | net.sf.bluecove
36 | bluecove-gpl
37 | 2.1.0
38 |
39 |
40 | com.fazecast
41 | jSerialComm
42 | 2.4.1
43 |
44 |
45 | org.eclipse.jgit
46 | org.eclipse.jgit
47 | 6.10.1.202505221210-r
48 |
49 |
50 | commons-io
51 | commons-io
52 | 2.14.0
53 |
54 |
55 | org.apache.commons
56 | commons-lang3
57 | 3.18.0
58 |
59 |
60 | org.jasypt
61 | jasypt
62 | 1.9.2
63 |
64 |
65 |
66 | com.github.lgooddatepicker
67 | LGoodDatePicker
68 | 10.3.1
69 |
70 |
71 | com.fifesoft
72 | rsyntaxtextarea
73 | 3.0.4
74 |
75 |
76 | org.jfree
77 | jfreechart
78 | 1.5.0
79 |
80 |
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-compiler-plugin
86 | 3.8.0
87 |
88 | ${jdk.version}
89 | ${jdk.version}
90 |
91 |
92 |
93 | org.apache.maven.plugins
94 | maven-jar-plugin
95 |
96 |
97 |
98 | ${freeboard.desktop.main.class}
99 |
100 |
101 |
102 |
103 |
104 | maven-assembly-plugin
105 | 2.6
106 |
107 |
108 | install
109 |
110 | single
111 |
112 |
113 |
114 | jar-with-dependencies
115 |
116 |
117 |
118 | ${freeboard.desktop.main.class}
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/grades/Grade.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.grades;
7 |
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.Objects;
15 | import java.util.Properties;
16 | import java.util.Vector;
17 | import java.util.regex.Matcher;
18 | import java.util.regex.Pattern;
19 | import org.fbb.board.Translator;
20 |
21 | /**
22 | *
23 | * @author jvanek
24 | */
25 | public class Grade implements Comparable {
26 |
27 | private static String[] columns;
28 | private static final List valuesPerGrade = new ArrayList<>(100);
29 | private static final Map> valuesPerColumn = new HashMap<>();
30 |
31 | //to be used by combobox
32 | public static Vector currentGrades() {
33 | return nice(new Vector<>(valuesPerColumn.get(usedGrades)));
34 | }
35 |
36 | public static void loadConversiontable() throws IOException {
37 | InputStream s = Grade.class.getResourceAsStream("tabulka");
38 | Properties p = new Properties();
39 | p.load(s);
40 | //<0 == random
41 | //>=0 grades
42 | columns = parseLine(p, "id");
43 | for (int i = 0; i < columns.length; i++) {
44 | String column = columns[i];
45 | valuesPerColumn.put(column, new ArrayList<>(100));
46 | }
47 | int x = -1;
48 | while (true) {
49 | x++;
50 | String[] stringsForX = parseLine(p, x + "");
51 | if (stringsForX == null) {
52 | break;
53 | }
54 | valuesPerGrade.add(stringsForX);
55 | for (int i = 0; i < columns.length; i++) {
56 | String column = columns[i];
57 | valuesPerColumn.get(column).add(valuesPerGrade.get(x)[i]);
58 | }
59 | }
60 | }
61 |
62 | private static String[] parseLine(Properties p, String id) {
63 | if (p.getProperty(id) == null) {
64 | return null;
65 | }
66 | String line = p.getProperty(id).trim();
67 | return line.split("\\s+");
68 | }
69 |
70 | private static final int RANDOM = -1;
71 | public static String usedGrades = "fountainbleu";
72 | private final int artificialValue;
73 |
74 | public static Grade RandomBoulder() {
75 | return new Grade(RANDOM);
76 | }
77 |
78 | public boolean isRandom() {
79 | return artificialValue < 0;
80 | }
81 |
82 | public Grade(String artificialValue) {
83 | this(Integer.valueOf(artificialValue));
84 | }
85 |
86 | public Grade(int artificialValue) {
87 | this.artificialValue = artificialValue;
88 | }
89 |
90 | public String toAllValues(String delimiter) {
91 | if (artificialValue <= RANDOM) {
92 | return Translator.R("RandomUnknown") + delimiter;
93 | }
94 | StringBuilder sbs = new StringBuilder();
95 | for (int i = 0; i < columns.length; i++) {
96 | String column = columns[i];
97 | sbs.append(column).append(": ").append(getValuePerGrade(i)).append(delimiter);
98 | }
99 | return sbs.toString();
100 | }
101 |
102 | private String getValuePerGrade(int i) {
103 | return nice(valuesPerGrade.get(artificialValue)[i]);
104 | }
105 |
106 | private String getValuesPerColumn() {
107 | return nice(valuesPerColumn.get(usedGrades).get(artificialValue));
108 | }
109 |
110 | @Override
111 | public String toString() {
112 | if (artificialValue <= RANDOM) {
113 | return Translator.R("RandomUnknown");
114 | }
115 | return getValuesPerColumn();
116 | }
117 |
118 | public int toNumber() {
119 | return artificialValue;
120 | }
121 |
122 | @Override
123 | public int hashCode() {
124 | return artificialValue;
125 | }
126 |
127 | @Override
128 | public boolean equals(Object obj) {
129 | return Objects.equals(((Grade) obj).toNumber(), toNumber());
130 | }
131 |
132 | public static String getStandardTooltip(int i) {
133 | return "" + new Grade(i).toAllValues("
") + "";
134 | }
135 |
136 | public static int getMinGrade() {
137 | return 0;
138 | }
139 |
140 | public static int getMaxGrade() {
141 | return valuesPerGrade.size() - 1;
142 | }
143 |
144 | private static String nice(String get) {
145 | return get.replace('_', ' ');
146 | }
147 |
148 | public String shorten() {
149 | return this.toString().replaceAll("fb\\s*", "");
150 | }
151 |
152 | private static Vector nice(Vector orig) {
153 | for (int i = 0; i < orig.size(); i++) {
154 | String get = orig.get(i);
155 | orig.set(i, nice(get));
156 |
157 | }
158 | return orig;
159 | }
160 |
161 | @Override
162 | public int compareTo(Grade t) {
163 | return t.artificialValue - this.artificialValue;
164 | }
165 |
166 | public static class ToStringGradeWrapper extends Grade {
167 |
168 | public ToStringGradeWrapper(int i) {
169 | super(i);
170 | }
171 |
172 | Pattern p = Pattern.compile(".* ");
173 |
174 | @Override
175 | public String toString() {
176 | return p.matcher(super.toString()).replaceAll("");
177 | }
178 |
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/BoulderCalc.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import javax.swing.JSpinner;
9 | import javax.swing.JTextField;
10 | import javax.swing.event.ChangeEvent;
11 | import javax.swing.event.DocumentEvent;
12 | import javax.swing.event.DocumentListener;
13 | import org.fbb.board.internals.GuiLogHelper;
14 |
15 | /**
16 | *
17 | * @author jvanek
18 | */
19 | public class BoulderCalc {
20 |
21 | private final JTextField timeOfBoulder;
22 | private final JTextField timeOfTraining;
23 | private final JSpinner numBoulders;
24 | private boolean active = true;
25 |
26 | private void setActive(boolean active) {
27 | this.active = active;
28 | }
29 |
30 | public BoulderCalc(JTextField timeOfBoulder, JTextField timeOfTraining, JSpinner numBoulders) {
31 | this.timeOfBoulder = timeOfBoulder;
32 | this.timeOfTraining = timeOfTraining;
33 | this.numBoulders = numBoulders;
34 |
35 | numBoulders.addChangeListener((ChangeEvent e) -> {
36 | numOfBouldersChanged();
37 | });
38 |
39 | timeOfBoulder.getDocument().addDocumentListener(new DocumentListener() {
40 |
41 | @Override
42 | public void insertUpdate(DocumentEvent e) {
43 | timeOfBouldersChanged();
44 | }
45 |
46 | @Override
47 | public void removeUpdate(DocumentEvent e) {
48 | timeOfBouldersChanged();
49 | }
50 |
51 | @Override
52 | public void changedUpdate(DocumentEvent e) {
53 | timeOfBouldersChanged();
54 | }
55 | });
56 |
57 | timeOfTraining.getDocument().addDocumentListener(new DocumentListener() {
58 |
59 | @Override
60 | public void insertUpdate(DocumentEvent e) {
61 | timeOfTrainingChanged();
62 | }
63 |
64 | @Override
65 | public void removeUpdate(DocumentEvent e) {
66 | timeOfTrainingChanged();
67 | }
68 |
69 | @Override
70 | public void changedUpdate(DocumentEvent e) {
71 | timeOfTrainingChanged();
72 | }
73 | });
74 | }
75 |
76 | private void numOfBouldersChanged() {
77 | if (!active) {
78 | return;
79 | }
80 | active = false;
81 | try {
82 | if (decode(timeOfBoulder.getText()) > 0) {
83 | int nwTimeOfTraining = ((Integer) numBoulders.getValue()) * decode(timeOfBoulder.getText());
84 | timeOfTraining.setText(code(nwTimeOfTraining));
85 | timeOfTraining.repaint();
86 | }
87 | } finally {
88 | active = true;
89 | }
90 | }
91 |
92 | private void timeOfBouldersChanged() {
93 | if (!active) {
94 | return;
95 | }
96 | active = false;
97 | try {
98 | if (decode(timeOfBoulder.getText()) > 0) {
99 | int nwTimeOfTraining = ((Integer) numBoulders.getValue()) * decode(timeOfBoulder.getText());
100 | timeOfTraining.setText(code(nwTimeOfTraining));
101 | timeOfTraining.repaint();
102 | }
103 | } finally {
104 | active = true;
105 | }
106 | }
107 |
108 | private void timeOfTrainingChanged() {
109 | if (!active) {
110 | return;
111 | }
112 | active = false;
113 | try {
114 | int oldTimeOfTrainig = decode(timeOfTraining.getText());
115 | if (oldTimeOfTrainig > 0) {
116 | int oldNumOfBoulders = ((Integer) numBoulders.getValue());
117 | int nwTimeOfBoulder = oldTimeOfTrainig / oldNumOfBoulders;
118 | timeOfBoulder.setText(code(nwTimeOfBoulder));
119 | timeOfBoulder.repaint();
120 | }
121 | } finally {
122 | active = true;
123 | }
124 | }
125 |
126 | public static String code(long seconds) {
127 | return (seconds / 60) + ":" + (seconds % 60);
128 |
129 | }
130 |
131 | public static int decode(String s) {
132 | if (s.trim().isEmpty()) {
133 | return 0;
134 | }
135 | try {
136 | String[] ss = s.trim().split(":");
137 | if (ss.length == 1) {
138 | return Integer.parseInt(ss[0].trim());
139 | }
140 | int miuntes = Integer.parseInt(ss[0].trim());
141 | int secs = Integer.parseInt(ss[1].trim());
142 | return miuntes * 60 + secs;
143 | } catch (Exception ex) {
144 | GuiLogHelper.guiLogger.loge(ex);
145 | //JOptionPane.showMessageDialog(null, Translator.R("parseTimeIssue"));
146 | return -1;
147 | }
148 | }
149 |
150 | public int getTotalTime() {
151 | return decode(timeOfTraining.getText());
152 | }
153 |
154 | public int getTimeOfBoulder() {
155 | return decode(timeOfBoulder.getText());
156 | }
157 |
158 | void setTimeOfBoulder(String text) {
159 | try {
160 | setActive(false);
161 | timeOfBoulder.setText(text);
162 | } finally {
163 | setActive(true);
164 | }
165 | }
166 |
167 | void setTimeOfTraining(String text) {
168 | try {
169 | setActive(false);
170 | timeOfTraining.setText(text);
171 | } finally {
172 | setActive(true);
173 | }
174 | }
175 |
176 | void setNumBoulders(int n) {
177 | try {
178 | setActive(false);
179 | numBoulders.setValue(n);
180 | } finally {
181 | setActive(true);
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/Training.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import java.io.ByteArrayOutputStream;
9 | import java.io.File;
10 | import java.io.FileOutputStream;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.OutputStream;
14 | import java.util.Date;
15 | import java.util.Enumeration;
16 | import java.util.Properties;
17 | import java.util.zip.ZipEntry;
18 | import java.util.zip.ZipFile;
19 | import java.util.zip.ZipOutputStream;
20 | import org.fbb.board.internals.Filter;
21 |
22 | /**
23 | *
24 | * @author jvanek
25 | */
26 | public class Training {
27 |
28 | public static class InnerSettings {
29 |
30 | public final boolean random;
31 | public final boolean regular;
32 | public final boolean jumps;
33 | public final String tOfBoulder;
34 | public final String tOfTraining;
35 | public final int numOfBoulders;
36 |
37 | public InnerSettings(boolean random, boolean regular, boolean jumps, String tOfBoulder, String tOfTraining, int numOfBoulders) {
38 | this.random = random;
39 | this.regular = regular;
40 | this.jumps = jumps;
41 | this.tOfBoulder = tOfBoulder;
42 | this.tOfTraining = tOfTraining;
43 | this.numOfBoulders = numOfBoulders;
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return "random/regular/jumps: " + random + "/" + regular + "/" + jumps + "\n"
49 | + "time per boulder/boulders: " + tOfTraining + "/" + numOfBoulders + "\n"
50 | + "time: " + tOfTraining;
51 | }
52 |
53 | private void save(OutputStream zos) throws IOException {
54 | Properties p = new Properties();
55 | p.setProperty("RANDOM", "" + random);
56 | p.setProperty("REGULAR", "" + regular);
57 | p.setProperty("JUMPS", "" + jumps);
58 | p.setProperty("TIME_TRAIN", tOfTraining);
59 | p.setProperty("TIME_BOULD", tOfBoulder);
60 | p.setProperty("BOULDERS", "" + numOfBoulders);
61 | p.store(zos, "FlashFreeBoard single timered training" + new Date());
62 | }
63 |
64 | private static InnerSettings load(InputStream zos) throws IOException {
65 | Properties p = new Properties();
66 | p.load(zos);
67 | boolean random = Boolean.valueOf(p.getProperty("RANDOM", "true"));
68 | boolean regular = Boolean.valueOf(p.getProperty("REGULAR", "true"));
69 | boolean jumps = Boolean.valueOf(p.getProperty("JUMPS", "true"));
70 | String tOfTraining = p.getProperty("TIME_TRAIN", "5:00");
71 | String tOfBoulder = p.getProperty("TIME_BOULD", "00:20");
72 | int numOfBoulders = Integer.valueOf(p.getProperty("BOULDERS", "15"));
73 | return new InnerSettings(random, regular, jumps, tOfBoulder, tOfTraining, numOfBoulders);
74 | }
75 |
76 | }
77 | public final InnerSettings innerSettings;
78 | public final Filter filter;
79 | public final String currentName;
80 |
81 | @Override
82 | public String toString() {
83 | return filter.toString() + "\n"
84 | + "Start at: " + currentName + "\n"
85 | + innerSettings.toString();
86 |
87 | }
88 |
89 | public Training(boolean random, boolean regular, boolean jumps, String tOfBoulder, String tOfTraining, int numOfBoulders, Filter filter, String currentName) {
90 | this.innerSettings = new InnerSettings(random, regular, jumps, tOfBoulder, tOfTraining, numOfBoulders);
91 | this.filter = filter;
92 | this.currentName = currentName;
93 | }
94 |
95 | private Training(InnerSettings innerSettings, Filter filter, String currentName) {
96 | this.innerSettings = innerSettings;
97 | this.filter = filter;
98 | this.currentName = currentName;
99 | }
100 |
101 | public static Training loadSavedTraining(File f) throws IOException {
102 | ZipFile zipFile = new ZipFile(f);
103 | Enumeration extends ZipEntry> entries = zipFile.entries();
104 | String current = null;
105 | InnerSettings setup = null;
106 | Filter filter = null;
107 | while (entries.hasMoreElements()) {
108 | ZipEntry entry = entries.nextElement();
109 | InputStream stream = zipFile.getInputStream(entry);
110 | if (entry.getName().equals("last.current")) {
111 | ByteArrayOutputStream result = new ByteArrayOutputStream();
112 | byte[] buffer = new byte[1024];
113 | int length;
114 | while ((length = stream.read(buffer)) != -1) {
115 | result.write(buffer, 0, length);
116 | }
117 | current = result.toString("UTF-8");
118 | } else if (entry.getName().equals("setup.prop")) {
119 | setup = InnerSettings.load(stream);
120 | } else if (entry.getName().equals("filter")) {
121 | filter = Filter.load(stream);
122 | }
123 | }
124 | return new Training(setup, filter, current);
125 | }
126 |
127 | public void saveSingleTraining(File out) throws IOException {
128 | ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(out));
129 | zos.putNextEntry(new ZipEntry("filter"));
130 | this.filter.write(zos);
131 | zos.closeEntry();
132 | zos.putNextEntry(new ZipEntry("last.current"));
133 | zos.write(this.currentName.getBytes("utf-8"));
134 | zos.closeEntry();
135 | zos.putNextEntry(new ZipEntry("setup.prop"));
136 | this.innerSettings.save(zos);
137 | zos.closeEntry();
138 | zos.flush();
139 | zos.close();
140 |
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/ContentReader.java:
--------------------------------------------------------------------------------
1 | /* ContentReader.java
2 | Copyright (C) 2011,2012 Red Hat, Inc.
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or
7 | modify it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, version 2.
9 |
10 | IcedTea is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with IcedTea; see the file COPYING. If not, write to
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 | 02110-1301 USA.
19 |
20 | Linking this library statically or dynamically with other modules is
21 | making a combined work based on this library. Thus, the terms and
22 | conditions of the GNU General Public License cover the whole
23 | combination.
24 |
25 | As a special exception, the copyright holders of this library give you
26 | permission to link this library with independent modules to produce an
27 | executable, regardless of the license terms of these independent
28 | modules, and to copy and distribute the resulting executable under
29 | terms of your choice, provided that you also meet, for each linked
30 | independent module, the terms and conditions of the license of that
31 | module. An independent module is a module which is not derived from
32 | or based on this library. If you modify this library, you may extend
33 | this exception to your version of the library, but you are not
34 | obligated to do so. If you do not wish to do so, delete this
35 | exception statement from your version.
36 | */
37 | package org.fbb.board.internals;
38 |
39 | import java.io.IOException;
40 | import java.io.InputStream;
41 | import java.io.InputStreamReader;
42 | import java.io.Reader;
43 | import java.util.ArrayList;
44 | import java.util.List;
45 |
46 | /**
47 | * Class to read content of stdout/stderr of process, and to cooperate with its
48 | * running/terminated/finished statuses.
49 | */
50 | class ContentReader implements Runnable {
51 |
52 | StringBuilder sb = new StringBuilder();
53 | private final InputStream is;
54 | private boolean done;
55 | final List listeners = new ArrayList(1);
56 |
57 | public String getContent() {
58 | return sb.toString();
59 | }
60 |
61 | public ContentReader(InputStream is) throws IOException {
62 | this.is = is;
63 | }
64 |
65 | public ContentReader(InputStream is, ContentReaderListener l) throws IOException {
66 | this.is = is;
67 | if (l != null) {
68 | this.listeners.add(l);
69 | }
70 | }
71 |
72 | public ContentReader(InputStream is, List l) throws IOException {
73 | this.is = is;
74 | if (l != null) {
75 | this.listeners.addAll(l);
76 | }
77 | }
78 |
79 | public void addListener(ContentReaderListener listener) {
80 | this.listeners.add(listener);
81 | }
82 |
83 | public List getListener() {
84 | return listeners;
85 | }
86 |
87 | /**
88 | * Blocks until the copy is complete, or until the thread is interrupted
89 | */
90 | public synchronized void waitUntilDone() throws InterruptedException {
91 | boolean interrupted = false;
92 | // poll interrupted flag, while waiting for copy to complete
93 | while (!(interrupted = Thread.interrupted()) && !done) {
94 | wait(1000);
95 | }
96 | if (interrupted) {
97 | //throw new InterruptedException();
98 | }
99 | }
100 |
101 | @Override
102 | public void run() {
103 | try {
104 | Reader br = new InputStreamReader(is, "UTF-8");
105 | StringBuilder line = new StringBuilder();
106 | while (true) {
107 | int s = br.read();
108 | if (s < 0) {
109 | if (line.length() > 0 && listeners != null) {
110 | for (ContentReaderListener listener : listeners) {
111 | if (listener != null) {
112 | listener.lineReaded(line.toString());
113 | }
114 | }
115 | }
116 | break;
117 | }
118 | char ch = (char) s;
119 | sb.append(ch);
120 | line.append(ch);
121 | if (ch == '\n') {
122 | if (listeners != null) {
123 | for (ContentReaderListener listener : listeners) {
124 | if (listener != null) {
125 | listener.lineReaded(line.toString());
126 | }
127 | }
128 | }
129 | line = new StringBuilder();
130 | }
131 | if (listeners != null) {
132 | for (ContentReaderListener listener : listeners) {
133 | if (listener != null) {
134 | listener.charReaded(ch);
135 | }
136 | }
137 | }
138 | }
139 | } catch (NullPointerException ex) {
140 | ex.printStackTrace();
141 | }
142 | //do not want to bother output with terminations
143 | //mostly compaling when assassin kill the process about StreamClosed
144 | catch (Exception ex) {
145 | // logException(ex);
146 | //ex.printStackTrace();
147 | } finally {
148 | try {
149 | is.close();
150 | } catch (Exception ex) {
151 | // ex.printStackTrace();
152 | } finally {
153 | done = true;
154 | }
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/MainWindow.java:
--------------------------------------------------------------------------------
1 | package org.fbb.board.desktop.gui;
2 |
3 | import org.fbb.board.desktop.gui.awtimpl.TipsListener;
4 | import java.awt.KeyEventDispatcher;
5 | import java.awt.KeyboardFocusManager;
6 | import java.awt.event.KeyEvent;
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.util.zip.ZipInputStream;
10 | import javax.swing.JOptionPane;
11 | import org.apache.commons.cli.CommandLine;
12 | import org.apache.commons.cli.CommandLineParser;
13 | import org.apache.commons.cli.DefaultParser;
14 | import org.apache.commons.cli.Option;
15 | import org.apache.commons.cli.Options;
16 | import org.apache.commons.cli.ParseException;
17 | import org.fbb.board.Translator;
18 | import org.fbb.board.desktop.Files;
19 | import org.fbb.board.desktop.gui.awtimpl.CreateWindow;
20 | import org.fbb.board.desktop.gui.awtimpl.MainWindowImpl;
21 | import org.fbb.board.internals.grid.Boulder;
22 | import org.fbb.board.internals.db.DB;
23 | import org.fbb.board.internals.GlobalSettings;
24 | import org.fbb.board.internals.grid.Grid;
25 | import org.fbb.board.internals.grid.GridPane;
26 | import org.fbb.board.internals.GuiLogHelper;
27 | import org.fbb.board.internals.db.Puller;
28 | import org.fbb.board.internals.grades.Grade;
29 |
30 | /**
31 | *
32 | * @author jvanek
33 | */
34 | //filters - by grade, by date, by number of holds
35 | public class MainWindow {
36 |
37 | public static final GlobalSettings gs = new GlobalSettings();
38 | public static final DB db = new DB(gs);
39 | public static final Puller puller = Puller.create(gs.getPullerDelay() * 60, db);
40 | private static final KeyEventDispatcher f1 = new KeyEventDispatcher() {
41 |
42 | @Override
43 | public boolean dispatchKeyEvent(KeyEvent e) {
44 | if (e.getKeyCode() == KeyEvent.VK_F1 && e.getID() == KeyEvent.KEY_PRESSED) {
45 | new TipsListener().actionPerformed(null);
46 | return true;
47 | }
48 | return false;
49 | }
50 | };
51 |
52 | public static void main(String... s) throws ParseException {
53 | Option o = new Option("w", "windows", true, "How many windows to open if all is ok, this is not guarded by internal limitation");
54 | Options ops = new Options();
55 | ops.addOption(o);
56 | CommandLineParser parser = new DefaultParser();
57 | CommandLine cmd = parser.parse(ops, s);
58 | int windows = 1;
59 | if (cmd.hasOption("-w")) {
60 | String sw = cmd.getOptionValue("w");
61 | windows = Integer.valueOf(sw);
62 | }
63 | try {
64 | KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(f1);
65 | Grid.colorProvider = gs;
66 | Grade.loadConversiontable();
67 | if (Files.getLastBoard() != null && Files.getLastBoulder() != null) {
68 | Boulder b = Boulder.load(Files.getBoulderFile(Files.getLastBoulder()));
69 | GridPane.Preload preloaded = GridPane.preload(new ZipInputStream(new FileInputStream(Files.getWallFile(Files.getLastBoard()))), Files.getLastBoard());
70 | //check if boards mathces
71 | if (!b.getWall().equals(preloaded.givenId)) {
72 | //if not warn, and ask user ifhe wont to keep wall or boulder. If not load wall only
73 | JOptionPane.showMessageDialog(null, Translator.R("NotMatchingBoulderWall", b.getWall(), preloaded.givenId));
74 | File bWall = Files.getWallFile(b.getWall());
75 | if (bWall.exists()) {
76 | //it is likely that wall had been changed intntionally, and old wall was simply not deleted, and boulder was not updated
77 | int a = JOptionPane.showConfirmDialog(null, Translator.R("PossiblyIncorrectLastBoulder"));
78 | if (a == JOptionPane.YES_OPTION) {
79 | Files.setLastBoulder((String) null);//delete alst boulder info
80 | MainWindowImpl.loadWallWithBoulder(Files.getLastBoard());
81 | } else {
82 | preloaded = GridPane.preload(new ZipInputStream(new FileInputStream(bWall)), bWall.getName());
83 | Files.setLastBoard(bWall.getName());
84 | MainWindowImpl.loadWallWithBoulder(preloaded, b);
85 | }
86 | } else {
87 | Files.setLastBoulder((String) null);//delete alst boulder info
88 | MainWindowImpl.loadWallWithBoulder(Files.getLastBoard());
89 | }
90 | } else {
91 | //if so, show last boulder on last wall
92 | for (int i = 0; i < windows; i++) {
93 | MainWindowImpl.loadWallWithBoulder(preloaded, b);
94 | }
95 | }
96 | } else if (Files.getLastBoulder() != null && Files.getLastBoard() == null) {
97 | //warn, but load last boulder on its wall, if wall does noto exists, empty(?)
98 | GuiLogHelper.guiLogger.loge("Last boulder but not lat wall!");
99 | Boulder b = Boulder.load(Files.getBoulderFile(Files.getLastBoulder()));
100 | File bWall = Files.getWallFile(b.getWall());
101 | if (bWall.exists()) {
102 | GridPane.Preload preloaded = GridPane.preload(new ZipInputStream(new FileInputStream(bWall)), bWall.getName());
103 | Files.setLastBoard(bWall.getName());
104 | MainWindowImpl.loadWallWithBoulder(preloaded, b);
105 | } else {
106 | CreateWindow.createSelectOrImportWall(LoadBackgroundOrImportOrLoadWall.getDefaultUrl());
107 | }
108 | } else if (Files.getLastBoard() != null && Files.getLastBoulder() == null) {
109 | //load last wall, generate random bouoder
110 | MainWindowImpl.loadWallWithBoulder(Files.getLastBoard());
111 | } else {
112 | //both null, sugest to create board
113 | CreateWindow.createSelectOrImportWall(LoadBackgroundOrImportOrLoadWall.getDefaultUrl());
114 | }
115 | } catch (Exception ex) {
116 | //do better?
117 | GuiLogHelper.guiLogger.loge(ex);
118 | JOptionPane.showMessageDialog(null, ex);
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/ProcessWrapper.java:
--------------------------------------------------------------------------------
1 | /* ProcessWrapper.java
2 | Copyright (C) 2011,2012 Red Hat, Inc.
3 |
4 | This file is part of IcedTea.
5 |
6 | IcedTea is free software; you can redistribute it and/or
7 | modify it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, version 2.
9 |
10 | IcedTea is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with IcedTea; see the file COPYING. If not, write to
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 | 02110-1301 USA.
19 |
20 | Linking this library statically or dynamically with other modules is
21 | making a combined work based on this library. Thus, the terms and
22 | conditions of the GNU General Public License cover the whole
23 | combination.
24 |
25 | As a special exception, the copyright holders of this library give you
26 | permission to link this library with independent modules to produce an
27 | executable, regardless of the license terms of these independent
28 | modules, and to copy and distribute the resulting executable under
29 | terms of your choice, provided that you also meet, for each linked
30 | independent module, the terms and conditions of the license of that
31 | module. An independent module is a module which is not derived from
32 | or based on this library. If you modify this library, you may extend
33 | this exception to your version of the library, but you are not
34 | obligated to do so. If you do not wish to do so, delete this
35 | exception statement from your version.
36 | */
37 |
38 | package org.fbb.board.internals;
39 |
40 | import java.io.ByteArrayInputStream;
41 | import java.io.File;
42 | import java.io.InputStream;
43 | import java.io.OutputStream;
44 | import java.net.URL;
45 | import java.nio.charset.StandardCharsets;
46 | import java.util.ArrayList;
47 | import java.util.Arrays;
48 | import java.util.List;
49 |
50 |
51 |
52 | /**
53 | * This class wraps execution of ThreadedProcess.
54 | * Add listeners and allows another setters, eg of ReactingProcess
55 | *
56 | */
57 | public class ProcessWrapper {
58 |
59 | private List args;
60 | private File dir;
61 | private final List stdoutl = new ArrayList<>(1);
62 | private final List stderrl = new ArrayList<>(1);
63 | private String[] vars;
64 | private InputStream writer;
65 |
66 | public ProcessWrapper(String... args) {
67 | List urledArgs = Arrays.asList(args);
68 | this.args = urledArgs;
69 | this.vars=null;
70 | }
71 |
72 | public final void addStdOutListener(ContentReaderListener l) {
73 | if (l == null) {
74 | return;
75 | }
76 | stdoutl.add(l);
77 |
78 | }
79 |
80 | public final void addStdErrListener(ContentReaderListener l) {
81 | if (l == null) {
82 | return;
83 | }
84 | stderrl.add(l);
85 |
86 | }
87 |
88 | public final void addStdOutListeners(List l) {
89 | if (l == null) {
90 | return;
91 | }
92 | stdoutl.addAll(l);
93 |
94 | }
95 |
96 | public final void addStdErrListeners(List l) {
97 | if (l == null) {
98 | return;
99 | }
100 | stderrl.addAll(l);
101 |
102 | }
103 |
104 | /**
105 | * @return the args
106 | */
107 | public List getArgs() {
108 | return args;
109 | }
110 |
111 | /**
112 | * @param args the args to set
113 | */
114 | public void setArgs(List args) {
115 | this.args = args;
116 | }
117 |
118 | /**
119 | * @return the dir
120 | */
121 | public File getDir() {
122 | return dir;
123 | }
124 |
125 | /**
126 | * @param dir the dir to set
127 | */
128 | public void setDir(File dir) {
129 | this.dir = dir;
130 | }
131 |
132 | /**
133 | * @return the stdoutl
134 | */
135 | public List getStdoutListeners() {
136 | return stdoutl;
137 | }
138 |
139 | /**
140 | * @return the stderrl
141 | */
142 | public List getStderrListeners() {
143 | return stderrl;
144 | }
145 |
146 | /**
147 | * @return the vars
148 | */
149 | public String[] getVars() {
150 | return vars;
151 | }
152 |
153 | /**
154 | * @param vars the vars to set
155 | */
156 | public void setVars(String[] vars) {
157 | this.vars = vars;
158 | }
159 |
160 | public ProcessResult execute() throws Exception {
161 | ThreadedProcess t = new ThreadedProcess(args, dir, vars);
162 | t.setWriter(writer);
163 | t.start();
164 | while (t.getP() == null && t.deadlyException == null) {
165 | Thread.sleep(100);
166 | }
167 | if (t.deadlyException != null) {
168 | return new ProcessResult("", "", null, true, Integer.MIN_VALUE, t.deadlyException);
169 | }
170 | ContentReader crs = new ContentReader(t.getP().getInputStream(), stdoutl);
171 | ContentReader cre = new ContentReader(t.getP().getErrorStream(), stderrl);
172 |
173 | OutputStream out = t.getP().getOutputStream();
174 | if (out != null) {
175 | out.close();
176 | }
177 |
178 | new Thread(crs).start();
179 | new Thread(cre).start();
180 | while (t.isRunning()) {
181 | Thread.sleep(100);
182 | }
183 |
184 | while (!t.isDestoyed()) {
185 | Thread.sleep(100);
186 | }
187 | // ServerAccess.logOutputReprint(t.getP().exitValue()); when process is killed, this throws exception
188 |
189 | ProcessResult pr = new ProcessResult(crs.getContent(), cre.getContent(), t.getP(), false, t.getExitCode(), null);
190 | return pr;
191 | }
192 |
193 |
194 | private static String createConnectionMessage(ThreadedProcess t) {
195 | return "Connecting " + t.getCommandLine();
196 | }
197 |
198 | public void setWriter(InputStream writer) {
199 | this.writer = writer;
200 | }
201 |
202 | public void setWriter(String writer) {
203 | setWriter(new ByteArrayInputStream(writer.getBytes(StandardCharsets.UTF_8)));
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/BoxesWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.Component;
10 | import java.awt.GridLayout;
11 | import java.awt.Window;
12 | import java.awt.event.WindowAdapter;
13 | import java.awt.event.WindowEvent;
14 | import java.util.Random;
15 | import javax.swing.JCheckBox;
16 | import javax.swing.JComboBox;
17 | import javax.swing.JDialog;
18 | import javax.swing.JFrame;
19 | import javax.swing.JLabel;
20 | import javax.swing.JOptionPane;
21 | import javax.swing.JPanel;
22 | import javax.swing.JTextField;
23 | import org.fbb.board.Translator;
24 | import org.fbb.board.desktop.gui.dialogs.parts.DefaultSnoozeAction;
25 | import org.fbb.board.desktop.gui.dialogs.parts.TimeAndSnooze;
26 | import org.fbb.board.internals.GuiLogHelper;
27 | import org.fbb.board.internals.grid.GridPane;
28 |
29 | /**
30 | *
31 | * @author jvanek
32 | */
33 | public class BoxesWindow extends JDialog implements Runnable {
34 |
35 | private final GridPane gp;
36 | private final TimeAndSnooze tas;
37 |
38 | private final JComboBox size;
39 |
40 | private final JCheckBox up = new JCheckBox(Translator.R("uc"));
41 | private final JCheckBox bottom = new JCheckBox(Translator.R("bc"));
42 | private final JCheckBox left = new JCheckBox(Translator.R("lw"));
43 | private final JCheckBox right = new JCheckBox(Translator.R("rw"));
44 |
45 | public BoxesWindow(Window parent, GridPane gp) {
46 | super(parent);
47 | this.gp = gp;
48 | this.setTitle(Translator.R("box"));
49 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
50 | this.setModalityType(ModalityType.DOCUMENT_MODAL);
51 | this.setSize(500, 400);
52 | this.setLocationRelativeTo(parent);
53 | this.add(new JTextField(Translator.R("boxHelp")), BorderLayout.SOUTH);
54 | JPanel panel = new JPanel();
55 | this.add(panel);
56 | panel.setLayout(new GridLayout(6, 2));
57 | panel.add(new JLabel(Translator.R("size")));
58 | size = new JComboBox<>(new Integer[]{1, 2, 3});
59 | size.setSelectedIndex(1);
60 | panel.add(size);
61 | up.setSelected(false);
62 | bottom.setSelected(false);
63 | panel.add(up);
64 | panel.add(bottom);
65 | left.setSelected(true);
66 | right.setSelected(true);
67 | panel.add(left);
68 | panel.add(right);
69 | tas = new TimeAndSnooze(panel, new DefaultSnoozeAction(gp), new Runnable() {
70 | @Override
71 | public void run() {
72 | BoxesWindow.this.reset();
73 | }
74 | }, this);
75 | this.pack();
76 | this.setSize(this.getWidth(), 350);
77 | this.setLocationRelativeTo(parent);
78 | this.addWindowListener(new WindowAdapter() {
79 |
80 | @Override
81 | public void windowClosed(WindowEvent e) {
82 | tas.stop();
83 | }
84 |
85 | });
86 | reset();
87 | tas.start();
88 | }
89 | private final Random move = new Random();
90 |
91 | int c1, c2, r1, r2;
92 | int t = 0;
93 | int v1, v2, v3, v4;
94 |
95 | @Override
96 | public void run() {
97 | try {
98 | if (t <= 0) {
99 | t = move.nextInt(Math.min(getGridWidth(), getgridHeight()) / 2)*2+1;
100 | v1 = move.nextInt(2) - 1;
101 | v2 = move.nextInt(2) - 1;
102 | v3 = move.nextInt(2) - 1;
103 | v4 = move.nextInt(2) - 1;
104 | }
105 | t--;
106 | c1 = c1 + v1;
107 | c2 = c2 + v2;
108 | r1 = r1 + v3;
109 | r2 = r2 + v4;
110 | int[] limited1 = limit(c1, 0, getGridWidth() / 2, v1);
111 | int[] limited2 = limit(c2, getGridWidth() / 2, getGridWidth(), v2);
112 | int[] limited3 = limit(r1, 0, getgridHeight() / 2, v3);
113 | int[] limited4 = limit(r2, getgridHeight() / 2, getgridHeight(), v4);
114 | c1 = limited1[0];
115 | v1 = limited1[1];
116 | c2 = limited2[0];
117 | v2 = limited2[1];
118 | r1 = limited3[0];
119 | v3 = limited3[1];
120 | r2 = limited4[0];
121 | v4 = limited4[1];
122 | gp.getGrid().clean();
123 | drawSIngleGrid(c1, c2, r1, r2, 0, (byte) 3);
124 | if (size.getSelectedIndex() > 0) {
125 | drawSIngleGrid(c1, c2, r1, r2, 1, (byte) 2);
126 | if (size.getSelectedIndex() > 1) {
127 | drawSIngleGrid(c1, c2, r1, r2, 2, (byte) 1);
128 | }
129 | }
130 | gp.repaintAndSendToKnown();
131 | } catch (Exception ex) {
132 | GuiLogHelper.guiLogger.loge(ex);
133 | JOptionPane.showMessageDialog(BoxesWindow.this, ex);
134 | }
135 | }
136 |
137 | private int getGridWidth() {
138 | return gp.getGrid().getWidth();
139 | }
140 |
141 | private void reset() {
142 | c1 = (getGridWidth() / 4);
143 | c2 = ((getGridWidth() * 3) / 4);
144 | r1 = (getgridHeight() / 4);
145 | r2 = ((getgridHeight() * 3) / 4);
146 |
147 | }
148 |
149 | private int getgridHeight() {
150 | return gp.getGrid().getHeight();
151 | }
152 |
153 | private void drawSIngleGrid(int c1, int c2, int r1, int r2, int i, byte c) {
154 | if (left.isSelected()) {
155 | if (c1 - i >= 0) {
156 | CampusLikeDialog.drawColumn(c1 - i, c, gp.getGrid());
157 | }
158 | }
159 | if (up.isSelected()) {
160 | if (r1 - i >= 0) {
161 | CampusLikeDialog.drawRow(r1 - i, c, gp.getGrid());
162 | }
163 | }
164 | if (right.isSelected()) {
165 | if (c2 + i < getGridWidth()) {
166 | CampusLikeDialog.drawColumn(c2 + i, c, gp.getGrid());
167 | }
168 | }
169 | if (bottom.isSelected()) {
170 | if (r2 + i < getgridHeight()) {
171 | CampusLikeDialog.drawRow(r2 + i, c, gp.getGrid());
172 | }
173 | }
174 |
175 | }
176 |
177 | private int[] limit(final int c, final int minInc, final int maxEx, final int v) {
178 | int[] r = new int[]{c, v};
179 | if (c < minInc) {
180 | r = new int[]{minInc, v * -1};
181 | }
182 | if (c >= maxEx) {
183 | r = new int[]{maxEx - 1, v * -1};
184 | }
185 | return r;
186 | }
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/ClockWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.Component;
10 | import java.awt.GridLayout;
11 | import java.awt.Point;
12 | import java.awt.Window;
13 | import java.awt.event.WindowAdapter;
14 | import java.awt.event.WindowEvent;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Random;
18 | import javax.swing.JCheckBox;
19 | import javax.swing.JComboBox;
20 | import javax.swing.JDialog;
21 | import javax.swing.JFrame;
22 | import javax.swing.JLabel;
23 | import javax.swing.JOptionPane;
24 | import javax.swing.JPanel;
25 | import javax.swing.JTextField;
26 | import org.fbb.board.Translator;
27 | import org.fbb.board.Utils;
28 | import org.fbb.board.desktop.gui.dialogs.parts.DefaultSnoozeAction;
29 | import org.fbb.board.desktop.gui.dialogs.parts.TimeAndSnooze;
30 | import org.fbb.board.internals.GuiLogHelper;
31 | import org.fbb.board.internals.grid.GridPane;
32 |
33 | /**
34 | *
35 | * @author jvanek
36 | */
37 | public class ClockWindow extends JDialog implements Runnable {
38 |
39 | private final GridPane gp;
40 | private final TimeAndSnooze tas;
41 |
42 | private JCheckBox clockwise;
43 | private final JComboBox size_line;
44 | private final JComboBox size_middle;
45 | private final JComboBox axes;
46 |
47 | public ClockWindow(Window parent, GridPane gp) {
48 | super(parent);
49 | this.gp = gp;
50 | this.setTitle(Translator.R("clock"));
51 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
52 | this.setModalityType(ModalityType.DOCUMENT_MODAL);
53 | this.setSize(500, 400);
54 | this.setLocationRelativeTo(parent);
55 | this.add(new JTextField(Translator.R("clockHelp")), BorderLayout.SOUTH);
56 | JPanel panel = new JPanel();
57 | this.add(panel);
58 | panel.setLayout(new GridLayout(8, 2));
59 | panel.add(new JLabel(Translator.R("size_l")));
60 | size_line = new JComboBox<>(new Integer[]{1, 2, 3});
61 | size_line.setSelectedIndex(1);
62 | panel.add(size_line);
63 |
64 | panel.add(new JLabel(Translator.R("size_m")));
65 | size_middle = new JComboBox<>(new Integer[]{1, 2, 3});
66 | size_middle.setSelectedIndex(1);
67 | panel.add(size_middle);
68 | panel.add(new JLabel());
69 | clockwise = new JCheckBox(Translator.R("clockwise"), true);
70 | panel.add(clockwise);
71 | panel.add(new JLabel(Translator.R("axes")));
72 | axes = new JComboBox<>(new Integer[]{1, 2, 3, 4, 5, 6});
73 | axes.setSelectedIndex(0);
74 | panel.add(axes);
75 | tas = new TimeAndSnooze(panel, new DefaultSnoozeAction(gp), new Runnable() {
76 | @Override
77 | public void run() {
78 | ClockWindow.this.reset();
79 | }
80 | }, this);
81 | this.pack();
82 | this.setSize(this.getWidth(), 350);
83 | this.setLocationRelativeTo(parent);
84 | this.addWindowListener(new WindowAdapter() {
85 |
86 | @Override
87 | public void windowClosed(WindowEvent e) {
88 | tas.stop();
89 | }
90 |
91 | });
92 | tas.start();
93 | }
94 | private Random move = new Random();
95 | int degrees = 0;
96 | int jump = 15;
97 |
98 | @Override
99 | public void run() {
100 | try {
101 | gp.getGrid().clean();
102 | Point center = new Point(gp.getGrid().getWidth() / 2, gp.getGrid().getHeight() / 2);
103 | int r = Math.max(gp.getGrid().getWidth() / 2, gp.getGrid().getHeight() / 2);
104 | int astep = 360 / (axes.getSelectedIndex() + 1);
105 | BallWindow.drawBall(gp.getGrid(), size_middle.getSelectedIndex(), center, (byte) 3, (byte) 2, (byte) 1);
106 | for (int i = 0; i <= axes.getSelectedIndex(); i++) {
107 | Double a = Math.toRadians(degrees + (i * astep));
108 | int x = (int) ((double) r * Math.cos(a) - r * Math.sin(a));
109 | int y = (int) ((double) r * Math.sin(a) + r * Math.cos(a));
110 | Point dest = new Point(x + center.x, y + center.y);
111 | //by width, create three lines
112 | //moved in corect way to suggest direction
113 | int ymove = 0;
114 | int xmove = 0;
115 | if (x <= 0 && y <= 0) {
116 | ymove = 1;
117 | }
118 | if (x >= 0 && y <= 0) {
119 | xmove = -1;
120 | }
121 | if (x <= 0 && y >= 0) {
122 | xmove = 1;
123 | }
124 | if (x >= 0 && y >= 0) {
125 | ymove = -1;
126 | }
127 | if (!clockwise.isSelected()) {
128 | xmove *= -1;
129 | ymove *= -1;
130 | }
131 | List l1 = Utils.bresenhamLine(center.x, center.y, dest.x, dest.y);
132 | //I keep drawing the line in two way, to get some more pixels in the most ignored ides.. not much sucess
133 | if (size_line.getSelectedIndex() > 1) {
134 | List l3 = Utils.bresenhamLine(center.x + 2 * xmove, center.y + 2 * ymove, dest.x + 2 * xmove, dest.y + 2 * ymove);
135 | gp.getGrid().set(l3, (byte) 1);
136 | l3 = new ArrayList(l1.size());
137 | for (int[] is : l1) {
138 | l3.add(new int[]{is[0] + 2 * xmove, is[1] + 2 * ymove});
139 | }
140 | gp.getGrid().set(l3, (byte) 1);
141 | }
142 | if (size_line.getSelectedIndex() > 0) {
143 | List l2 = Utils.bresenhamLine(center.x + xmove, center.y + ymove, dest.x + xmove, dest.y + ymove);
144 | gp.getGrid().set(l2, (byte) 2);
145 | l2 = new ArrayList(l1.size());
146 | for (int[] is : l1) {
147 | l2.add(new int[]{is[0] + xmove, is[1] + ymove});
148 | }
149 | gp.getGrid().set(l2, (byte) 2);
150 | }
151 | gp.getGrid().set(l1, (byte) 3);
152 | gp.repaintAndSendToKnown();
153 | }
154 | if (clockwise.isSelected()) {
155 | degrees = degrees + jump;
156 | } else {
157 | degrees = degrees - jump;
158 | }
159 | } catch (Exception ex) {
160 | GuiLogHelper.guiLogger.loge(ex);
161 | JOptionPane.showMessageDialog(ClockWindow.this, ex);
162 | }
163 | }
164 |
165 | private void reset() {
166 | degrees = 0;
167 |
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/dialogs/CampusLikeDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui.dialogs;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.Component;
10 | import java.awt.GridLayout;
11 | import java.awt.Window;
12 | import javax.swing.JDialog;
13 | import javax.swing.JFrame;
14 | import javax.swing.JLabel;
15 | import javax.swing.JOptionPane;
16 | import javax.swing.JPanel;
17 | import javax.swing.JTextField;
18 | import javax.swing.event.DocumentEvent;
19 | import javax.swing.event.DocumentListener;
20 | import org.fbb.board.Translator;
21 | import org.fbb.board.internals.GuiLogHelper;
22 | import org.fbb.board.internals.grid.Grid;
23 | import org.fbb.board.internals.grid.GridPane;
24 |
25 | /**
26 | *
27 | * @author jvanek
28 | */
29 | public class CampusLikeDialog extends JDialog {
30 |
31 | private final GridPane gp;
32 | final JTextField redLines;
33 | final JTextField greenLines;
34 | final JTextField blueLines;
35 |
36 | final JTextField redColumns;
37 | final JTextField greenColumns;
38 | final JTextField blueColumns;
39 |
40 | public CampusLikeDialog(Window parent, GridPane gp) {
41 | super(parent);
42 | this.gp = gp;
43 | this.setTitle(Translator.R("campus"));
44 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
45 | this.setModalityType(ModalityType.DOCUMENT_MODAL);
46 | this.setSize(500, 400);
47 | this.setLocationRelativeTo(parent);
48 | this.add(new JTextField(Translator.R("campusHelp", gp.getGrid().getHeight() - 1, gp.getGrid().getWidth() - 1)), BorderLayout.SOUTH);
49 | JPanel panel = new JPanel();
50 | this.add(panel);
51 | panel.setLayout(new GridLayout(6, 2));
52 | panel.add(new JLabel(Translator.R("rln")));
53 | redLines = new JTextField("" + (gp.getGrid().getHeight() / 2) + " " + (1 * gp.getGrid().getHeight()) / 4);
54 | panel.add(redLines);
55 | panel.add(new JLabel(Translator.R("gln")));
56 | greenLines = new JTextField("");
57 | panel.add(greenLines);
58 | panel.add(new JLabel(Translator.R("bln")));
59 | blueLines = new JTextField("");
60 | panel.add(blueLines);
61 | panel.add(new JLabel(Translator.R("rnc")));
62 | redColumns = new JTextField("" + (gp.getGrid().getWidth() / 3) + " " + (2 * gp.getGrid().getWidth() / 3));
63 | panel.add(redColumns);
64 | panel.add(new JLabel(Translator.R("gnc")));
65 | greenColumns = new JTextField("");
66 | panel.add(greenColumns);
67 | panel.add(new JLabel(Translator.R("bnc")));
68 | blueColumns = new JTextField("");
69 | panel.add(blueColumns);
70 | Changer ch = new Changer();
71 | redLines.getDocument().addDocumentListener(ch);
72 | greenLines.getDocument().addDocumentListener(ch);
73 | blueLines.getDocument().addDocumentListener(ch);
74 | redColumns.getDocument().addDocumentListener(ch);
75 | greenColumns.getDocument().addDocumentListener(ch);
76 | blueColumns.getDocument().addDocumentListener(ch);
77 | ch.work();
78 | this.pack();
79 | this.setSize(this.getWidth(), 400);
80 | this.setLocationRelativeTo(parent);
81 | }
82 |
83 | private class Changer implements DocumentListener {
84 |
85 | @Override
86 | public void insertUpdate(DocumentEvent e) {
87 | work();
88 | }
89 |
90 | @Override
91 | public void removeUpdate(DocumentEvent e) {
92 | work();
93 | }
94 |
95 | @Override
96 | public void changedUpdate(DocumentEvent e) {
97 | work();
98 | }
99 |
100 | private void work() {
101 | try {
102 | String[] rl = redLines.getText().split("[^\\d]+");
103 | String[] gl = greenLines.getText().split("[^\\d]+");
104 | String[] bl = blueLines.getText().split("[^\\d]+");
105 | String[] rc = redColumns.getText().split("[^\\d]+");
106 | String[] gc = greenColumns.getText().split("[^\\d]+");
107 | String[] bc = blueColumns.getText().split("[^\\d]+");
108 | int totall = countNonEmpty(rl) + countNonEmpty(gl) + countNonEmpty(bl);
109 | int totalc = countNonEmpty(rc) + countNonEmpty(gc) + countNonEmpty(bc);
110 |
111 | if (totalc > gp.getGrid().getWidth() / 2 || totall > gp.getGrid().getHeight() / 2) {
112 | throw new RuntimeException(Translator.R("outOfBonds2", (gp.getGrid().getWidth() / 2), (gp.getGrid().getHeight() / 2)));
113 | }
114 |
115 | gp.getGrid().clean();
116 | drawColumns(rc, 3);
117 | drawColumns(gc, 2);
118 | drawColumns(bc, 1);
119 | drawRows(rl, 3);
120 | drawRows(gl, 2);
121 | drawRows(bl, 1);
122 | gp.repaintAndSendToKnown();
123 | } catch (Exception ex) {
124 | GuiLogHelper.guiLogger.loge(ex);
125 | JOptionPane.showMessageDialog(CampusLikeDialog.this, ex);
126 | }
127 | }
128 |
129 | public void drawColumns(String[] cc, int color) throws NumberFormatException, IndexOutOfBoundsException {
130 | CampusLikeDialog.drawColumns(cc, color, gp.getGrid());
131 | }
132 |
133 | public void drawRows(String[] rr, int color) throws NumberFormatException, IndexOutOfBoundsException {
134 | CampusLikeDialog.drawRows(rr, color, gp.getGrid());
135 | }
136 |
137 | private int countNonEmpty(String[] s) {
138 | int r = 0;
139 | for (String s1 : s) {
140 | if (!s1.trim().isEmpty()) {
141 | r++;
142 | };
143 | }
144 | return r;
145 | }
146 |
147 | }
148 |
149 | public static void drawColumn(int x, int color, Grid gp) throws NumberFormatException, IndexOutOfBoundsException {
150 | for (int i = 0; i < gp.getHeight(); i++) {
151 | gp.set(x, i, (byte) color);
152 | }
153 | }
154 |
155 | public static void drawColumns(String[] cc, int color, Grid gp) throws NumberFormatException, IndexOutOfBoundsException {
156 | for (String c : cc) {
157 | if (!c.trim().isEmpty()) {
158 | drawColumn(Integer.valueOf(c), color, gp);
159 | }
160 | }
161 | }
162 |
163 | public static void drawRow(int y, int color, Grid gp) throws NumberFormatException, IndexOutOfBoundsException {
164 | for (int i = 0; i < gp.getWidth(); i++) {
165 | gp.set(i, y, (byte) color);
166 | }
167 | }
168 |
169 | public static void drawRows(String[] rr, int color, Grid gp) throws NumberFormatException, IndexOutOfBoundsException {
170 | for (String c : rr) {
171 | if (!c.trim().isEmpty()) {
172 | drawRow(Integer.valueOf(c), color, gp);
173 | }
174 | }
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/internals/training/TimeredTraining.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.internals.training;
7 |
8 | import java.awt.event.ActionEvent;
9 | import org.fbb.board.internals.grid.Boulder;
10 | import java.awt.event.ActionListener;
11 | import java.util.List;
12 | import java.util.Random;
13 | import javax.swing.JLabel;
14 | import org.fbb.board.desktop.TextToSpeech;
15 | import org.fbb.board.desktop.gui.awtimpl.MainWindowImpl;
16 | import org.fbb.board.internals.GuiLogHelper;
17 |
18 | /**
19 | *
20 | * @author jvanek
21 | */
22 | public class TimeredTraining implements Runnable {
23 |
24 | private final ActionListener next, prev, nextRandom, nextGenerateRandom;
25 | private boolean running = true;
26 | private boolean paused = false;
27 | private int counter;
28 | private final JLabel output;
29 | private TextToSpeech.TextId speak;
30 | private final List ts;
31 | private int currentInList = 0;
32 | private final ActionListener clear;
33 | private final MainWindowImpl parent;
34 |
35 | public void setJumpingAllowed(boolean jumpingAllowed) {
36 | ts.get(currentInList).allowJumps.setSelected(jumpingAllowed);
37 | }
38 |
39 | public void setRandomAllowed(boolean randomAllowed) {
40 | ts.get(currentInList).allowRandom.setSelected(randomAllowed);
41 | }
42 |
43 | public void setRegularAllowed(boolean regularAllowed) {
44 | ts.get(currentInList).allowRegular.setSelected(regularAllowed);
45 | }
46 |
47 | public boolean getJumpingAllowed() {
48 | return ts.get(currentInList).allowJumps.isSelected();
49 | }
50 |
51 | public boolean getRandomAllowed() {
52 | return ts.get(currentInList).allowRandom.isSelected();
53 | }
54 |
55 | public boolean getRegularAllowed() {
56 | return ts.get(currentInList).allowRegular.isSelected();
57 | }
58 |
59 | public boolean isPaused() {
60 | return paused;
61 | }
62 |
63 | public void setPaused(boolean paused) {
64 | this.paused = paused;
65 | }
66 |
67 | public void stop() {
68 | this.running = false;
69 | }
70 |
71 | public boolean isRunning() {
72 | return running;
73 | }
74 |
75 | public void setSpeak(TextToSpeech.TextId speak) {
76 | this.speak = speak;
77 | }
78 |
79 | public TimeredTraining(MainWindowImpl parent, ActionListener next, ActionListener prev, ActionListener nextRandom, ActionListener nextGenerateRandom, ActionListener clear, List ts, JLabel output, TextToSpeech.TextId speak) {
80 | this.parent = parent;
81 | this.next = next;
82 | this.prev = prev;
83 | this.nextRandom = nextRandom;
84 | this.nextGenerateRandom = nextGenerateRandom;
85 | this.clear=clear;
86 | this.output = output;
87 | this.speak = speak;
88 | this.ts = ts;
89 | counter = ts.get(currentInList).getTotalTime() + 1;
90 | }
91 |
92 | @Override
93 | public void run() {
94 | Random r = new Random();
95 | try {
96 | while (consultList() && running && counter > 0) {
97 | if (!paused) {
98 | counter--;
99 | if (counter == ts.get(currentInList).getTotalTime()) {
100 | if (ts.get(currentInList).getInitialDelay() > 0) {
101 | TextToSpeech.pause(speak);
102 | int delay = ts.get(currentInList).getInitialDelay();
103 | clear.actionPerformed(null);
104 | while (delay > 0) {
105 | if (!paused) {
106 | delay--;
107 | output.setText("Brak! " + delay / 60 + ":" + delay % 60);
108 | output.repaint();
109 | Thread.sleep(1000);
110 | }
111 | }
112 | TextToSpeech.change(speak);
113 | }
114 | }
115 | output.setText(counter / 60 + ":" + counter % 60);
116 | if (ts.size() > 1) {
117 | output.setText(output.getText() + "(" + (currentInList + 1) + "/" + ts.size() + ")");
118 | }
119 | output.repaint();
120 | if (counter % ts.get(currentInList).getTimeOfBoulder() == 0) {
121 | if (!getRegularAllowed() && !getRandomAllowed()) {
122 | continue;
123 | }
124 | boolean choice1 = r.nextBoolean();
125 | if (!getRegularAllowed() || (getRandomAllowed() && choice1)) {
126 | nextGenerateRandom.actionPerformed(null);
127 | }
128 | if (!getRandomAllowed() || (getRandomAllowed() && !choice1)) {
129 | if (getJumpingAllowed() && r.nextBoolean()) {
130 | int i = r.nextInt(parent.list.getSize());
131 | i = i--;
132 | parent.list.setIndex(i);
133 | next.actionPerformed(new ActionEvent(this, 0, null));
134 | } else {
135 | if (parent.list.canFwd()) {
136 | next.actionPerformed(new ActionEvent(this, 0, null));
137 | } else {
138 | parent.list.setIndex(-1);
139 | next.actionPerformed(new ActionEvent(this, 0, null));
140 | }
141 | }
142 | }
143 | Boulder b = parent.hm.getCurrentInHistory();
144 | if (b.getGrade().isRandom()) {
145 | TextToSpeech.tellImpl(b.getGrade().toString(), speak);
146 | } else {
147 | TextToSpeech.tellImpl(b.getAuthor()+" "+b.getGrade().shorten()+" "+b.getName(), speak);
148 | }
149 | }
150 | }
151 | Thread.sleep(1000);
152 | }
153 | } catch (Exception ex) {
154 | GuiLogHelper.guiLogger.loge(ex);
155 | }
156 | }
157 |
158 | private boolean consultList() {
159 | if (running && counter <= 0) {
160 | currentInList++;
161 | if (currentInList >= ts.size()) {
162 | return false;
163 | }
164 | //init filter and aply initial delay
165 | int delay = ts.get(currentInList).getInitialDelay();
166 | if (delay == 0) {
167 | TextToSpeech.change(speak);
168 | }
169 | counter = ts.get(currentInList).getTotalTime() + 1;
170 | TrainingWithBackends q = ts.get(currentInList);
171 | q.setBoulderCalc();
172 | q.setChecks();
173 | q.init();
174 | }
175 | return true;
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/tutorial/awt/HelpWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.tutorial.awt;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.Color;
10 | import java.awt.Component;
11 | import java.awt.GridLayout;
12 | import java.awt.Rectangle;
13 | import java.awt.Window;
14 | import java.awt.event.ActionEvent;
15 | import java.awt.event.ActionListener;
16 | import java.awt.event.WindowAdapter;
17 | import java.awt.event.WindowEvent;
18 | import java.io.IOException;
19 | import java.util.concurrent.atomic.AtomicInteger;
20 | import javax.swing.JButton;
21 | import javax.swing.JDialog;
22 | import javax.swing.JLabel;
23 | import javax.swing.JPanel;
24 | import javax.swing.SwingUtilities;
25 | import org.fbb.board.Translator;
26 | import org.fbb.board.desktop.ScreenFinder;
27 | import org.fbb.board.desktop.tutorial.ImgProvider;
28 | import org.fbb.board.desktop.tutorial.StoryPart;
29 | import org.fbb.board.desktop.tutorial.StoryProvider;
30 | import org.fbb.board.internals.GuiLogHelper;
31 |
32 | /**
33 | *
34 | * @author jvanek
35 | */
36 | public class HelpWindow extends JDialog {
37 |
38 | private final ImgProvider ip;
39 | private final JLabel welcome;
40 | private boolean running = true;
41 | private AtomicInteger index = new AtomicInteger();
42 | private final StoryProvider sp;
43 | private ImageWithTitles iwt;
44 | private boolean isAlive = true;
45 |
46 | public HelpWindow() throws IOException {
47 | this.setTitle(Translator.R("HELP"));
48 | this.setModal(true);
49 | this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
50 | this.setSize(900,1000);//from images
51 | setRelativeSize(this);
52 | sp = new StoryProvider();
53 | ip = new ImgProvider();
54 | welcome = new JLabel(Translator.R("nwBoulderWelcome"));
55 | welcome.setOpaque(true);
56 | this.add(welcome, BorderLayout.NORTH);
57 | final Color wc = welcome.getBackground();
58 | setImg();
59 | JPanel tools = new JPanel(new GridLayout(1, 3));
60 | final JButton backb = new JButton("<<");
61 | tools.add(backb);
62 | final JButton pauseb = new JButton("II");
63 | tools.add(pauseb);
64 | final JButton fwdb = new JButton(">>");
65 | tools.add(fwdb);
66 | this.add(tools, BorderLayout.SOUTH);
67 | pauseb.addActionListener(new ActionListener() {
68 | @Override
69 | public void actionPerformed(ActionEvent ae) {
70 | running = !running;
71 | if (running) {
72 | pauseb.setText("II");
73 | } else {
74 | pauseb.setText(">");
75 | }
76 | }
77 | });
78 | fwdb.addActionListener(new ActionListener() {
79 | @Override
80 | public void actionPerformed(ActionEvent ae) {
81 |
82 | try {
83 | index.addAndGet(1);
84 | if (index.get() >= sp.getStory().size()) {
85 | index.set(sp.getStory().size() - 1);
86 | }
87 | setImg();
88 | } catch (Exception ex) {
89 | GuiLogHelper.guiLogger.loge(ex);
90 | }
91 | }
92 | });
93 | backb.addActionListener(new ActionListener() {
94 | @Override
95 | public void actionPerformed(ActionEvent ae) {
96 | try {
97 | index.addAndGet(-1);
98 | if (index.get() < 0) {
99 | index.set(0);
100 | }
101 | setImg();
102 | } catch (Exception ex) {
103 | GuiLogHelper.guiLogger.loge(ex);
104 | }
105 | }
106 | });
107 | Thread t1 = new Thread(new Runnable() {
108 | @Override
109 | public void run() {
110 | try {
111 | Thread.sleep(500);
112 | for (int i = 0; i < 6; i++) {
113 | Thread.sleep(200);
114 | if (i % 2 == 0) {
115 | welcome.setBackground(Color.yellow);
116 | } else {
117 | welcome.setBackground(wc);
118 | }
119 | welcome.repaint();
120 | }
121 | } catch (Exception ex) {
122 | GuiLogHelper.guiLogger.loge(ex);
123 | }
124 | }
125 | });
126 | t1.setDaemon(true);
127 | t1.start();
128 | Thread t2 = new Thread(new Runner());
129 | t2.setDaemon(true);
130 | t2.start();
131 |
132 | this.addWindowListener(new WindowAdapter() {
133 | @Override
134 | public void windowClosed(WindowEvent we) {
135 | isAlive = false;
136 | }
137 |
138 | });
139 | }
140 |
141 | private void setImg() throws IOException {
142 | if (index.get() < 0 || index.get() >= sp.getStory().size()) {
143 | return;
144 | }
145 | StoryPart start = sp.getStory().get(index.get());
146 | if (iwt != null) {
147 | this.remove(iwt);
148 | }
149 | iwt = new ImageWithTitles(start.getLines(), ip.get(start.getImg()));
150 | this.add(iwt);
151 | this.validate();
152 | }
153 |
154 | private void setRelativeSize(Window bis) {
155 | Rectangle size = ScreenFinder.getCurrentScreenSizeWithoutBounds();
156 | double dw = (double) size.width / (double) bis.getWidth();
157 | double dh = (double) size.height / (double) bis.getHeight();
158 | double ratio = Math.min(dw, dh);
159 | ratio = ratio * 0.9d; // APROX 4/5 of screen
160 | double nwW = ratio * bis.getWidth();
161 | double nwH = ratio * bis.getHeight();
162 | bis.setSize((int)nwW, (int)nwH);
163 | }
164 |
165 | private class Runner implements Runnable {
166 |
167 | @Override
168 | public void run() {
169 | try {
170 | Thread.sleep(1000);
171 | } catch (Exception ex) {
172 | GuiLogHelper.guiLogger.loge(ex);
173 | }
174 | while (isAlive) {
175 | try {
176 | Thread.sleep(3000);
177 | if (running) {
178 | index.addAndGet(1);
179 | if (index.get() >= sp.getStory().size()) {
180 | index.set(0);
181 | }
182 | setImg();
183 | }
184 | } catch (Exception ex) {
185 | GuiLogHelper.guiLogger.loge(ex);
186 | }
187 | }
188 | }
189 | }
190 |
191 | public static void show(final Component c) {
192 | SwingUtilities.invokeLater(new Runnable() {
193 | @Override
194 | public void run() {
195 | try {
196 | HelpWindow h = new HelpWindow();
197 | h.setLocationRelativeTo(c);
198 | h.setVisible(true);
199 | } catch (IOException ex) {
200 | ex.printStackTrace();
201 | }
202 | }
203 | });
204 |
205 | }
206 |
207 | public static void main(String... args) {
208 | show(null);
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/ArduinoWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui;
7 |
8 | import java.awt.BorderLayout;
9 | import java.awt.Dimension;
10 | import java.awt.GridLayout;
11 | import java.awt.event.ActionEvent;
12 | import java.awt.event.ActionListener;
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.File;
15 | import java.io.IOException;
16 | import java.io.PrintStream;
17 | import java.util.ArrayList;
18 | import java.util.Arrays;
19 | import java.util.stream.Collectors;
20 | import javax.swing.JButton;
21 | import javax.swing.JComboBox;
22 | import javax.swing.JDialog;
23 | import javax.swing.JFrame;
24 | import javax.swing.JOptionPane;
25 | import javax.swing.JPanel;
26 | import javax.swing.JTabbedPane;
27 | import javax.swing.JTextField;
28 | import org.fbb.board.desktop.ScreenFinder;
29 | import org.fbb.board.internals.ContentReaderListener;
30 | import org.fbb.board.internals.GuiLogHelper;
31 | import org.fbb.board.internals.ProcessResult;
32 | import org.fbb.board.internals.ProcessWrapper;
33 | import org.fbb.board.internals.comm.ConnectionID;
34 | import org.fbb.board.internals.comm.wired.PortWork;
35 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
36 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
37 | import org.fife.ui.rtextarea.RTextScrollPane;
38 |
39 | /**
40 | *
41 | * @author jvanek
42 | */
43 | public class ArduinoWindow extends JDialog {
44 |
45 | public static void main(String... a) throws IOException {
46 | new ArduinoWindow(File.createTempFile("aaa", "bbb"), "aaa", "zz").setVisible(true);
47 | }
48 |
49 | private final File file;
50 | private final Object lock = new Object();
51 |
52 | public ArduinoWindow(final File f, String content, String currentPort) {
53 | this.file = f;
54 | this.setModal(true);
55 | this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
56 | Dimension s = ScreenFinder.getCurrentScreenSizeWithoutBounds().getSize();
57 | s.width = s.width / 6 * 5;
58 | s.height = s.height / 6 * 5;
59 | this.setSize(s);
60 | final RSyntaxTextArea readOnlySourceCode = new RSyntaxTextArea(content);
61 | readOnlySourceCode.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_C);
62 | readOnlySourceCode.setEditable(false);
63 |
64 | final RSyntaxTextArea readOnlyLog = new RSyntaxTextArea("");
65 | readOnlyLog.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_C);
66 | readOnlyLog.setEditable(false);
67 |
68 | final JTabbedPane pane = new JTabbedPane();
69 |
70 | pane.add(new RTextScrollPane(readOnlySourceCode));
71 | pane.add(new RTextScrollPane(readOnlyLog));
72 | pane.setTitleAt(0, "code");
73 | pane.setTitleAt(1, "log");
74 | this.add(pane);
75 | JPanel tools = new JPanel(new GridLayout(1, 3));
76 | ConnectionID[] ports = new PortWork().listDevices();
77 | if (ports.length == 0) {
78 | JOptionPane.showMessageDialog(null, "No ports! Maybe you are on bluetooh only? Do NOT execute run!");
79 | }
80 | final JComboBox port = new JComboBox(ports);
81 | boolean found = false;
82 | for (int i = 0; i < ports.length; i++) {
83 | ConnectionID p = ports[i];
84 | if (p.getId().equals(currentPort)) {
85 | port.setSelectedIndex(i);
86 | found = true;
87 | break;
88 | }
89 | }
90 | if (!found) {
91 | JOptionPane.showMessageDialog(null, "Warning, set port of `" + currentPort + "` not found in currently seen ports: `" + Arrays.toString(ports) + "`");
92 | if (ports.length > 0) {
93 | JOptionPane.showMessageDialog(null, "maybe you are on bluetooth? Do NOT execute run!");
94 | }
95 | }
96 | tools.add(port);
97 | final JTextField tf = new JTextField("arduino --upload {1} -v --port {2} #--board package:arch:board[:parameters]]");
98 | tf.setEditable(false);
99 | tools.add(tf);
100 | JButton run = new JButton("run");
101 | run.addActionListener(new ActionListener() {
102 |
103 | @Override
104 | public void actionPerformed(ActionEvent e) {
105 | pane.setSelectedIndex(1);
106 | new Thread() {
107 | public void run() {
108 | new ProcessRun().work(readOnlyLog, createCommand(tf.getText(), f, (ConnectionID) port.getSelectedItem()));
109 | }
110 | }.start();
111 | }
112 | });
113 | tools.add(run);
114 | this.add(tools, BorderLayout.SOUTH);
115 | }
116 |
117 | private String createCommand(String template, File f, ConnectionID port) {
118 | String s = template.replaceAll("#.*", "");
119 | if (file == null) {
120 | s = s.replace("--upload", "").replace("{1}", "");
121 | } else {
122 | s = s.replace("{1}", f.getAbsolutePath());
123 | }
124 | if (port == null) {
125 | s = s.replace("--port", "").replace("{2}", "");
126 | } else {
127 | //in wired work we work with connection directly, here we must translate manually
128 | String pp = port.getId();
129 | if (!pp.startsWith("/dev/")) {
130 | pp = "/dev/" + pp;
131 | }
132 | s = s.replace("{2}", pp);
133 | }
134 | return s;
135 | }
136 |
137 | private class ProcessRun {
138 |
139 | public void work(final RSyntaxTextArea t, String cmd) {
140 | t.setText("Executing: " + cmd + "\n");
141 | try {
142 | ProcessWrapper pw = new ProcessWrapper(cmd.split("\\s+"));
143 | pw.addStdErrListener(new ContentReaderListener() {
144 | @Override
145 | public void charReaded(char ch) {
146 |
147 | }
148 |
149 | @Override
150 | public void lineReaded(String s) {
151 | synchronized (lock) {
152 | t.setText(t.getText() + "# " + s);
153 | }
154 | }
155 | });
156 | pw.addStdOutListener(new ContentReaderListener() {
157 | @Override
158 | public void charReaded(char ch) {
159 |
160 | }
161 |
162 | @Override
163 | public void lineReaded(String s) {
164 | synchronized (lock) {
165 | t.setText(t.getText() + "$ " + s);
166 | }
167 | }
168 | });
169 | ProcessResult pr = pw.execute();
170 | if (pr.deadlyException != null) {
171 | t.setText(t.getText() + etoText(pr.deadlyException));
172 | }
173 | t.setText(t.getText() + "\n EXIT: " + pr.returnValue);
174 | } catch (Exception e) {
175 | GuiLogHelper.guiLogger.loge(e);
176 | String s = etoText(e);
177 | t.setText(t.getText() + "\n" + e.getMessage() + "\n" + s);
178 | }
179 | }
180 |
181 | private String etoText(Throwable e) {
182 | ByteArrayOutputStream out = new ByteArrayOutputStream();
183 | e.printStackTrace(new PrintStream(out));
184 | String str = new String(out.toByteArray());
185 | return str;
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/org/fbb/board/desktop/gui/LoadBackgroundOrImportOrLoadWall.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.fbb.board.desktop.gui;
7 |
8 | import java.awt.Color;
9 | import java.awt.GridLayout;
10 | import java.awt.event.ActionEvent;
11 | import java.awt.event.ActionListener;
12 | import java.io.File;
13 | import java.net.MalformedURLException;
14 | import java.net.URL;
15 | import javax.swing.JButton;
16 | import javax.swing.JFileChooser;
17 | import javax.swing.JLabel;
18 | import javax.swing.JPanel;
19 | import javax.swing.JTextField;
20 | import javax.swing.event.DocumentEvent;
21 | import javax.swing.event.DocumentListener;
22 | import org.fbb.board.Translator;
23 | import org.fbb.board.desktop.Files;
24 | import org.fbb.board.desktop.gui.awtimpl.WinUtils;
25 | import org.fbb.board.internals.GlobalSettings;
26 | import org.fbb.board.internals.GuiLogHelper;
27 | import org.fbb.board.internals.db.DB;
28 | import org.fbb.board.internals.db.Puller;
29 |
30 | /**
31 | *
32 | * @author jvanek
33 | */
34 | public class LoadBackgroundOrImportOrLoadWall extends JPanel {
35 |
36 | private JTextField input;
37 | private JLabel info;
38 | private JLabel valid;
39 | private JButton select;
40 | private JButton ok;
41 | private JButton settings;
42 |
43 | private final DB db;
44 | private final GlobalSettings gs;
45 | private final Authenticator auth;
46 | private final Puller puller;
47 |
48 | public static String getDefaultUrl() {
49 | try {
50 | return Files.wallsDir.toURI().toURL().toString();
51 | } catch (MalformedURLException ex) {
52 | GuiLogHelper.guiLogger.loge(ex);
53 | return Files.wallsDir.getAbsolutePath();
54 | }
55 | }
56 |
57 | public void setOkAction(ActionListener l) {
58 | ok.addActionListener(l);
59 | }
60 |
61 | public LoadBackgroundOrImportOrLoadWall(String defaultPath, Authenticator auth, DB db, GlobalSettings gs, Puller puller) {
62 | this.auth = auth;
63 | this.db = db;
64 | this.gs = gs;
65 | this.puller = puller;
66 |
67 | input = new JTextField(defaultPath);
68 | valid = new JLabel();
69 | input.getDocument().addDocumentListener(new DocumentListener() {
70 | @Override
71 | public void insertUpdate(DocumentEvent e) {
72 | validateUrl();
73 | }
74 |
75 | @Override
76 | public void removeUpdate(DocumentEvent e) {
77 | validateUrl();
78 | }
79 |
80 | @Override
81 | public void changedUpdate(DocumentEvent e) {
82 | validateUrl();
83 | }
84 |
85 | });
86 | validateUrl();
87 | //password?
88 | info = new JLabel(Translator.R("MainWindowSetWallInfo"));
89 | ok = new JButton(Translator.R("Bfinish"));
90 | if (Files.repoGit.exists()) {
91 | settings = new JButton(Translator.R("Settings"));
92 | } else {
93 | settings = new JButton(Translator.R("BinitialInit"));
94 | }
95 | settings.addActionListener(new SettingsListener(null, auth, gs, puller, db, 3, null));
96 | select = new JButton(Translator.R("Bselect"));
97 | select.addActionListener((ActionEvent e) -> {
98 | JFileChooser jf;
99 | try {
100 | URL u = new URL(input.getText());
101 | jf = new JFileChooser(u.getPath());
102 | } catch (MalformedURLException ex) {
103 | GuiLogHelper.guiLogger.loge(ex);
104 | jf = new JFileChooser(input.getText());
105 | }
106 | jf.setDialogType(JFileChooser.OPEN_DIALOG);
107 | int returnVal = jf.showDialog(LoadBackgroundOrImportOrLoadWall.this, Translator.R("Bok"));
108 |
109 | if (returnVal == JFileChooser.APPROVE_OPTION) {
110 | try {
111 | input.setText(jf.getSelectedFile().toURI().toURL().toExternalForm());
112 | } catch (MalformedURLException ex) {
113 | GuiLogHelper.guiLogger.loge(ex);
114 | }
115 | }
116 | });
117 | this.setLayout(new GridLayout(4, 1));
118 | JPanel p = new JPanel(new GridLayout(1, 3));
119 | this.add(info);
120 | this.add(input);
121 | this.add(valid);
122 | p.add(ok);
123 | p.add(select);
124 | p.add(settings);
125 | this.add(p);
126 | }
127 |
128 | private void validateUrl() {
129 | int i = validateImp();
130 | switch (i) {
131 | case 0:
132 | valid.setForeground(Color.red);
133 | valid.setText(Translator.R("EmptyUrl"));
134 | break;
135 | case 1:
136 | valid.setForeground(Color.green);
137 | valid.setText(WinUtils.addCtrLine(Translator.R("ExistsFile")));
138 | break;
139 | case 11:
140 | valid.setForeground(Color.red);
141 | valid.setText(Translator.R("ExistsDir"));
142 | break;
143 | case 2:
144 | valid.setForeground(Color.orange);
145 | valid.setText(WinUtils.addCtrLine(Translator.R("NotExistsFile")));
146 | break;
147 | case 3:
148 | valid.setForeground(Color.green);
149 | valid.setText(WinUtils.addCtrLine(Translator.R("OkRemoteUrl")));
150 | break;
151 | default:
152 | valid.setForeground(Color.red);
153 | valid.setText("?????");
154 | break;
155 | }
156 | }
157 |
158 | private int validateImp() {
159 | String candidate = input.getText();
160 | if (candidate == null || candidate.trim().isEmpty()) {
161 | //empty
162 | return 0;
163 | }
164 | URL u;
165 | try {
166 | u = new URL(candidate);
167 | if (u.getProtocol().toLowerCase().equals("file")) {
168 | String fileUrl = u.getPath();
169 | if (new File(fileUrl).exists()) {
170 | if (new File(fileUrl).isDirectory()) {
171 | return 11;
172 | } else {
173 | //existing fiel url
174 | return 1;
175 | }
176 | } else {
177 | //non existing file url
178 | return 2;
179 | }
180 | } else {
181 | //valid remote url
182 | return 3;
183 | }
184 | } catch (MalformedURLException ex) {
185 | GuiLogHelper.guiLogger.loge(ex);
186 | if (new File(candidate).exists()) {
187 | if (new File(candidate).isDirectory()) {
188 | return 11;
189 | } else {
190 | //existing fiel url
191 | return 1;
192 | }
193 | } else {
194 | return 2;
195 | }
196 | }
197 |
198 | }
199 |
200 | public URL getResult() {
201 | try {
202 | URL u = new URL(input.getText());
203 | return u;
204 | } catch (MalformedURLException ex) {
205 | GuiLogHelper.guiLogger.loge(ex);
206 | try {
207 | return new File(info.getText()).toURI().toURL();
208 | } catch (MalformedURLException eex) {
209 | throw new RuntimeException(eex);
210 | }
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------