content: /**
   * Copyright 2020 Alexander Herzog
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package systemtools;
  
  import java.awt.Component;
  import java.awt.Desktop;
  import java.awt.Toolkit;
  import java.awt.datatransfer.StringSelection;
  import java.io.File;
  import java.io.IOException;
  import java.net.URI;
  import java.net.URL;
  import java.util.Locale;
  
  import javax.swing.Icon;
  import javax.swing.JOptionPane;
  
  import mathtools.distribution.swing.JOpenURL;
  import systemtools.images.SimToolsImages;
  
  /**
   * Diese Klasse stellt einen Ersatz fr {@link JOptionPane} zur Verfgung.<br>
   * Sie stellt einige weitere statische Methoden ("Jetzt speichern?"-Abfrage, berschreib-Warnung)
   * zur Verfgung. Auerdem kann sie ber die statische Methode {@link #setBackend(MsgBoxBackend)}
   * mit alternativen Backends (statt dem Vorgabe-Backend, welches {@link JOptionPane} verwendet)
   * verbunden werden.
   * @author Alexander Herzog
   * @see MsgBoxBackend
   * @version 1.2
   */
  public class MsgBox {
  	/*
  	 * Diese Konstanten knnen von den Anzeige-Backends verwendet werden.<br>
  	 * Auf diese Weise ist eine einfache Internationalisierung mglich.
  	 */
  
  	/** Bezeichner fr den Dialogtitel "Information" */
  	public static String TitleInformation="Information";
  	/** Bezeichner fr den Dialogtitel "Warnung" */
  	public static String TitleWarning="Warnung";
  	/** Bezeichner fr den Dialogtitel "Fehler" */
  	public static String TitleError="Fehler";
  	/** Bezeichner fr den Dialogtitel "Frage" */
  	public static String TitleConfirmation="Frage";
  	/** Bezeichner fr den Dialogtitel "Auswahl" */
  	public static String TitleAlternatives="Auswahl";
  	/** Bezeichner fr die Dialogschaltflche "Ja" */
  	public static String OptionYes="Ja";
  	/** Bezeichner fr die Dialogschaltflche "Nein" */
  	public static String OptionNo="Nein";
  	/** Bezeichner fr die Dialogschaltflche "Abbrechen" */
  	public static String OptionCancel="Abbrechen";
  	/** Bezeichner fr die Dialogschaltflche "Jetzt speichern" */
  	public static String OptionSaveYes="Jetzt speichern";
  	/** Bezeichner fr den Erklrungstext fr die Dialogschaltflche "Jetzt speichern" */
  	public static String OptionSaveYesInfo="Speichert die aktuellen Daten bevor sie verworfen werden.";
  	/** Bezeichner fr die Dialogschaltflche "Nicht speichern" */
  	public static String OptionSaveNo="Nicht speichern";
  	/** Bezeichner fr den Erklrungstext fr die Dialogschaltflche "Nicht speichern" */
  	public static String OptionSaveNoInfo="Verwirft die aktuellen Daten ohne sie vorher zu speichern.";
  	/** Bezeichner fr den Erklrungstext fr die Dialogschaltflche "Abbrechen" (in Bezug auf eine Speichern ja/nein/abbrechen Frage) */
  	public static String OptionSaveCancelInfo="Fhrt den gewhlten Befehl nicht aus. Die Daten bleiben unverndert bestehen.";
  	/** Bezeichner fr den Dialogtitel "berschreiben" */
  	public static String OverwriteTitle="Vorhendene Datei berschreiben?";
  	/** Bezeichner fr die Erklrung zur berschreib-Frage */
  	public static String OverwriteInfo="Die Datei\n%s\nexistiert bereits.\nSoll die Datei jetzt berschrieben werden?";
  	/** Bezeichner fr die Dialogschaltflche "Datei berschreiben" */
  	public static String OverwriteYes="Datei berschreiben";
  	/** Bezeichner fr den Erklrungstext fr die Dialogschaltflche "Datei nicht berschreiben" */
  	public static String OverwriteYesInfo="Lscht die bisher unter diesem Namen existierende Datei und speichert die neuen Daten unter diesem Dateinamen.";
  	/** Bezeichner fr die Dialogschaltflche "Datei nicht berschreiben" */
  	public static String OverwriteNo="Datei nicht berschreiben";
  	/** Bezeichner fr den Erklrungstext fr die Dialogschaltflche "Datei nicht berschreiben" */
  	public static String OverwriteNoInfo="Behlt die bestehende Datei unverndert bei. Die neuen Daten werden nicht gespeichert.";
  	/** Bezeichner fr die Homepage-Aufruf-Erklrung */
  	public static String OpenURLInfo="Mchten Sie jetzt die externe Webseite\n%s\naufrufen?";
  	/** Bezeichner fr die Erklrung der Ja-Schaltflche des Homepage-Aufruf-Dialogs */
  	public static String OpenURLInfoYes="Webseite im Standard-Browser ffnen.";
  	/** Bezeichner fr die Erklrung der Nein-Schaltflche des Homepage-Aufruf-Dialogs */
  	public static String OpenURLInfoNo="Webseite nicht aufrufen.";
  	/** Bezeichner fr die Dialogschaltflche "Adresse kopieren" im Homepage-Aufruf-Dialog */
  	public static String OptionCopyURL="Adresse kopieren";
  	/** Bezeichner fr die Erklrung der "Adresse kopieren"-Schaltflche des Homepage-Aufruf-Dialogs */
  	public static String OptionInfoCopyURL="Adresse nur in Zwischenablage kopieren, Webseite nicht aufrufen.";
  	/** Bezeichner fr den Titel der URL-Fehlermeldung */
  	public static String OpenURLErrorTitle="Keine Internet-Verbindung mglich";
  	/** Bezeichner fr den Inhalt der URL-Fehlermeldung */
  	public static String OpenURLErrorMessage="Die angegebene Adresse\n%s\nkonnte nicht aufgerufen werden.";
  	/** Fr die Dialoge aktuell gltige Landeseinstellung */
  	public static Locale ActiveLocale=Locale.getDefault();
  
  	/**
  	 * Die Klasse {@link MsgBox} besitzt nur statische Methoden und kann
  	 * nicht instanziert werden.
  	 */
  	private MsgBox() {}
  
  	/**
  	 * Zu verwendendes Backend fr die Dialoge
  	 */
  	private static MsgBoxBackend backend;
  
  	static {
  		backend=new MsgBoxBackendJOptionPane();
  
  		JOpenURL.openURI=(parent,uri)->{
  			try {
  				if (!MsgBox.confirmOpenURL(parent,uri.toURL())) return;
  				Desktop.getDesktop().browse(uri);
  			} catch (IOException e) {
  				MsgBox.error(parent,OpenURLErrorTitle,String.format(OpenURLErrorMessage,uri.toString()));
  			}
  		};
  	}
  
  	/**
  	 * Setzt ein neues Backend, welches die Meldungs-Dialoge anzeigt
  	 * @param newBackend	Neues Backend
  	 * @see MsgBoxBackend
  	 */
  	public static void setBackend(final MsgBoxBackend newBackend) {
  		if (newBackend!=null) backend=newBackend;
  	}
  
  	/**
  	 * Zeigt einen Informationsdialog an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Meldung; kann <code>null</code> sein, dann wird "Information" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 */
  	public static void info(Component parentComponent, String title, String message) {
  		if (title==null || title.isEmpty()) title=TitleInformation;
  		backend.info(parentComponent,title,message);
  	}
  
  	/**
  	 * Zeigt einen Warnungdialog an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Meldung; kann <code>null</code> sein, dann wird "Warnung" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 */
  	public static void warning(Component parentComponent, String title, String message) {
  		if (title==null || title.isEmpty()) title=TitleWarning;
  		backend.warning(parentComponent,title,message);
  	}
  
  	/**
  	 * Zeigt eine Fehlermeldung an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Meldung; kann <code>null</code> sein, dann wird "Fehler" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 */
  	public static void error(Component parentComponent, String title, String message) {
  		if (title==null || title.isEmpty()) title=TitleError;
  		backend.error(parentComponent,title,message);
  	}
  
  	/**
  	 * Zeigt einen Ja/Nein/Abbrechen-Dialog an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Anfrage; kann <code>null</code> sein, dann wird "Frage" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 * @param infoYes	Infotext fr die "Ja"-Option (muss nicht von allen Backends verwendet werden)
  	 * @param infoNo	Infotext fr die "Nein"-Option (muss nicht von allen Backends verwendet werden)
  	 * @param infoCancel	Infotext fr die "Abbrechen"-Option (muss nicht von allen Backends verwendet werden)
  	 * @return	Gibt eine der Ja/Nein/Abbrechen-Konstanten aus <code>JOptionPane</code> zurck.
  	 */
  	public static int confirm(Component parentComponent, String title, String message, String infoYes, String infoNo, String infoCancel) {
  		if (title==null || title.isEmpty()) title=TitleConfirmation;
  		return backend.confirm(parentComponent,title,message,infoYes,infoNo,infoCancel);
  	}
  
  	/**
  	 * Zeigt einen "Sollen die nicht gespeicherten Daten jetzt gespeichert werden"-Dialog an; verwendet dafr
  	 * die Ja/Nein/Abbrechen-Schaltflchen.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Anfrage; kann <code>null</code> sein, dann wird "Frage" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 * @return Gibt eine der Ja/Nein/Abbrechen-Konstanten aus <code>JOptionPane</code> zurck.
  	 */
  	public static int confirmSave(Component parentComponent, String title, String message) {
  		if (title==null || title.isEmpty()) title=TitleConfirmation;
  		return backend.confirmSave(parentComponent,title,message);
  	}
  
  	/**
  	 * Zeigt einen Ja/Nein-Dialog an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Anfrage; kann <code>null</code> sein, dann wird "Frage" als Titel verwendet.
  	 * @param message	Anzuzeigende Meldung
  	 * @param infoYes	Infotext fr die "Ja"-Option (muss nicht von allen Backends verwendet werden)
  	 * @param infoNo	Infotext fr die "Nein"-Option (muss nicht von allen Backends verwendet werden)
  	 * @return	Gibt <code>true</code> zurck, wenn der Dialog mit "Ja" geschlossen wurde.
  	 */
  	public static boolean confirm(Component parentComponent, String title, String message, String infoYes, String infoNo) {
  		if (title==null || title.isEmpty()) title=TitleConfirmation;
  		return backend.confirm(parentComponent,title,message,infoYes,infoNo);
  	}
  
  	/**
  	 * Zeigt eine Abfrage an, ob die angegebene Datei berschrieben werden soll
  	 * @param parentComponent	bergeordnetes Element
  	 * @param file	Name der Datei, fr die die Abfrage durchgefhrt werden soll
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem berschreiben zugestimmt hat.
  	 */
  	public static boolean confirmOverwrite(Component parentComponent, File file) {
  		return backend.confirmOverwrite(parentComponent,file);
  	}
  
  	/**
  	 * Ist es zulssig, eine URL zu ffnen?
  	 */
  	public static boolean allowOpenURL=true;
  
  	/**
  	 * Zeigt eine Warnung an, dass eine externe Webseite im Browser geffnet werden soll
  	 * (mit Mglichkeit zum ffnen der Seite)
  	 * @param parentComponent	bergeordnetes Element
  	 * @param url	Aufzurufende URL
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem Aufruf zugestimmt hat.
  	 */
  	private static boolean confirmOpenURLWithOpen(final Component parentComponent, final URL url) {
  		final int result=backend.options(
  				parentComponent,
  				TitleConfirmation,
  				String.format(OpenURLInfo,url.toString()),
  				new String[] {OptionYes,OptionNo,OptionCopyURL},
  				new String[] {OpenURLInfoYes,OpenURLInfoNo,OptionInfoCopyURL},
  				new Icon[] {
  						SimToolsImages.MSGBOX_YES.getIcon(),
  						SimToolsImages.MSGBOX_NO.getIcon(),
  						SimToolsImages.MSGBOX_COPY.getIcon()
  				});
  		switch (result) {
  		case -1: return false;
  		case 0: return true;
  		case 1: return false;
  		case 2: Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(url.toString()),null); return false;
  		default: return false;
  		}
  	}
  
  	/**
  	 * Zeigt eine Warnung an, dass eine externe Webseite im Browser geffnet werden soll
  	 * (ohne Mglichkeit zum ffnen der Seite)
  	 * @param parentComponent	bergeordnetes Element
  	 * @param url	Aufzurufende URL
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem Aufruf zugestimmt hat.
  	 */
  	private static boolean confirmOpenURLWithoutOpen(final Component parentComponent, final URL url) {
  		final int result=backend.options(
  				parentComponent,
  				TitleConfirmation,
  				String.format(OpenURLInfo,url.toString()),
  				new String[] {OptionNo,OptionCopyURL},
  				new String[] {OpenURLInfoNo,OptionInfoCopyURL},
  				new Icon[] {
  						SimToolsImages.MSGBOX_NO.getIcon(),
  						SimToolsImages.MSGBOX_COPY.getIcon()
  				});
  		switch (result) {
  		case -1: return false;
  		case 0: return false;
  		case 1: Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(url.toString()),null); return false;
  		default: return false;
  		}
  	}
  
  	/**
  	 * Zeigt eine Warnung an, dass eine externe Webseite im Browser geffnet werden soll
  	 * @param parentComponent	bergeordnetes Element
  	 * @param url	Aufzurufende URL
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem Aufruf zugestimmt hat.
  	 */
  	public static boolean confirmOpenURL(final Component parentComponent, final URL url) {
  		if (allowOpenURL) {
  			return confirmOpenURLWithOpen(parentComponent,url);
  		} else {
  			return confirmOpenURLWithoutOpen(parentComponent,url);
  		}
  	}
  
  	/**
  	 * Zeigt eine Warnung an, dass eine externe Webseite im Browser geffnet werden soll
  	 * @param parentComponent	bergeordnetes Element
  	 * @param uri	Aufzurufende URL
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem Aufruf zugestimmt hat.
  	 */
  	public static boolean confirmOpenURL(Component parentComponent, URI uri) {
  		final int result=backend.options(
  				parentComponent,
  				TitleConfirmation,
  				String.format(OpenURLInfo,uri.toString()),
  				new String[] {OptionYes,OptionNo,OptionCopyURL},
  				new String[] {OpenURLInfoYes,OpenURLInfoNo,OptionInfoCopyURL},
  				new Icon[] {
  						SimToolsImages.MSGBOX_YES.getIcon(),
  						SimToolsImages.MSGBOX_NO.getIcon(),
  						SimToolsImages.MSGBOX_COPY.getIcon()
  				});
  		switch (result) {
  		case -1: return false;
  		case 0: return true;
  		case 1: return false;
  		case 2: Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(uri.toString()),null); return false;
  		default: return false;
  		}
  	}
  
  	/**
  	 * Zeigt eine Warnung an, dass eine externe Webseite im Browser geffnet werden soll
  	 * @param parentComponent	bergeordnetes Element
  	 * @param url	Aufzurufende URL
  	 * @return	Gibt <code>true</code> zurck, wenn der Nutzer dem Aufruf zugestimmt hat.
  	 */
  	public static boolean confirmOpenURL(Component parentComponent, String url) {
  		final int result=backend.options(
  				parentComponent,
  				TitleConfirmation,
  				String.format(OpenURLInfo,url),
  				new String[] {OptionYes,OptionNo,OptionCopyURL},
  				new String[] {OpenURLInfoYes,OpenURLInfoNo,OptionInfoCopyURL},
  				new Icon[] {
  						SimToolsImages.MSGBOX_YES.getIcon(),
  						SimToolsImages.MSGBOX_NO.getIcon(),
  						SimToolsImages.MSGBOX_COPY.getIcon()
  				});
  		switch (result) {
  		case -1: return false;
  		case 0: return true;
  		case 1: return false;
  		case 2: Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(url),null); return false;
  		default: return false;
  		}
  	}
  
  	/**
  	 * Zeigt einen Auswahldialog mit verschiedenen Optionen an.
  	 * @param parentComponent	bergeordnetes Element
  	 * @param title	Titel der Anfrage
  	 * @param message	Anzuzeigende Meldung
  	 * @param options	Texte zu den Optionen
  	 * @param info	Erklrungen zu den Texten zu den Optionen
  	 * @return	Gewhlte Option (0-basierend); -1 fr Abbruch
  	 */
  	public static int options(Component parentComponent, String title, String message, String[] options, String[] info) {
  		return backend.options(parentComponent,title,message,options,info,null);
  	}
  
  }