## Description
-(Si vous voulez juste voir les derniers changements, vous pouvez regarder le [Changelog](changelog-fr.md) -- remarquez que le programme affiche le changelog si une version plus récente est détectée depuis la version x.x.x.)
+(Si vous voulez juste voir les derniers changements, vous pouvez regarder le [Changelog](changelog-fr.md) -- remarquez que le programme affiche le changelog si une version plus récente est détectée depuis la version 1.2.0.)
![Main GUI](screenshots/fanfix-swing.png?raw=true "Fenêtre principale")
## Description
-(If you are interested in the recent changes, please check the [Changelog](changelog.md) -- note that starting from version x.x.x, the changelog is checked at startup.)
+(If you are interested in the recent changes, please check the [Changelog](changelog.md) -- note that starting from version 1.2.0, the changelog is checked at startup.)
![Main GUI](screenshots/fanfix-swing.png?raw=true "Main window")
## Version WIP
+- new: le programme vérifie si une version plus récente est disponible (comme Fanfix)
- new: l'afficheur d'images peut zoomer avec la molette de la souris et control
- fix: l'afficheur d'images affiche maintenant l'image retournée quand on fait une rotation, au lieu de retourner les pixels mais dans la même hauteur / lageur
- fix: l'afficheur d'images scroll correctement quand on zoom
## Version 1.1.1
-- fix: récupère maintenant correctement les hitsoires sans chaptitres
- new: l'afficheur de livres interne est maintenant correctement refait
+- fix: récupère maintenant correctement les hitsoires sans chaptitres
## Version 1.1.0
## Version WIP
+- new: the program checks if a new version is available (like Fanfix does)
- new: the image viewer now zooms on mousewheel + control
- fix: the image viewer now displayes turned images on rotation, instead of rotating the pixels but in the same height/width
- fix: the image viewer scrolls correctly when we zoom
## Version 1.1.1
-- fix: now correctly retrieve stories without chapters
- new: the internal viewer is now up to par
+- fix: now correctly retrieve stories without chapters
## Version 1.1.0
package be.nikiroo.fanfix_swing;
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.JEditorPane;
import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.SwingWorker;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.VersionCheck;
+import be.nikiroo.fanfix.bundles.StringIdGui;
+import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix_swing.gui.MainFrame;
+import be.nikiroo.utils.Version;
import be.nikiroo.utils.ui.UIUtils;
/**
*
* @author niki
*/
-public class Main {
+public class Main extends be.nikiroo.fanfix.Main {
+ private boolean busy;
+
/**
* The main entry point of the application.
* <p>
- * If arguments are passed, everything will be passed to Fanfix CLI; if no
- * argument are present, Fanfix-Swing proper will be launched.
+ * It overrides some function of Fanfix's Main.
*
* @param args
* the arguments (none, or will be passed to Fanfix)
*/
public static void main(String[] args) {
- // Defer to main application if parameters (we are only a UI)
- // (though we could handle some of the parameters in the future,
- // maybe importing via ImporterFrame? but that would require a
- // unique instance of the UI to be usable...)
- if (args != null && args.length > 0) {
- be.nikiroo.fanfix.Main.main(args);
- return;
+ new Main().start(args);
+ }
+
+ @Override
+ protected VersionCheck checkUpdates() {
+ new SwingWorker<VersionCheck, Void>() {
+ @Override
+ protected VersionCheck doInBackground() throws Exception {
+ return VersionCheck.check("nikiroo/fanfix-swing");
+ }
+
+ @Override
+ protected void done() {
+ try {
+ VersionCheck v = get();
+ if (v != null && v.isNewVersionAvailable()) {
+ notifyUpdates(v);
+ }
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+ }.execute();
+
+ return null;
+ }
+
+ @Override
+ protected void exit(final int status) {
+ if (busy) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (busy) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+
+ Main.super.exit(status);
+ }
+ }
+ }).start();
+ } else {
+ super.exit(status);
}
+ }
+ @Override
+ protected void start() throws IOException {
UIUtils.setLookAndFeel();
Instance.init();
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
}
+
+ @Override
+ protected int read(Story story, Integer chap) {
+ if (chap == null) {
+ Actions.openBook(Instance.getInstance().getLibrary(),
+ story.getMeta(), null, null);
+ return 0;
+ }
+
+ return super.read(story, chap);
+ }
+
+ @Override
+ protected void notifyUpdates(VersionCheck updates) {
+ StringBuilder builder = new StringBuilder();
+ final JEditorPane updateMessage = new JEditorPane("text/html", "");
+ builder.append(trans(StringIdGui.NEW_VERSION_AVAILABLE,
+ "<a href='https://github.com/nikiroo/fanfix-swing/releases'>"
+ + "https://github.com/nikiroo/fanfix-swing/releases"
+ + "</a>"));
+ builder.append("<br>");
+ builder.append("<br>");
+ for (Version v : updates.getNewer()) {
+ builder.append("\t<b>"
+ + trans(StringIdGui.NEW_VERSION_VERSION, v.toString())
+ + "</b>");
+ builder.append("<br>");
+ builder.append("<ul>");
+ for (String item : updates.getChanges().get(v)) {
+ builder.append("<li>" + item + "</li>");
+ }
+ builder.append("</ul>");
+ }
+
+ // html content
+ updateMessage.setText("<html><body>" //
+ + builder//
+ + "</body></html>");
+
+ // handle link events
+ updateMessage.addHyperlinkListener(new HyperlinkListener() {
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent e) {
+ if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED))
+ try {
+ Desktop.getDesktop().browse(e.getURL().toURI());
+ } catch (IOException ee) {
+ Instance.getInstance().getTraceHandler().error(ee);
+ } catch (URISyntaxException ee) {
+ Instance.getInstance().getTraceHandler().error(ee);
+ }
+ }
+ });
+ updateMessage.setEditable(false);
+ updateMessage.setBackground(new JLabel().getBackground());
+ updateMessage.addHyperlinkListener(new HyperlinkListener() {
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent evn) {
+ if (evn.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ if (Desktop.isDesktopSupported()) {
+ try {
+ Desktop.getDesktop().browse(evn.getURL().toURI());
+ } catch (IOException e) {
+ } catch (URISyntaxException e) {
+ }
+ }
+ }
+ }
+ });
+
+ int rep = JOptionPane.showConfirmDialog(null, updateMessage,
+ trans(StringIdGui.NEW_VERSION_TITLE),
+ JOptionPane.OK_CANCEL_OPTION);
+ if (rep == JOptionPane.OK_OPTION) {
+ updates.ok();
+ } else {
+ updates.ignore();
+ }
+ }
+
+ /**
+ * Translate the given id into user text.
+ *
+ * @param id
+ * the ID to translate
+ * @param values
+ * the values to insert instead of the place holders in the
+ * translation
+ *
+ * @return the translated text with the given value where required or NULL
+ * if not found (not present in the resource file)
+ */
+ static public String trans(StringIdGui id, Object... values) {
+ return Instance.getInstance().getTransGui().getString(id, values);
+ }
}
static public ImporterFrame getImporter() {
return importer;
}
-
- /**
- * Translate the given id into user text.
- *
- * @param id
- * the ID to translate
- * @param values
- * the values to insert instead of the place holders in the
- * translation
- *
- * @return the translated text with the given value where required or NULL
- * if not found (not present in the resource file)
- */
- static public String trans(StringIdGui id, Object... values) {
- return Instance.getInstance().getTransGui().getString(id, values);
- }
}
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix_swing.Main;
import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
/**
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setUndecorated(undecorated);
this.setLayout(new BorderLayout());
- this.setTitle(MainFrame.trans(StringIdGui.TITLE_STORY, meta.getLuid(),
+ this.setTitle(Main.trans(StringIdGui.TITLE_STORY, meta.getLuid(),
meta.getTitle()));
desc = new PropertiesPanel(lib, meta, undecorated);
import javax.swing.JPopupMenu;
import javax.swing.SwingWorker;
-import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.bundles.StringIdGui;
import be.nikiroo.fanfix.library.BasicLibrary;
import be.nikiroo.fanfix.library.BasicLibrary.Status;
import be.nikiroo.fanfix.library.MetaResultList;
+import be.nikiroo.fanfix_swing.Main;
import be.nikiroo.fanfix_swing.gui.BooksPanelActions;
import be.nikiroo.fanfix_swing.gui.BooksPanelActions.ChangeAction;
-import be.nikiroo.fanfix_swing.gui.MainFrame;
import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
public class BookPopup extends JPopupMenu {
*/
private JMenuItem createMenuItemExport() {
JMenuItem export = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_EXPORT), KeyEvent.VK_S);
+ Main.trans(StringIdGui.MENU_FILE_EXPORT), KeyEvent.VK_S);
export.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
*/
private JMenuItem createMenuItemClearCache() {
JMenuItem refresh = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_CLEAR_CACHE),
+ Main.trans(StringIdGui.MENU_EDIT_CLEAR_CACHE),
KeyEvent.VK_C);
refresh.addActionListener(new ActionListener() {
@Override
}
JMenu changeTo = new JMenu(
- MainFrame.trans(StringIdGui.MENU_FILE_MOVE_TO));
+ Main.trans(StringIdGui.MENU_FILE_MOVE_TO));
changeTo.setMnemonic(KeyEvent.VK_M);
JMenuItem item = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_TYPE));
+ Main.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_TYPE));
item.addActionListener(createMoveAction(ChangeAction.SOURCE, null));
changeTo.add(item);
changeTo.addSeparator();
}
JMenu changeTo = new JMenu(
- MainFrame.trans(StringIdGui.MENU_FILE_SET_AUTHOR));
+ Main.trans(StringIdGui.MENU_FILE_SET_AUTHOR));
changeTo.setMnemonic(KeyEvent.VK_A);
// New author
JMenuItem newItem = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_AUTHOR));
+ Main.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_AUTHOR));
changeTo.add(newItem);
changeTo.addSeparator();
newItem.addActionListener(createMoveAction(ChangeAction.AUTHOR, null));
JMenu group = new JMenu(key);
for (String value : groupedAuthors.get(key)) {
JMenuItem item = new JMenuItem(value.isEmpty()
- ? MainFrame.trans(StringIdGui.MENU_AUTHORS_UNKNOWN)
+ ? Main.trans(StringIdGui.MENU_AUTHORS_UNKNOWN)
: value);
item.addActionListener(
createMoveAction(ChangeAction.AUTHOR, value));
} else if (groupedAuthors.size() == 1) {
for (String value : groupedAuthors.values().iterator().next()) {
JMenuItem item = new JMenuItem(value.isEmpty()
- ? MainFrame.trans(StringIdGui.MENU_AUTHORS_UNKNOWN)
+ ? Main.trans(StringIdGui.MENU_AUTHORS_UNKNOWN)
: value);
item.addActionListener(
createMoveAction(ChangeAction.AUTHOR, value));
*/
private JMenuItem createMenuItemRename() {
JMenuItem changeTo = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_RENAME));
+ Main.trans(StringIdGui.MENU_FILE_RENAME));
changeTo.setMnemonic(KeyEvent.VK_R);
changeTo.addActionListener(createMoveAction(ChangeAction.TITLE, null));
return changeTo;
*/
private JMenuItem createMenuItemRedownload() {
JMenuItem refresh = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_REDOWNLOAD),
+ Main.trans(StringIdGui.MENU_EDIT_REDOWNLOAD),
KeyEvent.VK_R);
refresh.addActionListener(new ActionListener() {
@Override
*/
private JMenuItem createMenuItemDownloadToCache() {
JMenuItem refresh = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_DOWNLOAD_TO_CACHE),
+ Main.trans(StringIdGui.MENU_EDIT_DOWNLOAD_TO_CACHE),
KeyEvent.VK_T);
refresh.addActionListener(new ActionListener() {
@Override
*/
private JMenuItem createMenuItemDelete() {
JMenuItem delete = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_DELETE), KeyEvent.VK_D);
+ Main.trans(StringIdGui.MENU_EDIT_DELETE), KeyEvent.VK_D);
delete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
*/
private JMenuItem createMenuItemProperties() {
JMenuItem delete = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_PROPERTIES),
+ Main.trans(StringIdGui.MENU_FILE_PROPERTIES),
KeyEvent.VK_P);
delete.addActionListener(new ActionListener() {
@Override
*/
public JMenuItem createMenuItemOpenBook() {
JMenuItem open = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_FILE_OPEN), KeyEvent.VK_O);
+ Main.trans(StringIdGui.MENU_FILE_OPEN), KeyEvent.VK_O);
open.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
*/
private JMenuItem createMenuItemSetCoverForSource() {
JMenuItem open = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_SOURCE),
+ Main.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_SOURCE),
KeyEvent.VK_C);
open.addActionListener(new ActionListener() {
@Override
*/
private JMenuItem createMenuItemSetCoverForAuthor() {
JMenuItem open = new JMenuItem(
- MainFrame.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_AUTHOR),
+ Main.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_AUTHOR),
KeyEvent.VK_A);
open.addActionListener(new ActionListener() {
@Override
import be.nikiroo.fanfix.bundles.StringIdGui;
import be.nikiroo.fanfix.library.BasicLibrary;
-import be.nikiroo.fanfix_swing.gui.MainFrame;
+import be.nikiroo.fanfix_swing.Main;
import be.nikiroo.fanfix_swing.gui.book.BookInfo;
import be.nikiroo.fanfix_swing.gui.search.GRBook.BookActionListener;
import be.nikiroo.utils.ui.WrapLayout;
public void setTitle(String title) {
if (title != null) {
if (title.isEmpty()) {
- title = MainFrame.trans(StringIdGui.MENU_AUTHORS_UNKNOWN);
+ title = Main.trans(StringIdGui.MENU_AUTHORS_UNKNOWN);
}
titleLabel.setText(String.format("<html>"
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.Paragraph;
import be.nikiroo.fanfix.data.Story;
-import be.nikiroo.fanfix_swing.gui.MainFrame;
+import be.nikiroo.fanfix_swing.Main;
import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
import be.nikiroo.fanfix_swing.images.IconGenerator;
import be.nikiroo.fanfix_swing.images.IconGenerator.Icon;
* the {@link Story} to display
*/
public ViewerImages(Story story) {
- setTitle(MainFrame.trans(StringIdGui.TITLE_STORY,
+ setTitle(Main.trans(StringIdGui.TITLE_STORY,
story.getMeta().getLuid(), story.getMeta().getTitle()));
setSize(800, 600);