/* * Kontalk Java client * Copyright (C) 2016 Kontalk Devteam <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.view; import javax.swing.Icon; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import com.alee.extended.panel.GroupPanel; import com.alee.global.StyleConstants; import com.alee.laf.label.WebLabel; import com.alee.laf.panel.WebPanel; import com.alee.laf.rootpane.WebDialog; import com.alee.laf.rootpane.WebFrame; import com.alee.laf.separator.WebSeparator; import com.alee.laf.text.WebTextArea; import com.alee.managers.notification.NotificationIcon; import com.alee.managers.notification.NotificationListener; import com.alee.managers.notification.NotificationManager; import com.alee.managers.notification.NotificationOption; import com.alee.managers.notification.WebNotificationPopup; import com.alee.managers.popup.PopupStyle; import org.kontalk.crypto.Coder; import org.kontalk.crypto.PGPUtils; import org.kontalk.misc.KonException; import org.kontalk.misc.ViewEvent; import org.kontalk.model.Contact; import org.kontalk.model.message.InMessage; import org.kontalk.model.message.KonMessage; import org.kontalk.system.RosterHandler; import org.kontalk.util.MediaUtils; import org.kontalk.util.Tr; /** * Inform user about events. * @author Alexander Bikadorov {@literal <[email protected]>} */ final class Notifier { //private static final Icon NOTIFICATION_ICON = Utils.getIcon("ic_msg_pending.png"); private final View mView; private final WebFrame mWindow; Notifier(View view, WebFrame window) { mView = view; mWindow = window; } void onNewMessage(InMessage newMessage) { if (mView.chatIsVisible(newMessage.getChat())) return; MediaUtils.playSound(MediaUtils.Sound.NOTIFICATION); } void showException(KonException ex) { if (ex.getError() == KonException.Error.LOAD_KEY_DECRYPT) { mView.showPasswordDialog(true); return; } Icon icon = NotificationIcon.error.getIcon(); NotificationManager.showNotification(mWindow, textArea(Utils.getErrorText(ex)), icon); } // TODO more information for message exs void showSecurityErrors(KonMessage message) { //TODO too intrusive for user, but use the explanation for message view if (true) return; String errorText = "<html>"; boolean isOut = !message.isInMessage(); errorText += isOut ? Tr.tr("Encryption error") : Tr.tr("Decryption error"); errorText += ":"; for (Coder.Error error : message.getCoderStatus().getErrors()) { errorText += "<br>"; switch (error) { case UNKNOWN_ERROR: errorText += Tr.tr("Unknown error"); break; case KEY_UNAVAILABLE: errorText += Tr.tr("Public key for receiver not found."); break; case INVALID_PRIVATE_KEY: errorText += Tr.tr("This message was encrypted with an old or invalid public key"); break; default: errorText += Tr.tr("Unusual coder error")+": " + error.toString(); } } errorText += "</html>"; NotificationManager.showNotification(mWindow, errorText); } void showPresenceError(Contact contact, RosterHandler.Error error) { WebPanel panel = panel(Tr.tr("Contact error"), contact); panel.add(new WebLabel(Tr.tr("Error:")).setBoldFont()); String errorText = Tr.tr(error.toString()); switch (error) { case SERVER_NOT_FOUND: errorText = Tr.tr("Server not found"); break; } panel.add(textArea(errorText)); NotificationManager.showNotification(mWindow, panel, NotificationOption.cancel); } void confirmNewKey(final Contact contact, final PGPUtils.PGPCoderKey key) { final boolean overwriting = contact.hasKey(); WebPanel panel = panel(overwriting ? Tr.tr("Received a new public key for contact") : Tr.tr("Public key for contact was found"), contact); panel.add(new WebLabel(Tr.tr("Key fingerprint:"))); WebTextArea fpArea = Utils.createFingerprintArea(); fpArea.setText(Utils.fingerprint(key.fingerprint)); panel.add(fpArea); String expl = overwriting ? Tr.tr("When declining the key, communication with this contact will be blocked.") : Tr.tr("When accepting the key, communication with this contact will be encrypted."); panel.add(textArea(expl)); WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel, NotificationOption.accept, NotificationOption.decline, NotificationOption.cancel); popup.setClickToClose(false); popup.addNotificationListener(new NotificationListener() { @Override public void optionSelected(NotificationOption option) { switch (option) { case accept : mView.getControl().acceptKey(contact, key); break; case decline : if (overwriting) mView.getControl().declineKey(contact); } } @Override public void accepted() {} @Override public void closed() {} }); } void confirmContactDeletion(final Contact contact) { WebPanel panel = panel(Tr.tr("Contact was deleted on server"), contact); String expl = Tr.tr("Remove this contact from your contact list?") + "\n" + mView.tr_remove_contact; panel.add(textArea(expl)); panel.add(textArea(Tr.tr("The reset option will recreate the server entry."))); WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel, NotificationOption.yes, NotificationOption.reset, NotificationOption.cancel); popup.setClickToClose(false); popup.addNotificationListener(new NotificationListener() { @Override public void optionSelected(NotificationOption option) { switch (option) { case yes : mView.getControl().deleteContact(contact); break; case reset: mView.getControl().createRosterEntry(contact); break; } } @Override public void accepted() {} @Override public void closed() {} }); } void confirmSubscription(ViewEvent.SubscriptionRequest event){ final Contact contact = event.contact; WebPanel panel = panel(Tr.tr("Authorization request"), contact); String expl = Tr.tr("When accepting, this contact will be able to see your online status."); panel.add(textArea(expl)); WebNotificationPopup popup = NotificationManager.showNotification(mWindow, panel, NotificationOption.accept, NotificationOption.decline, NotificationOption.cancel); popup.setClickToClose(false); popup.addNotificationListener(new NotificationListener() { @Override public void optionSelected(NotificationOption option) { switch (option) { case accept : mView.getControl().sendSubscriptionResponse(contact, true); break; case decline : mView.getControl().sendSubscriptionResponse(contact, false); } } @Override public void accepted() {} @Override public void closed() {} }); } // TODO not used private void showNotification() { final WebDialog dialog = new WebDialog(); dialog.setUndecorated(true); dialog.setBackground(Color.BLACK); dialog.setBackground(StyleConstants.transparent); WebNotificationPopup popup = new WebNotificationPopup(PopupStyle.dark); popup.setIcon(Utils.getIcon("kontalk_small.png")); popup.setMargin(View.MARGIN_DEFAULT); popup.setDisplayTime(6000); popup.addNotificationListener(new NotificationListener() { @Override public void optionSelected(NotificationOption option) { } @Override public void accepted() { } @Override public void closed() { dialog.dispose(); } }); // content WebPanel panel = new WebPanel(); panel.setMargin(View.MARGIN_DEFAULT); panel.setOpaque(false); WebLabel title = new WebLabel("A new Message!"); title.setFontSize(View.FONT_SIZE_BIG); title.setForeground(Color.WHITE); panel.add(title, BorderLayout.NORTH); String text = "this is some message, and some longer text was added"; WebLabel message = new WebLabel(text); message.setForeground(Color.WHITE); panel.add(message, BorderLayout.CENTER); popup.setContent(panel); //popup.packPopup(); dialog.setSize(popup.getPreferredSize()); // set position on screen GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = gd.getDefaultConfiguration(); Rectangle screenBounds = gc.getBounds(); // get height of the task bar // doesn't work on all environments //Insets toolHeight = toolkit.getScreenInsets(popup.getGraphicsConfiguration()); int toolHeight = 40; dialog.setLocation(screenBounds.width - dialog.getWidth() - 10, screenBounds.height - toolHeight - dialog.getHeight()); dialog.setVisible(true); NotificationManager.showNotification(dialog, popup); } void hideNotifications() { NotificationManager.hideAllNotifications(); } private static WebPanel panel(String title, Contact contact) { WebPanel panel = new GroupPanel(View.GAP_DEFAULT, false); panel.setOpaque(false); panel.add(new WebLabel(title).setBoldFont()); panel.add(new WebSeparator(true, true)); panel.add(new WebLabel(Tr.tr("Contact:")).setBoldFont()); panel.add(new WebLabel(contactText(contact))); return panel; } private static String contactText(Contact contact){ return Utils.name(contact, View.MAX_NAME_IN_NOTIFIER_LENGTH) + " < " + Utils.jid(contact.getJID(), View.MAX_JID_IN_NOTIFIER_LENGTH) + " >"; } private static WebTextArea textArea(String text) { WebTextArea textArea = new WebTextArea(0, 30); textArea.setEditable(false); textArea.setLineWrap(true); textArea.setWrapStyleWord(true); textArea.setText(text); return textArea; } }