OSDN Git Service

fix: fix not start for the first time
[delesterandomselector/DelesteRandomSelector.git] / src / com / ranfa / main / DelesteRandomSelector.java
1 package com.ranfa.main;
2
3 import java.awt.BorderLayout;
4 import java.awt.CardLayout;
5 import java.awt.Desktop;
6 import java.awt.EventQueue;
7 import java.awt.Font;
8 import java.io.IOException;
9 import java.net.URI;
10 import java.net.URISyntaxException;
11 import java.nio.file.Files;
12 import java.nio.file.Paths;
13 import java.text.Normalizer;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Random;
19 import java.util.concurrent.CompletableFuture;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.function.BiConsumer;
23 import java.util.stream.Collectors;
24
25 import javax.swing.DefaultComboBoxModel;
26 import javax.swing.JButton;
27 import javax.swing.JCheckBox;
28 import javax.swing.JComboBox;
29 import javax.swing.JFrame;
30 import javax.swing.JLabel;
31 import javax.swing.JOptionPane;
32 import javax.swing.JPanel;
33 import javax.swing.JProgressBar;
34 import javax.swing.JScrollPane;
35 import javax.swing.JSpinner;
36 import javax.swing.JTabbedPane;
37 import javax.swing.JTextArea;
38 import javax.swing.border.EmptyBorder;
39
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import com.jgoodies.forms.layout.ColumnSpec;
44 import com.jgoodies.forms.layout.FormLayout;
45 import com.jgoodies.forms.layout.FormSpecs;
46 import com.jgoodies.forms.layout.RowSpec;
47 import com.ranfa.lib.CheckVersion;
48 import com.ranfa.lib.Easter;
49 import com.ranfa.lib.ManualUpdateThreadImpl;
50 import com.ranfa.lib.SettingJSONProperty;
51 import com.ranfa.lib.Settings;
52 import com.ranfa.lib.Suffix;
53 import com.ranfa.lib.TwitterIntegration;
54 import com.ranfa.lib.Version;
55 import com.ranfa.lib.concurrent.CountedThreadFactory;
56 import com.ranfa.lib.database.EstimateAlbumTypeCycle;
57 import com.ranfa.lib.database.Scraping;
58 import com.ranfa.lib.database.Song;
59 import com.ranfa.lib.handler.CrashHandler;
60 import com.ranfa.lib.songinfo.FetchFromAPI;
61
62 @Version(major = 4, minor = 0, patch = 1, suffix = Suffix.BETA)
63 public class DelesteRandomSelector extends JFrame {
64
65     private static ArrayList<Song> selectedSongsList = new ArrayList<>();
66
67     private JPanel contentPane;
68     private SettingJSONProperty property = new SettingJSONProperty();
69     private String[] integratorArray;
70     private boolean integratorBool = false;
71     private CompletableFuture<Void> softwareUpdateFuture = null;
72     private CompletableFuture<Void> albumTypeEstimateFuture = null;
73     private String albumType = Messages.MSGAlbumTypeBeingCalculated.toString();
74     private Logger logger = LoggerFactory.getLogger(DelesteRandomSelector.class);
75     private ManualUpdateThreadImpl impl;
76     private List<Song> toolIntegrateList;
77     private FetchFromAPI fetchData;
78     private List<Map<String, String>> listToolMapData;
79     private CompletableFuture<List<Map<String, String>>> listToolMapDataFuture;
80     private Easter easter;
81     private JPanel panelMain;
82     private JPanel panelNorthMain;
83     private JLabel labelTitle;
84     private JLabel labelVersion;
85     private JPanel panelWestMain;
86     private JLabel labelDifficulty;
87     private JComboBox<String[]> comboDifficultySelect;
88     private JComboBox<String[]> comboAttribute;
89     private JLabel labelLevel;
90     private JSpinner spinnerLevel;
91     private JCheckBox checkLessLv;
92     private JCheckBox checkMoreLv;
93     private JLabel labelLvCaution;
94     private JPanel panelEastMain;
95     private JButton btnImport;
96     private JButton btnConfig;
97     private JButton btnStart;
98     private JButton btnManualUpdate;
99     private JButton btnTwitterIntegration;
100     private JButton btnExit;
101     private JPanel panelCenterMain;
102     private JScrollPane scrollPane;
103     private JTextArea textArea;
104     private JTabbedPane tabbedPane;
105     private JPanel panelInfo;
106     private JPanel panelNorthTool;
107     private JLabel labelSubToolTitle;
108     private JLabel labelVersionTool;
109     private JPanel panelCenterTool;
110     private JLabel labelInfoPlaySongs;
111     private JLabel labelSongNameToolTitle;
112     private JLabel labelSongNameToolTip;
113     private JLabel labelAttributeToolTitle;
114     private JLabel labelAttributeToolTip;
115     private JLabel labelDifficultyToolTitle;
116     private JLabel labelDifficultyToolTip;
117     private JLabel labelLevelToolTitle;
118     private JLabel labelLevelToolTip;
119     private JLabel labelNotesToolTitle;
120     private JLabel labelNotesToolTip;
121     private JButton btnPrevSongTool;
122     private JButton btnNextSongTool;
123     private JLabel labelSlashTool;
124     private JLabel labelCurrentSongOrderTool;
125     private JLabel labelSongLimitTool;
126     private JLabel labelLyricToolTitle;
127     private JLabel labelLyricToolTip;
128     private JLabel labelComposerToolTitle;
129     private JLabel labelArrangeToolTitle;
130     private JLabel labelComposerToolTip;
131     private JLabel labelArrangeToolTip;
132     private JLabel labelMemberToolTitle;
133     private JLabel labelMemberToolTip;
134     private JButton btnMoreInfoTool;
135     
136     BiConsumer<ArrayList<Song>, ArrayList<Song>> updateConsumer = (list1, list2) -> {
137             this.logger.info("Checking database updates...");
138             if(list1.size() > list2.size()) {
139                 long time = System.currentTimeMillis();
140                 this.logger.info("{} Update detected.", (list1.size() - list2.size()));
141                 Scraping.writeToJson(list1);
142                 this.logger.info("Update completed in {} ms", (System.currentTimeMillis() - time));
143                 this.logger.info("Updated database size: {}", list1.size());
144             } else {
145                 this.logger.info("database is up-to-date.");
146             }
147         };
148         Runnable setEnabled = () -> {
149             try {
150                 Thread.sleep(3 * 1000L);
151             } catch (InterruptedException e1) {
152                 this.logger.error("Thread has been interrupted during waiting cooldown.", e1);
153             }
154             this.btnImport.setEnabled(true);
155             this.btnImport.setText(Messages.MSGNarrowingDownSongs.toString());
156         };
157         private JLabel labelToolProgress;
158         public static JProgressBar progressTool;
159         public static JLabel labelInfoProgressSongName;
160         private JPanel panelScore;
161         private JPanel panelScoreNorth;
162         private JPanel panelScoreCenter;
163         private JLabel labelScoreTitle;
164         private JLabel labelScoreVersion;
165
166     /**
167      * Launch the application.
168      */
169     public static void main(String[] args) {
170         EventQueue.invokeLater(() -> {
171             try {
172                 DelesteRandomSelector frame = new DelesteRandomSelector();
173                 frame.setVisible(true);
174             } catch (Exception e) {
175                 e.printStackTrace();
176             }
177
178         });
179     }
180
181     /**
182      * log file prefix:
183      *  this.getClass() + ":[LEVEL]: " +
184      */
185
186     /**
187      * Create the frame.
188      */
189     public DelesteRandomSelector() {
190     ExecutorService es = Executors.newCachedThreadPool(new CountedThreadFactory(() -> "DRS", "AsyncEventInquerier", false));
191         this.contentPane = new JPanel();
192         // output system info phase
193         CompletableFuture.runAsync(() -> {
194                 CrashHandler handle = new CrashHandler();
195                 handle.outSystemInfo();
196         }, es).whenCompleteAsync((ret, ex) -> {
197                 if(ex != null) {
198                         logger.error("Exception was thrown during concurrent process", ex);
199                         CrashHandler handle = new CrashHandler(ex);
200                         if(ex instanceof NullPointerException) {
201                                 handle.execute();
202                         }
203                         handle = new CrashHandler(new IllegalStateException(ex));
204                         handle.execute();
205                 }
206         }, es);
207         boolean isFirst = !Scraping.databaseExists();
208         // database check phase
209         CompletableFuture.runAsync(() -> {
210                 if(isFirst) {
211                     JOptionPane.showMessageDialog(this, Messages.MSGDatabaseNotExist.toString());
212                     if(!Scraping.writeToJson(Scraping.getWholeData())) {
213                         JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
214                         throw new NullPointerException("FATAL: cannot continue!");
215                     }
216                 }
217         }, es).whenCompleteAsync((ret, ex) -> {
218                 if(ex != null) {
219                         logger.error("Exception was thrown during concurrent process", ex);
220                         CrashHandler handle = new CrashHandler(ex);
221                         if(ex instanceof NullPointerException) {
222                                 handle.execute();
223                         }
224                         handle = new CrashHandler(new IllegalStateException(ex));
225                         handle.execute();
226                 }
227         }, es);
228         CompletableFuture<ArrayList<Song>> getFromJsonFuture = CompletableFuture.supplyAsync(() -> Scraping.getFromJson(), es);
229         CompletableFuture<ArrayList<Song>> getWholeDataFuture = CompletableFuture.supplyAsync(() -> Scraping.getWholeData(), es);
230         // setting check phase
231         CompletableFuture.runAsync(() -> {
232                 if(!Settings.fileExists() && !Settings.writeDownJSON()) {
233                     JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nPlease see crash report for more detail.");
234                     CrashHandler handle = new CrashHandler("Failed to generate setting file.", new NullPointerException("FATAL: cannot continue!"));
235                     handle.execute();
236                 }
237         }, es).whenCompleteAsync((ret, ex) -> {
238                 if(ex != null) {
239                         logger.error("Exception was thrown during concurrent process", ex);
240                         CrashHandler handle = new CrashHandler(ex);
241                         if(ex instanceof NullPointerException) {
242                                 handle.execute();
243                         }
244                         handle = new CrashHandler(new IllegalStateException(ex));
245                         handle.execute();
246                 }
247                 this.logger.debug("Loading settings...");
248                 this.property.setCheckLibraryUpdates(Settings.needToCheckLibraryUpdates());
249                 this.property.setCheckVersion(Settings.needToCheckVersion());
250                 this.property.setWindowWidth(Settings.getWindowWidth());
251                 this.property.setWindowHeight(Settings.getWindowHeight());
252                 this.property.setSongLimit(Settings.getSongsLimit());
253                 this.property.setSaveScoreLog(Settings.saveScoreLog());
254                 this.logger.debug("Load settings done.");
255                 this.logger.debug("Version check: {}", this.property.isCheckVersion());
256                 this.logger.debug("Library update check: {}", this.property.isCheckLibraryUpdates());
257                 this.logger.debug("Window Width: {}", this.property.getWindowWidth());
258                 this.logger.debug("Window Height: {}", this.property.getWindowHeight());
259                 this.logger.debug("Song Limit: {}", this.property.getSongLimit());
260                 this.logger.debug("SaveScoreLog: {}", this.property.isSaveScoreLog());
261                 this.setBounds(100, 100, this.property.getWindowWidth(), this.property.getWindowHeight());
262                 if(this.property.isCheckVersion()) {
263                     this.softwareUpdateFuture = CompletableFuture.runAsync(() -> CheckVersion.needToBeUpdated(), es);
264                 }
265                 if(this.property.isCheckLibraryUpdates()) {
266                     CompletableFuture<Void> updatedFuture = getWholeDataFuture.thenAcceptBothAsync(getFromJsonFuture, updateConsumer, es);
267                     updatedFuture.thenRunAsync(setEnabled, es);
268                 }
269         }, es);
270         CompletableFuture.runAsync(() -> {
271                 EstimateAlbumTypeCycle.Initialization();
272                 if(Files.exists(Paths.get("generated/albumCycle.json"))) {
273                     this.albumType = EstimateAlbumTypeCycle.getCurrentCycle();
274                 }
275         }, es).whenCompleteAsync((ret, ex) -> {
276                 if(ex != null) {
277                         logger.error("Exception was thrown during concurrent process", ex);
278                         CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
279                         handle.execute();
280                 }
281         }, es);
282         getWholeDataFuture.thenAcceptAsync(list -> this.logger.info("Scraping data size:" + list.size()), es);
283         getFromJsonFuture.thenAcceptAsync(list -> this.logger.info("Currently database size:" + list.size()), es);
284         // easter phase
285         CompletableFuture.runAsync(() -> {
286                 this.easter = new Easter();
287                 this.setTitle(this.easter.getTodaysBirth());
288         }, es);
289         this.logger.debug("Version: {}", CheckVersion.getVersion());
290         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
291         // this.setBounds(100, 100, 960, 643);
292         this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
293         this.setContentPane(this.contentPane);
294         contentPane.setLayout(new CardLayout(0, 0));
295         
296         panelMain = new JPanel();
297         panelMain.setLayout(new BorderLayout(0, 0));
298         
299         panelNorthMain = new JPanel();
300         panelMain.add(panelNorthMain, BorderLayout.NORTH);
301         panelNorthMain.setLayout(new FormLayout(new ColumnSpec[] {
302                         ColumnSpec.decode("829px"),
303                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
304                         ColumnSpec.decode("center:94px"),},
305                 new RowSpec[] {
306                         RowSpec.decode("20px"),}));
307         
308         labelTitle = new JLabel(Messages.MSGTitle.toString());
309         labelTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 16));
310         panelNorthMain.add(labelTitle, "1, 1, center, top");
311         
312         labelVersion = new JLabel(CheckVersion.getVersion());
313         labelVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
314         panelNorthMain.add(labelVersion, "3, 1, center, center");
315         
316         panelWestMain = new JPanel();
317         panelMain.add(panelWestMain, BorderLayout.WEST);
318         panelWestMain.setLayout(new FormLayout(new ColumnSpec[] {
319                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
320                         ColumnSpec.decode("120px"),},
321                 new RowSpec[] {
322                         FormSpecs.LINE_GAP_ROWSPEC,
323                         RowSpec.decode("25px"),
324                         FormSpecs.RELATED_GAP_ROWSPEC,
325                         FormSpecs.DEFAULT_ROWSPEC,
326                         FormSpecs.RELATED_GAP_ROWSPEC,
327                         FormSpecs.DEFAULT_ROWSPEC,
328                         FormSpecs.RELATED_GAP_ROWSPEC,
329                         FormSpecs.DEFAULT_ROWSPEC,
330                         FormSpecs.RELATED_GAP_ROWSPEC,
331                         FormSpecs.DEFAULT_ROWSPEC,
332                         FormSpecs.RELATED_GAP_ROWSPEC,
333                         FormSpecs.DEFAULT_ROWSPEC,
334                         FormSpecs.RELATED_GAP_ROWSPEC,
335                         FormSpecs.DEFAULT_ROWSPEC,
336                         FormSpecs.RELATED_GAP_ROWSPEC,
337                         RowSpec.decode("max(41dlu;default)"),}));
338         
339         labelDifficulty = new JLabel(Messages.MSGSelectDifficulty.toString());
340         labelDifficulty.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
341         panelWestMain.add(labelDifficulty, "2, 2, center, center");
342         
343         comboDifficultySelect = new JComboBox<>();
344         comboDifficultySelect.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "DEBUT", "REGULAR", "PRO", "MASTER", "MASTER+", "ⓁMASTER+", "LIGHT", "TRICK", "PIANO", "FORTE", "WITCH"}));
345         comboDifficultySelect.setFont(new Font("Dialog", Font.BOLD, 12));
346         panelWestMain.add(comboDifficultySelect, "2, 4, fill, fill");
347         
348         comboAttribute = new JComboBox<>();
349         comboAttribute.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "全タイプ", "キュート", "クール", "パッション"}));
350         comboAttribute.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
351         panelWestMain.add(comboAttribute, "2, 6, fill, top");
352         
353         labelLevel = new JLabel(Messages.MSGSongLevel.toString());
354         labelLevel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
355         panelWestMain.add(labelLevel, "2, 8, center, center");
356         
357         spinnerLevel = new JSpinner();
358         panelWestMain.add(spinnerLevel, "2, 10, fill, center");
359         
360         checkLessLv = new JCheckBox(Messages.MSGBelowSpecificLevel.toString());
361         checkLessLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
362         panelWestMain.add(checkLessLv, "2, 12, left, top");
363         
364         checkMoreLv = new JCheckBox(Messages.MSGOverSpecificLevel.toString());
365         checkMoreLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
366         panelWestMain.add(checkMoreLv, "2, 14, left, top");
367         
368         labelLvCaution = new JLabel(Messages.MSGLevelCheckboxInfo.toString());
369         labelLvCaution.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
370         panelWestMain.add(labelLvCaution, "2, 16, left, center");
371         
372         panelEastMain = new JPanel();
373         panelMain.add(panelEastMain, BorderLayout.EAST);
374         panelEastMain.setLayout(new FormLayout(new ColumnSpec[] {
375                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
376                         ColumnSpec.decode("100px"),},
377                 new RowSpec[] {
378                         FormSpecs.LINE_GAP_ROWSPEC,
379                         RowSpec.decode("77px"),
380                         FormSpecs.RELATED_GAP_ROWSPEC,
381                         FormSpecs.DEFAULT_ROWSPEC,
382                         FormSpecs.RELATED_GAP_ROWSPEC,
383                         FormSpecs.DEFAULT_ROWSPEC,
384                         FormSpecs.RELATED_GAP_ROWSPEC,
385                         FormSpecs.DEFAULT_ROWSPEC,
386                         FormSpecs.RELATED_GAP_ROWSPEC,
387                         RowSpec.decode("max(36dlu;default)"),
388                         FormSpecs.RELATED_GAP_ROWSPEC,
389                         FormSpecs.DEFAULT_ROWSPEC,}));
390         
391         btnImport = new JButton(Messages.MSGUpdatingDatabase.toString());
392         btnImport.addActionListener(e -> {
393                 CompletableFuture.runAsync(() -> {
394                         if(impl != null) {
395                                 if(!impl.getFlag()) {
396                                         JOptionPane.showMessageDialog(null, Messages.MSGManualUpdateNotCompleteYet.toString());
397                                 }
398                         }
399                         ArrayList<Song> fromJson = Scraping.getFromJson();
400                         ArrayList<Song> specificlevelList = Scraping.getSpecificLevelSongs(fromJson, (Integer)DelesteRandomSelector.this.spinnerLevel.getValue(), DelesteRandomSelector.this.checkLessLv.isSelected(), DelesteRandomSelector.this.checkMoreLv.isSelected());
401                         ArrayList<Song> specificDifficultyList = Scraping.getSpecificDifficultySongs(specificlevelList, DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().toString());
402                         ArrayList<Song> specificAttributeList = Scraping.getSpecificAttributeSongs(specificDifficultyList, DelesteRandomSelector.this.comboAttribute.getSelectedItem().toString());
403                         ArrayList<Song> specificTypeList = Scraping.getSpecificAlbumTypeSongs(specificAttributeList, EstimateAlbumTypeCycle.getCurrentCycle());
404                         if(!selectedSongsList.isEmpty()) {
405                                 selectedSongsList.clear();
406                         }
407                         selectedSongsList.addAll((DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS)) ? specificTypeList : specificAttributeList);
408                         DelesteRandomSelector.this.logger.info("Songs are selected.We are Ready to go.");
409                         JOptionPane.showMessageDialog(null, Messages.MSGCompleteNarrowDown.toString());
410                 }, es).whenCompleteAsync((ret, ex) -> {
411                         if(ex != null) {
412                                 logger.error("Exception was thrown during concurrent process", ex);
413                                 CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
414                                 handle.execute();
415                         }
416                 }, es);
417         });
418         btnImport.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
419         btnImport.setEnabled(false);
420         panelEastMain.add(btnImport, "2, 2, fill, fill");
421         
422         btnConfig = new JButton(Messages.MSGConfigurations.toString());
423         btnConfig.addActionListener(e -> {
424                 CompletableFuture.runAsync(() -> {
425                         ProcessBuilder builder = new ProcessBuilder("java", "-jar", "Configurations.jar");
426                         try {
427                                 builder.start();
428                         } catch (IOException e1) {
429                                 logger.error("Exception was thrown during concurrent process", e1);
430                                 CrashHandler handle = new CrashHandler(new IllegalStateException(e1));
431                                 handle.execute();
432                         }
433                 }, es).whenCompleteAsync((ret, ex) -> {
434                         if(ex != null) {
435                                 logger.error("Exception was thrown during concurrent process", ex);
436                                 CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
437                                 handle.execute();
438                         }
439                 }, es);
440         });
441         panelEastMain.add(btnConfig, "2, 6, fill, fill");
442         
443         btnStart = new JButton(Messages.MSGCalcStart.toString());
444         btnStart.addActionListener(e -> {
445                 CompletableFuture.runAsync(() -> {
446                         Random random = new Random(System.currentTimeMillis());
447                         toolIntegrateList = new ArrayList<>();
448                         StringBuilder paneBuilder = new StringBuilder();
449                         DelesteRandomSelector.this.integratorArray = new String[DelesteRandomSelector.this.property.getSongLimit()];
450                         for(int i = 0; i < DelesteRandomSelector.this.property.getSongLimit(); i++) {
451                                 int randomInt = random.nextInt(selectedSongsList.size());
452                                 String typeString = DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS) ? EstimateAlbumTypeCycle.getCurrentCycle() : "";
453                                 paneBuilder.append(i + 1)
454                                         .append(Messages.MSGNumberOfSongs.toString())
455                                         .append(" ")
456                                         .append(selectedSongsList.get(randomInt).getAttribute())
457                                         .append("[")
458                                         .append(selectedSongsList.get(randomInt).getDifficulty())
459                                         .append("]「")
460                                         .append(selectedSongsList.get(randomInt).getName())
461                                         .append("」!(Lv:")
462                                         .append(selectedSongsList.get(randomInt).getLevel())
463                                         .append(" ")
464                                         .append(typeString)
465                                         .append(")\n\n");
466                                 this.integratorArray[i] = selectedSongsList.get(randomInt).getName() + "(Lv" + selectedSongsList.get(randomInt).getLevel() + ")\n";
467                                 toolIntegrateList.add(selectedSongsList.get(randomInt));
468                         }
469                                 paneBuilder.append(Messages.MSGThisPhrase.toString())
470                                         .append(this.property.getSongLimit())
471                                         .append(Messages.MSGPlayPhrase.toString());
472                         DelesteRandomSelector.this.textArea.setText(paneBuilder.toString());
473                         DelesteRandomSelector.this.integratorBool = true;
474                         DelesteRandomSelector.this.logger.info("show up completed.");
475                         labelCurrentSongOrderTool.setText("null");
476                         progressTool.setValue(0);
477                         listToolMapDataFuture = CompletableFuture.supplyAsync(() -> {
478                                 List<String> data = toolIntegrateList.stream()
479                                                 .map(s -> s.getName())
480                                                 .collect(Collectors.toList());
481                                 fetchData = new FetchFromAPI(data.toArray(new String[0]));
482                                 return fetchData.getInformation();
483                         }, es);
484                         logger.debug("api fetch inquery published");
485                 }, es).whenCompleteAsync((ret, ex) -> {
486                         if(ex != null) {
487                                 logger.error("Exception was thrown during concurrent process", ex);
488                                 CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
489                                 handle.execute();
490                         }
491                 }, es);
492         });
493         btnStart.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
494         panelEastMain.add(btnStart, "2, 4, fill, fill");
495         
496         btnManualUpdate = new JButton(Messages.MSGManualUpdate.toString());
497         btnManualUpdate.addActionListener(e -> {
498                 impl = new ManualUpdateThreadImpl();
499                 CompletableFuture.runAsync(impl, es).whenCompleteAsync((t, u) -> {
500                         if(u != null) {
501                                 logger.warn("Exception while processing update manually.", u);
502                                 CrashHandler handle = new CrashHandler(new IllegalStateException(u));
503                                 handle.execute();
504                                 JOptionPane.showMessageDialog(null, "There was a problem during processing library update manually.\nIf this appears repeatedly, please contact developer with your app log.");
505                         }
506                 }, es);
507         });
508         panelEastMain.add(btnManualUpdate, "2, 8, fill, fill");
509         
510         btnTwitterIntegration = new JButton(Messages.MSGTwitterIntegration.toString());
511         btnTwitterIntegration.addActionListener(e -> {
512                 CompletableFuture.runAsync(() -> {
513                         boolean authorizationStatus = TwitterIntegration.authorization();
514                         String updatedStatus = Messages.MSGUsingThisAppPhrase.toString();
515                         int lengthLimit = updatedStatus.length();
516                         boolean isBroken = false;
517                         if(!DelesteRandomSelector.this.integratorBool) {
518                                 JOptionPane.showMessageDialog(null, Messages.MSGNotPlayYet.toString());
519                                 return;
520                         }
521                         for (String element : DelesteRandomSelector.this.integratorArray) {
522                                 updatedStatus = updatedStatus + element;
523                                 lengthLimit += element.length();
524                                 if(lengthLimit > 69) {
525                                         isBroken = true;
526                                         break;
527                                 }
528                         }
529                         if(isBroken) {
530                                 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOtherwisePhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
531                         } else {
532                                 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOnlyPhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
533                         }
534                         DelesteRandomSelector.this.logger.info("status message constructed.");
535                         lengthLimit = updatedStatus.length();
536                         if(authorizationStatus) {
537                                 int option = JOptionPane.showConfirmDialog(null, Messages.MSGTwitterIntegrationConfirm.toString() + updatedStatus + Messages.MSGStringLength.toString() + lengthLimit);
538                                 DelesteRandomSelector.this.logger.info("user seletced: " + option);
539                                 switch(option) {
540                                 case JOptionPane.OK_OPTION:
541                                         TwitterIntegration.PostTwitter(updatedStatus);
542                                         DelesteRandomSelector.this.logger.info("Success to update the status.");
543                                         JOptionPane.showMessageDialog(null, Messages.MSGCompletePost.toString());
544                                         break;
545                                 case JOptionPane.NO_OPTION:
546                                         DelesteRandomSelector.this.logger.info("There is no will to post.");
547                                         break;
548                                 case JOptionPane.CANCEL_OPTION:
549                                         DelesteRandomSelector.this.logger.info("The Operation was canceled by user.");
550                                         break;
551                                 default:
552                                         break;
553                                 }
554                         } else {
555                                 DelesteRandomSelector.this.logger.info("seems to reject the permission.it should need try again.");
556                         }
557                 }, es).whenCompleteAsync((ret, ex) -> {
558                         if(ex != null) {
559                                 logger.error("Exception was thrown during concurrent process", ex);
560                                 CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
561                                 handle.execute();
562                         }
563                 }, es);
564         });
565         btnTwitterIntegration.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 11));
566         panelEastMain.add(btnTwitterIntegration, "2, 10, fill, fill");
567         
568         btnExit = new JButton(Messages.MSGTerminate.toString());
569         btnExit.addActionListener(e -> {
570                 if(DelesteRandomSelector.this.softwareUpdateFuture.isDone() || DelesteRandomSelector.this.albumTypeEstimateFuture.isDone() || !this.impl.getFlag()) {
571                         DelesteRandomSelector.this.logger.info("Requested Exit by Button.");
572                         logger.info("Shut down thread pool.");
573                         es.shutdown();
574                         System.exit(0);
575                 } else {
576                         JOptionPane.showMessageDialog(null, Messages.MSGInternalYpdateNotDoneYet.toString());
577                 }
578         });
579         btnExit.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
580         panelEastMain.add(btnExit, "2, 12, fill, fill");
581         
582         panelCenterMain = new JPanel();
583         panelMain.add(panelCenterMain, BorderLayout.CENTER);
584         panelCenterMain.setLayout(new BorderLayout(0, 0));
585         
586         scrollPane = new JScrollPane();
587         panelCenterMain.add(scrollPane);
588         
589         textArea = new JTextArea();
590         textArea.setText(Messages.MSGNarrowDownProcedure.toString() + property.getSongLimit() + Messages.MSGCurrentAlbumType.toString() + albumType);
591         textArea.setEditable(false);
592         scrollPane.setViewportView(textArea);
593         
594         tabbedPane = new JTabbedPane(JTabbedPane.TOP);
595         tabbedPane.addChangeListener(e -> {
596                 CompletableFuture.runAsync(() -> {
597                         labelToolProgress.setText(Messages.MSGAPIWaitAPIFetch.toString());
598                         String currentTabName = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
599                         if(currentTabName.equals("SongInfo") && labelCurrentSongOrderTool.getText().equals("null")) {
600                                 logger.info("Detected switching tool tab");
601                                 listToolMapData = listToolMapDataFuture.join();
602                                 if(toolIntegrateList == null) {
603                                         return;
604                                 }
605                                 Song firstSong = toolIntegrateList.get(0);
606                                 Map<String, String> fetchMap = new HashMap<>();
607                                 for(Map<String, String> tmpMap : listToolMapData) {
608                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
609                                         String normalizeLocalName = Normalizer.normalize(firstSong.getName(), Normalizer.Form.NFKD);
610                                         if(normalizeApiName.equals(normalizeLocalName)) {
611                                                 fetchMap = tmpMap;
612                                                 break;
613                                         }
614                                 }
615                                 labelSongNameToolTip.setText(firstSong.getName());
616                                 labelAttributeToolTip.setText(firstSong.getAttribute());
617                                 labelDifficultyToolTip.setText(firstSong.getDifficulty());
618                                 labelLevelToolTip.setText(String.valueOf(firstSong.getLevel()));
619                                 labelNotesToolTip.setText(String.valueOf(firstSong.getNotes()));
620                                 labelCurrentSongOrderTool.setText("1");
621                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
622                                 labelComposerToolTip.setText(fetchMap.get("composer"));
623                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
624                                 labelMemberToolTip.setText("<html><body>" + fetchMap.get("member") + "</html></body>");
625                         }
626                 }, es).whenCompleteAsync((ret, ex) -> {
627                         labelToolProgress.setText("Information parse Complete.");
628                         if(ex != null) {
629                                 logger.error("Exception was thrown during concurrent process", ex);
630                                 CrashHandler handle = new CrashHandler(new IllegalStateException(ex));
631                                 handle.execute();
632                         }
633                 }, es);
634         });
635         tabbedPane.addTab("Main", null, panelMain, null);
636         contentPane.add(tabbedPane, "name_307238585319500");
637         
638         panelInfo = new JPanel();
639         tabbedPane.addTab("SongInfo", null, panelInfo, null);
640         panelInfo.setLayout(new BorderLayout(0, 0));
641         
642         panelNorthTool = new JPanel();
643         panelInfo.add(panelNorthTool, BorderLayout.NORTH);
644         panelNorthTool.setLayout(new FormLayout(new ColumnSpec[] {
645                         ColumnSpec.decode("center:max(524dlu;default)"),
646                         FormSpecs.RELATED_GAP_COLSPEC,
647                         ColumnSpec.decode("max(30dlu;default)"),},
648                 new RowSpec[] {
649                         RowSpec.decode("max(16dlu;default)"),}));
650         
651         labelSubToolTitle = new JLabel("楽曲情報");
652         labelSubToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 16));
653         panelNorthTool.add(labelSubToolTitle, "1, 1");
654         
655         labelVersionTool = new JLabel(CheckVersion.getVersion());
656         labelVersionTool.setFont(new Font("SansSerif", Font.BOLD, 12));
657         panelNorthTool.add(labelVersionTool, "3, 1");
658         
659         panelCenterTool = new JPanel();
660         panelInfo.add(panelCenterTool, BorderLayout.CENTER);
661         panelCenterTool.setLayout(new FormLayout(new ColumnSpec[] {
662                         FormSpecs.RELATED_GAP_COLSPEC,
663                         ColumnSpec.decode("max(40dlu;default)"),
664                         FormSpecs.RELATED_GAP_COLSPEC,
665                         ColumnSpec.decode("10dlu"),
666                         FormSpecs.RELATED_GAP_COLSPEC,
667                         ColumnSpec.decode("10dlu"),
668                         FormSpecs.RELATED_GAP_COLSPEC,
669                         ColumnSpec.decode("max(12dlu;default)"),
670                         FormSpecs.RELATED_GAP_COLSPEC,
671                         ColumnSpec.decode("max(90dlu;default)"),
672                         FormSpecs.RELATED_GAP_COLSPEC,
673                         ColumnSpec.decode("max(14dlu;default)"),
674                         FormSpecs.RELATED_GAP_COLSPEC,
675                         FormSpecs.RELATED_GAP_COLSPEC,
676                         ColumnSpec.decode("max(14dlu;default)"),
677                         FormSpecs.RELATED_GAP_COLSPEC,
678                         ColumnSpec.decode("max(90dlu;default)"),
679                         FormSpecs.RELATED_GAP_COLSPEC,
680                         FormSpecs.DEFAULT_COLSPEC,
681                         FormSpecs.RELATED_GAP_COLSPEC,
682                         FormSpecs.DEFAULT_COLSPEC,
683                         FormSpecs.RELATED_GAP_COLSPEC,
684                         FormSpecs.DEFAULT_COLSPEC,
685                         FormSpecs.RELATED_GAP_COLSPEC,
686                         ColumnSpec.decode("max(90dlu;default)"),},
687                 new RowSpec[] {
688                         FormSpecs.RELATED_GAP_ROWSPEC,
689                         FormSpecs.DEFAULT_ROWSPEC,
690                         FormSpecs.RELATED_GAP_ROWSPEC,
691                         FormSpecs.DEFAULT_ROWSPEC,
692                         FormSpecs.RELATED_GAP_ROWSPEC,
693                         FormSpecs.DEFAULT_ROWSPEC,
694                         FormSpecs.RELATED_GAP_ROWSPEC,
695                         FormSpecs.DEFAULT_ROWSPEC,
696                         FormSpecs.RELATED_GAP_ROWSPEC,
697                         FormSpecs.DEFAULT_ROWSPEC,
698                         FormSpecs.RELATED_GAP_ROWSPEC,
699                         FormSpecs.DEFAULT_ROWSPEC,
700                         FormSpecs.RELATED_GAP_ROWSPEC,
701                         FormSpecs.DEFAULT_ROWSPEC,
702                         FormSpecs.RELATED_GAP_ROWSPEC,
703                         FormSpecs.DEFAULT_ROWSPEC,
704                         FormSpecs.RELATED_GAP_ROWSPEC,
705                         FormSpecs.DEFAULT_ROWSPEC,
706                         FormSpecs.RELATED_GAP_ROWSPEC,
707                         FormSpecs.DEFAULT_ROWSPEC,
708                         FormSpecs.RELATED_GAP_ROWSPEC,
709                         FormSpecs.DEFAULT_ROWSPEC,
710                         FormSpecs.RELATED_GAP_ROWSPEC,
711                         FormSpecs.DEFAULT_ROWSPEC,
712                         FormSpecs.RELATED_GAP_ROWSPEC,
713                         FormSpecs.DEFAULT_ROWSPEC,
714                         FormSpecs.RELATED_GAP_ROWSPEC,
715                         FormSpecs.DEFAULT_ROWSPEC,
716                         FormSpecs.RELATED_GAP_ROWSPEC,
717                         FormSpecs.DEFAULT_ROWSPEC,
718                         FormSpecs.RELATED_GAP_ROWSPEC,
719                         FormSpecs.DEFAULT_ROWSPEC,
720                         FormSpecs.RELATED_GAP_ROWSPEC,
721                         FormSpecs.DEFAULT_ROWSPEC,
722                         FormSpecs.RELATED_GAP_ROWSPEC,
723                         FormSpecs.DEFAULT_ROWSPEC,
724                         FormSpecs.RELATED_GAP_ROWSPEC,
725                         FormSpecs.DEFAULT_ROWSPEC,
726                         FormSpecs.RELATED_GAP_ROWSPEC,
727                         FormSpecs.DEFAULT_ROWSPEC,
728                         FormSpecs.RELATED_GAP_ROWSPEC,
729                         FormSpecs.DEFAULT_ROWSPEC,}));
730         
731         labelInfoPlaySongs = new JLabel(Messages.MSGInfoPlayedSongs.toString());
732         labelInfoPlaySongs.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
733         panelCenterTool.add(labelInfoPlaySongs, "2, 2, center, default");
734         
735         labelSongNameToolTitle = new JLabel(Messages.MSGInfoSongName.toString());
736         labelSongNameToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
737         panelCenterTool.add(labelSongNameToolTitle, "2, 6, center, default");
738         
739         labelSongNameToolTip = new JLabel(Messages.MSGInfoWait.toString());
740         labelSongNameToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
741         panelCenterTool.add(labelSongNameToolTip, "10, 6, center, default");
742         
743         labelLyricToolTitle = new JLabel(Messages.MSGInfoLyricsBy.toString());
744         labelLyricToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
745         panelCenterTool.add(labelLyricToolTitle, "17, 6, center, default");
746         
747         labelLyricToolTip = new JLabel(Messages.MSGInfoWait.toString());
748         labelLyricToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
749         panelCenterTool.add(labelLyricToolTip, "25, 6, center, default");
750         
751         labelAttributeToolTitle = new JLabel(Messages.MSGInfoSongAttribute.toString());
752         labelAttributeToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
753         panelCenterTool.add(labelAttributeToolTitle, "2, 10, center, default");
754         
755         labelAttributeToolTip = new JLabel(Messages.MSGInfoWait.toString());
756         labelAttributeToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
757         panelCenterTool.add(labelAttributeToolTip, "10, 10, center, default");
758         
759         labelComposerToolTitle = new JLabel(Messages.MSGInfoComposedBy.toString());
760         labelComposerToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
761         panelCenterTool.add(labelComposerToolTitle, "17, 10, center, default");
762         
763         labelComposerToolTip = new JLabel(Messages.MSGInfoWait.toString());
764         labelComposerToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
765         panelCenterTool.add(labelComposerToolTip, "25, 10, center, default");
766         
767         labelDifficultyToolTitle = new JLabel(Messages.MSGInfoSongDifficulty.toString());
768         labelDifficultyToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
769         panelCenterTool.add(labelDifficultyToolTitle, "2, 14, center, default");
770         
771         labelDifficultyToolTip = new JLabel(Messages.MSGInfoWait.toString());
772         labelDifficultyToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
773         panelCenterTool.add(labelDifficultyToolTip, "10, 14, center, default");
774         
775         labelArrangeToolTitle = new JLabel(Messages.MSGInfoArrangedBy.toString());
776         labelArrangeToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
777         panelCenterTool.add(labelArrangeToolTitle, "17, 14, center, default");
778         
779         labelArrangeToolTip = new JLabel(Messages.MSGInfoWait.toString());
780         labelArrangeToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
781         panelCenterTool.add(labelArrangeToolTip, "25, 14, center, default");
782         
783         labelLevelToolTitle = new JLabel(Messages.MSGInfoSongLevel.toString());
784         labelLevelToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
785         panelCenterTool.add(labelLevelToolTitle, "2, 18, center, default");
786         
787         labelLevelToolTip = new JLabel(Messages.MSGInfoWait.toString());
788         labelLevelToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
789         panelCenterTool.add(labelLevelToolTip, "10, 18, center, default");
790         
791         labelMemberToolTitle = new JLabel(Messages.MSGInfoMember.toString());
792         labelMemberToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
793         panelCenterTool.add(labelMemberToolTitle, "17, 18, center, default");
794         
795         labelMemberToolTip = new JLabel(Messages.MSGInfoWait.toString());
796         labelMemberToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
797         panelCenterTool.add(labelMemberToolTip, "25, 18, center, default");
798         
799         labelNotesToolTitle = new JLabel(Messages.MSGInfoSongNotes.toString());
800         labelNotesToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
801         panelCenterTool.add(labelNotesToolTitle, "2, 22, center, default");
802         
803         labelNotesToolTip = new JLabel(Messages.MSGInfoWait.toString());
804         labelNotesToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
805         panelCenterTool.add(labelNotesToolTip, "10, 22, center, default");
806         
807         btnNextSongTool = new JButton("next");
808         btnNextSongTool.addActionListener(e -> {
809                 CompletableFuture.runAsync(() -> {
810                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
811                         if(currentIndex != property.getSongLimit() - 1) {
812                                 Song nextSong = toolIntegrateList.get(currentIndex + 1);
813                                 logger.info("currently : {} Next: {}", currentIndex + 1, currentIndex + 2);
814                                 logger.info("nextSong: {}", nextSong);
815                                 Map<String, String> fetchMap = new HashMap<>();
816                                 for(Map<String, String> tmpMap : listToolMapData) {
817                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
818                                         String normalizeLocalName = Normalizer.normalize(nextSong.getName(), Normalizer.Form.NFKD);
819                                         if(normalizeApiName.equals(normalizeLocalName)) {
820                                                 fetchMap = tmpMap;
821                                                 break;
822                                         }
823                                 }
824                                 labelSongNameToolTip.setText(nextSong.getName());
825                                 labelAttributeToolTip.setText(nextSong.getAttribute());
826                                 labelDifficultyToolTip.setText(nextSong.getDifficulty());
827                                 labelLevelToolTip.setText(String.valueOf(nextSong.getLevel()));
828                                 labelNotesToolTip.setText(String.valueOf(nextSong.getNotes()));
829                                 labelCurrentSongOrderTool.setText(String.valueOf(currentIndex + 2));
830                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
831                                 labelComposerToolTip.setText(fetchMap.get("composer"));
832                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
833                                 labelMemberToolTip.setText("<html><body>" + fetchMap.get("member") + "</html></body>");
834                         }
835                 }, es).whenCompleteAsync((ret, ex) -> {
836                         if(ex != null) {
837                                 logger.error("Exception was thrown during concurrent process", ex);
838                         }
839                 }, es);
840         });
841         
842         btnPrevSongTool = new JButton("prev");
843         btnPrevSongTool.addActionListener(e -> {
844                 CompletableFuture.runAsync(() -> {
845                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
846                         if(currentIndex != 0) {
847                                 Song prevSong = toolIntegrateList.get(currentIndex - 1);
848                                 logger.info("currently : {} Next: {}", currentIndex + 1, currentIndex);
849                                 logger.info("prevSong: {}", prevSong);
850                                 Map<String, String> fetchMap = new HashMap<>();
851                                 for(Map<String, String> tmpMap : listToolMapData) {
852                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
853                                         String normalizeLocalName = Normalizer.normalize(prevSong.getName(), Normalizer.Form.NFKD);
854                                         if(normalizeApiName.equals(normalizeLocalName)) {
855                                                 fetchMap = tmpMap;
856                                                 break;
857                                         }
858                                 }
859                                 labelSongNameToolTip.setText(prevSong.getName());
860                                 labelAttributeToolTip.setText(prevSong.getAttribute());
861                                 labelDifficultyToolTip.setText(prevSong.getDifficulty());
862                                 labelLevelToolTip.setText(String.valueOf(prevSong.getLevel()));
863                                 labelNotesToolTip.setText(String.valueOf(prevSong.getNotes()));
864                                 labelCurrentSongOrderTool.setText(String.valueOf(currentIndex));
865                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
866                                 labelComposerToolTip.setText(fetchMap.get("composer"));
867                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
868                                 labelMemberToolTip.setText("<html><body>" + fetchMap.get("member") + "</html></body>");
869                         }
870                 }, es).whenCompleteAsync((ret, ex) -> {
871                         if(ex != null) {
872                                 logger.error("Exception was thrown during concurrent process", ex);
873                         }
874                 }, es);
875         });
876         btnPrevSongTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
877         panelCenterTool.add(btnPrevSongTool, "10, 28");
878         
879         labelCurrentSongOrderTool = new JLabel("null");
880         panelCenterTool.add(labelCurrentSongOrderTool, "12, 28");
881         
882         labelSlashTool = new JLabel("/");
883         panelCenterTool.add(labelSlashTool, "14, 28");
884         
885         labelSongLimitTool = new JLabel(String.valueOf(this.property.getSongLimit()));
886         panelCenterTool.add(labelSongLimitTool, "15, 28");
887         btnNextSongTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
888         panelCenterTool.add(btnNextSongTool, "17, 28");
889         
890         btnMoreInfoTool = new JButton(Messages.MSGInfoOpenBrowser.toString());
891         btnMoreInfoTool.addActionListener(e -> {
892                 CompletableFuture.runAsync(() -> {
893                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
894                         Song currentSong = toolIntegrateList.get(currentIndex);
895                         Map<String, String> fetchMap = new HashMap<>();
896                         for(Map<String, String> tmpMap : listToolMapData) {
897                                 String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
898                                 String normalizeLocalName = Normalizer.normalize(currentSong.getName(), Normalizer.Form.NFKD);
899                                 if(normalizeApiName.equals(normalizeLocalName)) {
900                                         fetchMap = tmpMap;
901                                         break;
902                                 }
903                         }
904                         Desktop desk = Desktop.getDesktop();
905                         String api = fetchMap.get("link");
906                         URI uri;
907                         try {
908                                 uri = new URI(api);
909                                 logger.info("Opening default browser with : {}", uri);
910                                 desk.browse(uri);
911                         } catch (URISyntaxException | IOException e1) {
912                                 JOptionPane.showMessageDialog(null, "このメッセージは仮です。Exception : " + e1.getClass().getSimpleName());
913                                 logger.error("Exception while opening default browser.", e1);
914                         }
915                 }, es).whenCompleteAsync((ret, ex) -> {
916                         if(ex != null) {
917                                 logger.warn("Exception was thrown during action events.", ex);
918                         }
919                 }, es);
920         });
921         btnMoreInfoTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
922         panelCenterTool.add(btnMoreInfoTool, "25, 28");
923         
924         labelToolProgress = new JLabel(Messages.MSGAPIWaitAPIFetch.toString());
925         labelToolProgress.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
926         panelCenterTool.add(labelToolProgress, "10, 32, center, default");
927         
928         progressTool = new JProgressBar();
929         progressTool.setStringPainted(true);
930         progressTool.setValue(0);
931         progressTool.setMaximum(property.getSongLimit());
932         panelCenterTool.add(progressTool, "17, 32");
933         
934         labelInfoProgressSongName = new JLabel("Processing:");
935         labelInfoProgressSongName.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
936         panelCenterTool.add(labelInfoProgressSongName, "10, 34");
937         
938         panelScore = new JPanel();
939         tabbedPane.addTab("Scores", null, panelScore, null);
940         panelScore.setLayout(new BorderLayout(0, 0));
941         
942         panelScoreNorth = new JPanel();
943         panelScore.add(panelScoreNorth, BorderLayout.NORTH);
944         panelScoreNorth.setLayout(new FormLayout(new ColumnSpec[] {
945                         ColumnSpec.decode("828px"),
946                         FormSpecs.RELATED_GAP_COLSPEC,
947                         ColumnSpec.decode("max(53dlu;default)"),},
948                 new RowSpec[] {
949                         RowSpec.decode("20px"),}));
950         
951         labelScoreTitle = new JLabel("スコア、ファン計算");
952         labelScoreTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 16));
953         panelScoreNorth.add(labelScoreTitle, "1, 1, center, center");
954         
955         labelScoreVersion = new JLabel(CheckVersion.getVersion());
956         labelScoreVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
957         panelScoreNorth.add(labelScoreVersion, "3, 1, center, default");
958         
959         panelScoreCenter = new JPanel();
960         panelScore.add(panelScoreCenter, BorderLayout.CENTER);
961         if(isFirst || !this.property.isCheckLibraryUpdates()) {
962             setEnabled.run();
963         }
964     }
965 }