source: AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.java@ 622

Last change on this file since 622 was 622, checked in by alloc, 12 years ago

AEI2:

  • Fixed update-window always popping up
  • Fixed unpacker not unpacking over existing packages
  • Fixed type-counter (did count mandatory mods)
File size: 20.4 KB
Line 
1package net.oni2.aeinstaller.gui;
2
3import java.awt.Desktop;
4import java.awt.event.ActionEvent;
5import java.awt.event.ActionListener;
6import java.awt.event.MouseAdapter;
7import java.awt.event.MouseEvent;
8import java.io.File;
9import java.io.IOException;
10import java.util.ArrayList;
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.List;
14import java.util.ResourceBundle;
15import java.util.TreeMap;
16import java.util.TreeSet;
17import java.util.Vector;
18
19import javax.swing.JButton;
20import javax.swing.JComboBox;
21import javax.swing.JComponent;
22import javax.swing.JFileChooser;
23import javax.swing.JFrame;
24import javax.swing.JLabel;
25import javax.swing.JMenu;
26import javax.swing.JMenuItem;
27import javax.swing.JOptionPane;
28import javax.swing.JPopupMenu;
29import javax.swing.JSplitPane;
30import javax.swing.JTable;
31import javax.swing.ListSelectionModel;
32import javax.swing.RowSorter;
33import javax.swing.SortOrder;
34import javax.swing.SwingUtilities;
35import javax.swing.event.ListSelectionEvent;
36import javax.swing.event.ListSelectionListener;
37import javax.swing.filechooser.FileFilter;
38import javax.swing.table.TableRowSorter;
39
40import net.oni2.aeinstaller.backend.Paths;
41import net.oni2.aeinstaller.backend.Settings;
42import net.oni2.aeinstaller.backend.Settings.Platform;
43import net.oni2.aeinstaller.backend.SizeFormatter;
44import net.oni2.aeinstaller.backend.depot.DepotCacheUpdateProgressListener;
45import net.oni2.aeinstaller.backend.depot.DepotManager;
46import net.oni2.aeinstaller.backend.mods.Mod;
47import net.oni2.aeinstaller.backend.mods.ModManager;
48import net.oni2.aeinstaller.backend.mods.Type;
49import net.oni2.aeinstaller.backend.mods.download.ModDownloader;
50import net.oni2.aeinstaller.backend.mods.download.ModDownloader.State;
51import net.oni2.aeinstaller.backend.mods.download.ModDownloaderListener;
52import net.oni2.aeinstaller.backend.oni.InstallProgressListener;
53import net.oni2.aeinstaller.backend.oni.Installer;
54import net.oni2.aeinstaller.backend.oni.OniSplit;
55import net.oni2.aeinstaller.gui.about.AboutDialog;
56import net.oni2.aeinstaller.gui.downloadwindow.Downloader;
57import net.oni2.aeinstaller.gui.modtable.DownloadSizeListener;
58import net.oni2.aeinstaller.gui.modtable.ModTableFilter;
59import net.oni2.aeinstaller.gui.modtable.ModTableModel;
60import net.oni2.aeinstaller.gui.settings.SettingsDialog;
61
62import org.javabuilders.BuildResult;
63import org.javabuilders.annotations.DoInBackground;
64import org.javabuilders.event.BackgroundEvent;
65import org.javabuilders.swing.SwingJavaBuilder;
66import org.simplericity.macify.eawt.ApplicationEvent;
67import org.simplericity.macify.eawt.ApplicationListener;
68
69/**
70 * @author Christian Illy
71 */
72public class MainWin extends JFrame implements ApplicationListener,
73 DownloadSizeListener {
74 private static final long serialVersionUID = -4027395051382659650L;
75
76 private ResourceBundle bundle = ResourceBundle.getBundle(getClass()
77 .getName());
78 @SuppressWarnings("unused")
79 private BuildResult result = SwingJavaBuilder.build(this, bundle);
80
81 private JMenu mainMenu;
82
83 private JSplitPane contents;
84
85 private JComboBox cmbModTypes;
86 private JTable tblMods;
87 private ModTableModel model;
88 private TableRowSorter<ModTableModel> sorter;
89 private JLabel lblDownloadSizeVal;
90
91 private JLabel lblSubmitterVal;
92 private JLabel lblCreatorVal;
93 private JLabel lblTypesVal;
94 private JLabel lblPlatformVal;
95 private JLabel lblPackageNumberVal;
96 private HTMLLinkLabel lblDescriptionVal;
97
98 private JButton btnInstall;
99
100 private TreeSet<Mod> execUpdates = null;
101
102 private enum EInstallResult {
103 DONE,
104 OFFLINE,
105 INCOMPATIBLE
106 };
107
108 private EInstallResult installDone = EInstallResult.DONE;
109
110 /**
111 * Constructor of main window.
112 */
113 public MainWin() {
114 this.setTitle(SwingJavaBuilder.getConfig().getResource("appname")
115 + " - v"
116 + SwingJavaBuilder.getConfig().getResource("appversion"));
117
118 contents.setDividerLocation(400);
119
120 if (Settings.getPlatform() == Platform.MACOS) {
121 mainMenu.setVisible(false);
122 }
123
124 getRootPane().setDefaultButton(btnInstall);
125 lblDownloadSizeVal.setText(SizeFormatter.format(0, 2));
126 }
127
128 private void initModTypeBox() {
129 cmbModTypes.removeAllItems();
130
131 TreeMap<String, Type> types = new TreeMap<String, Type>();
132 for (Type t : ModManager.getInstance().getTypesWithContent()) {
133 types.put(t.getName(), t);
134 }
135 for (Type t : types.values()) {
136 cmbModTypes.addItem(t);
137 }
138 cmbModTypes.setSelectedIndex(0);
139 }
140
141 private void initTable() {
142 tblMods.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
143 tblMods.getSelectionModel().addListSelectionListener(
144 new ListSelectionListener() {
145 @Override
146 public void valueChanged(ListSelectionEvent e) {
147 int viewRow = tblMods.getSelectedRow();
148 if (viewRow < 0) {
149 modSelection(null);
150 } else {
151 int modelRow = tblMods
152 .convertRowIndexToModel(viewRow);
153 Mod mod = (Mod) model.getValueAt(modelRow, -1);
154 modSelection(mod);
155 }
156 }
157 });
158 tblMods.addMouseListener(new MouseAdapter() {
159 private void common(MouseEvent e) {
160 int r = tblMods.rowAtPoint(e.getPoint());
161 if (r >= 0 && r < tblMods.getRowCount())
162 tblMods.setRowSelectionInterval(r, r);
163 else
164 tblMods.clearSelection();
165
166 int rowindex = tblMods.getSelectedRow();
167 if (rowindex >= 0) {
168 if (e.isPopupTrigger()
169 && e.getComponent() instanceof JTable) {
170 int modelRow = tblMods.convertRowIndexToModel(rowindex);
171 final Mod mod = (Mod) model.getValueAt(modelRow, -1);
172
173 if (mod.isLocalAvailable()) {
174 JPopupMenu popup = new JPopupMenu();
175 JMenuItem openModFolder = new JMenuItem(bundle
176 .getString("openModFolder.text"));
177 openModFolder
178 .addActionListener(new ActionListener() {
179 @Override
180 public void actionPerformed(
181 ActionEvent arg0) {
182 try {
183 Desktop.getDesktop().open(
184 mod.getLocalPath());
185 } catch (IOException e) {
186 e.printStackTrace();
187 }
188 }
189 });
190 popup.add(openModFolder);
191 popup.show(e.getComponent(), e.getX(), e.getY());
192 }
193 }
194 }
195 }
196
197 @Override
198 public void mousePressed(MouseEvent e) {
199 common(e);
200 }
201
202 @Override
203 public void mouseReleased(MouseEvent e) {
204 common(e);
205 }
206 });
207 // To get checkbox-cells with background of row
208 ((JComponent) tblMods.getDefaultRenderer(Boolean.class))
209 .setOpaque(true);
210
211 model = new ModTableModel();
212 model.addDownloadSizeListener(this);
213
214 tblMods.setModel(model);
215
216 sorter = new TableRowSorter<ModTableModel>(model);
217 tblMods.setRowSorter(sorter);
218
219 sorter.setRowFilter(new ModTableFilter(null));
220
221 List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
222 sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));
223 sorter.setSortKeys(sortKeys);
224
225 for (int i = 0; i < model.getColumnCount(); i++) {
226 model.setColumnConstraints(i, tblMods.getColumnModel().getColumn(i));
227 }
228 }
229
230 private void exit() {
231 dispose();
232 System.exit(0);
233 }
234
235 private void saveLocalData() {
236 Settings.getInstance().serializeToFile();
237 DepotManager.getInstance().saveToFile(Settings.getDepotCacheFilename());
238 }
239
240 @DoInBackground(progressMessage = "updateDepot.title", cancelable = false, indeterminateProgress = false)
241 private void execDepotUpdate(final BackgroundEvent evt) {
242 if (!Settings.getInstance().isOfflineMode()) {
243 try {
244 DepotManager.getInstance().updateInformation(false,
245 new DepotCacheUpdateProgressListener() {
246
247 @Override
248 public void cacheUpdateProgress(String stepName,
249 int current, int total) {
250 evt.setProgressEnd(total);
251 evt.setProgressValue(current);
252 evt.setProgressMessage(stepName);
253 }
254 });
255 } catch (Exception e) {
256 e.printStackTrace();
257 }
258 }
259 ModManager.getInstance().init();
260 initTable();
261 initModTypeBox();
262
263 tblMods.setVisible(true);
264 }
265
266 @SuppressWarnings("unused")
267 private void checkUpdates(Object evtSource) {
268 if ((evtSource != this)
269 || Settings.getInstance().get("notifyupdates", true)) {
270 if (Settings.getInstance().isOfflineMode()) {
271 if (evtSource != this) {
272 JOptionPane.showMessageDialog(this,
273 bundle.getString("offlineMode.text"),
274 bundle.getString("offlineMode.title"),
275 JOptionPane.WARNING_MESSAGE);
276 }
277 } else {
278 TreeSet<Mod> mods = ModManager.getInstance().getUpdatableMods();
279 TreeSet<Mod> tools = ModManager.getInstance()
280 .getUpdatableTools();
281 int size = 0;
282 String strMods = "";
283 for (Mod m : mods) {
284 size += m.getZipSize();
285 if (strMods.length() > 0)
286 strMods += "<br>";
287 strMods += " - " + m.getName();
288 }
289 String strTools = "";
290 for (Mod m : tools) {
291 size += m.getZipSize();
292 if (strTools.length() > 0)
293 strTools += "<br>";
294 strTools += " - " + m.getName();
295 }
296 if (size > 0) {
297 String message = "<html>";
298 message += String.format(
299 bundle.getString("updatesAvailable.text"), strMods,
300 strTools, SizeFormatter.format(size, 3));
301 message += "</html>";
302 int res = JOptionPane.showConfirmDialog(this, message,
303 bundle.getString("updatesAvailable.title"),
304 JOptionPane.YES_NO_OPTION,
305 JOptionPane.QUESTION_MESSAGE);
306 if (res == JOptionPane.YES_OPTION) {
307 execUpdates = new TreeSet<Mod>();
308 execUpdates.addAll(mods);
309 execUpdates.addAll(tools);
310 }
311 }
312 }
313 }
314 }
315
316 @DoInBackground(progressMessage = "doUpdate.title", cancelable = false, indeterminateProgress = false)
317 private void doUpdate(final BackgroundEvent evt) {
318 if (execUpdates != null) {
319 // TODO
320 System.out.println("Update: " + execUpdates.toString());
321 // TODO: install new tools if previously installed
322 }
323 execUpdates = null;
324 }
325
326 @SuppressWarnings("unused")
327 private void focus() {
328 SwingUtilities.invokeLater(new Runnable() {
329
330 @Override
331 public void run() {
332 toFront();
333 repaint();
334 }
335 });
336
337 }
338
339 private void showSettings() {
340 new SettingsDialog().setVisible(true);
341 }
342
343 private void showAbout() {
344 new AboutDialog().setVisible(true);
345 }
346
347 private JFileChooser getConfigOpenSaveDialog(boolean save) {
348 JFileChooser fc = new JFileChooser();
349 fc.setCurrentDirectory(Paths.getEditionBasePath());
350 if (save)
351 fc.setDialogType(JFileChooser.SAVE_DIALOG);
352 else
353 fc.setDialogType(JFileChooser.OPEN_DIALOG);
354 fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
355 fc.setFileFilter(new FileFilter() {
356 @Override
357 public String getDescription() {
358 return "XML files";
359 }
360
361 @Override
362 public boolean accept(File arg0) {
363 return (arg0.isDirectory())
364 || (arg0.getName().toLowerCase().endsWith(".xml"));
365 }
366 });
367 fc.setMultiSelectionEnabled(false);
368 return fc;
369 }
370
371 @SuppressWarnings("unused")
372 private void loadConfig() {
373 JFileChooser fc = getConfigOpenSaveDialog(false);
374 int res = fc.showOpenDialog(this);
375 if (res == JFileChooser.APPROVE_OPTION) {
376 if (fc.getSelectedFile().exists())
377 model.reloadSelection(fc.getSelectedFile());
378 }
379 }
380
381 @SuppressWarnings("unused")
382 private void saveConfig() {
383 JFileChooser fc = getConfigOpenSaveDialog(true);
384 int res = fc.showSaveDialog(this);
385 if (res == JFileChooser.APPROVE_OPTION) {
386 File f = fc.getSelectedFile();
387 if (!f.getName().endsWith(".xml"))
388 f = new File(f.getParentFile(), f.getName() + ".xml");
389 ModManager.getInstance().saveModSelection(f,
390 model.getSelectedMods());
391 }
392 }
393
394 @DoInBackground(progressMessage = "initializingEdition.title", cancelable = false, indeterminateProgress = false)
395 private void reglobalize(final BackgroundEvent evt) {
396 Installer.initializeEdition(new InstallProgressListener() {
397 @Override
398 public void installProgressUpdate(int done, int total, String step) {
399 evt.setProgressEnd(total);
400 evt.setProgressValue(done);
401 evt.setProgressMessage(step);
402 }
403 });
404 }
405
406 @SuppressWarnings("unused")
407 private void tools() {
408 // TODO method stub
409 JOptionPane.showMessageDialog(this, "tools", "todo",
410 JOptionPane.INFORMATION_MESSAGE);
411 }
412
413 @SuppressWarnings("unused")
414 private void revertSelection() {
415 model.revertSelection();
416 }
417
418 @DoInBackground(progressMessage = "mandatoryFiles.title", cancelable = false, indeterminateProgress = false)
419 private void checkMandatoryFiles(final BackgroundEvent evt) {
420 if (!Settings.getInstance().isOfflineMode()) {
421 TreeSet<Mod> mand = new TreeSet<Mod>();
422 for (Mod m : ModManager.getInstance().getMandatoryTools()) {
423 if (m.isNewerAvailable()) {
424 mand.add(m);
425 }
426 }
427 for (Mod m : ModManager.getInstance().getMandatoryMods()) {
428 if (m.isNewerAvailable()) {
429 mand.add(m);
430 }
431 }
432 if (mand.size() > 0) {
433 ModDownloader m = new ModDownloader(mand,
434 new ModDownloaderListener() {
435 @Override
436 public void updateStatus(ModDownloader source,
437 State state, int filesDown, int filesTotal,
438 int bytesDown, int bytesTotal,
439 int duration, int remaining, int speed) {
440 evt.setProgressEnd(filesTotal);
441 evt.setProgressValue(filesDown);
442 }
443 });
444 while (!m.isFinished()) {
445 try {
446 Thread.sleep(10);
447 } catch (InterruptedException e) {
448 e.printStackTrace();
449 }
450 }
451 }
452 evt.setProgressMessage(bundle
453 .getString("mandatoryToolsInstall.title"));
454 Installer
455 .installTools(ModManager.getInstance().getMandatoryTools());
456 }
457 }
458
459 @DoInBackground(progressMessage = "installing.title", cancelable = false, indeterminateProgress = false)
460 private void install(final BackgroundEvent evt) {
461 TreeSet<Mod> mods = new TreeSet<Mod>();
462 mods.addAll(ModManager.getInstance().getMandatoryMods());
463 mods.addAll(model.getSelectedMods());
464
465 boolean instReady = false;
466 installDone = EInstallResult.DONE;
467
468 while (!instReady) {
469 TreeSet<Mod> toDownload = new TreeSet<Mod>();
470 for (Mod m : mods) {
471 if (!m.isLocalAvailable())
472 toDownload.add(m);
473 }
474 if (Settings.getInstance().isOfflineMode()) {
475 installDone = EInstallResult.OFFLINE;
476 break;
477 }
478 if (toDownload.size() > 0) {
479 Downloader dl = new Downloader(toDownload);
480 try {
481 dl.setVisible(true);
482 if (!dl.isFinished())
483 break;
484 } finally {
485 dl.dispose();
486 }
487 }
488 HashMap<Mod, HashSet<Mod>> dependencies = ModManager.getInstance()
489 .checkDependencies(mods);
490 if (dependencies.size() > 0) {
491 System.out.println("Unmet dependencies: "
492 + dependencies.toString());
493 for (Mod m : dependencies.keySet()) {
494 for (Mod mDep : dependencies.get(m))
495 mods.add(mDep);
496 }
497 } else {
498 HashMap<Mod, HashSet<Mod>> conflicts = ModManager.getInstance()
499 .checkIncompabitilites(mods);
500 if (conflicts.size() > 0) {
501 installDone = EInstallResult.INCOMPATIBLE;
502 System.err.println("Incompatible mods: "
503 + conflicts.toString());
504 break;
505 } else {
506 instReady = true;
507 }
508 }
509 }
510
511 if (instReady) {
512 Installer.install(mods, new InstallProgressListener() {
513 @Override
514 public void installProgressUpdate(int done, int total,
515 String step) {
516 evt.setProgressEnd(total);
517 evt.setProgressValue(done);
518 evt.setProgressMessage(step);
519 }
520 });
521 installDone = EInstallResult.DONE;
522 }
523 }
524
525 @SuppressWarnings("unused")
526 private void installDone() {
527 switch (installDone) {
528 case DONE:
529 JOptionPane.showMessageDialog(this,
530 bundle.getString("installDone.text"),
531 bundle.getString("installDone.title"),
532 JOptionPane.INFORMATION_MESSAGE);
533 break;
534 case OFFLINE:
535 JOptionPane.showMessageDialog(this,
536 bundle.getString("offlineMode.text"),
537 bundle.getString("offlineMode.title"),
538 JOptionPane.WARNING_MESSAGE);
539 break;
540 case INCOMPATIBLE:
541 break;
542 }
543 }
544
545 private void modSelection(Mod m) {
546 lblSubmitterVal.setText("");
547 lblCreatorVal.setText("");
548 lblDescriptionVal.setText("");
549 lblTypesVal.setText("");
550 lblPlatformVal.setText("");
551 lblPackageNumberVal.setText("");
552 if (m != null) {
553 lblSubmitterVal.setText(m.getName());
554 lblCreatorVal.setText(m.getCreator());
555 lblDescriptionVal.setText(m.getDescription());
556
557 String types = "";
558 for (Type t : m.getTypes()) {
559 if (types.length() > 0)
560 types += ", ";
561 types += t.getName();
562 }
563 lblTypesVal.setText(types);
564 lblPlatformVal.setText(m.getPlatform().toString());
565 lblPackageNumberVal.setText(m.getPackageNumberString());
566 }
567 }
568
569 @SuppressWarnings("unused")
570 private void modTypeSelection() {
571 Type t = (Type) cmbModTypes.getSelectedItem();
572 if (t != null)
573 sorter.setRowFilter(new ModTableFilter(t));
574 else
575 sorter.setRowFilter(new ModTableFilter(null));
576 }
577
578 @Override
579 public void downloadSizeChanged(int newSize) {
580 lblDownloadSizeVal.setText(SizeFormatter.format(newSize, 2));
581 }
582
583 @SuppressWarnings("unused")
584 private void checkInitialize() {
585 if (!Installer.isEditionInitialized()) {
586 if (!OniSplit.isOniSplitInstalled()) {
587 JOptionPane.showMessageDialog(this,
588 bundle.getString("noOniSplit.text"),
589 bundle.getString("noOniSplit.title"),
590 JOptionPane.ERROR_MESSAGE);
591 exit();
592 } else {
593 int res = JOptionPane
594 .showConfirmDialog(this,
595 bundle.getString("askInitialize.text"),
596 bundle.getString("askInitialize.title"),
597 JOptionPane.YES_NO_OPTION,
598 JOptionPane.QUESTION_MESSAGE);
599 if (res == JOptionPane.NO_OPTION) {
600 saveLocalData();
601 exit();
602 }
603 }
604 }
605 }
606
607 @DoInBackground(progressMessage = "initializingEdition.title", cancelable = false, indeterminateProgress = false)
608 private void initialize(final BackgroundEvent evt) {
609 if (!Installer.isEditionInitialized()) {
610 Installer.initializeEdition(new InstallProgressListener() {
611 @Override
612 public void installProgressUpdate(int done, int total,
613 String step) {
614 evt.setProgressEnd(total);
615 evt.setProgressValue(done);
616 evt.setProgressMessage(step);
617 }
618 });
619 }
620 }
621
622 private Vector<String> getBasicOniLaunchParams() {
623 Vector<String> params = new Vector<String>();
624 File exe = null;
625 switch (Settings.getPlatform()) {
626 case WIN:
627 exe = new File(Paths.getEditionBasePath(), "Oni.exe");
628 if (exe.exists())
629 params.add(exe.getPath());
630 break;
631 case MACOS:
632 exe = new File(Paths.getEditionBasePath(),
633 "Oni.app/Contents/MacOS/Oni");
634 if (exe.exists())
635 params.add(exe.getPath());
636 break;
637 case LINUX:
638 String wine = Settings.getWinePath();
639 exe = new File(Paths.getEditionBasePath(), "Oni.exe");
640 if (exe.exists()) {
641 if (wine != null) {
642 params.add(wine);
643 params.add(exe.getPath());
644 }
645 }
646 break;
647 default:
648 }
649 if (params.size() > 0) {
650 params.add("-debugfiles");
651 }
652 return params;
653 }
654
655 @SuppressWarnings("unused")
656 private void oniFull() {
657 Vector<String> params = getBasicOniLaunchParams();
658 if (params.size() > 0) {
659 try {
660 ProcessBuilder pb = new ProcessBuilder(params);
661 pb.directory(Paths.getEditionBasePath());
662 pb.start();
663 } catch (IOException e) {
664 e.printStackTrace();
665 }
666 }
667 }
668
669 @SuppressWarnings("unused")
670 private void oniWin() {
671 Vector<String> params = getBasicOniLaunchParams();
672 if (params.size() > 0) {
673 params.add("-noswitch");
674 try {
675 ProcessBuilder pb = new ProcessBuilder(params);
676 pb.directory(Paths.getEditionBasePath());
677 pb.start();
678 } catch (IOException e) {
679 e.printStackTrace();
680 }
681 }
682 }
683
684 @SuppressWarnings("unused")
685 private void openEditionFolder() {
686 try {
687 Desktop.getDesktop().open(Paths.getEditionBasePath());
688 } catch (IOException e) {
689 e.printStackTrace();
690 }
691 }
692
693 @Override
694 public void handleAbout(ApplicationEvent event) {
695 event.setHandled(true);
696 showAbout();
697 }
698
699 @Override
700 public void handleOpenApplication(ApplicationEvent event) {
701 }
702
703 @Override
704 public void handleOpenFile(ApplicationEvent event) {
705 }
706
707 @Override
708 public void handlePreferences(ApplicationEvent event) {
709 showSettings();
710 }
711
712 @Override
713 public void handlePrintFile(ApplicationEvent event) {
714 }
715
716 @Override
717 public void handleQuit(ApplicationEvent event) {
718 event.setHandled(true);
719 saveLocalData();
720 exit();
721 }
722
723 @Override
724 public void handleReOpenApplication(ApplicationEvent event) {
725 }
726
727}
Note: See TracBrowser for help on using the repository browser.