aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/sip/communicator/plugin')
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/AdvancedConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/advancedconfig/AdvancedConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/advancedconfig/advancedconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/aimaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/aimaccregwizz/aimaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/branding/AboutWindow.java7
-rw-r--r--src/net/java/sip/communicator/plugin/branding/JitsiWarningWindow.java2
-rw-r--r--src/net/java/sip/communicator/plugin/branding/WelcomeWindow.java2
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/branding/branding.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/plugin/certconfig/CertConfigEntryDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/certconfig/CertConfigPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/certconfig/certconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/chatconfig/ChatConfigActivator.java2
-rw-r--r--src/net/java/sip/communicator/plugin/chatconfig/ChatConfigPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/chatconfig/chatconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/chatconfig/replacement/ReplacementConfigPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/contactinfo/ContactInfoContactPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDetailsPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/contactinfo/contactinfo.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/contactsourceconfig/ContactSourceConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/contactsourceconfig/contactsourceconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/AntialiasingManager.java32
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/AuthenticationWindow.java742
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ComponentMover.java108
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ComponentUtils.java139
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java177
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/EmphasizedLabel.java104
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ErrorDialog.java381
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ExtendedTooltip.java392
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ExtendedTransferHandler.java468
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FadeInBalloonPanel.java190
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FileDragLabel.java206
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java189
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java279
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/GenericFileDialog.java100
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ImageCanvas.java91
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ImageUtils.java449
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/LightGrayFilter.java49
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/LowPriorityEventQueue.java53
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/MasterPasswordInputDialog.java296
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/MoveableTableModel.java25
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/NetworkUtils.java1661
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/OrderedComponent.java28
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/OrderedTransparentPanel.java66
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/PasswordChangeDialog.java385
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/PopupNotificationPanel.java158
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/PriorityTable.java170
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommButton.java454
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommCheckBox.java48
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommDialog.java446
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommFrame.java835
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommHTMLEditorKit.java214
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommLinkButton.java279
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenu.java308
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenuBar.java71
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommPopupMenu.java67
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommRadioButton.java48
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommScrollPane.java236
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommTabbedPane.java512
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextButton.java279
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextField.java287
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SIPCommToggleButton.java444
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/ScreenInformation.java68
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SelectedObject.java80
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooser.java99
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooserImpl.java163
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SipCommFileDialogImpl.java162
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SipCommFileFilter.java52
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SoundLevelIndicator.java402
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/StyledHTMLEditorPane.java108
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/SwingWorker.java229
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/TransparentPanel.java30
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/TrimTextField.java36
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/UIAction.java26
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/WindowUtils.java158
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/X509CertificatePanel.java423
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/border/ExtendedEtchedBorder.java127
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf64
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/ConfigurableDnssecResolver.java356
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/DnsUtilActivator.java181
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecException.java30
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecRuntimeException.java35
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/ParallelResolver.java694
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/SecureMessage.java93
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/SecureResolveMode.java43
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundApi.java228
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundException.java31
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResolver.java384
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResult.java117
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/dns/desktoputil.dns.manifest.mf19
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/event/CloseListener.java22
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/event/DoubleClickListener.java22
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/event/MaxListener.java22
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/event/PopupOutsideListener.java22
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/event/TextFieldChangeListener.java27
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommLinkButtonUI.java75
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommMenuBarUI.java33
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneEnhancedUI.java477
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneUI.java1770
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTextFieldUI.java513
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTreeUI.java258
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/transparent/AWTUtilitiesWrapper.java161
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/transparent/TransparentFrame.java102
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsPanel.java227
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsRegistration.java41
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/EncryptionConfigurationTableModel.java223
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityAccountRegistration.java253
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java591
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java2
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/dictaccregwizz/ProgressPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/dnsconfig/DnsContainerPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/dnsconfig/DnssecPanel.java7
-rw-r--r--src/net/java/sip/communicator/plugin/dnsconfig/DnssecTableModel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/dnsconfig/ParallelDnsPanel.java30
-rw-r--r--src/net/java/sip/communicator/plugin/dnsconfig/dnsconfig.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/plugin/exampleplugin/PluginDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/exampleplugin/exampleplugin.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/facebookaccregwizz/facebookaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/OpusConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/SIPConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/SilkConfigForm.java4
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/autoaway/AutoAwayConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/gibberishaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/gibberishaccregwizz/gibberishaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/globalproxyconfig/GlobalProxyConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/globalproxyconfig/globalproxyconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/googletalkaccregwizz/googletalkaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/icqaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/icqaccregwizz/icqaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/ippiaccregwizz/CreateIppiAccountForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/ippiaccregwizz/ippiaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/iptelaccregwizz/iptelaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/ircaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/ircaccregwizz/ircaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/AccountPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/ConnectionPanel.java3
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/IceConfigPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountCreationForm.java2
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistration.java2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java4
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberServerChooserDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/jabberaccregwizz/TelephonyConfigPanel.java2
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/jabberaccregwizz/jabberaccregwizz.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/KeybindingsConfigPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingChooser.java2
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingEntry.java2
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutDialog.java4
-rw-r--r--src/net/java/sip/communicator/plugin/keybindingchooser/keybindingChooser.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/configform/DirectorySettingsForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/configform/LdapConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/loggingutils/loggingutils.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/msnaccregwizz/FirstWizardPage.java2
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/msnaccregwizz/msnaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/notificationconfiguration/NotificationConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/notificationconfiguration/SoundFilter.java2
-rw-r--r--src/net/java/sip/communicator/plugin/notificationconfiguration/notificationconfiguration.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java1
-rw-r--r--src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrMetaContactMenu.java2
-rw-r--r--src/net/java/sip/communicator/plugin/otr/otr.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java2
-rw-r--r--src/net/java/sip/communicator/plugin/pluginmanager/PluginManagerPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/pluginmanager/pluginmanager.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/provisioning/ProvisioningForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java2
-rw-r--r--src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/rssaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/rssaccregwizz/rssaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/SecurityConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/masterpassword/ConfigurationPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordChangeDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/securityconfig/securityconfig.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/simpleaccreg/InitialAccountRegistrationFrame.java2
-rw-r--r--src/net/java/sip/communicator/plugin/simpleaccreg/simpleaccreg.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/sip2sipaccregwizz/CreateSip2SipAccountForm.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sip2sipaccregwizz/sip2sipaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/AccountPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java3
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java4
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/sipaccregwizz.manifest.mf4
-rw-r--r--src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/skinmanager/SkinSelectionListener.java2
-rw-r--r--src/net/java/sip/communicator/plugin/skinmanager/SkinSelectorRenderer.java2
-rw-r--r--src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java4
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/sshaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/update/Update.java2
-rw-r--r--src/net/java/sip/communicator/plugin/update/update.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/gui/InvitationReceivedDialog.java2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFileFilter.java2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFrame.java2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardPanel.java2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/gui/whiteboardshapes/WhiteboardShape.java2
-rw-r--r--src/net/java/sip/communicator/plugin/whiteboard/whiteboard.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/yahooaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/yahooaccregwizz/yahooaccregwizz.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/zeroconfaccregwizz/FirstWizardPage.java2
-rw-r--r--src/net/java/sip/communicator/plugin/zeroconfaccregwizz/zeroconfaccregwizz.manifest.mf2
228 files changed, 20913 insertions, 171 deletions
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
index 4425f92..b5eaa11 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
@@ -14,6 +14,7 @@ import java.util.*;
import javax.imageio.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BinaryDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BirthDateDetail;
@@ -26,7 +27,6 @@ import net.java.sip.communicator.service.protocol.ServerStoredDetails.MiddleName
import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The right side panel of AccountDetailsDialog. Shows one tab of a summary of
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
index 700a45b..99d8c40 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
@@ -10,9 +10,9 @@ import java.util.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf b/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
index e329076..3426abd 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
@@ -14,7 +14,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/addrbook/AdvancedConfigForm.java b/src/net/java/sip/communicator/plugin/addrbook/AdvancedConfigForm.java
index 7872636..5bd25c1 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/AdvancedConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/addrbook/AdvancedConfigForm.java
@@ -12,7 +12,7 @@ import javax.swing.*;
import net.java.sip.communicator.plugin.addrbook.macosx.*;
import net.java.sip.communicator.plugin.addrbook.msoutlook.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf b/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf
index ee9e92d..47b6cc1 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf
@@ -11,6 +11,6 @@ Import-Package: javax.swing,
net.java.sip.communicator.service.protocol,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
org.osgi.framework
System-Bundle: yes
diff --git a/src/net/java/sip/communicator/plugin/advancedconfig/AdvancedConfigurationPanel.java b/src/net/java/sip/communicator/plugin/advancedconfig/AdvancedConfigurationPanel.java
index f209d39..ae79138 100644
--- a/src/net/java/sip/communicator/plugin/advancedconfig/AdvancedConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/advancedconfig/AdvancedConfigurationPanel.java
@@ -11,9 +11,9 @@ import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/advancedconfig/advancedconfig.manifest.mf b/src/net/java/sip/communicator/plugin/advancedconfig/advancedconfig.manifest.mf
index b0065cf..b6e84bb 100644
--- a/src/net/java/sip/communicator/plugin/advancedconfig/advancedconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/advancedconfig/advancedconfig.manifest.mf
@@ -14,7 +14,7 @@ Import-Package: org.osgi.framework,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/aimaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/aimaccregwizz/FirstWizardPage.java
index 92ce0f4..3ae8f22 100644
--- a/src/net/java/sip/communicator/plugin/aimaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/aimaccregwizz/FirstWizardPage.java
@@ -11,9 +11,9 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
diff --git a/src/net/java/sip/communicator/plugin/aimaccregwizz/aimaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/aimaccregwizz/aimaccregwizz.manifest.mf
index d71dd91..956d6c1 100644
--- a/src/net/java/sip/communicator/plugin/aimaccregwizz/aimaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/aimaccregwizz/aimaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/branding/AboutWindow.java b/src/net/java/sip/communicator/plugin/branding/AboutWindow.java
index 47ba575..3b8958f 100644
--- a/src/net/java/sip/communicator/plugin/branding/AboutWindow.java
+++ b/src/net/java/sip/communicator/plugin/branding/AboutWindow.java
@@ -14,13 +14,12 @@ import javax.imageio.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.service.browserlauncher.*;
import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
import net.java.sip.communicator.util.skin.*;
-import net.java.sip.communicator.util.swing.*;
-import net.java.sip.communicator.util.swing.plaf.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
@@ -266,7 +265,7 @@ public class AboutWindow
"close");
}
- GuiUtils.addWindow(this);
+ WindowUtils.addWindow(this);
}
/**
diff --git a/src/net/java/sip/communicator/plugin/branding/JitsiWarningWindow.java b/src/net/java/sip/communicator/plugin/branding/JitsiWarningWindow.java
index b072869..c94457d 100644
--- a/src/net/java/sip/communicator/plugin/branding/JitsiWarningWindow.java
+++ b/src/net/java/sip/communicator/plugin/branding/JitsiWarningWindow.java
@@ -11,8 +11,8 @@ import java.awt.event.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.browserlauncher.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/branding/WelcomeWindow.java b/src/net/java/sip/communicator/plugin/branding/WelcomeWindow.java
index 345546b..2692799 100644
--- a/src/net/java/sip/communicator/plugin/branding/WelcomeWindow.java
+++ b/src/net/java/sip/communicator/plugin/branding/WelcomeWindow.java
@@ -14,7 +14,7 @@ import java.io.*;
import javax.imageio.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/branding/branding.manifest.mf b/src/net/java/sip/communicator/plugin/branding/branding.manifest.mf
index 659f89d..73f314f 100755
--- a/src/net/java/sip/communicator/plugin/branding/branding.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/branding/branding.manifest.mf
@@ -13,8 +13,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
- net.java.sip.communicator.util.swing.plaf,
+ net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.plaf,
net.java.sip.communicator.util.skin,
javax.swing,
javax.swing.event,
diff --git a/src/net/java/sip/communicator/plugin/certconfig/CertConfigEntryDialog.java b/src/net/java/sip/communicator/plugin/certconfig/CertConfigEntryDialog.java
index c2f9e4c..aa9e9dd 100644
--- a/src/net/java/sip/communicator/plugin/certconfig/CertConfigEntryDialog.java
+++ b/src/net/java/sip/communicator/plugin/certconfig/CertConfigEntryDialog.java
@@ -18,9 +18,9 @@ import javax.security.auth.callback.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/certconfig/CertConfigPanel.java b/src/net/java/sip/communicator/plugin/certconfig/CertConfigPanel.java
index c6e12c7..4e631c2 100644
--- a/src/net/java/sip/communicator/plugin/certconfig/CertConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/certconfig/CertConfigPanel.java
@@ -14,9 +14,9 @@ import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/certconfig/certconfig.manifest.mf b/src/net/java/sip/communicator/plugin/certconfig/certconfig.manifest.mf
index e58c0bd..58ca8f4 100644
--- a/src/net/java/sip/communicator/plugin/certconfig/certconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/certconfig/certconfig.manifest.mf
@@ -13,7 +13,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.border,
javax.swing.event,
diff --git a/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigActivator.java b/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigActivator.java
index 16f7db7..7e19374 100644
--- a/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigActivator.java
+++ b/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigActivator.java
@@ -10,11 +10,11 @@ import java.util.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.replacement.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigPanel.java b/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigPanel.java
index faf91c3..4656c7d 100644
--- a/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/chatconfig/ChatConfigPanel.java
@@ -10,7 +10,7 @@ import java.awt.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.chatconfig.replacement.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The chat configuration panel.
diff --git a/src/net/java/sip/communicator/plugin/chatconfig/chatconfig.manifest.mf b/src/net/java/sip/communicator/plugin/chatconfig/chatconfig.manifest.mf
index f332b74..a503b1c 100644
--- a/src/net/java/sip/communicator/plugin/chatconfig/chatconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/chatconfig/chatconfig.manifest.mf
@@ -10,7 +10,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.service.replacement,
javax.swing,
javax.swing.event,
diff --git a/src/net/java/sip/communicator/plugin/chatconfig/replacement/ReplacementConfigPanel.java b/src/net/java/sip/communicator/plugin/chatconfig/replacement/ReplacementConfigPanel.java
index 7ea8e9d..e4c1d3e 100644
--- a/src/net/java/sip/communicator/plugin/chatconfig/replacement/ReplacementConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/chatconfig/replacement/ReplacementConfigPanel.java
@@ -15,8 +15,8 @@ import javax.swing.table.*;
import net.java.sip.communicator.impl.replacement.smiley.*;
import net.java.sip.communicator.plugin.chatconfig.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.replacement.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
diff --git a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoContactPanel.java b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoContactPanel.java
index b570b77..3783346 100644
--- a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoContactPanel.java
+++ b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoContactPanel.java
@@ -11,8 +11,8 @@ import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The left side panel of ContactInfoDialog. Display all associated subcontacts
diff --git a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDetailsPanel.java b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDetailsPanel.java
index e0bdf90..1e2ba22 100644
--- a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDetailsPanel.java
+++ b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDetailsPanel.java
@@ -15,6 +15,7 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.html.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BinaryDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BirthDateDetail;
@@ -29,7 +30,6 @@ import net.java.sip.communicator.service.protocol.ServerStoredDetails.MiddleName
import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.TimeZoneDetail;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The right side panel of ContactInfoDialog. Shows one tab of a summary of
diff --git a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDialog.java b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDialog.java
index 0e8075d..69ed2eb 100644
--- a/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDialog.java
+++ b/src/net/java/sip/communicator/plugin/contactinfo/ContactInfoDialog.java
@@ -9,9 +9,9 @@ package net.java.sip.communicator.plugin.contactinfo;
import java.awt.*;
import java.util.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* A GUI plug-in for SIP Communicator that will allow cross protocol contact
diff --git a/src/net/java/sip/communicator/plugin/contactinfo/contactinfo.manifest.mf b/src/net/java/sip/communicator/plugin/contactinfo/contactinfo.manifest.mf
index 09bf6c1..b1ec3ca 100644
--- a/src/net/java/sip/communicator/plugin/contactinfo/contactinfo.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/contactinfo/contactinfo.manifest.mf
@@ -13,7 +13,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/contactsourceconfig/ContactSourceConfigForm.java b/src/net/java/sip/communicator/plugin/contactsourceconfig/ContactSourceConfigForm.java
index 77984f7..8fb25e4 100644
--- a/src/net/java/sip/communicator/plugin/contactsourceconfig/ContactSourceConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/contactsourceconfig/ContactSourceConfigForm.java
@@ -10,8 +10,8 @@ import java.awt.event.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/contactsourceconfig/contactsourceconfig.manifest.mf b/src/net/java/sip/communicator/plugin/contactsourceconfig/contactsourceconfig.manifest.mf
index 0814977..e60f6bd 100644
--- a/src/net/java/sip/communicator/plugin/contactsourceconfig/contactsourceconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/contactsourceconfig/contactsourceconfig.manifest.mf
@@ -7,7 +7,7 @@ Import-Package: net.java.sip.communicator.service.contactsource,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.util,
net.java.sip.communicator.service.gui,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
org.jitsi.service.configuration,
org.osgi.framework,
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/AntialiasingManager.java b/src/net/java/sip/communicator/plugin/desktoputil/AntialiasingManager.java
new file mode 100644
index 0000000..bc0b2fd
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/AntialiasingManager.java
@@ -0,0 +1,32 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+/**
+ * Through the <tt>AntialiasingManager</tt> the developer could activate the
+ * antialiasing mechanism when painting. The method that do the job is
+ * the <code>activateAntialiasing</code> method. It takes a <tt>Graphics</tt>
+ * object and activates the antialiasing for it.
+ *
+ * @author Yana Stamcheva
+ */
+public class AntialiasingManager
+{
+
+ /**
+ * Activates the antialiasing mechanism for the given <tt>Graphics</tt>
+ * object.
+ * @param g The <tt>Graphics</tt> object.
+ */
+ public static void activateAntialiasing(Graphics g)
+ {
+ ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/AuthenticationWindow.java b/src/net/java/sip/communicator/plugin/desktoputil/AuthenticationWindow.java
new file mode 100644
index 0000000..07eefc0
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/AuthenticationWindow.java
@@ -0,0 +1,742 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.Logger;
+
+import org.jitsi.util.*;
+
+/**
+ * The <tt>AuthenticationWindow</tt> is the window where the user should type
+ * his user identifier and password to login.
+ *
+ * @author Yana Stamcheva
+ */
+public class AuthenticationWindow
+ extends SIPCommDialog
+ implements ActionListener
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Used for logging.
+ */
+ private static Logger logger = Logger.getLogger(AuthenticationWindow.class);
+
+ /**
+ * Info text area.
+ */
+ private final JTextArea infoTextArea = new JTextArea();
+
+ /**
+ * The uin component.
+ */
+ private JComponent uinValue;
+
+ /**
+ * The password field.
+ */
+ private final JPasswordField passwdField = new JPasswordField(15);
+
+ /**
+ * The login button.
+ */
+ private final JButton loginButton = new JButton(
+ DesktopUtilActivator.getResources().getI18NString("service.gui.OK"));
+
+ /**
+ * The cancel button.
+ */
+ private final JButton cancelButton = new JButton(
+ DesktopUtilActivator.getResources().getI18NString("service.gui.CANCEL"));
+
+ /**
+ * The check box indicating if the password should be remembered.
+ */
+ private final JCheckBox rememberPassCheckBox = new SIPCommCheckBox(
+ DesktopUtilActivator.getResources()
+ .getI18NString("service.gui.REMEMBER_PASSWORD"),
+ DesktopUtilActivator.getConfigurationService()
+ .getBoolean(PNAME_SAVE_PASSWORD_TICKED, false));
+
+ /**
+ * Property to disable/enable allow save password option
+ * in authentication window. By default it is enabled.
+ */
+ private static final String PNAME_ALLOW_SAVE_PASSWORD =
+ "net.java.sip.communicator.util.swing.auth.ALLOW_SAVE_PASSWORD";
+
+ /**
+ * Property to set whether the save password option in
+ * the authentication window is ticked by default or not.
+ * By default it is not ticked
+ */
+ private static final String PNAME_SAVE_PASSWORD_TICKED =
+ "net.java.sip.communicator.util.swing.auth.SAVE_PASSWORD_TICKED";
+
+ /**
+ * The name of the server, for which this authentication window is about.
+ */
+ private String server;
+
+ /**
+ * The user name.
+ */
+ private String userName;
+
+ /**
+ * The password.
+ */
+ private char[] password;
+
+ /**
+ * Indicates if the password should be remembered.
+ */
+ private boolean isRememberPassword = false;
+
+ /**
+ * Indicates if the window has been canceled.
+ */
+ private boolean isCanceled = false;
+
+ /**
+ * A lock used to synchronize data setting.
+ */
+ private final Object lock = new Object();
+
+ /**
+ * The condition that decides whether to continue waiting for data.
+ */
+ private boolean buttonClicked = false;
+
+ /**
+ * Used to override default Authentication window title.
+ */
+ private String windowTitle = null;
+
+ /**
+ * Used to override default window text.
+ */
+ private String windowText = null;
+
+ /**
+ * Used to override username label text.
+ */
+ private String usernameLabelText = null;
+
+ /**
+ * Used to override password label text.
+ */
+ private String passwordLabelText = null;
+
+ /**
+ * The sign up link if specified.
+ */
+ private String signupLink = null;
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param server the server name
+ * @param isUserNameEditable indicates if the user name is editable
+ * @param icon the icon to display on the left of the authentication window
+ */
+ public AuthenticationWindow(String server,
+ boolean isUserNameEditable,
+ ImageIcon icon)
+ {
+ this(null, null, server, isUserNameEditable, false,
+ icon, null, null, null, null, null, null);
+ }
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param server the server name
+ * @param isUserNameEditable indicates if the user name is editable
+ * @param icon the icon to display on the left of the authentication window
+ * @param windowTitle customized window title
+ * @param windowText customized window text
+ * @param usernameLabelText customized username field label text
+ * @param passwordLabelText customized password field label text
+ * @param errorMessage an error message if this dialog is shown to indicate
+ * the user that something went wrong
+ * @param signupLink an URL that allows the user to sign up
+ */
+ private AuthenticationWindow(String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ boolean isRememberPassword,
+ ImageIcon icon,
+ String windowTitle,
+ String windowText,
+ String usernameLabelText,
+ String passwordLabelText,
+ String errorMessage,
+ String signupLink)
+ {
+ super(false);
+
+ this.windowTitle = windowTitle;
+ this.windowText = windowText;
+ this.usernameLabelText = usernameLabelText;
+ this.passwordLabelText = passwordLabelText;
+ this.isRememberPassword = isRememberPassword;
+ this.signupLink = signupLink;
+
+ init(userName, password, server, isUserNameEditable, icon, errorMessage);
+ }
+
+ /**
+ * Initializes this authentication window.
+ *
+ * @param server the server
+ * @param isUserNameEditable indicates if the user name is editable
+ * @param icon the icon to show on the authentication window
+ */
+ private void init( String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ ImageIcon icon,
+ String errorMessage)
+ {
+ this.server = server;
+
+ initIcon(icon);
+
+ if(!isUserNameEditable)
+ this.uinValue = new JLabel();
+ else
+ this.uinValue = new JTextField();
+
+ this.init();
+
+ this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+ this.enableKeyActions();
+
+ this.setResizable(false);
+
+ /*
+ * Workaround for the following bug:
+ * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4446522
+ * Need to pack() the window after it's opened in order to obtain the
+ * correct size of our infoTextArea, otherwise window size is wrong and
+ * buttons on the south are cut.
+ */
+ this.addWindowListener(new WindowAdapter()
+ {
+ public void windowOpened(WindowEvent e)
+ {
+ pack();
+ removeWindowListener(this);
+ }
+ });
+
+ if (OSUtils.IS_MAC)
+ getRootPane()
+ .putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE);
+
+ if (userName != null)
+ {
+ if (uinValue instanceof JLabel)
+ ((JLabel) uinValue).setText(userName);
+ else if (uinValue instanceof JTextField)
+ ((JTextField) uinValue).setText(userName);
+ }
+
+ if (password != null)
+ passwdField.setText(new String(password));
+
+ if(errorMessage != null)
+ {
+ this.infoTextArea.setForeground(Color.RED);
+ this.infoTextArea.setText(errorMessage);
+ }
+ }
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param userName the user name to set by default
+ * @param password the password to set by default
+ * @param server the server name this authentication window is about
+ * @param isUserNameEditable indicates if the user name should be editable
+ * by the user or not
+ * @param icon the icon displayed on the left of the authentication window
+ * @param errorMessage an error message explaining a reason for opening
+ * the authentication dialog (when a wrong password was provided, etc.)
+ */
+ public AuthenticationWindow(String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ ImageIcon icon,
+ String errorMessage)
+ {
+ this(userName, password, server,
+ isUserNameEditable,
+ false,
+ icon, null, null, null, null, errorMessage, null);
+ }
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param userName the user name to set by default
+ * @param password the password to set by default
+ * @param server the server name this authentication window is about
+ * @param isUserNameEditable indicates if the user name should be editable
+ * by the user or not
+ * @param icon the icon displayed on the left of the authentication window
+ * @param errorMessage an error message explaining a reason for opening
+ * the authentication dialog (when a wrong password was provided, etc.)
+ * @param signupLink an URL that allows the user to sign up
+ */
+ public AuthenticationWindow(String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ ImageIcon icon,
+ String errorMessage,
+ String signupLink)
+ {
+ this(userName, password, server,
+ isUserNameEditable,
+ false,
+ icon, null, null, null, null, errorMessage, signupLink);
+ }
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param userName the user name to set by default
+ * @param password the password to set by default
+ * @param server the server name this authentication window is about
+ * @param isUserNameEditable indicates if the user name should be editable
+ * by the user or not
+ * @param icon the icon displayed on the left of the authentication window
+ */
+ public AuthenticationWindow(
+ String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ ImageIcon icon)
+ {
+ this(userName, password, server, isUserNameEditable, icon, null, null);
+ }
+
+ /**
+ * Creates an instance of the <tt>LoginWindow</tt>.
+ *
+ * @param owner the owner of this dialog
+ * @param userName the user name to set by default
+ * @param password the password to set by default
+ * @param server the server name this authentication window is about
+ * @param isUserNameEditable indicates if the user name should be editable
+ * by the user or not
+ * @param icon the icon displayed on the left of the authentication window
+ */
+ public AuthenticationWindow(
+ Dialog owner,
+ String userName,
+ char[] password,
+ String server,
+ boolean isUserNameEditable,
+ ImageIcon icon)
+ {
+ super(owner, false);
+
+ init(userName, password, server, isUserNameEditable, icon, null);
+ }
+
+ /**
+ * Shows or hides the "save password" checkbox.
+ * @param allow the checkbox is shown when allow is <tt>true</tt>
+ */
+ public void setAllowSavePassword(boolean allow)
+ {
+ rememberPassCheckBox.setVisible(allow);
+ }
+
+ /**
+ * Initializes the icon image.
+ *
+ * @param icon the icon to show on the left of the window
+ */
+ private void initIcon(ImageIcon icon)
+ {
+ // If an icon isn't provided set the application logo icon by default.
+ if (icon == null)
+ icon = DesktopUtilActivator.getResources()
+ .getImage("service.gui.SIP_COMMUNICATOR_LOGO_64x64");
+
+ JLabel iconLabel = new JLabel(icon);
+
+ iconLabel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+
+ iconLabel.setAlignmentY(Component.TOP_ALIGNMENT);
+
+ JPanel iconPanel = new TransparentPanel(new BorderLayout());
+ iconPanel.add(iconLabel, BorderLayout.NORTH);
+
+ getContentPane().add(iconPanel, BorderLayout.WEST);
+ }
+
+ /**
+ * Constructs the <tt>LoginWindow</tt>.
+ */
+ private void init()
+ {
+ String title;
+
+ if(windowTitle != null)
+ title = windowTitle;
+ else
+ title = DesktopUtilActivator.getResources().getI18NString(
+ "service.gui.AUTHENTICATION_WINDOW_TITLE", new String[]{server});
+
+ String text;
+ if(windowText != null)
+ text = windowText;
+ else
+ text = DesktopUtilActivator.getResources().getI18NString(
+ "service.gui.AUTHENTICATION_REQUESTED_SERVER",
+ new String[]{server});
+
+ String uinText;
+ if(usernameLabelText != null)
+ uinText = usernameLabelText;
+ else
+ uinText = DesktopUtilActivator.getResources().getI18NString(
+ "service.gui.IDENTIFIER");
+
+ String passText;
+ if(passwordLabelText != null)
+ passText = passwordLabelText;
+ else
+ passText = DesktopUtilActivator.getResources().getI18NString(
+ "service.gui.PASSWORD");
+
+ setTitle(title);
+
+ infoTextArea.setEditable(false);
+ infoTextArea.setOpaque(false);
+ infoTextArea.setLineWrap(true);
+ infoTextArea.setWrapStyleWord(true);
+ infoTextArea.setFont(
+ infoTextArea.getFont().deriveFont(Font.BOLD));
+ infoTextArea.setText(text);
+ infoTextArea.setAlignmentX(0.5f);
+
+ JLabel uinLabel = new JLabel(uinText);
+ uinLabel.setFont(uinLabel.getFont().deriveFont(Font.BOLD));
+
+ JLabel passwdLabel = new JLabel(passText);
+ passwdLabel.setFont(passwdLabel.getFont().deriveFont(Font.BOLD));
+
+ TransparentPanel labelsPanel
+ = new TransparentPanel(new GridLayout(0, 1, 8, 8));
+
+ labelsPanel.add(uinLabel);
+ labelsPanel.add(passwdLabel);
+
+ TransparentPanel textFieldsPanel
+ = new TransparentPanel(new GridLayout(0, 1, 8, 8));
+
+ textFieldsPanel.add(uinValue);
+ textFieldsPanel.add(passwdField);
+
+ JPanel southFieldsPanel = new TransparentPanel(new GridLayout(1, 2));
+
+ this.rememberPassCheckBox.setOpaque(false);
+ this.rememberPassCheckBox.setBorder(null);
+
+ southFieldsPanel.add(rememberPassCheckBox);
+ if (signupLink != null && signupLink.length() > 0)
+ southFieldsPanel.add(createWebSignupLabel(
+ DesktopUtilActivator.getResources().getI18NString(
+ "plugin.simpleaccregwizz.SIGNUP"), signupLink));
+ else
+ southFieldsPanel.add(new JLabel());
+
+ boolean allowRememberPassword = true;
+
+ String allowRemPassStr = DesktopUtilActivator.getResources().getSettingsString(
+ PNAME_ALLOW_SAVE_PASSWORD);
+ if(allowRemPassStr != null)
+ {
+ allowRememberPassword = Boolean.parseBoolean(allowRemPassStr);
+ }
+ allowRememberPassword = DesktopUtilActivator.getConfigurationService()
+ .getBoolean(PNAME_ALLOW_SAVE_PASSWORD, allowRememberPassword);
+
+ setAllowSavePassword(allowRememberPassword);
+
+ JPanel buttonPanel
+ = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
+
+ buttonPanel.add(loginButton);
+ buttonPanel.add(cancelButton);
+
+ JPanel southEastPanel = new TransparentPanel(new BorderLayout());
+ southEastPanel.add(buttonPanel, BorderLayout.EAST);
+
+ TransparentPanel mainPanel
+ = new TransparentPanel(new BorderLayout(10, 10));
+
+ mainPanel.setBorder(
+ BorderFactory.createEmptyBorder(20, 0, 20, 20));
+
+ JPanel mainFieldsPanel = new TransparentPanel(new BorderLayout(0, 10));
+ mainFieldsPanel.add(labelsPanel, BorderLayout.WEST);
+ mainFieldsPanel.add(textFieldsPanel, BorderLayout.CENTER);
+ mainFieldsPanel.add(southFieldsPanel, BorderLayout.SOUTH);
+
+ mainPanel.add(infoTextArea, BorderLayout.NORTH);
+ mainPanel.add(mainFieldsPanel, BorderLayout.CENTER);
+ mainPanel.add(southEastPanel, BorderLayout.SOUTH);
+
+ this.getContentPane().add(mainPanel, BorderLayout.EAST);
+
+ this.loginButton.setName("ok");
+ this.cancelButton.setName("cancel");
+ if(loginButton.getPreferredSize().width
+ > cancelButton.getPreferredSize().width)
+ cancelButton.setPreferredSize(loginButton.getPreferredSize());
+ else
+ loginButton.setPreferredSize(cancelButton.getPreferredSize());
+
+ this.loginButton.setMnemonic(
+ DesktopUtilActivator.getResources().getI18nMnemonic("service.gui.OK"));
+ this.cancelButton.setMnemonic(
+ DesktopUtilActivator.getResources().getI18nMnemonic("service.gui.CANCEL"));
+
+ this.loginButton.addActionListener(this);
+ this.cancelButton.addActionListener(this);
+
+ this.getRootPane().setDefaultButton(loginButton);
+ }
+
+ /**
+ * Handles the <tt>ActionEvent</tt> triggered when one of the buttons is
+ * clicked. When "Login" button is chosen installs a new account from
+ * the user input and logs in.
+ *
+ * @param evt the action event that has just occurred.
+ */
+ public void actionPerformed(ActionEvent evt)
+ {
+ JButton button = (JButton) evt.getSource();
+ String buttonName = button.getName();
+
+ if ("ok".equals(buttonName))
+ {
+ if(uinValue instanceof JLabel)
+ userName = ((JLabel) uinValue).getText();
+ else if(uinValue instanceof JTextField)
+ userName = ((JTextField) uinValue).getText();
+
+ password = passwdField.getPassword();
+ isRememberPassword = rememberPassCheckBox.isSelected();
+ }
+ else
+ {
+ isCanceled = true;
+ }
+
+ // release the caller that opened the window
+ buttonClicked = true;
+ synchronized (lock)
+ {
+ lock.notify();
+ }
+
+ this.dispose();
+ }
+
+ /**
+ * Enables the actions when a key is pressed, for now
+ * closes the window when esc is pressed.
+ */
+ private void enableKeyActions()
+ {
+ @SuppressWarnings("serial")
+ UIAction act = new UIAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ close(true);
+ }
+ };
+
+ getRootPane().getActionMap().put("close", act);
+
+ InputMap imap = this.getRootPane().getInputMap(
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
+ }
+
+ /**
+ * Automatically clicks the cancel button, when this window is closed.
+ *
+ * @param isEscaped indicates if the window has been closed by pressing the
+ * Esc key
+ */
+ @Override
+ protected void close(boolean isEscaped)
+ {
+ this.cancelButton.doClick();
+ }
+
+ /**
+ * Shows this modal dialog.
+ *
+ * @param isVisible specifies whether we should be showing or hiding the
+ * window.
+ */
+ @Override
+ public void setVisible(final boolean isVisible)
+ {
+ this.setName("AUTHENTICATION");
+
+ if(getOwner() != null)
+ setModal(true);
+
+ if(isVisible)
+ {
+ addWindowFocusListener(new WindowAdapter() {
+ public void windowGainedFocus(WindowEvent e)
+ {
+ removeWindowFocusListener(this);
+
+ if (uinValue instanceof JTextField &&
+ "".equals(((JTextField) uinValue).getText()))
+ {
+ uinValue.requestFocusInWindow();
+ }
+ else
+ passwdField.requestFocusInWindow();
+ }
+ });
+ }
+
+ super.setVisible(isVisible);
+
+ if(isVisible)
+ {
+ if(getOwner() != null)
+ return;
+
+ synchronized (lock)
+ {
+ while(!buttonClicked)
+ {
+ try
+ {
+ lock.wait();
+ }
+ catch (InterruptedException e)
+ {} // we don't care, just retry
+ }
+ }
+ }
+ }
+
+ /**
+ * Indicates if this window has been canceled.
+ *
+ * @return <tt>true</tt> if this window has been canceled, <tt>false</tt> -
+ * otherwise
+ */
+ public boolean isCanceled()
+ {
+ return isCanceled;
+ }
+
+ /**
+ * Returns the user name entered by the user or previously set if the
+ * user name is not editable.
+ *
+ * @return the user name
+ */
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ /**
+ * Returns the password entered by the user.
+ *
+ * @return the password
+ */
+ public char[] getPassword()
+ {
+ return password;
+ }
+
+ /**
+ * Indicates if the password should be remembered.
+ *
+ * @return <tt>true</tt> if the password should be remembered,
+ * <tt>false</tt> - otherwise
+ */
+ public boolean isRememberPassword()
+ {
+ return isRememberPassword;
+ }
+
+ /**
+ * Creates the subscribe label.
+ * @param linkName the link name
+ * @return the newly created subscribe label
+ */
+ private Component createWebSignupLabel( String linkName,
+ final String linkURL)
+ {
+ JLabel subscribeLabel =
+ new JLabel("<html><a href=''>"
+ + linkName
+ + "</a></html>",
+ JLabel.RIGHT);
+
+ subscribeLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ subscribeLabel.setToolTipText(
+ DesktopUtilActivator.getResources().getI18NString(
+ "plugin.simpleaccregwizz.SPECIAL_SIGNUP"));
+ subscribeLabel.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ try
+ {
+ DesktopUtilActivator.getBrowserLauncher()
+ .openURL(linkURL);
+ }
+ catch (UnsupportedOperationException ex)
+ {
+ // This should not happen, because we check if the
+ // operation is supported, before adding the sign
+ // up.
+ logger.error("The web sign up is not supported.",
+ ex);
+ }
+ }
+ });
+ return subscribeLabel;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ComponentMover.java b/src/net/java/sip/communicator/plugin/desktoputil/ComponentMover.java
new file mode 100644
index 0000000..5a0c5b6
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ComponentMover.java
@@ -0,0 +1,108 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ *
+ * @author Yana Stamcheva
+ */
+public class ComponentMover
+{
+ /**
+ * Registers the given component for component dragging/moving functionality.
+ *
+ * @param c the component, which should be moved on drag
+ */
+ public static void registerComponent(Component c)
+ {
+ MoverMouseListener l = new MoverMouseListener();
+
+ c.addMouseListener(l);
+ c.addMouseMotionListener(l);
+ }
+
+ /**
+ * The Mouse listener for local video. It is responsible for dragging local
+ * video.
+ */
+ private static class MoverMouseListener
+ implements MouseListener,
+ MouseMotionListener
+ {
+ /**
+ * Indicates if we're currently during a drag operation.
+ */
+ private boolean inDrag = false;
+
+ /**
+ * The previous x coordinate of the drag.
+ */
+ private int previousX = 0;
+
+ /**
+ * The previous y coordinate of the drag.
+ */
+ private int previousY = 0;
+
+ /**
+ * Indicates that the mouse has been dragged.
+ *
+ * @param event the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseDragged(MouseEvent event)
+ {
+ Point p = event.getPoint();
+
+ if (inDrag)
+ {
+ Component c = (Component) event.getSource();
+
+ int newX = c.getX() + p.x - previousX;
+ int newY = c.getY() + p.y - previousY;
+
+ c.setLocation(newX, newY);
+ }
+ }
+
+ public void mouseMoved(MouseEvent event) {}
+
+ public void mouseClicked(MouseEvent event) {}
+
+ public void mouseEntered(MouseEvent event) {}
+
+ public void mouseExited(MouseEvent event) {}
+
+ /**
+ * Indicates that the mouse has been pressed.
+ *
+ * @param event the <tt>MouseEvent</tt> that notified us
+ */
+ public void mousePressed(MouseEvent event)
+ {
+ Point p = event.getPoint();
+
+ previousX = p.x;
+ previousY = p.y;
+ inDrag = true;
+ }
+
+ /**
+ * Indicates that the mouse has been released.
+ *
+ * @param event the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseReleased(MouseEvent event)
+ {
+ inDrag = false;
+ previousX = 0;
+ previousY = 0;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ComponentUtils.java b/src/net/java/sip/communicator/plugin/desktoputil/ComponentUtils.java
new file mode 100644
index 0000000..8cb945d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ComponentUtils.java
@@ -0,0 +1,139 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+
+/**
+ * Utility class for component related operations. For example: calculating size
+ * of strings depending on the component, obtaining component index, updating
+ * component tree UI, etc.
+ *
+ * @author Yana Stamcheva
+ */
+public class ComponentUtils
+{
+ /**
+ * Returns the width in pixels of a text.
+ *
+ * @param c the component where the text is contained
+ * @param text the text to measure
+ * @return the width in pixels of a text.
+ */
+ public static int getStringWidth(Component c, String text)
+ {
+ return SwingUtilities.computeStringWidth(c
+ .getFontMetrics(c.getFont()), text);
+ }
+
+ /**
+ * Returns the size of the given text computed towards to the given
+ * component.
+ *
+ * @param c the component where the text is contained
+ * @param text the text to measure
+ * @return the dimensions of the text
+ */
+ public static Dimension getStringSize(Component c, String text)
+ {
+ // get metrics from the graphics
+ FontMetrics metrics = c.getFontMetrics(c.getFont());
+ // get the height of a line of text in this font and render context
+ int hgt = metrics.getHeight();
+ // get the advance of my text in this font and render context
+ int adv = metrics.stringWidth(text);
+ // calculate the size of a box to hold the text with some padding.
+ return new Dimension(adv+2, hgt+2);
+ }
+
+ /**
+ * Returns the bounds of the given string.
+ *
+ * @param text the string to measure
+ * @return the bounds of the given string
+ */
+ public static Rectangle2D getDefaultStringSize(String text)
+ {
+ Font font = UIManager.getFont("Label.font");
+ FontRenderContext frc = new FontRenderContext(null, true, false);
+ TextLayout layout = new TextLayout(text, font, frc);
+
+ return layout.getBounds();
+ }
+
+ /**
+ * A simple minded look and feel change: ask each node in the tree
+ * to <code>updateUI()</code> -- that is, to initialize its UI property
+ * with the current look and feel.
+ *
+ * @param c UI component.
+ */
+ public static void updateComponentTreeUI(Component c)
+ {
+ updateComponentTreeUI0(c);
+ c.invalidate();
+ c.validate();
+ c.repaint();
+ }
+
+ /**
+ * Returns the index of the given component in the given container.
+ *
+ * @param c the Component to look for
+ * @param container the parent container, where this component is added
+ * @return the index of the component in the container or -1 if no such
+ * component is contained in the container
+ */
+ public static int getComponentIndex(Component c, Container container)
+ {
+ for (int i = 0, count = container.getComponentCount(); i < count; i++)
+ {
+ if (container.getComponent(i).equals(c))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Repaints UI tree recursively.
+ *
+ * @param c UI component.
+ */
+ private static void updateComponentTreeUI0(Component c)
+ {
+ if (c instanceof JComponent)
+ {
+ JComponent jc = (JComponent) c;
+ jc.invalidate();
+ jc.validate();
+ jc.repaint();
+ JPopupMenu jpm =jc.getComponentPopupMenu();
+ if(jpm != null && jpm.isVisible() && jpm.getInvoker() == jc)
+ {
+ updateComponentTreeUI(jpm);
+ }
+ }
+ Component[] children = null;
+ if (c instanceof JMenu)
+ {
+ children = ((JMenu)c).getMenuComponents();
+ }
+ else if (c instanceof java.awt.Container)
+ {
+ children = ((java.awt.Container)c).getComponents();
+ }
+ if (children != null)
+ {
+ for(int i = 0; i < children.length; i++)
+ updateComponentTreeUI0(children[i]);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java b/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java
new file mode 100644
index 0000000..dc23458
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java
@@ -0,0 +1,177 @@
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.image.*;
+import java.net.*;
+
+import javax.imageio.*;
+
+import net.java.sip.communicator.service.browserlauncher.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.keybindings.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
+import org.osgi.framework.*;
+
+public class DesktopUtilActivator
+ implements BundleActivator
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>SwingUtilActivator</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(DesktopUtilActivator.class);
+
+ private static ConfigurationService configurationService;
+
+ private static ResourceManagementService resourceService;
+
+ private static KeybindingsService keybindingsService;
+
+ private static BrowserLauncherService browserLauncherService;
+
+ private static UIService uiService;
+
+ static BundleContext bundleContext;
+
+ /**
+ * Calls <tt>Thread.setUncaughtExceptionHandler()</tt>
+ *
+ * @param context The execution context of the bundle being started
+ * (unused).
+ * @throws Exception If this method throws an exception, this bundle is
+ * marked as stopped and the Framework will remove this bundle's
+ * listeners, unregister all services registered by this bundle, and
+ * release all services used by this bundle.
+ */
+ public void start(BundleContext context) throws Exception
+ {
+ bundleContext = context;
+ }
+
+ /**
+ * Doesn't do anything.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the bundle is
+ * still marked as stopped, and the Framework will remove the bundle's
+ * listeners, unregister all services registered by the bundle, and
+ * release all services used by the bundle.
+ */
+ public void stop(BundleContext context)
+ throws Exception
+ {
+ }
+
+ /**
+ * Returns the <tt>ConfigurationService</tt> currently registered.
+ *
+ * @return the <tt>ConfigurationService</tt>
+ */
+ public static ConfigurationService getConfigurationService()
+ {
+ if (configurationService == null)
+ {
+ configurationService
+ = ServiceUtils.getService(
+ bundleContext,
+ ConfigurationService.class);
+ }
+ return configurationService;
+ }
+
+ /**
+ * Returns the service giving access to all application resources.
+ *
+ * @return the service giving access to all application resources.
+ */
+ public static ResourceManagementService getResources()
+ {
+ if (resourceService == null)
+ {
+ resourceService
+ = ResourceManagementServiceUtils.getService(bundleContext);
+ }
+ return resourceService;
+ }
+
+ /**
+ * Returns the image corresponding to the given <tt>imageID</tt>.
+ *
+ * @param imageID the identifier of the image
+ * @return the image corresponding to the given <tt>imageID</tt>
+ */
+ public static BufferedImage getImage(String imageID)
+ {
+ BufferedImage image = null;
+
+ URL path = getResources().getImageURL(imageID);
+
+ if (path == null)
+ return null;
+
+ try
+ {
+ image = ImageIO.read(path);
+ }
+ catch (Exception exc)
+ {
+ logger.error("Failed to load image:" + path, exc);
+ }
+
+ return image;
+ }
+
+ /**
+ * Returns the <tt>KeybindingsService</tt> currently registered.
+ *
+ * @return the <tt>KeybindingsService</tt>
+ */
+ public static KeybindingsService getKeybindingsService()
+ {
+ if (keybindingsService == null)
+ {
+ keybindingsService
+ = ServiceUtils.getService(
+ bundleContext,
+ KeybindingsService.class);
+ }
+ return keybindingsService;
+ }
+
+
+ /**
+ * Returns the <tt>BrowserLauncherService</tt> obtained from the bundle
+ * context.
+ * @return the <tt>BrowserLauncherService</tt> obtained from the bundle
+ * context
+ */
+ public static BrowserLauncherService getBrowserLauncher()
+ {
+ if (browserLauncherService == null)
+ {
+ browserLauncherService
+ = ServiceUtils.getService(
+ bundleContext,
+ BrowserLauncherService.class);
+ }
+ return browserLauncherService;
+ }
+
+ /**
+ * Gets the <tt>UIService</tt> instance registered in the
+ * <tt>BundleContext</tt> of the <tt>UtilActivator</tt>.
+ *
+ * @return the <tt>UIService</tt> instance registered in the
+ * <tt>BundleContext</tt> of the <tt>UtilActivator</tt>
+ */
+ public static UIService getUIService()
+ {
+ if (uiService == null)
+ uiService = ServiceUtils.getService(bundleContext, UIService.class);
+ return uiService;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/EmphasizedLabel.java b/src/net/java/sip/communicator/plugin/desktoputil/EmphasizedLabel.java
new file mode 100644
index 0000000..488030f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/EmphasizedLabel.java
@@ -0,0 +1,104 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * A label with white shadow.
+ * Based on code published on http://explodingpixels.wordpress.com.
+ *
+ * @author Yana Stamcheva
+ */
+public class EmphasizedLabel
+ extends JLabel
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private boolean fUseEmphasisColor;
+
+ /**
+ * The color used to paint the shadow.
+ */
+ public static final Color EMPHASIZED_FONT_COLOR =
+ new Color(255, 255, 255, 110);
+
+ /**
+ * The color used to paint focused view.
+ */
+ public static final Color EMPHASIZED_FOCUSED_FONT_COLOR =
+ new Color(0x000000);
+
+ /**
+ * The color used to paint unfocused view.
+ */
+ public static final Color EMPHASIZED_UNFOCUSED_FONT_COLOR =
+ new Color(0x3f3f3f);
+
+ /**
+ * Creates an instance of <tt>EmphasizedLabel</tt>.
+ *
+ * @param text the text to show in this label
+ */
+ public EmphasizedLabel(String text)
+ {
+ super(text);
+ }
+
+ /**
+ * Overrides the <tt>getPreferredSize()</tt> method in order to enlarge the
+ * height of this label, which should welcome the lightening shadow.
+ */
+ @Override
+ public Dimension getPreferredSize()
+ {
+ Dimension d = super.getPreferredSize();
+ d.height += 1;
+ return d;
+ }
+
+ /**
+ * Overrides the <tt>getForeground()</tt> method in order to provide
+ * different foreground color, depending on whether the label is focused.
+ */
+ @Override
+ public Color getForeground()
+ {
+ Color retVal;
+ Window window = SwingUtilities.getWindowAncestor(this);
+ boolean hasFoucs = window != null && window.isFocused();
+
+ if (fUseEmphasisColor)
+ retVal = EMPHASIZED_FONT_COLOR;
+ else if (hasFoucs)
+ retVal = EMPHASIZED_FOCUSED_FONT_COLOR;
+ else
+ retVal = EMPHASIZED_UNFOCUSED_FONT_COLOR;
+
+ return retVal;
+ }
+
+ /**
+ * Paints this label.
+ *
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ @Override
+ protected void paintComponent(Graphics g)
+ {
+ fUseEmphasisColor = true;
+ g.translate(0,1);
+ super.paintComponent(g);
+ g.translate(0,-1);
+ fUseEmphasisColor = false;
+ super.paintComponent(g);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ErrorDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/ErrorDialog.java
new file mode 100644
index 0000000..91ad614
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ErrorDialog.java
@@ -0,0 +1,381 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+/**
+ * Implements a <tt>JDialog</tt> which displays an error message and,
+ * optionally, a <tt>Throwable</tt> stack trace. <tt>ErrorDialog</tt> has an OK
+ * button which dismisses the message and a link to display the
+ * <tt>Throwable</tt> stack trace upon request if available.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ * @author Lyubomir Marinov
+ */
+public class ErrorDialog
+ extends SIPCommDialog
+ implements ActionListener,
+ HyperlinkListener,
+ Skinnable
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>ErrorDialog</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger = Logger.getLogger(ErrorDialog.class);
+
+ private JButton okButton
+ = new JButton(
+ DesktopUtilActivator.getResources().getI18NString("service.gui.OK"));
+
+ private JLabel iconLabel
+ = new JLabel(new ImageIcon(
+ DesktopUtilActivator.getImage("service.gui.icons.ERROR_ICON")));
+
+ private StyledHTMLEditorPane htmlMsgEditorPane = new StyledHTMLEditorPane();
+
+ private JTextArea stackTraceTextArea = new JTextArea();
+
+ private JScrollPane stackTraceScrollPane = new JScrollPane();
+
+ private TransparentPanel buttonsPanel
+ = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
+
+ private TransparentPanel infoMessagePanel = new TransparentPanel();
+
+ private TransparentPanel messagePanel
+ = new TransparentPanel(new BorderLayout());
+
+ private TransparentPanel mainPanel
+ = new TransparentPanel(new BorderLayout(10, 10));
+
+ /**
+ * Load the "net.java.sip.communicator.SHOW_STACK_TRACE" property to
+ * determine whether we should show stack trace in error dialogs.
+ * Default is show.
+ */
+ private static String showStackTraceDefaultProp
+ = DesktopUtilActivator.getResources().getSettingsString(
+ "net.java.sip.communicator.SHOW_STACK_TRACE");
+
+ /**
+ * Should we show stack trace.
+ */
+ private final static boolean showStackTrace =
+ (showStackTraceDefaultProp != null) ?
+ Boolean.parseBoolean(showStackTraceDefaultProp) : true;
+
+ /**
+ * The indicator which determines whether the details of the error are
+ * currently shown.
+ * <p>
+ * The indicator is initially set to <tt>true</tt> because the constructor
+ * {@link #ErrorDialog(Frame, String, String, Throwable)} calls
+ * {@link #showOrHideDetails()} and thus <tt>ErrorDialog</tt> defaults to
+ * not showing the details of the error.
+ * </p>
+ */
+ private boolean detailsShown = true;
+
+ /**
+ * The type of <tt>ErrorDialog</tt> which displays a warning instead of an
+ * error.
+ */
+ public static final int WARNING = 1;
+
+ /**
+ * The type of this <tt>ErrorDialog</tt> (e.g. {@link #WARNING}). The
+ * default <tt>ErrorDialog</tt> displays an error.
+ */
+ private int type = 0;
+
+ /**
+ * The maximum width that we allow message dialogs to have.
+ */
+ private static final int MAX_MSG_PANE_WIDTH = 340;
+
+ /**
+ * The maximum height that we allow message dialogs to have.
+ */
+ private static final int MAX_MSG_PANE_HEIGHT = 800;
+
+ /**
+ * Initializes a new <tt>ErrorDialog</tt> with a specific owner
+ * <tt>Frame</tt>, title and message to be displayed.
+ *
+ * @param owner the dialog owner
+ * @param title the title of the dialog
+ * @param message the message to be displayed
+ */
+ public ErrorDialog( Frame owner,
+ String title,
+ String message)
+ {
+ super(owner, false);
+
+ this.mainPanel.setBorder(
+ BorderFactory.createEmptyBorder(20, 20, 10, 20));
+
+ if (showStackTrace)
+ {
+ this.stackTraceScrollPane.setBorder(BorderFactory.createLineBorder(
+ iconLabel.getForeground()));
+
+ this.stackTraceScrollPane.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ }
+
+ this.setTitle(title);
+
+ this.infoMessagePanel.setLayout(new BorderLayout());
+
+ JEditorPane messageArea = new JEditorPane();
+
+ /*
+ * Make JEditorPane respect our default font because we will be using it
+ * to just display text.
+ */
+ messageArea.putClientProperty(
+ JEditorPane.HONOR_DISPLAY_PROPERTIES,
+ true);
+
+ messageArea.setOpaque(false);
+ messageArea.setEditable(false);
+ messageArea.setContentType("text/html");
+ messageArea.setText(
+ "<html><body><p align=\"left\" >"+message+"</p></body></html>");
+ //try to reevaluate the preferred size of the message pane.
+ //(this is definitely not a neat way to do it ... but it works).
+ messageArea.setSize(
+ new Dimension(MAX_MSG_PANE_WIDTH, MAX_MSG_PANE_HEIGHT));
+ messageArea.setPreferredSize(
+ new Dimension(
+ MAX_MSG_PANE_WIDTH,
+ messageArea.getPreferredSize().height));
+
+ this.infoMessagePanel.add(messageArea, BorderLayout.CENTER);
+
+ this.init();
+ }
+
+ /**
+ * Initializes a new <tt>ErrorDialog</tt> with a specific owner
+ * <tt>Frame</tt>, title, error message to be displayed and the
+ * <tt>Throwable</tt> associated with the error.
+ *
+ * @param owner the dialog owner
+ * @param title the title of the dialog
+ * @param message the message to be displayed
+ * @param e the exception corresponding to the error
+ */
+ public ErrorDialog( Frame owner,
+ String title,
+ String message,
+ Throwable e)
+ {
+ this(owner, title, message);
+
+ if (showStackTrace)
+ {
+ this.setTitle(title);
+
+ this.htmlMsgEditorPane.setEditable(false);
+ this.htmlMsgEditorPane.setOpaque(false);
+
+ this.htmlMsgEditorPane.addHyperlinkListener(this);
+
+ showOrHideDetails();
+
+ this.infoMessagePanel.add(htmlMsgEditorPane, BorderLayout.SOUTH);
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ pw.close();
+
+ String stackTrace = sw.toString();
+
+ try
+ {
+ sw.close();
+ }
+ catch (IOException ex)
+ {
+ //really shouldn't happen. but log anyway
+ logger.error("Failed to close a StringWriter. ", ex);
+ }
+
+ this.stackTraceTextArea.setText(stackTrace);
+ }
+ }
+
+ /**
+ * Initializes a new <tt>ErrorDialog</tt> with a specific owner
+ * <tt>Frame</tt>, title and message to be displayed and of a specific type.
+ *
+ * @param owner the dialog owner
+ * @param title the title of the error dialog
+ * @param message the message to be displayed
+ * @param type the dialog type
+ */
+ public ErrorDialog( Frame owner,
+ String title,
+ String message,
+ int type)
+ {
+ this(owner, title, message);
+
+ if(type == WARNING)
+ {
+ iconLabel.setIcon(new ImageIcon(
+ DesktopUtilActivator.getImage("service.gui.icons.WARNING_ICON")));
+ this.type = type;
+ }
+ }
+
+ /**
+ * Initializes this dialog.
+ */
+ private void init()
+ {
+ this.getRootPane().setDefaultButton(okButton);
+
+ this.stackTraceScrollPane.getViewport().add(stackTraceTextArea);
+ this.stackTraceScrollPane.setPreferredSize(
+ new Dimension(this.getWidth(), 100));
+
+ this.buttonsPanel.add(okButton);
+
+ this.okButton.addActionListener(this);
+
+ this.mainPanel.add(iconLabel, BorderLayout.WEST);
+
+ this.messagePanel.add(infoMessagePanel, BorderLayout.NORTH);
+
+ this.mainPanel.add(messagePanel, BorderLayout.CENTER);
+ this.mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
+
+ this.getContentPane().add(mainPanel);
+ }
+
+ /**
+ * Shows if previously hidden or hides if previously shown the details of
+ * the error. Called when the "more" link is clicked.
+ */
+ public void showOrHideDetails()
+ {
+ String startDivTag = "<div id=\"message\">";
+ String endDivTag = "</div>";
+ String msgString;
+
+ detailsShown = !detailsShown;
+
+ if(detailsShown)
+ {
+ msgString = startDivTag
+ + " <p align=\"right\"><a href=\"\">&lt;&lt; Hide info</a></p>"
+ + endDivTag;
+ this.messagePanel.add(stackTraceScrollPane, BorderLayout.CENTER);
+ }
+ else
+ {
+ msgString = startDivTag
+ + " <p align=\"right\"><a href=\"\">More info &gt;&gt;</a></p>"
+ + endDivTag;
+ this.messagePanel.remove(stackTraceScrollPane);
+ }
+
+ htmlMsgEditorPane.setText(msgString);
+
+ this.messagePanel.revalidate();
+ this.messagePanel.repaint();
+ // restore default values for preferred size,
+ // as we have resized its components let it calculate
+ // that size
+ setPreferredSize(null);
+ this.pack();
+ }
+
+ /**
+ * Shows the dialog.
+ */
+ public void showDialog()
+ {
+ this.pack();
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ this.setLocation(screenSize.width/2 - this.getWidth()/2,
+ screenSize.height/2 - this.getHeight()/2);
+
+ this.setVisible(true);
+
+ this.toFront();
+ }
+
+ /**
+ * Handles the <tt>ActionEvent</tt>. Depending on the user choice sets
+ * the return code to the appropriate value.
+ *
+ * @param e the <tt>ActionEvent</tt> instance that has just been fired.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ JButton button = (JButton) e.getSource();
+
+ if(button.equals(okButton))
+ this.dispose();
+ }
+
+ /**
+ * Close the ErrorDialog. This function is invoked when user
+ * presses the Escape key.
+ *
+ * @param isEscaped Specifies whether the close was triggered by pressing
+ * the escape key.
+ */
+ protected void close(boolean isEscaped)
+ {
+ this.okButton.doClick();
+ }
+
+ /**
+ * Update the ErrorDialog when the user clicks on the hyperlink.
+ *
+ * @param e The event generated by the click on the hyperlink.
+ */
+ public void hyperlinkUpdate(HyperlinkEvent e)
+ {
+ if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+ showOrHideDetails();
+ }
+
+ /**
+ * Reloads icon.
+ */
+ public void loadSkin()
+ {
+ String icon
+ = (type == WARNING)
+ ? "service.gui.icons.WARNING_ICON"
+ : "service.gui.icons.ERROR_ICON";
+
+ iconLabel.setIcon(new ImageIcon(DesktopUtilActivator.getImage(icon)));
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTooltip.java b/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTooltip.java
new file mode 100644
index 0000000..6960fbb
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTooltip.java
@@ -0,0 +1,392 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.metal.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * The tooltip shown over a contact in the contact list.
+ *
+ * @author Yana Stamcheva
+ */
+public class ExtendedTooltip
+ extends JToolTip
+{
+ private static final Logger logger
+ = Logger.getLogger(ExtendedTooltip.class);
+
+ /**
+ * Class id key used in UIDefaults.
+ */
+ private static final String uiClassID =
+ ExtendedTooltip.class.getName() + "ToolTipUI";
+
+ /**
+ * Adds the ui class to UIDefaults.
+ */
+ static
+ {
+ UIManager.getDefaults().put(uiClassID,
+ ImageToolTipUI.class.getName());
+ }
+
+ private final JLabel imageLabel = new JLabel();
+
+ private final JLabel titleLabel = new JLabel();
+
+ private final JPanel linesPanel = new JPanel();
+
+ private final JTextArea bottomTextArea = new JTextArea();
+
+ private int textWidth = 0;
+
+ private int textHeight = 0;
+
+ private boolean isListViewEnabled;
+
+ /**
+ * Created a <tt>MetaContactTooltip</tt>.
+ * @param isListViewEnabled indicates if the list view is enabled
+ */
+ public ExtendedTooltip(boolean isListViewEnabled)
+ {
+ this.isListViewEnabled = isListViewEnabled;
+
+ this.setLayout(new BorderLayout());
+
+ JPanel mainPanel = new JPanel(new BorderLayout(5, 5));
+ JPanel centerPanel = new JPanel(new BorderLayout());
+
+ mainPanel.setOpaque(false);
+ centerPanel.setOpaque(false);
+ linesPanel.setOpaque(false);
+ bottomTextArea.setOpaque(false);
+
+ titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD));
+
+ if (isListViewEnabled)
+ {
+ linesPanel.setLayout(
+ new BoxLayout(linesPanel, BoxLayout.Y_AXIS));
+
+ mainPanel.add(imageLabel, BorderLayout.WEST);
+ mainPanel.add(centerPanel, BorderLayout.CENTER);
+
+ centerPanel.add(titleLabel, BorderLayout.NORTH);
+ centerPanel.add(linesPanel, BorderLayout.CENTER);
+ }
+ else
+ {
+ titleLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
+ mainPanel.add(imageLabel, BorderLayout.CENTER);
+ mainPanel.add(titleLabel, BorderLayout.NORTH);
+ }
+
+ bottomTextArea.setEditable(false);
+ bottomTextArea.setLineWrap(true);
+ bottomTextArea.setWrapStyleWord(true);
+ bottomTextArea.setFont(bottomTextArea.getFont().deriveFont(10f));
+ mainPanel.add(bottomTextArea, BorderLayout.SOUTH);
+
+ final Window parentWindow
+ = KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .getActiveWindow();
+
+ // Hide the tooltip when the parent window hides.
+ /*
+ * FIXME The parentWindow will surely outlive this ExtendedTooltip so
+ * adding a WindowFocusListener without removing the same
+ * WindowFocusListener later on is guaranteed to cause a memory leak.
+ */
+ if (parentWindow != null)
+ parentWindow.addWindowFocusListener(new WindowFocusListener()
+ {
+ public void windowLostFocus(WindowEvent e)
+ {
+ Window popupWindow
+ = SwingUtilities.getWindowAncestor(
+ ExtendedTooltip.this);
+
+ if ((popupWindow != null)
+ && popupWindow.isVisible()
+ // The popup window should normally be a JWindow, so we
+ // check here explicitly if for some reason we didn't
+ // get something else.
+ && (popupWindow instanceof JWindow))
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Tooltip window ancestor to hide: "
+ + popupWindow);
+
+ popupWindow.setVisible(false);
+ }
+ }
+
+ public void windowGainedFocus(WindowEvent e) {}
+ });
+
+ this.add(mainPanel);
+ }
+
+ /**
+ * Sets the given image to this tooltip.
+ *
+ * @param imageIcon The image icon to set.
+ */
+ public void setImage(ImageIcon imageIcon)
+ {
+ imageLabel.setIcon(imageIcon);
+ }
+
+ /**
+ * Sets the title of the tooltip. The text would be shown in bold on the top
+ * of the tooltip panel.
+ *
+ * @param titleText The title of the tooltip.
+ */
+ public void setTitle(String titleText)
+ {
+ titleLabel.setText(titleText);
+
+ Dimension labelSize
+ = ComponentUtils.getStringSize(titleLabel,titleText);
+ recalculateTooltipSize(labelSize.width, labelSize.height);
+ }
+
+ /**
+ * Adds an icon-string list, which would appear on the right of the image
+ * panel.
+ *
+ * @param icon the icon to show
+ * @param text the name to show
+ */
+ public void addLine(Icon icon,
+ String text)
+ {
+ JLabel lineLabel = new JLabel( text,
+ icon,
+ JLabel.LEFT);
+
+ linesPanel.add(lineLabel);
+
+ Dimension labelSize = calculateLabelSize(lineLabel);
+
+ recalculateTooltipSize(labelSize.width, labelSize.height);
+ }
+
+ /**
+ * Adds the given array of labels as one line in this tool tip.
+ *
+ * @param labels the labels to add
+ */
+ public void addLine(JLabel[] labels)
+ {
+ Dimension lineSize = null;
+ JPanel labelPanel = null;
+
+ if (labels.length > 0)
+ {
+ labelPanel = new TransparentPanel(
+ new FlowLayout(FlowLayout.LEFT, 2, 0));
+ linesPanel.add(labelPanel);
+ }
+ else
+ return;
+
+ if (labelPanel != null)
+ for (JLabel label : labels)
+ {
+ labelPanel.add(label);
+ if (lineSize == null)
+ lineSize = calculateLabelSize(label);
+ else
+ lineSize = new Dimension(
+ lineSize.width + calculateLabelSize(label).width,
+ lineSize.height);
+ }
+
+ recalculateTooltipSize(lineSize.width, lineSize.height);
+ }
+
+ /**
+ * Clear all lines.
+ */
+ public void removeAllLines()
+ {
+ linesPanel.removeAll();
+ }
+
+ /**
+ * Sets the text that would appear on the bottom of the tooltip.
+ * @param text the text to set
+ */
+ public void setBottomText(String text)
+ {
+ this.bottomTextArea.setText(text);
+ }
+
+ /**
+ * Calculates label size.
+ *
+ * @param label the label, which size we should calculate
+ * @return the Dimension indicating the label size
+ */
+ private Dimension calculateLabelSize(JLabel label)
+ {
+ Icon icon = label.getIcon();
+ String text = label.getText();
+
+ int iconWidth = 0;
+ int iconHeight = 0;
+ if (icon != null)
+ {
+ iconWidth = icon.getIconWidth();
+ iconHeight = icon.getIconHeight();
+ }
+
+ int labelWidth
+ = ComponentUtils.getStringWidth(label, text)
+ + iconWidth
+ + label.getIconTextGap();
+
+ int textHeight = ComponentUtils.getStringSize(label, text).height;
+
+ int labelHeight = (iconHeight > textHeight) ? iconHeight : textHeight;
+
+ return new Dimension(labelWidth, labelHeight);
+ }
+
+ /**
+ * Re-calculates the tooltip size.
+ *
+ * @param newTextWidth the width of the newly added text that should be
+ * added to the global width
+ * @param newTextHeight the height of the newly added text that should be
+ * added to the global height
+ */
+ private void recalculateTooltipSize(int newTextWidth, int newTextHeight)
+ {
+ if (textWidth < newTextWidth)
+ textWidth = newTextWidth;
+
+ textHeight += newTextHeight;
+ }
+
+ /**
+ * Customized UI for this MetaContactTooltip.
+ */
+ public static class ImageToolTipUI extends MetalToolTipUI
+ {
+ static ImageToolTipUI sharedInstance = new ImageToolTipUI();
+
+ /**
+ * Creates the UI.
+ * @param c
+ * @return
+ */
+ public static ComponentUI createUI(JComponent c)
+ {
+ return sharedInstance;
+ }
+
+ /**
+ * Overwrite the UI paint method to do nothing in order fix double
+ * painting of the tooltip text.
+ * @param g the <tt>Graphics</tt> object
+ * @param c the component used to render the tooltip
+ */
+ @Override
+ public void paint(Graphics g, JComponent c)
+ {}
+
+ /**
+ * Override ComponentUI update method to set visibility of bottomText.
+ * @param g <tt>Graphics</tt> object
+ * @param c the component used to render the tooltip
+ */
+ @Override
+ public void update(Graphics g, JComponent c)
+ {
+ JTextArea bottomTextArea =
+ ((ExtendedTooltip)c).bottomTextArea;
+
+ String bottomText = bottomTextArea.getText();
+ if(bottomText == null || bottomText.length() <= 0)
+ bottomTextArea.setVisible(false);
+ else
+ bottomTextArea.setVisible(true);
+ super.update(g, c);
+ }
+
+ /**
+ * Returns the size of the given component.
+ * @param c the component used to render the tooltip
+ * @return the size of the given component.
+ */
+ @Override
+ public Dimension getPreferredSize(JComponent c)
+ {
+ ExtendedTooltip tooltip = (ExtendedTooltip)c;
+
+ Icon icon = tooltip.imageLabel.getIcon();
+ int width = 0;
+ if (icon != null)
+ width += icon.getIconWidth();
+
+ if (tooltip.isListViewEnabled)
+ width += tooltip.textWidth + 15;
+ else
+ width = tooltip.textWidth > width ? tooltip.textWidth : width;
+
+ int imageHeight = 0;
+ if (icon != null)
+ imageHeight = icon.getIconHeight();
+
+ int height = 0;
+ if (tooltip.isListViewEnabled)
+ {
+ height = imageHeight > tooltip.textHeight
+ ? imageHeight : tooltip.textHeight;
+ }
+ else
+ height = imageHeight + tooltip.textHeight;
+
+ String bottomText = tooltip.bottomTextArea.getText();
+ if(bottomText != null && bottomText.length() > 0)
+ {
+ // Seems a little messy, but sets the proper size.
+ tooltip.bottomTextArea.setColumns(5);
+ tooltip.bottomTextArea.setSize(0,0);
+ tooltip.bottomTextArea.setSize(
+ tooltip.bottomTextArea.getPreferredSize());
+
+ height += tooltip.bottomTextArea.getPreferredSize().height;
+ }
+
+ return new Dimension(width, height);
+ }
+ }
+
+ /**
+ * Returns the name of the L&F class that renders this component.
+ *
+ * @return the string "TreeUI"
+ * @see JComponent#getUIClassID
+ * @see UIDefaults#getUI
+ */
+ public String getUIClassID()
+ {
+ return uiClassID;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTransferHandler.java b/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTransferHandler.java
new file mode 100644
index 0000000..9a23017
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ExtendedTransferHandler.java
@@ -0,0 +1,468 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.io.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+
+/**
+ * A TransferHandler that we use to handle copying, pasting and DnD operations.
+ * The string handler is heavily inspired by Sun's
+ * <tt>DefaultTransferHandler</tt> with the main difference being that
+ * we only accept pasting of plain text. We do this in order to avoid HTML
+ * support problems that appear when pasting formatted text into our editable
+ * area.
+ *
+ * @author Emil Ivov
+ * @author Yana Stamcheva
+ */
+public class ExtendedTransferHandler
+ extends TransferHandler
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Returns the type of transfer actions supported by the source;
+ * any bitwise-OR combination of <tt>COPY</tt>, <tt>MOVE</tt>
+ * and <tt>LINK</tt>.
+ * <p>
+ * Some models are not mutable, so a transfer operation of <tt>MOVE</tt>
+ * should not be advertised in that case. Returning <tt>NONE</tt>
+ * disables transfers from the component.
+ *
+ * @param c the component holding the data to be transferred;
+ * provided to enable sharing of <code>TransferHandler</code>s
+ * @return {@code COPY} if the transfer property can be found,
+ * otherwise returns <code>NONE</code>
+ */
+ public int getSourceActions(JComponent c)
+ {
+ return TransferHandler.COPY;
+ }
+
+ /**
+ * Indicates whether a component will accept an import of the given
+ * set of data flavors prior to actually attempting to import it. We return
+ * <tt>true</tt> to indicate that the transfer with at least one of the
+ * given flavors would work and <tt>false</tt> to reject the transfer.
+ * <p>
+ * @param comp component
+ * @param flavor the data formats available
+ * @return true if the data can be inserted into the component, false
+ * otherwise
+ * @throws NullPointerException if <code>support</code> is {@code null}
+ */
+ public boolean canImport(JComponent comp, DataFlavor flavor[])
+ {
+ for (int i = 0, n = flavor.length; i < n; i++)
+ {
+ if (flavor[i].equals(DataFlavor.javaFileListFlavor))
+ {
+ return true;
+ }
+ else if (flavor[i].equals(DataFlavor.stringFlavor))
+ {
+ if (comp instanceof JTextComponent)
+ {
+ JTextComponent c = (JTextComponent) comp;
+
+ if (c.isEditable() && c.isEnabled())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a transferable for text pane components in order to enable drag
+ * and drop of text.
+ * @param component the component for which to create a
+ * <tt>Transferable</tt>
+ * @return the created <tt>Transferable</tt>
+ */
+ protected Transferable createTransferable(JComponent component)
+ {
+ if ((component instanceof JTextPane
+ || component instanceof JTextField))
+ {
+ return new SelectedTextTransferable((JTextComponent) component);
+ }
+
+ return super.createTransferable(component);
+ }
+
+ /**
+ * Handles transport (cut and copy) from the chat panel to
+ * <tt>clipboard</tt>. This method will only transfer plain text and would
+ * explicitly ignore any formatting.
+ * <p>
+ * @param comp the component holding the data to be transferred;
+ * provided to enable sharing of <code>TransferHandler</code>s
+ * @param clipboard the clipboard to transfer the data into
+ * @param action the transfer action requested; this should
+ * be a value of either <code>COPY</code> or <code>MOVE</code>;
+ * the operation performed is the intersection of the transfer
+ * capabilities given by getSourceActions and the requested action;
+ * the intersection may result in an action of <code>NONE</code>
+ * if the requested action isn't supported
+ * @throws IllegalStateException if the clipboard is currently unavailable
+ * @see Clipboard#setContents(Transferable, ClipboardOwner)
+ */
+ public void exportToClipboard(JComponent comp,
+ Clipboard clipboard,
+ int action)
+ throws IllegalStateException
+ {
+ if (comp instanceof JTextComponent)
+ {
+ JTextComponent textComponent = (JTextComponent)comp;
+ int startIndex = textComponent.getSelectionStart();
+ int endIndex = textComponent.getSelectionEnd();
+ if (startIndex != endIndex)
+ {
+ try
+ {
+ Document doc = textComponent.getDocument();
+ String srcData = doc.getText(startIndex,
+ endIndex - startIndex);
+ StringSelection contents = new StringSelection(srcData);
+
+ // this may throw an IllegalStateException,
+ // but it will be caught and handled in the
+ // action that invoked this method
+ clipboard.setContents(contents, null);
+
+ if (action == TransferHandler.MOVE)
+ {
+ doc.remove(startIndex, endIndex - startIndex);
+ }
+ }
+ catch (BadLocationException ble)
+ {
+ //we simply ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Transferable for text pane components that enables drag and drop of text.
+ */
+ public class SelectedTextTransferable implements Transferable
+ {
+ private JTextComponent textComponent;
+
+ /**
+ * Creates an instance of <tt>SelectedTextTransferable</tt>.
+ * @param component the text component
+ */
+ public SelectedTextTransferable(JTextComponent component)
+ {
+ this.textComponent = component;
+ }
+
+ /**
+ * Returns supported flavors.
+ * @return an array of supported flavors
+ */
+ public DataFlavor[] getTransferDataFlavors()
+ {
+ return new DataFlavor[]{DataFlavor.stringFlavor};
+ }
+
+ /**
+ * Returns <tt>true</tt> if the given <tt>flavor</tt> is supported,
+ * otherwise returns <tt>false</tt>.
+ * @param flavor the data flavor to verify
+ * @return <tt>true</tt> if the given <tt>flavor</tt> is supported,
+ * otherwise returns <tt>false</tt>
+ */
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ return DataFlavor.stringFlavor.equals(flavor);
+ }
+
+ /**
+ * Returns the selected text.
+ * @param flavor the flavor
+ * @return the selected text
+ * @exception IOException if the data is no longer available in the
+ * requested flavor.
+ * @exception UnsupportedFlavorException if the requested data flavor
+ * is not supported.
+ */
+ public Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException,
+ IOException
+ {
+ if (!DataFlavor.stringFlavor.equals(flavor))
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+
+ return textComponent.getSelectedText();
+ }
+ }
+
+ /**
+ * Overrides <tt>TransferHandler.getVisualRepresentation(Transferable t)</tt>
+ * in order to return a custom drag icon.
+ * <p>
+ * The default parent implementation of this method returns null.
+ *
+ * @param t the data to be transferred; this value is expected to have been
+ * created by the <code>createTransferable</code> method
+ * @return the icon to show when dragging
+ */
+ public Icon getVisualRepresentation(Transferable t)
+ {
+ Icon icon = null;
+ if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
+ {
+ String text = null;
+ try
+ {
+ text = (String) t.getTransferData(DataFlavor.stringFlavor);
+ }
+ catch (UnsupportedFlavorException e) {}
+ catch (IOException e) {}
+
+ if (text != null)
+ {
+ Rectangle2D bounds = ComponentUtils.getDefaultStringSize(text);
+ BufferedImage image = new BufferedImage(
+ (int) Math.ceil(bounds.getWidth()),
+ (int) Math.ceil(bounds.getHeight()),
+ BufferedImage.TYPE_INT_ARGB);
+
+ Graphics g = image.getGraphics();
+ AntialiasingManager.activateAntialiasing(g);
+ g.setColor(Color.BLACK);
+ // Don't know why if we draw the string on y = 0 it doesn't
+ // appear in the visible area.
+ g.drawString(text, 0, 10);
+
+ icon = new ImageIcon(image);
+ }
+ }
+
+ return icon;
+ }
+
+ // Patch for bug 4816922 "No way to set drag icon:
+ // TransferHandler.getVisualRepresentation() is not used".
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4816922
+ // The following workaround comes from bug comments section!
+ private static SwingDragGestureRecognizer recognizer = null;
+
+ private static class SwingDragGestureRecognizer
+ extends DragGestureRecognizer
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ SwingDragGestureRecognizer(DragGestureListener dgl)
+ {
+ super(DragSource.getDefaultDragSource(), null, NONE, dgl);
+ }
+
+ void gestured(JComponent c, MouseEvent e, int srcActions, int action)
+ {
+ setComponent(c);
+ setSourceActions(srcActions);
+ appendEvent(e);
+ fireDragGestureRecognized(action, e.getPoint());
+ }
+
+ /**
+ * Registers this DragGestureRecognizer's Listeners with the Component.
+ */
+ protected void registerListeners() {}
+
+ /**
+ * Unregister this DragGestureRecognizer's Listeners with the Component.
+ * <p/>
+ * Subclasses must override this method.
+ */
+ protected void unregisterListeners() {}
+ }
+
+ /**
+ * Overrides <tt>TransferHandler.exportAsDrag</tt> method in order to call
+ * our own <tt>SwingDragGestureRecognizer</tt>, which takes care of the
+ * visual representation icon.
+ *
+ * @param comp the component holding the data to be transferred; this
+ * argument is provided to enable sharing of <code>TransferHandler</code>s
+ * by multiple components
+ * @param e the event that triggered the transfer
+ * @param action the transfer action initially requested; this should
+ * be a value of either <code>COPY</code> or <code>MOVE</code>;
+ * the value may be changed during the course of the drag operation
+ */
+ public void exportAsDrag(JComponent comp, InputEvent e, int action)
+ {
+ int srcActions = getSourceActions(comp);
+ int dragAction = srcActions & action;
+
+ // only mouse events supported for drag operations
+ if (! (e instanceof MouseEvent))
+ action = NONE;
+
+ if (action != NONE && !GraphicsEnvironment.isHeadless())
+ {
+ if (recognizer == null)
+ {
+ recognizer = new SwingDragGestureRecognizer(new DragHandler());
+ }
+ recognizer.gestured(comp, (MouseEvent) e, srcActions, dragAction);
+ }
+ else
+ {
+ exportDone(comp, null, NONE);
+ }
+ }
+
+ /**
+ * This is the default drag handler for drag and drop operations that
+ * use the <code>TransferHandler</code>.
+ */
+ private static class DragHandler
+ implements DragGestureListener,
+ DragSourceListener
+ {
+ private boolean scrolls;
+
+ // --- DragGestureListener methods -----------------------------------
+
+ /**
+ * A Drag gesture has been recognized.
+ * @param dge the <tt>DragGestureEvent</tt> that notified us
+ */
+ public void dragGestureRecognized(DragGestureEvent dge)
+ {
+ JComponent c = (JComponent) dge.getComponent();
+ ExtendedTransferHandler th
+ = (ExtendedTransferHandler) c.getTransferHandler();
+
+ Transferable t = th.createTransferable(c);
+ if (t != null)
+ {
+ scrolls = c.getAutoscrolls();
+ c.setAutoscrolls(false);
+ try
+ {
+ Image img = null;
+ Icon icn = th.getVisualRepresentation(t);
+
+ if (icn != null)
+ {
+ if (icn instanceof ImageIcon)
+ {
+ img = ((ImageIcon) icn).getImage();
+ }
+ else
+ {
+ img = new BufferedImage(icn.getIconWidth(),
+ icn.getIconHeight(),
+ BufferedImage.TYPE_4BYTE_ABGR);
+ Graphics g = img.getGraphics();
+ icn.paintIcon(c, g, 0, 0);
+ }
+ }
+ if (img == null)
+ {
+ dge.startDrag(null, t, this);
+ }
+ else
+ {
+ dge.startDrag(null, img,
+ new Point(0, -1 * img.getHeight(null)), t, this);
+ }
+
+ return;
+ }
+ catch (RuntimeException re)
+ {
+ c.setAutoscrolls(scrolls);
+ }
+ }
+
+ th.exportDone(c, t, NONE);
+ }
+
+ // --- DragSourceListener methods -----------------------------------
+
+ /**
+ * As the hotspot enters a platform dependent drop site.
+ * @param e the <tt>DragSourceDragEvent</tt> containing the details of
+ * the drag
+ */
+ public void dragEnter(DragSourceDragEvent e)
+ {}
+
+ /**
+ * As the hotspot moves over a platform dependent drop site.
+ * @param e the <tt>DragSourceDragEvent</tt> containing the details of
+ * the drag
+ */
+ public void dragOver(DragSourceDragEvent e)
+ {
+ }
+
+ /**
+ * As the hotspot exits a platform dependent drop site.
+ * @param e the <tt>DragSourceDragEvent</tt> containing the details of
+ * the drag
+ */
+ public void dragExit(DragSourceEvent e)
+ {}
+
+ /**
+ * As the operation completes.
+ * @param e the <tt>DragSourceDragEvent</tt> containing the details of
+ * the drag
+ */
+ public void dragDropEnd(DragSourceDropEvent e)
+ {
+ DragSourceContext dsc = e.getDragSourceContext();
+ JComponent c = (JComponent) dsc.getComponent();
+
+ if (e.getDropSuccess())
+ {
+ ((ExtendedTransferHandler) c.getTransferHandler())
+ .exportDone(c, dsc.getTransferable(), e.getDropAction());
+ }
+ else
+ {
+ ((ExtendedTransferHandler) c.getTransferHandler())
+ .exportDone(c, dsc.getTransferable(), NONE);
+ }
+ c.setAutoscrolls(scrolls);
+ }
+
+ public void dropActionChanged(DragSourceDragEvent dsde) {}
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FadeInBalloonPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/FadeInBalloonPanel.java
new file mode 100644
index 0000000..ec3bbb7
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FadeInBalloonPanel.java
@@ -0,0 +1,190 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * The <tt>FadeInBaloonPanel</tt> is a semi-transparent "balloon" panel, which
+ * could be shown in a glass pane for example. You can define a begin point,
+ * where the balloon triangle would show.
+ *
+ * @author Yana Stamcheva
+ */
+public class FadeInBalloonPanel
+ extends TransparentPanel
+{
+ /**
+ * The begin point, where the balloon triangle will be shown.
+ */
+ private Point beginPoint;
+
+ /**
+ * The begin point shift, which defines the rectangle point shift.
+ */
+ private final static int beginPointShift = 6;
+
+ /**
+ * Sets the begin point.
+ *
+ * @param beginPoint the begin point
+ */
+ public void setBeginPoint(Point beginPoint)
+ {
+ this.beginPoint = beginPoint;
+ }
+
+ /**
+ * Overrides the <code>paintComponent</code> method of <tt>JButton</tt> to
+ * paint the button background and icon, and all additional effects of this
+ * configurable button.
+ *
+ * @param g The Graphics object.
+ */
+ protected void paintComponent(Graphics g)
+ {
+ g = g.create();
+ try
+ {
+ internalPaintComponent((Graphics2D) g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ /**
+ * Paints this button.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ private void internalPaintComponent(Graphics2D g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+ /*
+ * As JComponent#paintComponent says, if you do not invoke super's
+ * implementation you must honor the opaque property, that is if this
+ * component is opaque, you must completely fill in the background in a
+ * non-opaque color. If you do not honor the opaque property you will
+ * likely see visual artifacts.
+ */
+ if (isOpaque())
+ {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+
+ // Paint a roll over fade out.
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = isVisible() ? 0.8f : 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ }
+
+ g.setColor(new Color(0f, 0f, 0f, visibility));
+
+ int y = 0;
+
+ // draw triangle (polygon)
+ if (beginPoint != null)
+ {
+ y = beginPointShift;
+
+ int x1Points[] = { beginPoint.x,
+ beginPoint.x + beginPointShift,
+ beginPoint.x - beginPointShift};
+
+ int y1Points[] = { beginPoint.y,
+ beginPoint.y + beginPointShift,
+ beginPoint.y + beginPointShift};
+
+ GeneralPath polygon =
+ new GeneralPath(GeneralPath.WIND_EVEN_ODD,
+ x1Points.length);
+
+ polygon.moveTo(x1Points[0], y1Points[0]);
+
+ for (int index = 1; index < x1Points.length; index++) {
+ polygon.lineTo(x1Points[index], y1Points[index]);
+ };
+
+ polygon.closePath();
+ g.fill(polygon);
+ }
+
+ if (visibility != 0.0f)
+ {
+ g.fillRoundRect(
+ 0, y, this.getWidth(), this.getHeight(), 10, 10);
+ }
+ }
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class PanelRepaintCallback implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ FadeInBalloonPanel.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ /**
+ * Shows/hides this panel.
+ *
+ * @param isVisible <tt>true</tt> to show this panel, <tt>false</tt> to
+ * hide it
+ */
+ public void setVisible(boolean isVisible)
+ {
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ if (isVisible)
+ {
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ FadeInBalloonPanel.this,
+ true,
+ new PanelRepaintCallback());
+ }
+ else
+ {
+ fadeTracker.trackFadeOut(FadeKind.ROLLOVER,
+ FadeInBalloonPanel.this,
+ true,
+ new PanelRepaintCallback());
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FileDragLabel.java b/src/net/java/sip/communicator/plugin/desktoputil/FileDragLabel.java
new file mode 100644
index 0000000..4865e11
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FileDragLabel.java
@@ -0,0 +1,206 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>FileDragLabel</tt> extends <tt>JLabel</tt> and associates to it a
+ * file. The label is made draggable and it is possible to drag it directly to
+ * the file browser of the operating system.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileDragLabel
+ extends JLabel
+ implements DropTargetListener,
+ DragSourceListener,
+ DragGestureListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private static final Logger logger = Logger.getLogger(FileDragLabel.class);
+
+ private final DragSource dragSource = DragSource.getDefaultDragSource();
+
+ private File file;
+
+ /**
+ * Creates a <tt>FileDragLabel</tt>.
+ */
+ public FileDragLabel()
+ {
+ dragSource.createDefaultDragGestureRecognizer(
+ this, DnDConstants.ACTION_COPY, this);
+ }
+
+ /**
+ * Sets the file associated with this file drag label.
+ *
+ * @param file the file associated with this file drag label
+ */
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ /**
+ * Called while a drag operation is ongoing, when the mouse pointer enters
+ * the operable part of the drop site for the <code>DropTarget</code>
+ * registered with this listener.
+ *
+ * @param dropTargetDragEvent the <code>DropTargetDragEvent</code>
+ */
+ public void dragEnter(DropTargetDragEvent dropTargetDragEvent)
+ {
+ dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+ }
+
+ /**Called when the drag operation has terminated with a drop on
+ * the operable part of the drop site for the <code>DropTarget</code>
+ * registered with this listener.
+ */
+ public synchronized void drop(DropTargetDropEvent event)
+ {
+ try
+ {
+ Transferable transferable = event.getTransferable();
+
+ if (transferable.isDataFlavorSupported(
+ DataFlavor.javaFileListFlavor))
+ {
+ event.acceptDrop(DnDConstants.ACTION_COPY);
+ event.getDropTargetContext().dropComplete(true);
+ }
+ else
+ {
+ event.rejectDrop();
+ }
+ }
+ catch (Exception ex)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Unable to drop label.", ex);
+ event.rejectDrop();
+ }
+ }
+
+ /**
+ * A <code>DragGestureRecognizer</code> has detected
+ * a platform-dependent drag initiating gesture and
+ * is notifying this listener
+ * in order for it to initiate the action for the user.
+ * <P>
+ * @param dragGestureEvent the <code>DragGestureEvent</code> describing
+ * the gesture that has just occurred
+ */
+ public void dragGestureRecognized(DragGestureEvent dragGestureEvent)
+ {
+ if (file == null)
+ {
+ // Nothing selected, nothing to drag
+ getToolkit().beep();
+ }
+ else
+ {
+ FileTransferable transferable = new FileTransferable(file);
+ dragGestureEvent.startDrag( DragSource.DefaultCopyDrop,
+ transferable,
+ this);
+ }
+ }
+
+ public void dragDropEnd(DragSourceDropEvent DragSourceDropEvent) {}
+
+ public void dragEnter(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dragExit(DragSourceEvent DragSourceEvent) {}
+
+ public void dragOver(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dropActionChanged(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dragExit(DropTargetEvent dropTargetEvent) {}
+
+ public void dragOver(DropTargetDragEvent dropTargetDragEvent) {}
+
+ public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent) {}
+
+ /**
+ * File transferable.
+ */
+ @SuppressWarnings("deprecation") //can't find an alternative.
+ private class FileTransferable
+ extends Vector<File>
+ implements Transferable
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ final static int FILE = 0;
+ final static int STRING = 1;
+ final static int PLAIN = 2;
+
+ // Don't have other possibility for now instead of using the deprecated
+ // plainTextFlavor method.
+ DataFlavor flavors[] = {DataFlavor.javaFileListFlavor,
+ DataFlavor.stringFlavor,
+ DataFlavor.plainTextFlavor};
+
+ public FileTransferable(File file)
+ {
+ addElement(file);
+ }
+
+ public synchronized DataFlavor[] getTransferDataFlavors()
+ {
+ return flavors;
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ boolean b = false;
+ b = b | flavor.equals(flavors[FILE]);
+ b |= flavor.equals(flavors[STRING]);
+ b |= flavor.equals(flavors[PLAIN]);
+ return (b);
+ }
+
+ public synchronized Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException
+ {
+ if (flavor.equals(flavors[FILE]))
+ {
+ return this;
+ }
+ else if (flavor.equals(flavors[PLAIN]))
+ {
+ return new StringReader(file.getAbsolutePath());
+ }
+ else if (flavor.equals(flavors[STRING]))
+ {
+ return (file.getAbsolutePath());
+ }
+ else
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java b/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java
new file mode 100644
index 0000000..ecbea59
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java
@@ -0,0 +1,189 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+/**
+ * A custom component, used to show images in a frame.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class FramedImage
+ extends JComponent
+ implements Skinnable
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The frame image.
+ */
+ private Image frameImage;
+
+ /**
+ * The icon image.
+ */
+ private ImageIcon icon;
+
+ /**
+ * The default width of the image.
+ */
+ protected final int width;
+
+ /**
+ * The default height of the image.
+ */
+ protected final int height;
+
+ /**
+ * Creates a FramedImage by specifying the width and the height of the
+ * label. These are used to paint the image frame in the correct bounds.
+ *
+ * @param imageIcon the icon to show within the frame
+ * @param width the width of the frame
+ * @param height the height of the frame
+ */
+ public FramedImage(ImageIcon imageIcon, int width, int height)
+ {
+ this.width = width;
+ this.height = height;
+
+ this.setPreferredSize(new Dimension(width, height));
+
+ loadSkin();
+
+ if (imageIcon != null)
+ this.icon = getScaledImage(imageIcon.getImage());
+ }
+
+ /**
+ * Creates a FramedImage by specifying the width and the height of the frame.
+ *
+ * @param width the width of the frame
+ * @param height the height of the frame
+ */
+ public FramedImage(int width, int height)
+ {
+ this(null, width, height);
+ }
+
+ /**
+ * Sets the image to display in the frame.
+ *
+ * @param image the image to display in the frame
+ */
+ public void setImageIcon(byte[] image)
+ {
+ icon = getScaledImage(image);
+
+ if (this.isVisible())
+ {
+ this.revalidate();
+ this.repaint();
+ }
+ }
+
+ /**
+ * Sets the image to display in the frame.
+ *
+ * @param image the image to display in the frame
+ */
+ public void setImageIcon(Image image)
+ {
+ icon = getScaledImage(image);
+
+ if (this.isVisible())
+ {
+ this.revalidate();
+ this.repaint();
+ }
+ }
+
+ /**
+ * Returns the image that is shown.
+ * @return the image that is shown
+ */
+ public Image getImage()
+ {
+ return icon.getImage();
+ }
+
+ /**
+ * Paints the contained image in a frame.
+ *
+ * Overrides {@link JComponent#paintComponent(Graphics)}.
+ */
+ public void paintComponent(Graphics g)
+ {
+ if (icon != null)
+ {
+ int imageWidth = icon.getIconWidth();
+ int imageHeight = icon.getIconHeight();
+ if ((imageWidth != -1) && (imageHeight != -1))
+ g.drawImage(
+ icon.getImage(),
+ width / 2 - imageWidth / 2,
+ height / 2 - imageHeight / 2,
+ null);
+ }
+
+ int frameWidth = frameImage.getWidth(this);
+ int frameHeight = frameImage.getHeight(this);
+ if ((frameWidth != -1) && (frameHeight != -1))
+ g.drawImage(
+ frameImage,
+ width / 2 - frameWidth / 2,
+ height / 2 - frameHeight / 2,
+ null);
+ }
+
+ /**
+ * Loads the framed image.
+ */
+ public void loadSkin()
+ {
+ this.frameImage
+ = ImageUtils
+ .scaleImageWithinBounds(
+ DesktopUtilActivator
+ .getResources()
+ .getImage("service.gui.USER_PHOTO_FRAME").getImage(),
+ width,
+ height);
+ }
+
+ /**
+ * Returns the scaled image version of the given image.
+ *
+ * @param image the image to transform
+ * @return the scaled image version of the given image
+ */
+ private ImageIcon getScaledImage(Image image)
+ {
+ return ImageUtils.getScaledRoundedIcon(image, width - 2, height - 2);
+ }
+
+ /**
+ * Returns the scaled image version of the given image.
+ *
+ * @param image the image to transform
+ * @return the scaled image version of the given image
+ */
+ private ImageIcon getScaledImage(byte[] image)
+ {
+ return ImageUtils.getScaledRoundedIcon(image, width - 2, height - 2);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java b/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java
new file mode 100644
index 0000000..b46211b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java
@@ -0,0 +1,279 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * A custom component, used to show images in a frame. A rollover for the
+ * content image and optional menu in dialog.
+ *
+ * @author Damien Roth
+ */
+public class FramedImageWithMenu
+ extends FramedImage
+ implements MouseListener, PopupMenuListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The dialog containing the menu with actions.
+ */
+ private JPopupMenu popupMenu;
+
+ /**
+ * The parent frame.
+ */
+ private JFrame mainFrame;
+
+ /**
+ * Should we currently draw overlay.
+ */
+ private boolean drawOverlay = false;
+
+ /**
+ * Are we showing custom image or the default one.
+ */
+ private boolean isDefaultImage = true;
+
+ /**
+ * The current image.
+ */
+ private Image currentImage;
+
+ /**
+ * Creates the component.
+ * @param mainFrame the parent frame.
+ * @param imageIcon the image icon to show as default one.
+ * @param width width of component.
+ * @param height height of component.
+ */
+ public FramedImageWithMenu(
+ JFrame mainFrame,
+ ImageIcon imageIcon,
+ int width,
+ int height)
+ {
+ super(imageIcon, width, height);
+
+ this.mainFrame = mainFrame;
+ this.addMouseListener(this);
+ }
+
+ /**
+ * Sets the dialog used for menu for this Image.
+ * @param popupMenu the dialog to show as menu. Can be null if no menu
+ * will be available.
+ */
+ public void setPopupMenu(JPopupMenu popupMenu)
+ {
+ this.popupMenu = popupMenu;
+ if(popupMenu != null)
+ this.popupMenu.addPopupMenuListener(this);
+ }
+
+ /**
+ * Sets the image to display in the frame.
+ *
+ * @param imageIcon the image to display in the frame
+ */
+ public void setImageIcon(ImageIcon imageIcon)
+ {
+ // Intercept the action to validate the user icon and not the default
+ super.setImageIcon(imageIcon.getImage());
+ this.isDefaultImage = false;
+
+ this.currentImage = imageIcon.getImage();
+ }
+
+ /**
+ * Returns the current image with no rounded corners. Only return the user
+ * image and not the default image.
+ *
+ * @return the current image - null if it's the default image
+ */
+ public Image getAvatar()
+ {
+ return (!this.isDefaultImage) ? this.currentImage : this.getImage();
+ }
+
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ if (drawOverlay)
+ {
+ g = g.create();
+ AntialiasingManager.activateAntialiasing(g);
+
+ try
+ {
+ // Paint a roll over fade out.
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ visibility /= 4;
+ }
+ else
+ visibility = 0.5f;
+
+ // Draw black overlay
+ g.setColor(new Color(0.0f, 0.0f, 0.0f, visibility));
+ g.fillRoundRect(1, 1, width - 2, height - 2, 10, 10);
+
+ // Draw arrow
+ g.setColor(Color.WHITE);
+
+ int[] arrowX = new int[] {
+ width - 17,
+ width - 7,
+ width - 12
+ };
+ int[] arrowY = new int[] {
+ height - 12,
+ height - 12,
+ height - 7
+ };
+ g.fillPolygon(arrowX, arrowY, arrowX.length);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+ }
+
+ /**
+ * Show the avatar dialog as a glasspane of the mainframe
+ *
+ * @param show show dialogs if sets to TRUE - hide otherwise
+ */
+ private void showDialog(MouseEvent e, boolean show)
+ {
+ if (this.popupMenu == null)
+ {
+ return;
+ }
+
+ if (show)
+ {
+ Point imageLoc = this.getLocationOnScreen();
+ Point rootPaneLoc = mainFrame.getRootPane().getLocationOnScreen();
+
+ this.popupMenu.setSize(mainFrame.getRootPane().getWidth(),
+ this.popupMenu.getHeight());
+
+ this.popupMenu.show(this, (rootPaneLoc.x - imageLoc.x),
+ this.getHeight());
+ }
+ else
+ {
+ this.drawOverlay = false;
+ this.repaint();
+ }
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ if (this.drawOverlay)
+ return;
+
+ this.drawOverlay = true;
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ FramedImageWithMenu.this,
+ true,
+ new AvatarRepaintCallback());
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ // Remove overlay only if the dialog isn't visible
+ if (!popupMenu.isVisible())
+ {
+ this.drawOverlay = false;
+ this.repaint();
+ }
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ showDialog(e, !popupMenu.isVisible());
+ }
+
+ /**
+ * This method is called before the popup menu becomes visible
+ */
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
+
+ /**
+ * This method is called before the popup menu becomes invisible
+ * Note that a JPopupMenu can become invisible any time
+ */
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
+ {
+ this.drawOverlay = false;
+ this.repaint();
+ }
+
+ /**
+ * This method is called when the popup menu is canceled
+ */
+ public void popupMenuCanceled(PopupMenuEvent e){}
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class AvatarRepaintCallback
+ implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ FramedImageWithMenu.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {}
+
+ public void mousePressed(MouseEvent e) {}
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/GenericFileDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/GenericFileDialog.java
new file mode 100644
index 0000000..d818561
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/GenericFileDialog.java
@@ -0,0 +1,100 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+import org.jitsi.util.*;
+
+
+/**
+ * This class is the entry point for creating a file dialog regarding to the OS.
+ *
+ * If the current operating system is Apple Mac OS X, we create an AWT
+ * FileDialog (user interface is more practical under Mac OS than a
+ * JFileChooser), else, a Swing JFileChooser.
+ *
+ * @author Valentin Martinet
+ */
+public class GenericFileDialog
+{
+ /**
+ * Creates a file dialog (AWT's FileDialog or Swing's JFileChooser)
+ * regarding to user's operating system.
+ *
+ * @param parent the parent Frame/JFrame of this dialog
+ * @param title dialog's title
+ * @param fileOperation
+ * @return a SipCommFileChooser instance
+ */
+ public static SipCommFileChooser create(
+ Frame parent,
+ String title,
+ int fileOperation)
+ {
+ int operation;
+
+ if(OSUtils.IS_MAC)
+ {
+ switch (fileOperation)
+ {
+ case SipCommFileChooser.LOAD_FILE_OPERATION:
+ operation = FileDialog.LOAD;
+ break;
+ case SipCommFileChooser.SAVE_FILE_OPERATION:
+ operation = FileDialog.SAVE;
+ break;
+ default:
+ throw new IllegalArgumentException("fileOperation");
+ }
+
+ if (parent == null)
+ parent = new Frame();
+
+ return new SipCommFileDialogImpl(parent, title, operation);
+ }
+ else
+ {
+ switch (fileOperation)
+ {
+ case SipCommFileChooser.LOAD_FILE_OPERATION:
+ operation = JFileChooser.OPEN_DIALOG;
+ break;
+ case SipCommFileChooser.SAVE_FILE_OPERATION:
+ operation = JFileChooser.SAVE_DIALOG;
+ break;
+ default:
+ throw new IllegalArgumentException("fileOperation");
+ }
+
+ return new SipCommFileChooserImpl(title, operation);
+ }
+ }
+
+ /**
+ * Creates a file dialog (AWT FileDialog or Swing JFileChooser) regarding to
+ * user's operating system.
+ *
+ * @param parent the parent Frame/JFrame of this dialog
+ * @param title dialog's title
+ * @param fileOperation
+ * @param path start path of this dialog
+ * @return SipCommFileChooser an implementation of SipCommFileChooser
+ */
+ public static SipCommFileChooser create(
+ Frame parent, String title, int fileOperation, String path)
+ {
+ SipCommFileChooser scfc
+ = GenericFileDialog.create(parent, title, fileOperation);
+
+ if(path != null)
+ scfc.setStartPath(path);
+ return scfc;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ImageCanvas.java b/src/net/java/sip/communicator/plugin/desktoputil/ImageCanvas.java
new file mode 100644
index 0000000..86ccd90
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ImageCanvas.java
@@ -0,0 +1,91 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class ImageCanvas
+ extends TransparentPanel
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private ImageIcon icon;
+
+ /**
+ * Constructor.
+ *
+ * @param image the image for the canvas
+ */
+ public ImageCanvas(Image image)
+ {
+ setImage(image);
+ }
+
+ protected void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ if (icon == null)
+ return;
+
+ int imageWidth = icon.getIconWidth();
+ if (imageWidth < 1)
+ return;
+ int imageHeight = icon.getIconHeight();
+ if (imageHeight < 1)
+ return;
+
+ int width = getWidth();
+ boolean scale = false;
+ float scaleFactor = 1;
+ if (imageWidth > width)
+ {
+ scale = true;
+ scaleFactor = width / (float) imageWidth;
+ }
+ int height = getHeight();
+ if (imageHeight > height)
+ {
+ scale = true;
+ scaleFactor = Math.min(scaleFactor, height / (float) imageHeight);
+ }
+ if (scale)
+ {
+ imageWidth = Math.round(imageWidth * scaleFactor);
+ imageHeight = Math.round(imageHeight * scaleFactor);
+ }
+
+ g.drawImage(icon.getImage(), (width - imageWidth) / 2,
+ (height - imageHeight) / 2, imageWidth, imageHeight, null);
+ }
+
+ /**
+ * Sets image to be painted.
+ * @param image Image to be painted.
+ */
+ public void setImage(Image image)
+ {
+ icon = (image == null) ? null : new ImageIcon(image);
+
+ if (icon != null)
+ {
+ final int preferredWidth = icon.getIconWidth();
+ final int preferredHeight = icon.getIconHeight();
+ setMinimumSize(new Dimension(preferredWidth / 2,
+ preferredHeight / 2));
+ setPreferredSize(new Dimension(preferredWidth, preferredHeight));
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ImageUtils.java b/src/net/java/sip/communicator/plugin/desktoputil/ImageUtils.java
new file mode 100644
index 0000000..4ec5b74
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ImageUtils.java
@@ -0,0 +1,449 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.io.*;
+import java.net.*;
+
+import javax.imageio.*;
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * Utility methods for image manipulation.
+ *
+ * @author Sebastien Mazy
+ * @author Yana Stamcheva
+ * @author Lubomir Marinov
+ */
+public class ImageUtils
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>ImageUtils</tt> class for logging
+ * output.
+ */
+ private static final Logger logger = Logger.getLogger(ImageUtils.class);
+
+ /**
+ * Returns a scaled image fitting within the given bounds while keeping the
+ * aspect ratio.
+ *
+ * @param image the image to scale
+ * @param width maximum width of the scaled image
+ * @param height maximum height of the scaled image
+ * @return the scaled image
+ */
+ public static Image scaleImageWithinBounds( Image image,
+ int width,
+ int height)
+ {
+ int initialWidth = image.getWidth(null);
+ int initialHeight = image.getHeight(null);
+
+ Image scaledImage;
+ int scaleHint = Image.SCALE_SMOOTH;
+ double originalRatio =
+ (double) initialWidth / initialHeight;
+ double areaRatio = (double) width / height;
+
+ if(originalRatio > areaRatio)
+ scaledImage = image.getScaledInstance(width, -1, scaleHint);
+ else
+ scaledImage = image.getScaledInstance(-1, height, scaleHint);
+ return scaledImage;
+ }
+
+ /**
+ * Scales the given <tt>image</tt> to fit in the given <tt>width</tt> and
+ * <tt>height</tt>.
+ * @param image the image to scale
+ * @param width the desired width
+ * @param height the desired height
+ * @return the scaled image
+ */
+ public static ImageIcon scaleIconWithinBounds(Image image, int width,
+ int height)
+ {
+ return new ImageIcon(scaleImageWithinBounds(image, width, height));
+ }
+
+ /**
+ * Scales the given <tt>image</tt> to fit in the given <tt>width</tt> and
+ * <tt>height</tt>.
+ *
+ * @param imageBytes the bytes of the image to scale
+ * @param width the desired width
+ * @param height the desired height
+ * @return the scaled image
+ */
+ public static ImageIcon scaleImageWithinBounds( byte[] imageBytes,
+ int width,
+ int height)
+ {
+
+ if (imageBytes == null || !(imageBytes.length > 0))
+ return null;
+
+ Image imageIcon = null;
+
+ try
+ {
+ Image image = null;
+
+ // sometimes ImageIO fails, will fall back to awt Toolkit
+ try
+ {
+ image = ImageIO.read(new ByteArrayInputStream(imageBytes));
+ } catch (Exception e)
+ {
+ try
+ {
+ image = Toolkit.getDefaultToolkit().createImage(imageBytes);
+ } catch (Exception e1)
+ {
+ // if it fails throw the original exception
+ throw e;
+ }
+ }
+ if(image != null)
+ imageIcon = scaleImageWithinBounds(image, width, height);
+ else
+ if (logger.isTraceEnabled())
+ logger.trace("Unknown image format or error reading image");
+ }
+ catch (Exception e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Could not create image.", e);
+ }
+
+ if (imageIcon != null)
+ return new ImageIcon(imageIcon);
+
+ return null;
+ }
+
+ /**
+ * Creates a rounded avatar image.
+ *
+ * @param image image of the initial avatar image.
+ * @param width the desired width
+ * @param height the desired height
+ * @return The rounded corner image.
+ */
+ public static Image getScaledRoundedImage( Image image,
+ int width,
+ int height)
+ {
+ ImageIcon scaledImage =
+ ImageUtils.scaleIconWithinBounds(image, width, height);
+ int scaledImageWidth = scaledImage.getIconWidth();
+ int scaledImageHeight = scaledImage.getIconHeight();
+
+ if(scaledImageHeight <= 0 ||
+ scaledImageWidth <= 0)
+ return null;
+
+ // Just clipping the image would cause jaggies on Windows and Linux.
+ // The following is a soft clipping solution based on the solution
+ // proposed by Chris Campbell:
+ // http://java.sun.com/mailers/techtips/corejava/2006/tt0923.html
+ BufferedImage destImage
+ = new BufferedImage(scaledImageWidth, scaledImageHeight,
+ BufferedImage.TYPE_INT_ARGB);
+
+ Graphics2D g = destImage.createGraphics();
+
+ try
+ {
+ // Render our clip shape into the image. Note that we enable
+ // antialiasing to achieve the soft clipping effect.
+ g.setComposite(AlphaComposite.Src);
+ AntialiasingManager.activateAntialiasing(g);
+ g.setColor(Color.WHITE);
+ g.fillRoundRect(0, 0, scaledImageWidth, scaledImageHeight, 5, 5);
+
+ // We use SrcAtop, which effectively uses the
+ // alpha value as a coverage value for each pixel stored in the
+ // destination. For the areas outside our clip shape, the
+ // destination alpha will be zero, so nothing is rendered in those
+ // areas. For the areas inside our clip shape, the destination alpha
+ // will be fully opaque, so the full color is rendered. At the edges,
+ // the original antialiasing is carried over to give us the desired
+ // soft clipping effect.
+ g.setComposite(AlphaComposite.SrcAtop);
+ g.drawImage(scaledImage.getImage(), 0, 0, null);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ return destImage;
+ }
+
+ /**
+ * Returns a scaled instance of the given <tt>image</tt>.
+ * @param image the image to scale
+ * @param width the desired width
+ * @param height the desired height
+ * @return a byte array containing the scaled image
+ */
+ public static byte[] getScaledInstanceInBytes(
+ Image image, int width, int height)
+ {
+ byte[] scaledBytes = null;
+
+ BufferedImage scaledImage
+ = (BufferedImage) getScaledRoundedImage(image, width, height);
+
+ if (scaledImage != null)
+ {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+ try
+ {
+ ImageIO.write(scaledImage, "png", outStream);
+ scaledBytes = outStream.toByteArray();
+ }
+ catch (IOException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Could not scale image in bytes.", e);
+ }
+
+ }
+
+ return scaledBytes;
+ }
+
+ /**
+ * Returns a scaled rounded icon from the given <tt>image</tt>, scaled
+ * within the given <tt>width</tt> and <tt>height</tt>.
+ * @param image the image to scale
+ * @param width the maximum width of the scaled icon
+ * @param height the maximum height of the scaled icon
+ * @return a scaled rounded icon
+ */
+ public static ImageIcon getScaledRoundedIcon(Image image, int width,
+ int height)
+ {
+ Image scaledImage = getScaledRoundedImage(image, width, height);
+
+ if (scaledImage != null)
+ return new ImageIcon(scaledImage);
+
+ return null;
+ }
+
+ /**
+ * Creates a rounded corner scaled image.
+ *
+ * @param imageBytes The bytes of the image to be scaled.
+ * @param width The maximum width of the scaled image.
+ * @param height The maximum height of the scaled image.
+ *
+ * @return The rounded corner scaled image.
+ */
+ public static ImageIcon getScaledRoundedIcon( byte[] imageBytes,
+ int width,
+ int height)
+ {
+ if (imageBytes == null || !(imageBytes.length > 0))
+ return null;
+
+ ImageIcon imageIcon = null;
+
+ try
+ {
+ Image image = null;
+
+ // sometimes ImageIO fails, will fall back to awt Toolkit
+ try
+ {
+ image = ImageIO.read(new ByteArrayInputStream(imageBytes));
+ } catch (Exception e)
+ {
+ try
+ {
+ image = Toolkit.getDefaultToolkit().createImage(imageBytes);
+ } catch (Exception e1)
+ {
+ // if it fails throw the original exception
+ throw e;
+ }
+ }
+ if(image != null)
+ imageIcon = getScaledRoundedIcon(image, width, height);
+ else
+ if (logger.isTraceEnabled())
+ logger.trace("Unknown image format or error reading image");
+ }
+ catch (Exception e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Could not create image.", e);
+ }
+
+ return imageIcon;
+ }
+
+ /**
+ * Returns the buffered image corresponding to the given url image path.
+ *
+ * @param imagePath the path indicating, where we can find the image.
+ *
+ * @return the buffered image corresponding to the given url image path.
+ */
+ public static BufferedImage getBufferedImage(URL imagePath)
+ {
+ BufferedImage image = null;
+
+ if (imagePath != null)
+ {
+ try
+ {
+ image = ImageIO.read(imagePath);
+ }
+ catch (IOException ex)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to load image:" + imagePath, ex);
+ }
+ }
+ return image;
+ }
+
+ /**
+ * Returns the buffered image corresponding to the given image
+ * @param source an image
+ * @return the buffered image corresponding to the given image
+ */
+ public static BufferedImage getBufferedImage(Image source)
+ {
+ if (source == null)
+ {
+ return null;
+ }
+ else if (source instanceof BufferedImage)
+ {
+ return (BufferedImage) source;
+ }
+
+ int width = source.getWidth(null);
+ int height = source.getHeight(null);
+
+ BufferedImage image
+ = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+ Graphics graphics = image.createGraphics();
+ graphics.drawImage(source, 0, 0, null);
+ graphics.dispose();
+
+ return image;
+ }
+
+ /**
+ * Extracts bytes from image.
+ * @param image the image.
+ * @return the bytes of the image.
+ */
+ public static byte[] toByteArray(BufferedImage image)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try
+ {
+ ImageIO.write(image, "png", out);
+ }
+ catch (IOException e)
+ {
+ logger.debug("Cannot convert buffered image to byte[]", e);
+ return null;
+ }
+
+ return out.toByteArray();
+ }
+
+ /**
+ * Loads an image from a given bytes array.
+ * @param imageBytes The bytes array to load the image from.
+ * @return The image for the given bytes array.
+ */
+ public static Image getBytesInImage(byte[] imageBytes)
+ {
+ Image image = null;
+ try
+ {
+ image = ImageIO.read(
+ new ByteArrayInputStream(imageBytes));
+
+ }
+ catch (Exception e)
+ {
+ logger.error("Failed to convert bytes to image.", e);
+ }
+ return image;
+ }
+
+ /**
+ * Creates a composed image from two images. If one of the images
+ * is missing will add an empty space on its place.
+ * @param leftImage the left image.
+ * @param rightImage the right image
+ * @param imageObserver need to calculate image sizes.
+ * @return the composed image.
+ */
+ public static Image getComposedImage(
+ Image leftImage, Image rightImage,
+ ImageObserver imageObserver)
+ {
+ int height = 0;
+ if(leftImage == null && rightImage == null)
+ return null;
+ if(leftImage != null && rightImage != null)
+ height = Math.max(leftImage.getHeight(imageObserver),
+ rightImage.getHeight(imageObserver));
+ else if(leftImage == null)
+ height = rightImage.getHeight(imageObserver);
+ else
+ height = leftImage.getHeight(imageObserver);
+
+ int width = 0;
+ int leftWidth = 0;
+ if(leftImage != null && rightImage != null)
+ {
+ leftWidth = leftImage.getWidth(imageObserver);
+ width = leftWidth +
+ rightImage.getWidth(imageObserver);
+ }
+ else if(leftImage == null)
+ {
+ leftWidth = rightImage.getWidth(imageObserver);
+ width = leftWidth*2;
+ }
+ else
+ {
+ leftWidth = leftImage.getWidth(imageObserver);
+ width = leftWidth*2;
+ }
+
+ BufferedImage buffImage =
+ new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = (Graphics2D) buffImage.getGraphics();
+
+ AntialiasingManager.activateAntialiasing(g);
+ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+ if(leftImage != null)
+ g.drawImage(leftImage, 0, 0, null);
+ if(rightImage != null)
+ g.drawImage(rightImage, leftWidth + 1, 0, null);
+
+ return buffImage;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/LightGrayFilter.java b/src/net/java/sip/communicator/plugin/desktoputil/LightGrayFilter.java
new file mode 100644
index 0000000..44c8e4e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/LightGrayFilter.java
@@ -0,0 +1,49 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.image.*;
+
+import javax.swing.*;
+
+/**
+ * An image filter that "disables" an image by turning
+ * it into a grayscale image, and brightening the pixels
+ * in the image. Used by buttons to create an image for
+ * a disabled button. Creates a more brighter image than
+ * the javax.swing.GrayFilter.
+ *
+ * @author Yana Stamcheva
+ */
+public class LightGrayFilter extends GrayFilter
+{
+ /**
+ * Creates an instance of a LightGrayFilter.
+ * @param b a boolean -- true if the pixels should be brightened
+ * @param p an int in the range 0..100 that determines the percentage
+ * of gray, where 100 is the darkest gray, and 0 is the lightest
+ */
+ public LightGrayFilter(boolean b, int p)
+ {
+ super(b, p);
+ }
+
+ /**
+ * Creates a disabled image.
+ * @param i The source image.
+ * @return A disabled image based on the source image.
+ */
+ public static Image createDisabledImage(Image i)
+ {
+ LightGrayFilter filter = new LightGrayFilter(true, 50);
+ ImageProducer prod = new FilteredImageSource(i.getSource(), filter);
+ Image grayImage = Toolkit.getDefaultToolkit().createImage(prod);
+
+ return grayImage;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/LowPriorityEventQueue.java b/src/net/java/sip/communicator/plugin/desktoputil/LowPriorityEventQueue.java
new file mode 100644
index 0000000..a904448
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/LowPriorityEventQueue.java
@@ -0,0 +1,53 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * The <tt>LowPriorityEventQueue</tt> schedules low priority events to be
+ * dispatched through the system event queue.
+ *
+ * @author Yana Stamcheva
+ */
+public class LowPriorityEventQueue
+{
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the event dispatch thread with low priority.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed synchronously on the <code>EventQueue</code>
+ */
+ public static void invokeLater(Runnable runnable)
+ {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
+ new LowPriorityInvocationEvent(
+ Toolkit.getDefaultToolkit(), runnable));
+ }
+
+ /**
+ * The <tt>LowPriorityInvocationEvent</tt> is an <tt>InvocationEvent</tt>
+ * that replaces the default event id with the <tt>PaintEvent.UPDATE</tt>
+ * in order to indicate that this event should be dispatched with the same
+ * priority as an update paint event, which is normally with lower priority
+ * than other events.
+ */
+ private static class LowPriorityInvocationEvent extends InvocationEvent
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public LowPriorityInvocationEvent(Object source, Runnable runnable)
+ {
+ super(source, PaintEvent.UPDATE, runnable, null, false);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/MasterPasswordInputDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/MasterPasswordInputDialog.java
new file mode 100644
index 0000000..6542b96
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/MasterPasswordInputDialog.java
@@ -0,0 +1,296 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.resources.*;
+
+/**
+ * The master password input dialog.
+ *
+ * @author Dmitri Melnikov
+ */
+public class MasterPasswordInputDialog
+ extends SIPCommDialog
+ implements ActionListener,
+ KeyListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Instance of this class.
+ */
+ private static MasterPasswordInputDialog dialog;
+
+ /**
+ * The <tt>ResourceManagementService</tt> used by this instance to access
+ * the localized and internationalized resources of the application.
+ */
+ private final ResourceManagementService resources
+ = DesktopUtilActivator.getResources();
+
+ /**
+ * Password obtained from the user.
+ */
+ private String password;
+
+ /**
+ * UI components.
+ */
+ private JPasswordField currentPasswdField;
+ private JButton okButton;
+ private JButton cancelButton;
+ private JTextArea infoTextArea;
+ private JTextArea errorTextArea;
+ private JPanel buttonsPanel;
+ private JPanel dataPanel;
+
+ /**
+ * Builds the dialog.
+ */
+ private MasterPasswordInputDialog()
+ {
+ super(false);
+
+ initComponents();
+
+ this.setTitle(resources
+ .getI18NString("plugin.securityconfig.masterpassword.MP_TITLE"));
+ this.setModal(true);
+ this.setResizable(false);
+
+ JPanel mainPanel = new TransparentPanel(new BorderLayout(10, 10));
+ mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ mainPanel.add(createIconComponent(), BorderLayout.WEST);
+ mainPanel.add(dataPanel);
+
+ this.getContentPane().add(mainPanel);
+
+ this.pack();
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int x = (screenSize.width - this.getWidth()) / 2;
+ int y = (screenSize.height - this.getHeight()) / 2;
+
+ this.setLocation(x, y);
+ }
+
+ /**
+ * Initializes the UI components.
+ */
+ private void initComponents()
+ {
+ dataPanel = new TransparentPanel();
+ dataPanel.setLayout(new BoxLayout(dataPanel, BoxLayout.Y_AXIS));
+
+ // info text
+ infoTextArea = new JTextArea();
+ infoTextArea.setEditable(false);
+ infoTextArea.setOpaque(false);
+ infoTextArea.setFont(infoTextArea.getFont().deriveFont(Font.BOLD));
+ infoTextArea.setText(resources
+ .getI18NString("plugin.securityconfig.masterpassword.MP_INPUT"));
+
+ // error text
+ errorTextArea = new JTextArea();
+ errorTextArea.setEditable(false);
+ errorTextArea.setOpaque(false);
+ errorTextArea.setForeground(Color.red);
+ errorTextArea.setFont(errorTextArea.getFont().deriveFont(Font.BOLD));
+ errorTextArea.setText(resources
+ .getI18NString("plugin.securityconfig.masterpassword"
+ + ".MP_VERIFICATION_FAILURE_MSG"));
+
+ // password fields
+ currentPasswdField = new JPasswordField(15);
+ currentPasswdField.addKeyListener(this);
+ currentPasswdField.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ okButton.doClick();
+ }
+ });
+ // Prevents the password field to select the whole text automatically
+ // when it regains the focus. The master password dialog may loose the
+ // focus and regain it when the main contact list window is loaded, so
+ // we make sure here that we won't delete everything that we've already
+ // typed when the focus lost/gained events happen.
+ currentPasswdField.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusGained(FocusEvent evt2)
+ {
+ int caretPosition = currentPasswdField.getCaretPosition();
+ currentPasswdField.setSelectionEnd(0);
+ // Reset the caret position.
+ currentPasswdField.setCaretPosition(caretPosition);
+ }
+ });
+
+ // OK and cancel buttons
+ okButton = new JButton(resources.getI18NString("service.gui.OK"));
+ okButton.setMnemonic(resources.getI18nMnemonic("service.gui.OK"));
+ okButton.addActionListener(this);
+
+ cancelButton =
+ new JButton(resources.getI18NString("service.gui.CANCEL"));
+ cancelButton.setMnemonic(resources.getI18nMnemonic(
+ "service.gui.CANCEL"));
+ cancelButton.addActionListener(this);
+
+ buttonsPanel = new TransparentPanel(
+ new FlowLayout(FlowLayout.RIGHT, 0, 5));
+ buttonsPanel.add(okButton);
+ buttonsPanel.add(cancelButton);
+
+ rebuildMainPanel(false);
+ }
+
+ /**
+ * Removes and adds again all the components to the main panel.
+ *
+ * @param includeErrorMsg when true also includes an error text component
+ */
+ private void rebuildMainPanel(boolean includeErrorMsg)
+ {
+ dataPanel.removeAll();
+
+ if (includeErrorMsg)
+ dataPanel.add(errorTextArea);
+ dataPanel.add(infoTextArea);
+ dataPanel.add(currentPasswdField);
+ dataPanel.add(buttonsPanel);
+ }
+
+ /**
+ * Shows an input dialog to the user to obtain the master password.
+ *
+ * @param prevSuccess <tt>true</tt> if any previous call returned a correct
+ * master password and there is no need to show an extra "verification
+ * failed" message
+ * @return the master password obtained from the user or <tt>null</tt> if
+ * none was provided
+ */
+ public static String showInput(boolean prevSuccess)
+ {
+ if (dialog == null)
+ dialog = new MasterPasswordInputDialog();
+
+ dialog.rebuildMainPanel(!prevSuccess);
+ dialog.resetPassword();
+
+ // blocks until user performs an action
+ dialog.setVisible(true);
+
+ return dialog.password;
+ }
+
+ /**
+ * OK button click event handler. Retrieves the password and hides the
+ * dialog.
+ *
+ * @param e action event
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ JButton sourceButton = (JButton) e.getSource();
+ if (sourceButton.equals(okButton))
+ {
+ password
+ = new String(
+ currentPasswdField.getPassword());
+ }
+ // hide dialog and unblock application
+ dialog.dispose();
+ }
+
+ /**
+ * Closes the dialog.
+ *
+ * @param escaped <tt>true</tt> if this dialog has been closed by pressing
+ * the Esc key; otherwise, <tt>false</tt>
+ */
+ protected void close(boolean escaped)
+ {
+ cancelButton.doClick();
+ }
+
+ /**
+ * Resets the password by clearing the input field and setting
+ * <tt>password</tt> to <tt>null</tt>. Disables the OK button.
+ */
+ private void resetPassword()
+ {
+ password = null;
+ currentPasswdField.setText("");
+ currentPasswdField.requestFocusInWindow();
+ okButton.setEnabled(false);
+ }
+
+ /**
+ * Disables OK button if the password input field is empty.
+ *
+ * @param event key event
+ */
+ public void keyReleased(KeyEvent event)
+ {
+ JPasswordField source = (JPasswordField) event.getSource();
+ if (currentPasswdField.equals(source))
+ {
+ String password = new String(currentPasswdField.getPassword());
+ okButton.setEnabled(password.length() > 0);
+ password = null;
+ }
+ }
+
+ /**
+ * Not overriding.
+ *
+ * @param arg0 key event
+ */
+ public void keyPressed(KeyEvent arg0)
+ {
+ }
+
+ /**
+ * Not overriding.
+ *
+ * @param arg0 key event
+ */
+ public void keyTyped(KeyEvent arg0)
+ {
+ }
+
+ /**
+ * Creates the icon component to show on the left of this dialog.
+ *
+ * @return the created component
+ */
+ private static Component createIconComponent()
+ {
+ JPanel wrapIconPanel = new TransparentPanel(new BorderLayout());
+
+ JLabel iconLabel = new JLabel();
+
+ iconLabel.setIcon(DesktopUtilActivator.getResources()
+ .getImage("service.gui.icons.AUTHORIZATION_ICON"));
+
+ wrapIconPanel.add(iconLabel, BorderLayout.NORTH);
+
+ return wrapIconPanel;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/MoveableTableModel.java b/src/net/java/sip/communicator/plugin/desktoputil/MoveableTableModel.java
new file mode 100644
index 0000000..66830a5
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/MoveableTableModel.java
@@ -0,0 +1,25 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.table.*;
+
+/**
+ * @author Vincent Lucas
+ */
+public abstract class MoveableTableModel
+ extends AbstractTableModel
+{
+ /**
+ * Move the row.
+ *
+ * @param rowIndex index of the row
+ * @param up true to move up, false to move down
+ 8
+ * @return the next row index
+ */
+ public abstract int move(int rowIndex, boolean up);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/NetworkUtils.java b/src/net/java/sip/communicator/plugin/desktoputil/NetworkUtils.java
new file mode 100644
index 0000000..7d76511
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/NetworkUtils.java
@@ -0,0 +1,1661 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.beans.*;
+import java.net.*;
+import java.text.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import net.java.sip.communicator.plugin.desktoputil.dns.*;
+import net.java.sip.communicator.service.netaddr.event.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.SRVRecord;
+
+import org.xbill.DNS.*;
+
+/**
+ * Utility methods and fields to use when working with network addresses.
+ *
+ * @author Emil Ivov
+ * @author Damian Minkov
+ * @author Vincent Lucas
+ * @author Alan Kelly
+ */
+public class NetworkUtils
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>NetworkUtils</tt> class for logging
+ * output.
+ */
+ private static final Logger logger = Logger.getLogger(NetworkUtils.class);
+
+ /**
+ * A string containing the "any" local address for IPv6.
+ */
+ public static final String IN6_ADDR_ANY = "::0";
+
+ /**
+ * A string containing the "any" local address for IPv4.
+ */
+ public static final String IN4_ADDR_ANY = "0.0.0.0";
+
+ /**
+ * A string containing the "any" local address.
+ */
+ public static final String IN_ADDR_ANY = determineAnyAddress();
+
+ /**
+ * The length of IPv6 addresses.
+ */
+ private final static int IN6_ADDR_SIZE = 16;
+
+ /**
+ * The size of the tokens in a <tt>String</tt> representation of IPv6
+ * addresses.
+ */
+ private final static int IN6_ADDR_TOKEN_SIZE = 2;
+
+ /**
+ * The length of IPv4 addresses.
+ */
+ private final static int IN4_ADDR_SIZE = 4;
+
+ /**
+ * The maximum int value that could correspond to a port number.
+ */
+ public static final int MAX_PORT_NUMBER = 65535;
+
+ /**
+ * The minimum int value that could correspond to a port number bindable
+ * by the SIP Communicator.
+ */
+ public static final int MIN_PORT_NUMBER = 1024;
+
+ /**
+ * The random port number generator that we use in getRandomPortNumer()
+ */
+ private static Random portNumberGenerator = new Random();
+
+ /**
+ * The name of the property that users may use to override the
+ * address of our backup DNS resolver.
+ */
+ public static final String PNAME_BACKUP_RESOLVER
+ = "net.java.sip.communicator.util.dns.BACKUP_RESOLVER";
+
+ /**
+ * The name of the property that users may use to disable
+ * our backup DNS resolver.
+ */
+ public static final String PNAME_BACKUP_RESOLVER_ENABLED
+ = "net.java.sip.communicator.util.dns.BACKUP_RESOLVER_ENABLED";
+
+ /**
+ * The default of the property that users may use to disable
+ * our backup DNS resolver.
+ */
+ public static final boolean PDEFAULT_BACKUP_RESOLVER_ENABLED = true;
+
+ /**
+ * The name of the property that users may use to override the port
+ * of our backup DNS resolver.
+ */
+ public static final String PNAME_BACKUP_RESOLVER_PORT
+ = "net.java.sip.communicator.util.dns.BACKUP_RESOLVER_PORT";
+
+ /**
+ * The address of the backup resolver we would use by default.
+ */
+ public static final String DEFAULT_BACKUP_RESOLVER
+ = "backup-resolver.jitsi.net";
+
+ /**
+ * The name of the property that users may use to override the
+ * IP address of our backup DNS resolver. This is only used when the
+ * backup resolver name cannot be determined.
+ */
+ public static final String PNAME_BACKUP_RESOLVER_FALLBACK_IP
+ = "net.java.sip.communicator.util.dns.BACKUP_RESOLVER_FALLBACK_IP";
+
+ /**
+ * The name of the boolean property that defines whether all domain names
+ * looked up from Jitsi should be treated as absolute.
+ */
+ public static final String PNAME_DNS_ALWAYS_ABSOLUTE
+ = "net.java.sip.communicator.util.dns.DNSSEC_ALWAYS_ABSOLUTE";
+
+ /**
+ * Default value of {@link #PNAME_DNS_ALWAYS_ABSOLUTE}.
+ */
+ public static final boolean PDEFAULT_DNS_ALWAYS_ABSOLUTE = false;
+
+ /**
+ * The DNSjava resolver that we use with SRV and NAPTR queries in order to
+ * try and smooth the problem of DNS servers that silently drop them.
+ */
+ private static Resolver parallelResolver = null;
+
+ /**
+ * Monitor object to set or reset the parallel resolver.
+ */
+ private final static Object parallelResolverLock = new Object();
+
+ /**
+ * Initialization flag for {@link #netListener}
+ */
+ private static final AtomicBoolean netListenerAdded = new AtomicBoolean();
+
+ /**
+ * Listener for network change events to reset the DNS resolvers.
+ */
+ private static final NetworkListener netListener = new NetworkListener();
+
+ /**
+ * A random number generator.
+ */
+ private static final Random random = new Random();
+
+ /**
+ * Determines whether the address is the result of windows auto configuration.
+ * (i.e. One that is in the 169.254.0.0 network)
+ * @param add the address to inspect
+ * @return true if the address is autoconfigured by windows, false otherwise.
+ */
+ public static boolean isWindowsAutoConfiguredIPv4Address(InetAddress add)
+ {
+ return (add.getAddress()[0] & 0xFF) == 169
+ && (add.getAddress()[1] & 0xFF) == 254;
+ }
+
+ /**
+ * Determines whether the address is an IPv4 link local address. IPv4 link
+ * local addresses are those in the following networks:
+ *
+ * 10.0.0.0 to 10.255.255.255
+ * 172.16.0.0 to 172.31.255.255
+ * 192.168.0.0 to 192.168.255.255
+ *
+ * @param add the address to inspect
+ * @return true if add is a link local ipv4 address and false if not.
+ */
+ public static boolean isLinkLocalIPv4Address(InetAddress add)
+ {
+ if (add instanceof Inet4Address)
+ {
+ byte address[] = add.getAddress();
+ if ( (address[0] & 0xFF) == 10)
+ return true;
+ if ( (address[0] & 0xFF) == 172
+ && (address[1] & 0xFF) >= 16 && address[1] <= 31)
+ return true;
+ if ( (address[0] & 0xFF) == 192
+ && (address[1] & 0xFF) == 168)
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a random local port number that user applications could bind to.
+ * (i.e. above 1024).
+ * @return a random int located between 1024 and 65 535.
+ */
+ public static int getRandomPortNumber()
+ {
+ return getRandomPortNumber(MIN_PORT_NUMBER, MAX_PORT_NUMBER);
+ }
+
+ /**
+ * Returns a random local port number, greater than min and lower than max.
+ *
+ * @param min the minimum allowed value for the returned port number.
+ * @param max the maximum allowed value for the returned port number.
+ *
+ * @return a random int located between greater than min and lower than max.
+ */
+ public static int getRandomPortNumber(int min, int max)
+ {
+ return portNumberGenerator.nextInt(max - min) + min;
+ }
+
+ /**
+ * Returns a random local port number, greater than min and lower than max.
+ * If the pair flag is set to true, then the returned port number is
+ * guaranteed to be pair. This is useful for protocols that require this
+ * such as RTP
+ *
+ * @param min the minimum allowed value for the returned port number.
+ * @param max the maximum allowed value for the returned port number.
+ * @param pair specifies whether the caller would like the returned port to
+ * be pair.
+ *
+ * @return a random int located between greater than min and lower than max.
+ */
+ public static int getRandomPortNumber(int min, int max, boolean pair)
+ {
+ if(pair)
+ {
+ int delta = max - min;
+ delta /= 2;
+ int port = getRandomPortNumber(min, min + delta);
+ return port * 2;
+ }
+ else
+ {
+ return getRandomPortNumber(min, max);
+ }
+ }
+
+ /**
+ * Verifies whether <tt>address</tt> could be an IPv4 address string.
+ *
+ * @param address the String that we'd like to determine as an IPv4 address.
+ *
+ * @return true if the address contained by <tt>address</tt> is an IPv4
+ * address and false otherwise.
+ */
+ public static boolean isIPv4Address(String address)
+ {
+ return strToIPv4(address) != null;
+ }
+
+ /**
+ * Verifies whether <tt>address</tt> could be an IPv6 address string.
+ *
+ * @param address the String that we'd like to determine as an IPv6 address.
+ *
+ * @return true if the address contained by <tt>address</tt> is an IPv6
+ * address and false otherwise.
+ */
+ public static boolean isIPv6Address(String address)
+ {
+ return strToIPv6(address) != null;
+ }
+
+ /**
+ * Checks whether <tt>address</tt> is a valid IP address string.
+ *
+ * @param address the address that we'd like to check
+ * @return true if address is an IPv4 or IPv6 address and false otherwise.
+ */
+ public static boolean isValidIPAddress(String address)
+ {
+ // empty string
+ if (address == null || address.length() == 0)
+ {
+ return false;
+ }
+
+ // look for IPv6 brackets and remove brackets for parsing
+ boolean ipv6Expected = false;
+ if (address.charAt(0) == '[')
+ {
+ // This is supposed to be an IPv6 literal
+ if (address.length() > 2
+ && address.charAt(address.length() - 1) == ']')
+ {
+ // remove brackets from IPv6
+ address = address.substring(1, address.length() - 1);
+ ipv6Expected = true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // look for IP addresses
+ if (Character.digit(address.charAt(0), 16) != -1
+ || (address.charAt(0) == ':'))
+ {
+ byte[] addr = null;
+
+ // see if it is IPv4 address
+ addr = strToIPv4(address);
+ // if not, see if it is IPv6 address
+ if (addr == null)
+ {
+ addr = strToIPv6(address);
+ }
+ // if IPv4 is found when IPv6 is expected
+ else if (ipv6Expected)
+ {
+ // invalid address: IPv4 address surrounded with brackets!
+ return false;
+ }
+ // if an IPv4 or IPv6 address is found
+ if (addr != null)
+ {
+ // is an IP address
+ return true;
+ }
+ }
+ // no matches found
+ return false;
+ }
+
+ /**
+ * Creates a byte array containing the specified <tt>ipv4AddStr</tt>.
+ *
+ * @param ipv4AddrStr a <tt>String</tt> containing an IPv4 address.
+ *
+ * @return a byte array containing the four bytes of the address represented
+ * by ipv4AddrStr or <tt>null</tt> if <tt>ipv4AddrStr</tt> does not contain
+ * a valid IPv4 address string.
+ */
+ public static byte[] strToIPv4(String ipv4AddrStr)
+ {
+ if (ipv4AddrStr == null || ipv4AddrStr.length() == 0)
+ return null;
+
+ byte[] address = new byte[IN4_ADDR_SIZE];
+ String[] tokens = ipv4AddrStr.split("\\.", -1);
+ long currentTkn;
+ try
+ {
+ switch(tokens.length)
+ {
+ case 1:
+ //If the address was specified as a single String we can
+ //directly copy it into the byte array.
+ currentTkn = Long.parseLong(tokens[0]);
+ if (currentTkn < 0 || currentTkn > 0xffffffffL)
+ return null;
+ address[0] = (byte) ((currentTkn >> 24) & 0xff);
+ address[1] = (byte) (((currentTkn & 0xffffff) >> 16) & 0xff);
+ address[2] = (byte) (((currentTkn & 0xffff) >> 8) & 0xff);
+ address[3] = (byte) (currentTkn & 0xff);
+ break;
+ case 2:
+ // If the address was passed in two parts (e.g. when dealing
+ // with a Class A address representation), we place the
+ // first one in the leftmost byte and the rest in the three
+ // remaining bytes of the address array.
+ currentTkn = Integer.parseInt(tokens[0]);
+
+ if (currentTkn < 0 || currentTkn > 0xff)
+ return null;
+
+ address[0] = (byte) (currentTkn & 0xff);
+ currentTkn = Integer.parseInt(tokens[1]);
+
+ if (currentTkn < 0 || currentTkn > 0xffffff)
+ return null;
+
+ address[1] = (byte) ((currentTkn >> 16) & 0xff);
+ address[2] = (byte) (((currentTkn & 0xffff) >> 8) &0xff);
+ address[3] = (byte) (currentTkn & 0xff);
+ break;
+ case 3:
+ // If the address was passed in three parts (e.g. when
+ // dealing with a Class B address representation), we place
+ // the first two parts in the two leftmost bytes and the
+ // rest in the two remaining bytes of the address array.
+ for (int i = 0; i < 2; i++)
+ {
+ currentTkn = Integer.parseInt(tokens[i]);
+
+ if (currentTkn < 0 || currentTkn > 0xff)
+ return null;
+
+ address[i] = (byte) (currentTkn & 0xff);
+ }
+
+ currentTkn = Integer.parseInt(tokens[2]);
+
+ if (currentTkn < 0 || currentTkn > 0xffff)
+ return null;
+
+ address[2] = (byte) ((currentTkn >> 8) & 0xff);
+ address[3] = (byte) (currentTkn & 0xff);
+ break;
+ case 4:
+ // And now for the most common - four part case. This time
+ // there's a byte for every part :). Yuppiee! :)
+ for (int i = 0; i < 4; i++)
+ {
+ currentTkn = Integer.parseInt(tokens[i]);
+
+ if (currentTkn < 0 || currentTkn > 0xff)
+ return null;
+
+ address[i] = (byte) (currentTkn & 0xff);
+ }
+ break;
+ default:
+ return null;
+ }
+ }
+ catch(NumberFormatException e)
+ {
+ return null;
+ }
+
+ return address;
+ }
+
+ /**
+ * Creates a byte array containing the specified <tt>ipv6AddStr</tt>.
+ *
+ * @param ipv6AddrStr a <tt>String</tt> containing an IPv6 address.
+ *
+ * @return a byte array containing the four bytes of the address represented
+ * by <tt>ipv6AddrStr</tt> or <tt>null</tt> if <tt>ipv6AddrStr</tt> does
+ * not contain a valid IPv6 address string.
+ */
+ public static byte[] strToIPv6(String ipv6AddrStr)
+ {
+ // Bail out if the string is shorter than "::"
+ if (ipv6AddrStr == null || ipv6AddrStr.length() < 2)
+ return null;
+
+ int colonIndex;
+ char currentChar;
+ boolean sawtDigit;
+ int currentTkn;
+ char[] addrBuff = ipv6AddrStr.toCharArray();
+ byte[] dst = new byte[IN6_ADDR_SIZE];
+
+ int srcb_length = addrBuff.length;
+ int scopeID = ipv6AddrStr.indexOf ("%");
+
+ if (scopeID == srcb_length -1)
+ return null;
+
+ if (scopeID != -1)
+ srcb_length = scopeID;
+
+ colonIndex = -1;
+ int i = 0, j = 0;
+ // Starting : mean we need to have at least one more.
+ if (addrBuff[i] == ':')
+ if (addrBuff[++i] != ':')
+ return null;
+
+ int curtok = i;
+ sawtDigit = false;
+ currentTkn = 0;
+ while (i < srcb_length)
+ {
+ currentChar = addrBuff[i++];
+ int chval = Character.digit(currentChar, 16);
+ if (chval != -1)
+ {
+ currentTkn <<= 4;
+ currentTkn |= chval;
+ if (currentTkn > 0xffff)
+ return null;
+ sawtDigit = true;
+ continue;
+ }
+
+ if (currentChar == ':')
+ {
+ curtok = i;
+
+ if (!sawtDigit)
+ {
+ if (colonIndex != -1)
+ return null;
+ colonIndex = j;
+ continue;
+ }
+ else if (i == srcb_length)
+ {
+ return null;
+ }
+
+ if (j + IN6_ADDR_TOKEN_SIZE > IN6_ADDR_SIZE)
+ return null;
+
+ dst[j++] = (byte) ((currentTkn >> 8) & 0xff);
+ dst[j++] = (byte) (currentTkn & 0xff);
+ sawtDigit = false;
+ currentTkn = 0;
+ continue;
+ }
+
+ if (currentChar == '.' && ((j + IN4_ADDR_SIZE) <= IN6_ADDR_SIZE))
+ {
+ String ia4 = ipv6AddrStr.substring(curtok, srcb_length);
+ // check this IPv4 address has 3 dots, ie. A.B.C.D
+ int dot_count = 0, index=0;
+ while ((index = ia4.indexOf ('.', index)) != -1)
+ {
+ dot_count ++;
+ index ++;
+ }
+
+ if (dot_count != 3)
+ return null;
+
+ byte[] v4addr = strToIPv4(ia4);
+ if (v4addr == null)
+ return null;
+
+ for (int k = 0; k < IN4_ADDR_SIZE; k++)
+ {
+ dst[j++] = v4addr[k];
+ }
+
+ sawtDigit = false;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return null;
+ }
+
+ if (sawtDigit)
+ {
+ if (j + IN6_ADDR_TOKEN_SIZE > IN6_ADDR_SIZE)
+ return null;
+
+ dst[j++] = (byte) ((currentTkn >> 8) & 0xff);
+ dst[j++] = (byte) (currentTkn & 0xff);
+ }
+
+ if (colonIndex != -1)
+ {
+ int n = j - colonIndex;
+
+ if (j == IN6_ADDR_SIZE)
+ return null;
+
+ for (i = 1; i <= n; i++)
+ {
+ dst[IN6_ADDR_SIZE - i] = dst[colonIndex + n - i];
+ dst[colonIndex + n - i] = 0;
+ }
+
+ j = IN6_ADDR_SIZE;
+ }
+
+ if (j != IN6_ADDR_SIZE)
+ return null;
+
+ byte[] newdst = mappedIPv4ToRealIPv4(dst);
+
+ if (newdst != null)
+ {
+ return newdst;
+ }
+ else
+ {
+ return dst;
+ }
+ }
+
+ /**
+ * Returns array of hosts from the SRV record of the specified domain.
+ * The records are ordered against the SRV record priority
+ * @param domain the name of the domain we'd like to resolve (_proto._tcp
+ * included).
+ * @return an array of SRVRecord containing records returned by the DNS
+ * server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static SRVRecord[] getSRVRecords(String domain)
+ throws ParseException, DnssecException
+ {
+ Record[] records = null;
+ try
+ {
+ Lookup lookup = createLookup(domain, Type.SRV);
+ records = lookup.run();
+ }
+ catch (TextParseException tpe)
+ {
+ logger.error("Failed to parse domain=" + domain, tpe);
+ throw new ParseException(tpe.getMessage(), 0);
+ }
+ catch(DnssecRuntimeException e)
+ {
+ throw new DnssecException(e);
+ }
+ if (records == null)
+ {
+ return null;
+ }
+
+ //String[][] pvhn = new String[records.length][4];
+ SRVRecord srvRecords[] = new SRVRecord[records.length];
+
+ for (int i = 0; i < records.length; i++)
+ {
+ org.xbill.DNS.SRVRecord srvRecord =
+ (org.xbill.DNS.SRVRecord) records[i];
+ srvRecords[i] = new SRVRecord(srvRecord);
+ }
+
+ // Sort the SRV RRs by priority (lower is preferred) and weight.
+ sortSrvRecord(srvRecords);
+
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("DNS SRV query for domain " + domain + " returned:");
+ for (int i = 0; i < srvRecords.length; i++)
+ {
+ if (logger.isTraceEnabled())
+ logger.trace(srvRecords[i]);
+ }
+ }
+ return srvRecords;
+ }
+
+ /**
+ * Returns an <tt>InetSocketAddress</tt> representing the first SRV
+ * record available for the specified domain or <tt>null</tt> if there are
+ * not SRV records for <tt>domain</tt>.
+ *
+ * @param domain the name of the domain we'd like to resolve.
+ * @param service the service that we are trying to get a record for.
+ * @param proto the protocol that we'd like <tt>service</tt> on.
+ *
+ * @return the first InetSocketAddress containing records returned by the
+ * DNS server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static SRVRecord getSRVRecord(String service,
+ String proto,
+ String domain)
+ throws ParseException, DnssecException
+ {
+ SRVRecord[] records = getSRVRecords("_" + service
+ + "._" + proto
+ + "." + domain);
+
+ if(records == null || records.length == 0)
+ return null;
+
+ return records[0];
+ }
+
+ /**
+ * Returns an <tt>InetSocketAddress</tt> representing the first SRV
+ * record available for the specified domain or <tt>null</tt> if there are
+ * not SRV records for <tt>domain</tt>.
+ *
+ * @param domain the name of the domain we'd like to resolve.
+ * @param service the service that we are trying to get a record for.
+ * @param proto the protocol that we'd like <tt>service</tt> on.
+ *
+ * @return the InetSocketAddress[] containing records returned by the
+ * DNS server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static SRVRecord[] getSRVRecords(String service,
+ String proto,
+ String domain)
+ throws ParseException, DnssecException
+ {
+ SRVRecord[] records = getSRVRecords("_" + service
+ + "._" + proto
+ + "." + domain);
+
+ if(records == null || records.length == 0)
+ return null;
+
+ return records;
+ }
+
+ /**
+ * Makes a NAPTR query and returns the result. The returned records are an
+ * array of [Order, Service(Transport) and Replacement
+ * (the srv to query for servers and ports)] this all for supplied
+ * <tt>domain</tt>.
+ *
+ * @param domain the name of the domain we'd like to resolve.
+ * @return an array with the values or null if no records found.
+ *
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static String[][] getNAPTRRecords(String domain)
+ throws ParseException, DnssecException
+ {
+ Record[] records = null;
+ try
+ {
+ Lookup lookup = createLookup(domain, Type.NAPTR);
+ records = lookup.run();
+ }
+ catch (TextParseException tpe)
+ {
+ logger.error("Failed to parse domain="+domain, tpe);
+ throw new ParseException(tpe.getMessage(), 0);
+ }
+ catch(DnssecRuntimeException e)
+ {
+ throw new DnssecException(e);
+ }
+ if (records == null)
+ {
+
+ if(logger.isTraceEnabled())
+ logger.trace("No NAPTRs found for " + domain);
+ return null;
+ }
+
+ String[][] recVals = new String[records.length][4];
+ for (int i = 0; i < records.length; i++)
+ {
+ NAPTRRecord r = (NAPTRRecord)records[i];
+
+ // todo - check here for broken records as missing transport
+ recVals[i][0] = "" + r.getOrder();
+ recVals[i][1] = getProtocolFromNAPTRRecords(r.getService());
+ String replacement = r.getReplacement().toString();
+
+ if (replacement.endsWith("."))
+ {
+ recVals[i][2] =
+ replacement.substring(0, replacement.length() - 1);
+ }
+ else
+ {
+ recVals[i][2] = replacement;
+ }
+ recVals[i][3] = "" + r.getPreference();
+ }
+
+ // sort the SRV RRs by RR value (lower is preferred)
+ Arrays.sort(recVals, new Comparator<String[]>()
+ {
+ // Sorts NAPTR records by ORDER (low number first), PREFERENCE (low
+ // number first) and PROTOCOL (0-TLS, 1-TCP, 2-UDP).
+ public int compare(String array1[], String array2[])
+ {
+ // First tries to define the priority with the NAPTR order.
+ int order
+ = Integer.parseInt(array1[0]) - Integer.parseInt(array2[0]);
+ if(order != 0)
+ {
+ return order;
+ }
+
+ // Second tries to define the priority with the NAPTR
+ // preference.
+ int preference
+ = Integer.parseInt(array1[4]) - Integer.parseInt(array2[4]);
+ if(preference != 0)
+ {
+ return preference;
+ }
+
+ // Finally defines the priority with the NAPTR protocol.
+ int protocol
+ = getProtocolPriority(array1[1])
+ - getProtocolPriority(array2[1]);
+ return protocol;
+ }
+ });
+
+ if(logger.isTraceEnabled())
+ logger.trace("NAPTRs for " + domain + "="
+ + Arrays.toString(recVals));
+ return recVals;
+ }
+
+ /**
+ * Returns the mapping from rfc3263 between service and the protocols.
+ *
+ * @param service the service from NAPTR record.
+ * @return the protocol TCP, UDP or TLS.
+ */
+ private static String getProtocolFromNAPTRRecords(String service)
+ {
+ if(service.equalsIgnoreCase("SIP+D2U"))
+ return "UDP";
+ else if(service.equalsIgnoreCase("SIP+D2T"))
+ return "TCP";
+ else if(service.equalsIgnoreCase("SIPS+D2T"))
+ return "TLS";
+ else
+ return null;
+ }
+
+ /**
+ * Returns the priority of a protocol. The lowest priority is the highest:
+ * 0-TLS, 1-TCP, 2-UDP.
+ *
+ * @param protocol The protocol name: "TLS", "TCP" or "UDP".
+ *
+ * @return The priority of a protocol. The lowest priority is the highest:
+ * 0-TLS, 1-TCP, 2-UDP.
+ */
+ private static int getProtocolPriority(String protocol)
+ {
+ if(protocol.equals("TLS"))
+ return 0;
+ else if(protocol.equals("TCP"))
+ return 1;
+ return 2; // "UDP".
+ }
+
+ /**
+ * Creates an InetAddress from the specified <tt>hostAddress</tt>. The point
+ * of using the method rather than creating the address by yourself is that
+ * it would first check whether the specified <tt>hostAddress</tt> is indeed
+ * a valid ip address. It this is the case, the method would create the
+ * <tt>InetAddress</tt> using the <tt>InetAddress.getByAddress()</tt>
+ * method so that no DNS resolution is attempted by the JRE. Otherwise
+ * it would simply use <tt>InetAddress.getByName()</tt> so that we would an
+ * <tt>InetAddress</tt> instance even at the cost of a potential DNS
+ * resolution.
+ *
+ * @param hostAddress the <tt>String</tt> representation of the address
+ * that we would like to create an <tt>InetAddress</tt> instance for.
+ *
+ * @return an <tt>InetAddress</tt> instance corresponding to the specified
+ * <tt>hostAddress</tt>.
+ *
+ * @throws UnknownHostException if any of the <tt>InetAddress</tt> methods
+ * we are using throw an exception.
+ */
+ public static InetAddress getInetAddress(String hostAddress)
+ throws UnknownHostException
+ {
+ //is null
+ if (hostAddress == null || hostAddress.length() == 0)
+ {
+ throw new UnknownHostException(
+ hostAddress + " is not a valid host address");
+ }
+
+ //transform IPv6 literals into normal addresses
+ if (hostAddress.charAt(0) == '[')
+ {
+ // This is supposed to be an IPv6 literal
+ if (hostAddress.length() > 2
+ && hostAddress.charAt(hostAddress.length()-1) == ']')
+ {
+ hostAddress = hostAddress.substring(1, hostAddress.length() -1);
+ }
+ else
+ {
+ // This was supposed to be a IPv6 address, but it's not!
+ throw new UnknownHostException(hostAddress);
+ }
+ }
+
+ if (NetworkUtils.isValidIPAddress(hostAddress))
+ {
+ byte[] addr = null;
+
+ // attempt parse as IPv4 address
+ addr = strToIPv4(hostAddress);
+
+ // if not IPv4, parse as IPv6 address
+ if (addr == null)
+ {
+ addr = strToIPv6(hostAddress);
+ }
+ return InetAddress.getByAddress(hostAddress, addr);
+ }
+ else
+ {
+ return InetAddress.getByName(hostAddress);
+ }
+ }
+
+ /**
+ * Returns array of hosts from the A and AAAA records of the specified
+ * domain. The records are ordered against the IPv4/IPv6 protocol priority
+ *
+ * @param domain the name of the domain we'd like to resolve.
+ * @param port the port number of the returned <tt>InetSocketAddress</tt>
+ * @return an array of InetSocketAddress containing records returned by the
+ * DNS server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static InetSocketAddress[] getAandAAAARecords(String domain, int port)
+ throws ParseException, DnssecException
+ {
+ byte[] address = null;
+ if((address = strToIPv4(domain)) != null
+ || (address = strToIPv6(domain)) != null)
+ {
+ try
+ {
+ return new InetSocketAddress[]
+ {
+ new InetSocketAddress(
+ InetAddress.getByAddress(domain, address), port)
+ };
+ }
+ catch (UnknownHostException e)
+ {
+ //should not happen
+ logger.error(
+ "Unable to create InetAddress for <" + domain + ">", e);
+ return null;
+ }
+ }
+
+ List<InetSocketAddress> addresses = new LinkedList<InetSocketAddress>();
+ boolean v6lookup = Boolean.getBoolean("java.net.preferIPv6Addresses");
+
+ for(int i = 0; i < 2; i++)
+ {
+ Lookup lookup;
+ try
+ {
+ lookup = createLookup(domain, v6lookup ? Type.AAAA : Type.A);
+ }
+ catch (TextParseException tpe)
+ {
+ logger.error("Failed to parse domain <" + domain + ">", tpe);
+ throw new ParseException(tpe.getMessage(), 0);
+ }
+ Record[] records = null;
+ try
+ {
+ records = lookup.run();
+ }
+ catch(DnssecRuntimeException e)
+ {
+ throw new DnssecException(e);
+ }
+ if(records != null)
+ {
+ for(Record r : records)
+ {
+ try
+ {
+ addresses.add(
+ new InetSocketAddress(
+ // create a new InetAddress filled with the
+ // domain name to avoid PTR queries
+ InetAddress.getByAddress(
+ domain,
+ v6lookup
+ ? ((AAAARecord)r).getAddress().getAddress()
+ : ((ARecord)r).getAddress().getAddress()
+ ),
+ port
+ )
+ );
+ }
+ catch (UnknownHostException e)
+ {
+ logger.error("Invalid record returned from DNS", e);
+ }
+ }
+ }
+ v6lookup = !v6lookup;
+ }
+ if(logger.isTraceEnabled())
+ logger.trace("A or AAAA addresses: " + addresses);
+ return addresses.toArray(new InetSocketAddress[0]);
+ }
+
+ /**
+ * Returns array of hosts from the A record of the specified domain.
+ * The records are ordered against the A record priority
+ * @param domain the name of the domain we'd like to resolve.
+ * @param port the port number of the returned <tt>InetSocketAddress</tt>
+ * @return an array of InetSocketAddress containing records returned by the
+ * DNS server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException when a DNSSEC validation failure occurred.
+ */
+ public static InetSocketAddress getARecord(String domain, int port)
+ throws ParseException, DnssecException
+ {
+ byte[] address;
+ if((address = strToIPv4(domain)) != null)
+ {
+ try
+ {
+ return new InetSocketAddress(
+ InetAddress.getByAddress(domain, address), port);
+ }
+ catch (UnknownHostException e)
+ {
+ //should not happen
+ logger.error(
+ "Unable to create InetAddress for <" + domain + ">", e);
+ return null;
+ }
+ }
+
+ Record[] records;
+ try
+ {
+ //note that we intentionally do not use our parallel resolver here.
+ //for starters we'd like to make sure that it works well enough
+ //with SRV and NAPTR queries. We may then also adopt it for As
+ //and AAAAs once it proves to be reliable (posted on: 2010-11-24)
+ Lookup lookup = createLookup(domain, Type.A);
+ records = lookup.run();
+ }
+ catch (TextParseException tpe)
+ {
+ logger.error("Failed to parse domain="+domain, tpe);
+ throw new ParseException(tpe.getMessage(), 0);
+ }
+ catch(DnssecRuntimeException e)
+ {
+ throw new DnssecException(e);
+ }
+ if (records != null && records.length > 0)
+ {
+ if(logger.isTraceEnabled())
+ logger.trace("A record for " + domain + "="
+ + ((ARecord)records[0]).getAddress());
+ try
+ {
+ return new InetSocketAddress(
+ InetAddress.getByAddress(domain,
+ ((ARecord)records[0]).getAddress().getAddress()),
+ port);
+ }
+ catch (UnknownHostException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ if(logger.isTraceEnabled())
+ logger.trace("No A record found for " + domain);
+ return null;
+ }
+ }
+
+ /**
+ * Returns array of hosts from the AAAA record of the specified domain.
+ * The records are ordered against the AAAA record priority
+ * @param domain the name of the domain we'd like to resolve.
+ * @param port the port number of the returned <tt>InetSocketAddress</tt>
+ * @return an array of InetSocketAddress containing records returned by the
+ * DNS server - address and port .
+ * @throws ParseException if <tt>domain</tt> is not a valid domain name.
+ * @throws DnssecException
+ */
+ public static InetSocketAddress getAAAARecord(String domain, int port)
+ throws ParseException, DnssecException
+ {
+ byte[] address;
+ if((address = strToIPv6(domain)) != null)
+ {
+ try
+ {
+ return new InetSocketAddress(
+ InetAddress.getByAddress(domain, address), port);
+ }
+ catch (UnknownHostException e)
+ {
+ //should not happen
+ logger.error(
+ "Unable to create InetAddress for <" + domain + ">", e);
+ return null;
+ }
+ }
+
+ Record[] records;
+ try
+ {
+ //note that we intentionally do not use our parallel resolver here.
+ //for starters we'd like to make sure that it works well enough
+ //with SRV and NAPTR queries. We may then also adopt it for As
+ //and AAAAs once it proves to be reliable (posted on: 2010-11-24)
+ Lookup lookup = createLookup(domain, Type.AAAA);
+ records = lookup.run();
+ }
+ catch (TextParseException tpe)
+ {
+ logger.error("Failed to parse domain="+domain, tpe);
+ throw new ParseException(tpe.getMessage(), 0);
+ }
+ catch(DnssecRuntimeException e)
+ {
+ throw new DnssecException(e);
+ }
+ if (records != null && records.length > 0)
+ {
+ if(logger.isTraceEnabled())
+ logger.trace("AAAA record for " + domain + "="
+ + ((AAAARecord)records[0]).getAddress());
+ try
+ {
+ return new InetSocketAddress(
+ InetAddress.getByAddress(domain,
+ ((AAAARecord)records[0]).getAddress().getAddress()),
+ port);
+ }
+ catch (UnknownHostException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ if(logger.isTraceEnabled())
+ logger.trace("No AAAA record found for " + domain);
+ return null;
+ }
+ }
+
+ /**
+ * Tries to determine if this host supports IPv6 addresses (i.e. has at
+ * least one IPv6 address) and returns IN6_ADDR_ANY or IN4_ADDR_ANY
+ * accordingly. This method is only used to initialize IN_ADDR_ANY so that
+ * it could be used when binding sockets. The reason we need it is because
+ * on mac (contrary to lin or win) binding a socket on 0.0.0.0 would make
+ * it deaf to IPv6 traffic. Binding on ::0 does the trick but that would
+ * fail on hosts that have no IPv6 support. Using the result of this method
+ * provides an easy way to bind sockets in cases where we simply want any
+ * IP packets coming on the port we are listening on (regardless of IP
+ * version).
+ *
+ * @return IN6_ADDR_ANY or IN4_ADDR_ANY if this host supports or not IPv6.
+ */
+ private static String determineAnyAddress()
+ {
+ Enumeration<NetworkInterface> ifaces;
+ try
+ {
+ ifaces = NetworkInterface.getNetworkInterfaces();
+ }
+ catch (SocketException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Couldn't retrieve local interfaces.", e);
+ return IN4_ADDR_ANY;
+ }
+
+ while(ifaces.hasMoreElements())
+ {
+ Enumeration<InetAddress> addrs
+ = ifaces.nextElement().getInetAddresses();
+ while (addrs.hasMoreElements())
+ {
+ if(addrs.nextElement() instanceof Inet6Address)
+ return IN6_ADDR_ANY;
+ }
+ }
+
+ return IN4_ADDR_ANY;
+ }
+
+ /**
+ * Determines whether <tt>port</tt> is a valid port number bindable by an
+ * application (i.e. an integer between 1024 and 65535).
+ *
+ * @param port the port number that we'd like verified.
+ *
+ * @return <tt>true</tt> if port is a valid and bindable port number and
+ * <tt>alse</tt> otherwise.
+ */
+ public static boolean isValidPortNumber(int port)
+ {
+ return MIN_PORT_NUMBER < port && port < MAX_PORT_NUMBER;
+ }
+
+ /**
+ * Returns an IPv4 address matching the one mapped in the IPv6
+ * <tt>addr</tt>. Both input and returned value are in network order.
+ *
+ * @param addr a String representing an IPv4-Mapped address in textual
+ * format
+ *
+ * @return a byte array numerically representing the IPv4 address
+ */
+ public static byte[] mappedIPv4ToRealIPv4(byte[] addr)
+ {
+ if (isMappedIPv4Addr(addr))
+ {
+ byte[] newAddr = new byte[IN4_ADDR_SIZE];
+ System.arraycopy(addr, 12, newAddr, 0, IN6_ADDR_SIZE);
+ return newAddr;
+ }
+
+ return null;
+ }
+
+ /**
+ * Utility method to check if the specified <tt>address</tt> is an IPv4
+ * mapped IPv6 address.
+ *
+ * @param address the address that we'd like to determine as an IPv4 mapped
+ * one or not.
+ *
+ * @return <tt>true</tt> if address is an IPv4 mapped IPv6 address and
+ * <tt>false</tt> otherwise.
+ */
+ private static boolean isMappedIPv4Addr(byte[] address)
+ {
+ if (address.length < IN6_ADDR_SIZE)
+ {
+ return false;
+ }
+
+ if ((address[0] == 0x00) && (address[1] == 0x00)
+ && (address[2] == 0x00) && (address[3] == 0x00)
+ && (address[4] == 0x00) && (address[5] == 0x00)
+ && (address[6] == 0x00) && (address[7] == 0x00)
+ && (address[8] == 0x00) && (address[9] == 0x00)
+ && (address[10] == (byte)0xff)
+ && (address[11] == (byte)0xff))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a new {@link Lookup} instance using our own {@link
+ * ParallelResolver} if it is enabled and DNSSEC is not active.
+ *
+ * @param domain the domain we will be resolving
+ * @param type the type of the record we will be trying to obtain.
+ *
+ * @return the newly created {@link Lookup} instance.
+ *
+ * @throws TextParseException if <tt>domain</tt> is not a valid domain name.
+ */
+ private static Lookup createLookup(String domain, int type)
+ throws TextParseException
+ {
+ // listens for network changes up/down so we can reset
+ // dns configuration
+ if(netListenerAdded.compareAndSet(false, true))
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("NetConfigChange listener added: "
+ + netListener.hashCode());
+ UtilActivator.getNetworkAddressManagerService()
+ .addNetworkConfigurationChangeListener(netListener);
+ }
+
+ // make domain name absolute if requested
+ if(UtilActivator.getConfigurationService().getBoolean(
+ PNAME_DNS_ALWAYS_ABSOLUTE,
+ PDEFAULT_DNS_ALWAYS_ABSOLUTE))
+ {
+ if(!Name.fromString(domain).isAbsolute())
+ domain = domain + ".";
+ }
+
+ Lookup lookup = new Lookup(domain, type);
+
+ if(logger.isTraceEnabled())
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Active DNS servers in default resolver: ");
+ for(String s : ResolverConfig.getCurrentConfig().servers())
+ {
+ sb.append(s);
+ sb.append(", ");
+ }
+ logger.trace(sb.toString());
+ }
+
+ if(!UtilActivator.getConfigurationService()
+ .getBoolean(PNAME_BACKUP_RESOLVER_ENABLED,
+ PDEFAULT_BACKUP_RESOLVER_ENABLED)
+ || UtilActivator.getConfigurationService().getBoolean(
+ DnsUtilActivator.PNAME_DNSSEC_RESOLVER_ENABLED,
+ DnsUtilActivator.PDEFAULT_DNSSEC_RESOLVER_ENABLED
+ ))
+ {
+ return lookup;
+ }
+
+ //Initiate our global parallel resolver if this is our first ever
+ //DNS query. The lock here is heavy but necessary as a) the config
+ //form can cause an intermittent reset and b) multiple accounts signing
+ //in at the same time could cause multiple ParallelResolver instances
+ synchronized(parallelResolverLock)
+ {
+ if(parallelResolver == null)
+ {
+ try
+ {
+ String rslvrAddrStr
+ = UtilActivator.getConfigurationService()
+ .getString(PNAME_BACKUP_RESOLVER,
+ DEFAULT_BACKUP_RESOLVER);
+ String customRslvrIP
+ = UtilActivator.getConfigurationService().getString(
+ PNAME_BACKUP_RESOLVER_FALLBACK_IP,
+ UtilActivator.getResources().getSettingsString(
+ PNAME_BACKUP_RESOLVER_FALLBACK_IP));
+
+ InetAddress resolverAddress = null;
+
+ try
+ {
+ resolverAddress = getInetAddress(rslvrAddrStr);
+ }
+ catch(UnknownHostException exc)
+ {
+ logger.warn("Oh! Seems like our primary DNS is down!"
+ + "Don't panic! We'll try to fall back to "
+ + customRslvrIP);
+ }
+
+ if(resolverAddress == null)
+ {
+ /* name resolution failed for backup DNS resolver,
+ * try with the IP address of the default backup resolver
+ */
+ resolverAddress = getInetAddress(customRslvrIP);
+ }
+
+ int rslvrPort = UtilActivator.getConfigurationService().getInt(
+ PNAME_BACKUP_RESOLVER_PORT, SimpleResolver.DEFAULT_PORT);
+
+ InetSocketAddress resolverSockAddr
+ = new InetSocketAddress(resolverAddress, rslvrPort);
+
+ parallelResolver = new ParallelResolver(
+ new InetSocketAddress[]{resolverSockAddr});
+
+ //listens for changes on the parallel DNS settings
+ UtilActivator.getConfigurationService()
+ .addPropertyChangeListener(
+ new DnsConfigurationChangeListener());
+ }
+ catch(Throwable t)
+ {
+ //We don't want to a problem with our parallel resolver to
+ //make our entire DNS resolution to fail so in case something
+ //goes wrong during initialization so we default to the
+ //dns java default resolver
+ logger.info("failed to initialize parallel resolver. we will "
+ +"be using dnsjava's default one instead");
+
+ if(logger.isDebugEnabled())
+ logger.debug("exception was: ", t);
+
+ parallelResolver = Lookup.getDefaultResolver();
+ }
+ }
+
+ lookup.setResolver(parallelResolver);
+ }
+
+ return lookup;
+ }
+
+ /**
+ * Gets the default port used by DNS servers obtained through
+ * SimpleResolver.DEFAULT_PORT.
+ * @return The default DNS server port
+ */
+ public static short getDefaultDnsPort()
+ {
+ return SimpleResolver.DEFAULT_PORT;
+ }
+
+ /**
+ * Listens when network is going from down to up and
+ * resets dns configuration.
+ */
+ private static class NetworkListener
+ implements NetworkConfigurationChangeListener
+ {
+ /**
+ * Fired when a change has occurred in the
+ * computer network configuration.
+ *
+ * @param event the change event.
+ */
+ public void configurationChanged(ChangeEvent event)
+ {
+ if((event.getType() == ChangeEvent.IFACE_UP
+ || event.getType() == ChangeEvent.DNS_CHANGE)
+ && !event.isInitial())
+ {
+ reloadDnsResolverConfig();
+ }
+ }
+ }
+
+ /**
+ * Listens for changes in the DNS configuration and resets
+ * the parallelResolver when necessary
+ */
+ private static class DnsConfigurationChangeListener
+ implements PropertyChangeListener
+ {
+ @SuppressWarnings("serial")
+ private final Set<String> configNames = new HashSet<String>(5){{
+ add(PNAME_BACKUP_RESOLVER);
+ add(PNAME_BACKUP_RESOLVER_FALLBACK_IP);
+ add(PNAME_BACKUP_RESOLVER_PORT);
+ add(ParallelResolver.PNAME_DNS_PATIENCE);
+ add(ParallelResolver.PNAME_DNS_REDEMPTION);
+ }};
+
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ if(configNames.contains(evt.getPropertyName()) &&
+ parallelResolver != null)
+ {
+ parallelResolver = null;
+ logger.info("Parallel DNS resolver reset");
+ }
+ }
+ }
+
+ /**
+ * Reloads dns server configuration in the resolver.
+ */
+ public static void reloadDnsResolverConfig()
+ {
+ // reread system dns configuration
+ ResolverConfig.refresh();
+ try
+ {
+ DnsUtilActivator.refreshResolver();
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error reloading dns util activator");
+ }
+ if(parallelResolver instanceof ParallelResolver)
+ {
+ //needs a separate lock object because the parallelResolver could
+ //be set to null in between
+ synchronized(parallelResolverLock)
+ {
+ ((ParallelResolver)parallelResolver).reset();
+ }
+ }
+
+ if(logger.isTraceEnabled())
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Reloaded resolver config, active DNS servers are: ");
+ for(String s : ResolverConfig.getCurrentConfig().servers())
+ {
+ sb.append(s);
+ sb.append(", ");
+ }
+ logger.trace(sb.toString());
+ }
+ }
+
+ /**
+ * Compares two DNS names against each other. Helper method to avoid the
+ * export of DNSJava.
+ * @param dns1 The first DNS name
+ * @param dns2 The DNS name that is compared against dns1
+ * @return The value 0 if dns2 is a name equivalent to dns1;
+ * a value less than 0 if dns2 is less than dns1 in the canonical ordering,
+ * and a value greater than 0 if dns2 is greater than dns1 in the canonical
+ * ordering.
+ * @throws ParseException if the dns1 or dns2 is not a DNS Name
+ */
+ public static int compareDnsNames(String dns1, String dns2)
+ throws ParseException
+ {
+ try
+ {
+ return Name.fromString(dns1).compareTo(Name.fromString(dns2));
+ }
+ catch(TextParseException e)
+ {
+ throw new ParseException(e.getMessage(), 0);
+ }
+ }
+
+ /**
+ * Sorts the SRV record list by priority and weight.
+ *
+ * @param srvRecords The list of SRV records.
+ */
+ private static void sortSrvRecord(SRVRecord[] srvRecords)
+ {
+ // Sort the SRV RRs by priority (lower is preferred).
+ Arrays.sort(srvRecords, new Comparator<SRVRecord>()
+ {
+ public int compare(SRVRecord obj1, SRVRecord obj2)
+ {
+ return (obj1.getPriority() - obj2.getPriority());
+ }
+ });
+
+ // Sort the SRV RRs by weight (larger weight has a proportionately
+ // higher probability of being selected).
+ sortSrvRecordByWeight(srvRecords);
+ }
+
+ /**
+ * Sorts each priority of the SRV record list. Each priority is sorted with
+ * the probabilty given by the weight attribute.
+ *
+ * @param srvRecords The list of SRV records already sorted by priority.
+ */
+ private static void sortSrvRecordByWeight(SRVRecord[] srvRecords)
+ {
+ int currentPriority = srvRecords[0].getPriority();
+ int startIndex = 0;
+
+ for(int i = 0; i < srvRecords.length; ++i)
+ {
+ if(currentPriority != srvRecords[i].getPriority())
+ {
+ // Sort the current priority.
+ sortSrvRecordPriorityByWeight(srvRecords, startIndex, i);
+ // Reinit variables for the next priority.
+ startIndex = i;
+ currentPriority = srvRecords[i].getPriority();
+ }
+ }
+ }
+
+ /**
+ * Sorts SRV record list for a given priority: this priority is sorted with
+ * the probabilty given by the weight attribute.
+ *
+ * @param srvRecords The list of SRV records already sorted by priority.
+ * @param startIndex The first index (included) for the current priority.
+ * @param endIndex The last index (excluded) for the current priority.
+ */
+ private static void sortSrvRecordPriorityByWeight(
+ SRVRecord[] srvRecords,
+ int startIndex,
+ int endIndex)
+ {
+ int randomWeight;
+
+ // Loops over the items of the current priority.
+ while(startIndex < endIndex)
+ {
+ // Compute a random number in [0...totalPriorityWeight].
+ randomWeight = getRandomWeight(srvRecords, startIndex, endIndex);
+
+ // Move the selected item on top of the unsorted items for this
+ // priority.
+ moveSelectedSRVRecord(
+ srvRecords,
+ startIndex,
+ endIndex,
+ randomWeight);
+
+ // Move to next index.
+ ++startIndex;
+ }
+ }
+
+ /**
+ * Compute a random number in [0...totalPriorityWeight] with
+ * totalPriorityWeight the sum of all weight for the current priority.
+ *
+ * @param srvRecords The list of SRV records already sorted by priority.
+ * @param startIndex The first index (included) for the current priority.
+ * @param endIndex The last index (excluded) for the current priority.
+ *
+ * @return A random number in [0...totalPriorityWeight] with
+ * totalPriorityWeight the sum of all weight for the current priority.
+ */
+ private static int getRandomWeight(
+ SRVRecord[] srvRecords,
+ int startIndex,
+ int endIndex)
+ {
+ int totalPriorityWeight = 0;
+
+ // Compute the max born.
+ for(int i = startIndex; i < endIndex; ++i)
+ {
+ totalPriorityWeight += srvRecords[i].getWeight();
+ }
+
+ // Compute a random number in [0...totalPriorityWeight].
+ return random.nextInt(totalPriorityWeight + 1);
+ }
+
+ /**
+ * Moves the selected SRV record in top of the unsorted items for this
+ * priority.
+ *
+ * @param srvRecords The list of SRV records already sorted by priority.
+ * @param startIndex The first unsorted index (included) for the current
+ * priority.
+ * @param endIndex The last unsorted index (excluded) for the current
+ * priority.
+ * @param selectedWeight The selected weight used to design the selected
+ * item to move.
+ */
+ private static void moveSelectedSRVRecord(
+ SRVRecord[] srvRecords,
+ int startIndex,
+ int endIndex,
+ int selectedWeight)
+ {
+ SRVRecord tmpSrvRecord;
+ int totalPriorityWeight = 0;
+
+ for(int i = startIndex; i < endIndex; ++i)
+ {
+ totalPriorityWeight += srvRecords[i].getWeight();
+
+ // If we found the selecting record.
+ if(totalPriorityWeight >= selectedWeight)
+ {
+ // Switch between startIndex and j.
+ tmpSrvRecord = srvRecords[startIndex];
+ srvRecords[startIndex] = srvRecords[i];
+ srvRecords[i] = tmpSrvRecord;
+ // Break the loop;
+ return;
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/OrderedComponent.java b/src/net/java/sip/communicator/plugin/desktoputil/OrderedComponent.java
new file mode 100644
index 0000000..054e31b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/OrderedComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+/**
+ * Components (like buttons) implement this interface to be able to
+ * order them in a Ordered Transparent Panels.
+ *
+ * @author Damian Minkov
+ */
+public interface OrderedComponent
+{
+ /**
+ * Change component index when we want to order it.
+ * @param index the button index.
+ */
+ public void setIndex(int index);
+
+ /**
+ * Returns the current component index we have set, or -1 if none used.
+ * @return
+ */
+ public int getIndex();
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/OrderedTransparentPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/OrderedTransparentPanel.java
new file mode 100644
index 0000000..21dd398
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/OrderedTransparentPanel.java
@@ -0,0 +1,66 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+/**
+ * Ordered transparent panel. Components added to the panel
+ * must implement OrderedComponent to be able to order them or
+ * will leave the parent to add them as usual.
+ *
+ * @author Damian Minkov
+ */
+public class OrderedTransparentPanel
+ extends TransparentPanel
+{
+ private static final long serialVersionUID = 0L;
+
+ @Override
+ public Component add(Component comp)
+ {
+ if(comp instanceof OrderedComponent)
+ return addOrdered(comp);
+ else
+ return super.add(comp);
+ }
+
+ /**
+ * Method to order add OrderedComponents.
+ * @param comp the component to order.
+ * @return the component argument
+ */
+ private Component addOrdered(Component comp)
+ {
+ int orederIndex = ((OrderedComponent)comp).getIndex();
+
+ Component[] cs = getComponents();
+
+ // don't add a component if already added or it will be removed
+ // and added at the end
+ for(Component c : cs)
+ {
+ if(c.equals(comp))
+ return comp;
+ }
+
+ for(int i = 0; i < cs.length; i++)
+ {
+ Component c = cs[i];
+
+ if(c instanceof OrderedComponent)
+ {
+ int cIndex = ((OrderedComponent) c).getIndex();
+
+ if(orederIndex < cIndex)
+ return super.add(comp, i);
+ }
+ }
+
+ return super.add(comp);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/PasswordChangeDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/PasswordChangeDialog.java
new file mode 100644
index 0000000..4e4e773
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/PasswordChangeDialog.java
@@ -0,0 +1,385 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.resources.*;
+
+/**
+ * UI dialog to change the master password.
+ *
+ * @author Dmitri Melnikov
+ * @author Boris Grozev
+ */
+public class PasswordChangeDialog
+ extends SIPCommDialog
+ implements KeyListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The <tt>ResourceManagementService</tt> used by this instance to access
+ * the localized and internationalized resources of the application.
+ */
+ protected final ResourceManagementService resources
+ = DesktopUtilActivator.getResources();
+
+ /**
+ * Password quality meter.
+ */
+ private PasswordQualityMeter passwordMeter =
+ new PasswordQualityMeter();
+
+ /**
+ * Whether to show a current password field or not
+ */
+ private boolean showCurrentPassword = false;
+
+ /**
+ * UI components.
+ */
+ private JPasswordField currentPasswdField;
+ private JPasswordField newPasswordField;
+ private JPasswordField newAgainPasswordField;
+ private JButton okButton;
+ private JButton cancelButton;
+ private JTextArea infoTextArea;
+ private JProgressBar passwordQualityBar;
+ private JPanel textFieldsPanel;
+ private JPanel labelsPanel;
+ private JPanel buttonsPanel;
+ private JPanel qualityPanel;
+ private JPanel dataPanel;
+
+ /**
+ * Builds the dialog, no current password
+ */
+ public PasswordChangeDialog()
+ {
+ this(false);
+ }
+
+ /**
+ * Builds the dialog.
+ *
+ * @param showCurrentPassword Whether to show a "current password" field
+ */
+ public PasswordChangeDialog(boolean showCurrentPassword)
+ {
+ super(false);
+
+ this.showCurrentPassword = showCurrentPassword;
+
+ initComponents();
+
+ this.setTitle(resources
+ .getI18NString("service.gui.CHANGE_PASSWORD"));
+ this.setResizable(false);
+
+ JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+ mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ mainPanel.add(createIconComponent(), BorderLayout.WEST);
+ mainPanel.add(dataPanel);
+
+ this.getContentPane().add(mainPanel);
+
+ this.pack();
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Dimension screenSize = toolkit.getScreenSize();
+
+ int x = (screenSize.width - this.getWidth()) / 2;
+ int y = (screenSize.height - this.getHeight()) / 2;
+
+ this.setLocation(x, y);
+
+ if (showCurrentPassword)
+ {
+ currentPasswdField.requestFocusInWindow();
+ }
+ else
+ {
+ newPasswordField.requestFocusInWindow();
+ }
+ }
+
+ /**
+ * Initializes the UI components.
+ */
+ private void initComponents()
+ {
+ dataPanel = new TransparentPanel(new BorderLayout(10, 10));
+ dataPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+
+ // info text
+ infoTextArea = new JTextArea();
+ infoTextArea.setEditable(false);
+ infoTextArea.setOpaque(false);
+ infoTextArea.setLineWrap(true);
+ infoTextArea.setWrapStyleWord(true);
+ infoTextArea.setFont(infoTextArea.getFont().deriveFont(Font.BOLD));
+ infoTextArea.setText(resources
+ .getI18NString("service.gui.CHANGE_PASSWORD"));
+
+ // label fields
+ labelsPanel = new TransparentPanel(new GridLayout(0, 1, 8, 8));
+
+ if(showCurrentPassword)
+ {
+ labelsPanel.add(new JLabel(resources.getI18NString(
+ "plugin.securityconfig.masterpassword.CURRENT_PASSWORD")));
+ }
+ labelsPanel.add(new JLabel(resources.getI18NString(
+ "plugin.securityconfig.masterpassword.ENTER_PASSWORD")));
+ labelsPanel.add(new JLabel(resources.getI18NString(
+ "plugin.securityconfig.masterpassword.REENTER_PASSWORD")));
+
+ // password fields
+ ActionListener clickOkButton = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (okButton.isEnabled())
+ okButton.doClick();
+ }
+ };
+
+ if(showCurrentPassword)
+ {
+ currentPasswdField = new JPasswordField(15);
+ currentPasswdField.addActionListener(clickOkButton);
+ }
+ newPasswordField = new JPasswordField(15);
+ newPasswordField.addKeyListener(this);
+ newPasswordField.addActionListener(clickOkButton);
+ newAgainPasswordField = new JPasswordField(15);
+ newAgainPasswordField.addKeyListener(this);
+ newAgainPasswordField.addActionListener(clickOkButton);
+
+ textFieldsPanel = new TransparentPanel(new GridLayout(0, 1, 8, 8));
+ if(showCurrentPassword)
+ {
+ textFieldsPanel.add(currentPasswdField);
+ }
+ textFieldsPanel.add(newPasswordField);
+ textFieldsPanel.add(newAgainPasswordField);
+
+ // OK and cancel buttons
+ okButton = new JButton(resources.getI18NString("service.gui.OK"));
+ okButton.setMnemonic(resources.getI18nMnemonic("service.gui.OK"));
+ okButton.setEnabled(false);
+ cancelButton
+ = new JButton(resources.getI18NString("service.gui.CANCEL"));
+ cancelButton.setMnemonic(resources.getI18nMnemonic(
+ "service.gui.CANCEL"));
+ cancelButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ dispose();
+ }
+ });
+
+ passwordQualityBar =
+ new JProgressBar(0, PasswordQualityMeter.TOTAL_POINTS);
+ passwordQualityBar.setValue(0);
+
+ qualityPanel = new TransparentPanel();
+ qualityPanel.setLayout(new BoxLayout(qualityPanel, BoxLayout.Y_AXIS));
+
+ JLabel qualityMeterLabel = new JLabel(resources.getI18NString(
+ "plugin.securityconfig.masterpassword.PASSWORD_QUALITY_METER"));
+ qualityMeterLabel.setAlignmentX(CENTER_ALIGNMENT);
+
+ qualityPanel.add(qualityMeterLabel);
+ qualityPanel.add(passwordQualityBar);
+ qualityPanel.add(Box.createVerticalStrut(15));
+
+ buttonsPanel = new TransparentPanel(
+ new FlowLayout(FlowLayout.RIGHT, 0, 5));
+ buttonsPanel.add(okButton);
+ buttonsPanel.add(cancelButton);
+ qualityPanel.add(buttonsPanel);
+
+ dataPanel.add(infoTextArea, BorderLayout.NORTH);
+ dataPanel.add(labelsPanel, BorderLayout.WEST);
+ dataPanel.add(textFieldsPanel, BorderLayout.CENTER);
+ dataPanel.add(qualityPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Displays an error pop-up.
+ *
+ * @param message the message to display
+ */
+ protected void displayPopupError(String message)
+ {
+ DesktopUtilActivator
+ .getUIService()
+ .getPopupDialog()
+ .showMessagePopupDialog(
+ message,
+ resources.getI18NString(
+ "service.gui.PASSWORD_CHANGE_FAILURE"),
+ PopupDialog.ERROR_MESSAGE);
+ }
+
+ /**
+ * Displays an info pop-up.
+ *
+ * @param message the message to display.
+ */
+ protected void displayPopupInfo(String message)
+ {
+ DesktopUtilActivator
+ .getUIService()
+ .getPopupDialog()
+ .showMessagePopupDialog(
+ message,
+ resources.getI18NString(
+ "service.gui.PASSWORD_CHANGE_SUCCESS"),
+ PopupDialog.INFORMATION_MESSAGE);
+ }
+
+ protected void close(boolean isEscaped)
+ {
+ cancelButton.doClick();
+ }
+
+ /**
+ * When a key is pressed we do 2 things. The first is to compare the two
+ * password input fields and enable OK button if they are equal. The second
+ * is to measure the password quality of the password from the first input
+ * field.
+ *
+ * @param event key event
+ */
+ public void keyReleased(KeyEvent event)
+ {
+ JPasswordField source = (JPasswordField) event.getSource();
+ if (newPasswordField.equals(source)
+ || newAgainPasswordField.equals(source))
+ {
+ String password1 = new String(newPasswordField.getPassword());
+ String password2 = new String(newAgainPasswordField.getPassword());
+ // measure password quality
+ passwordQualityBar
+ .setValue(passwordMeter.assessPassword(password1));
+ // enable OK button if passwords are equal
+ boolean eq = (password1.length() != 0)
+ && password1.equals(password2);
+ okButton.setEnabled(eq);
+ password1 = null;
+ password2 = null;
+ }
+ }
+
+ /**
+ * Not overriding.
+ *
+ * @param arg0 key event
+ */
+ public void keyPressed(KeyEvent arg0)
+ {
+ }
+
+ /**
+ * Not overriding.
+ *
+ * @param arg0 key event
+ */
+ public void keyTyped(KeyEvent arg0)
+ {
+ }
+
+ /**
+ * Creates the icon component to show on the left of this dialog.
+ *
+ * @return the created component
+ */
+ private static Component createIconComponent()
+ {
+ JPanel wrapIconPanel = new JPanel(new BorderLayout());
+
+ JLabel iconLabel = new JLabel();
+
+ iconLabel.setIcon(DesktopUtilActivator.getResources()
+ .getImage("service.gui.icons.AUTHORIZATION_ICON"));
+
+ wrapIconPanel.add(iconLabel, BorderLayout.NORTH);
+
+ return wrapIconPanel;
+ }
+
+ /**
+ * Return a reference to the "ok" button.
+ *
+ * @return a reference to the "ok" button.
+ */
+ protected JButton getOkButton()
+ {
+ return okButton;
+ }
+
+ /**
+ * Return a reference to the "cancel" button.
+ *
+ * @return a reference to the "cancel" button.
+ */
+ protected JButton getCancelButton()
+ {
+ return cancelButton;
+ }
+
+ /**
+ * Return the string entered in the password field.
+ *
+ * @return the string entered in the password field.
+ */
+ protected String getNewPassword()
+ {
+ return new String(newPasswordField.getPassword());
+ }
+
+ /**
+ * Return the string entered in the "current password" field, or null if
+ * that field is not shown.
+ *
+ * @return the string entered in the "current password" field.
+ */
+ protected String getCurrentPassword()
+ {
+ if(currentPasswdField == null)
+ {
+ return null;
+ }
+ else
+ {
+ return new String(currentPasswdField.getPassword());
+ }
+ }
+
+ /**
+ * Sets the descriptional text that is displayed
+ * @param infoText the new text to display.
+ */
+ protected void setInfoText(String infoText)
+ {
+ infoTextArea.setText(infoText);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/PopupNotificationPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/PopupNotificationPanel.java
new file mode 100644
index 0000000..5963148
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/PopupNotificationPanel.java
@@ -0,0 +1,158 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.Logger;
+import net.java.sip.communicator.util.skin.*;
+
+import org.jitsi.util.*;
+
+/**
+ * A custom panel to handle systray popup notification
+ *
+ * @author Symphorien Wanko
+ * @author Adam Netocny
+ */
+public class PopupNotificationPanel
+ extends SIPCommFrame.MainContentPane
+ implements Skinnable
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Logger for this class.
+ **/
+ private final Logger logger = Logger.getLogger(SIPCommFrame.class);
+
+ /**
+ * An object to distinguish this <tt>PopupNotificationPanel</tt>
+ */
+ private Object tag;
+
+ /**
+ * Close button.
+ */
+ private final SIPCommButton notifClose;
+
+ /**
+ * Notification title.
+ */
+ private JLabel notifTitle;
+
+ /**
+ * Creates a new <tt>PopupNotificationPanel</tt> with a customized panel
+ * title.
+ * @param titleString The title of the popup
+ */
+ private PopupNotificationPanel(String titleString)
+ {
+ notifTitle = new JLabel(
+ DesktopUtilActivator.getResources().getSettingsString(
+ "service.gui.APPLICATION_NAME")
+ + (StringUtils.isNullOrEmpty(titleString, true)
+ ? ""
+ : ": " + titleString),
+ SwingConstants.LEFT);
+
+ notifClose = new SIPCommButton();
+
+ notifClose.setToolTipText(DesktopUtilActivator.getResources()
+ .getI18NString("service.gui.CLOSE"));
+
+ notifClose.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ try
+ {
+ Window parentWindow
+ = SwingUtilities.getWindowAncestor(
+ PopupNotificationPanel.this);
+
+ parentWindow.dispose();
+ }
+ catch (Exception ex)
+ {
+ // should never happens : if the user clicks on the close
+ // icon, it means that the popup window were visible
+ logger.warn("Error while getting the popup window :", ex);
+ }
+ }
+ });
+
+ JPanel notificationWindowTitle
+ = new JPanel(new BorderLayout(0, 2));
+ notificationWindowTitle
+ .setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
+ notificationWindowTitle.setOpaque(false);
+ notificationWindowTitle.add(notifTitle, BorderLayout.WEST);
+ notificationWindowTitle.add(notifClose, BorderLayout.EAST);
+
+ JSeparator jSep = new JSeparator();
+
+ notificationWindowTitle.add(jSep, BorderLayout.SOUTH);
+
+ add(notificationWindowTitle, BorderLayout.NORTH);
+ setBorder(BorderFactory.createLineBorder(Color.GRAY));
+
+ // All items are now instantiated and could safely load the skin.
+ loadSkin();
+ }
+
+ /**
+ * Creates a new notification panel with <tt>notificationContent</tt> as
+ * the component to put in that panel
+ *
+ * @param titleString The title of the popup
+ * @param notificationContent content to add in the new created
+ * <tt>PopupNotificationPanel</tt>
+ * @param tag an object to distinguish this <tt>PopupNotificationPanel</tt>
+ */
+ public PopupNotificationPanel(String titleString,
+ JPanel notificationContent, Object tag)
+ {
+ this(titleString);
+ add(notificationContent, BorderLayout.CENTER);
+ this.tag = tag;
+ }
+
+ /**
+ * @return the tag
+ */
+ public Object getTag()
+ {
+ return tag;
+ }
+
+ /**
+ * @param tag the tag to set
+ */
+ public void setTag(Object tag)
+ {
+ this.tag = tag;
+ }
+
+ /**
+ * Reloads resources for this component.
+ */
+ public void loadSkin()
+ {
+ notifTitle.setIcon(DesktopUtilActivator.getResources().getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO"));
+ notifClose.setBackgroundImage(DesktopUtilActivator.getResources()
+ .getImage("service.gui.lookandfeel.CLOSE_TAB_ICON").getImage());
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/PriorityTable.java b/src/net/java/sip/communicator/plugin/desktoputil/PriorityTable.java
new file mode 100644
index 0000000..7ab72e9
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/PriorityTable.java
@@ -0,0 +1,170 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.resources.*;
+
+/**
+ * Creates a component containing a table and two buttons for the encodings of
+ * type(AUDIO or VIDEO) or to sort the priority of the encryption protocols.
+ *
+ * @author Vincent Lucas
+ */
+public class PriorityTable
+ extends TransparentPanel
+{
+ /**
+ * The table containing the different elements to sort by priority.
+ */
+ private JTable table;
+
+ /**
+ * The button to increase the priority of one item by moving it up in the
+ * table.
+ */
+ private JButton upButton;
+
+ /**
+ * The button to decrease the priority of one item by moving it down in the
+ * table.
+ */
+ private JButton downButton;
+
+ /**
+ * The preferred width of all panels.
+ */
+ private final static int WIDTH = 350;
+
+ /**
+ * Creates a component for the encodings of type(AUDIO or VIDEO) or to sort
+ * the priority of the encryption protocols.
+ * @param tableModel The table model to display encodings (AUDIO or VIDEO),
+ * or to sort the priority of the encryption protocols.
+ * @param height The height (preferred and maximum height) of the component.
+ * @return the component.
+ */
+ public PriorityTable(
+ MoveableTableModel tableModel,
+ int height)
+ {
+ super(new BorderLayout());
+
+ ResourceManagementService resources = DesktopUtilActivator.getResources();
+ String key;
+ String i18NresourcesKey;
+
+ table = new JTable();
+ table.setShowGrid(false);
+ table.setTableHeader(null);
+
+ key = "impl.media.configform.UP";
+ upButton = new JButton(resources.getI18NString(key));
+ upButton.setMnemonic(resources.getI18nMnemonic(key));
+ upButton.setOpaque(false);
+
+ key = "impl.media.configform.DOWN";
+ downButton = new JButton(resources.getI18NString(key));
+ downButton.setMnemonic(resources.getI18nMnemonic(key));
+ downButton.setOpaque(false);
+
+ Container buttonBar = new TransparentPanel(new GridLayout(0, 1));
+ buttonBar.add(upButton);
+ buttonBar.add(downButton);
+
+ Container parentButtonBar = new TransparentPanel(new BorderLayout());
+ parentButtonBar.add(buttonBar, BorderLayout.NORTH);
+
+ //Container container = new TransparentPanel(new BorderLayout());
+ this.setPreferredSize(new Dimension(WIDTH, height));
+ this.setMaximumSize(new Dimension(WIDTH, height));
+
+ this.add(new JScrollPane(table), BorderLayout.CENTER);
+ this.add(parentButtonBar, BorderLayout.EAST);
+
+ table.setModel(tableModel);
+
+ /*
+ * The first column contains the check boxes which enable/disable their
+ * associated encodings and it doesn't make sense to make it wider than
+ * the check boxes.
+ */
+ TableColumnModel tableColumnModel = table.getColumnModel();
+ TableColumn tableColumn = tableColumnModel.getColumn(0);
+ tableColumn.setMaxWidth(tableColumn.getMinWidth());
+
+ ListSelectionListener tableSelectionListener =
+ new ListSelectionListener()
+ {
+ public void valueChanged(ListSelectionEvent event)
+ {
+ if (table.getSelectedRowCount() == 1)
+ {
+ int selectedRow = table.getSelectedRow();
+ if (selectedRow > -1)
+ {
+ upButton.setEnabled(selectedRow > 0);
+ downButton.setEnabled(selectedRow < (table
+ .getRowCount() - 1));
+ return;
+ }
+ }
+ upButton.setEnabled(false);
+ downButton.setEnabled(false);
+ }
+ };
+ table.getSelectionModel().addListSelectionListener(
+ tableSelectionListener);
+ tableSelectionListener.valueChanged(null);
+
+ ActionListener buttonListener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Object source = event.getSource();
+ boolean up;
+ if (source == upButton)
+ up = true;
+ else if (source == downButton)
+ up = false;
+ else
+ return;
+
+ move(up);
+ }
+ };
+ upButton.addActionListener(buttonListener);
+ downButton.addActionListener(buttonListener);
+ }
+
+ /**
+ * Used to move encoding options.
+ * @param table the table with encodings
+ * @param up move direction.
+ */
+ private void move(boolean up)
+ {
+ int index =
+ ((MoveableTableModel) table.getModel()).move(table
+ .getSelectedRow(), up);
+ table.getSelectionModel().setSelectionInterval(index, index);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled)
+ {
+ this.table.setEnabled(enabled);
+ this.upButton.setEnabled(enabled);
+ this.downButton.setEnabled(enabled);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommButton.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommButton.java
new file mode 100644
index 0000000..ee58c87
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommButton.java
@@ -0,0 +1,454 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * The <tt>SIPCommButton</tt> is a very flexible <tt>JButton</tt> that allows
+ * to configure its background, its icon, the look when a mouse is over it, etc.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommButton
+ extends JButton
+ implements OrderedComponent
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private Image bgImage;
+
+ private Image pressedImage;
+
+ private Image rolloverImage;
+
+ private Image rolloverIconImage;
+
+ private Image pressedIconImage;
+
+ private Image iconImage;
+
+ /**
+ * The index of the button, used when we want to order our buttons.
+ */
+ private int index = -1;
+
+ /**
+ * Creates a button.
+ */
+ public SIPCommButton()
+ {
+ this(null);
+ }
+
+ /**
+ * Creates a button with custom background image and icon image.
+ *
+ * @param bgImage The background image.
+ * @param rolloverImage The rollover background image.
+ * @param pressedImage The pressed image.
+ * @param iconImage The icon.
+ * @param rolloverIconImage The rollover icon image.
+ * @param pressedIconImage The pressed icon image.
+ */
+ public SIPCommButton( Image bgImage,
+ Image rolloverImage,
+ Image pressedImage,
+ Image iconImage,
+ Image rolloverIconImage,
+ Image pressedIconImage)
+ {
+ MouseRolloverHandler mouseHandler = new MouseRolloverHandler();
+
+ this.addMouseListener(mouseHandler);
+ this.addMouseMotionListener(mouseHandler);
+
+ /*
+ * Explicitly remove all borders that may be set from the current look
+ * and feel.
+ */
+ this.setContentAreaFilled(false);
+ this.setBorder(null);
+
+ this.bgImage = bgImage;
+ this.rolloverImage = rolloverImage;
+ this.pressedImage = pressedImage;
+ this.rolloverIconImage = rolloverIconImage;
+ this.pressedIconImage = pressedIconImage;
+ this.iconImage = iconImage;
+
+ if (bgImage != null)
+ {
+ this.setPreferredSize(new Dimension(bgImage.getWidth(null),
+ bgImage.getHeight(null)));
+
+ this.setIcon(new ImageIcon(this.bgImage));
+ }
+ }
+
+ /**
+ * Creates a button with custom background image and icon image.
+ *
+ * @param bgImage The background image.
+ * @param pressedImage The pressed image.
+ * @param iconImage The icon.
+ */
+ public SIPCommButton( Image bgImage,
+ Image pressedImage,
+ Image iconImage)
+ {
+ this(bgImage, null, pressedImage, iconImage, null, null);
+ }
+
+ /**
+ * Creates a button with custom background image.
+ *
+ * @param bgImage the background button image
+ * @param iconImage the icon of this button
+ */
+ public SIPCommButton( Image bgImage,
+ Image iconImage)
+ {
+ this(bgImage, null, iconImage);
+ }
+
+ /**
+ * Creates a button with custom background image.
+ *
+ * @param bgImage The background button image.
+ */
+ public SIPCommButton(Image bgImage)
+ {
+ this(bgImage, null);
+ }
+
+ /**
+ * Resets the background image for this button.
+ *
+ * @param bgImage the new image to set.
+ */
+ public void setImage(Image bgImage)
+ {
+ this.bgImage = bgImage;
+
+ this.repaint();
+ }
+
+ /**
+ * Overrides the <code>paintComponent</code> method of <tt>JButton</tt> to
+ * paint the button background and icon, and all additional effects of this
+ * configurable button.
+ *
+ * @param g The Graphics object.
+ */
+ protected void paintComponent(Graphics g)
+ {
+ g = g.create();
+ try
+ {
+ internalPaintComponent(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ /**
+ * Paints this button.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ private void internalPaintComponent(Graphics g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+ /*
+ * As JComponent#paintComponent says, if you do not invoke super's
+ * implementation you must honor the opaque property, that is if this
+ * component is opaque, you must completely fill in the background in a
+ * non-opaque color. If you do not honor the opaque property you will
+ * likely see visual artifacts.
+ */
+ if (isOpaque())
+ {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+
+ if (this.bgImage != null)
+ {
+ // If there's no icon, we make grey the backgroundImage
+ // when disabled.
+ Image paintBgImage;
+ if (this.iconImage == null && !isEnabled())
+ {
+ paintBgImage = new ImageIcon(LightGrayFilter
+ .createDisabledImage(bgImage)).getImage();
+ }
+ else
+ paintBgImage = bgImage;
+
+ g.drawImage(paintBgImage,
+ this.getWidth()/2 - paintBgImage.getWidth(null)/2,
+ this.getHeight()/2 - paintBgImage.getHeight(null)/2,
+ this);
+ }
+
+ // Paint a roll over fade out.
+ if (rolloverImage == null)
+ {
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = this.getModel().isRollover() ? 1.0f : 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ }
+
+ visibility /= 2;
+
+ g.setColor(new Color(1.0f, 1.0f, 1.0f, visibility));
+
+ if (this.bgImage == null
+ && (isContentAreaFilled() || (visibility != 0.0f)))
+ {
+ g.fillRoundRect(
+ 0, 0, this.getWidth(), this.getHeight(), 8, 8);
+ }
+ }
+
+ // Paint pressed state.
+ if (this.getModel().isPressed() && this.pressedImage != null)
+ {
+ g.drawImage(this.pressedImage, 0, 0, this);
+ }
+ else if (this.getModel().isRollover() && this.rolloverImage != null)
+ {
+ g.drawImage(this.rolloverImage, 0, 0, this);
+ }
+
+ Image paintIconImage = null;
+ if (getModel().isPressed() && pressedIconImage != null)
+ {
+ paintIconImage = pressedIconImage;
+ }
+ else if (this.getModel().isRollover() && rolloverIconImage != null)
+ {
+ paintIconImage = rolloverIconImage;
+ }
+ else if (this.iconImage != null)
+ {
+ if (!isEnabled())
+ {
+ paintIconImage = new ImageIcon(LightGrayFilter
+ .createDisabledImage(iconImage)).getImage();
+ }
+ else
+ paintIconImage = iconImage;
+ }
+
+ if (paintIconImage != null)
+ g.drawImage(paintIconImage,
+ this.getWidth()/2 - paintIconImage.getWidth(null)/2,
+ this.getHeight()/2 - paintIconImage.getHeight(null)/2,
+ this);
+ }
+
+ /**
+ * Returns the background image of this button.
+ *
+ * @return the background image of this button.
+ */
+ public Image getBackgroundImage()
+ {
+ return bgImage;
+ }
+
+ /**
+ * Sets the background image of this button.
+ *
+ * @param bgImage the background image of this button.
+ */
+ public void setBackgroundImage(Image bgImage)
+ {
+ this.bgImage = bgImage;
+
+ if (bgImage != null)
+ {
+ this.setPreferredSize(new Dimension(bgImage.getWidth(null),
+ bgImage.getHeight(null)));
+
+ this.setIcon(new ImageIcon(this.bgImage));
+ }
+ }
+
+ /**
+ * Sets the rollover background image of this button.
+ *
+ * @param rolloverImage the rollover background image of this button.
+ */
+ public void setRolloverImage(Image rolloverImage)
+ {
+ this.rolloverImage = rolloverImage;
+ }
+
+ /**
+ * Sets the pressed image of this button.
+ *
+ * @param pressedImage the pressed image of this button.
+ */
+ public void setPressedImage(Image pressedImage)
+ {
+ this.pressedImage = pressedImage;
+ }
+
+ /**
+ * Sets the rollover icon image of this button.
+ *
+ * @param rolloverIconImage the rollover icon image of this button.
+ */
+ public void setRolloverIcon(Image rolloverIconImage)
+ {
+ this.rolloverIconImage = rolloverIconImage;
+ }
+
+ /**
+ * Sets the pressed icon image of this button.
+ *
+ * @param pressedIconImage the pressed icon image of this button.
+ */
+ public void setPressedIcon(Image pressedIconImage)
+ {
+ this.pressedIconImage = pressedIconImage;
+ }
+
+ /**
+ * Sets the icon image of this button.
+ *
+ * @param iconImage the icon image of this button.
+ */
+ public void setIconImage(Image iconImage)
+ {
+ this.iconImage = iconImage;
+ }
+
+ /**
+ * Change buttons index when we want to order it.
+ * @param index the button index.
+ */
+ public void setIndex(int index)
+ {
+ this.index = index;
+ }
+
+ /**
+ * Returns the current button index we have set, or -1 if none used.
+ * @return
+ */
+ public int getIndex()
+ {
+ return this.index;
+ }
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class ButtonRepaintCallback implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ SIPCommButton.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ /**
+ * Perform a fade animation on mouse over.
+ */
+ private class MouseRolloverHandler
+ implements MouseListener,
+ MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(false);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeOut(FadeKind.ROLLOVER,
+ SIPCommButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(true);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ SIPCommButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommCheckBox.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommCheckBox.java
new file mode 100644
index 0000000..a7770d4
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommCheckBox.java
@@ -0,0 +1,48 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+import org.jitsi.util.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class SIPCommCheckBox
+ extends JCheckBox
+{
+ private static final long serialVersionUID = 0L;
+
+ private static final boolean setContentAreaFilled = (OSUtils.IS_WINDOWS
+ || OSUtils.IS_LINUX);
+
+ public SIPCommCheckBox()
+ {
+ init();
+ }
+
+ public SIPCommCheckBox(String text)
+ {
+ super(text);
+
+ init();
+ }
+
+ public SIPCommCheckBox(String text, boolean selected)
+ {
+ super(text, selected);
+
+ init();
+ }
+
+ private void init()
+ {
+ if (setContentAreaFilled)
+ setContentAreaFilled(false);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommDialog.java
new file mode 100644
index 0000000..50d99f9
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommDialog.java
@@ -0,0 +1,446 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.Logger;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.util.*;
+
+/**
+ * @author Yana Stamcheva
+ * @author Lubomir Marinov
+ */
+public class SIPCommDialog
+ extends JDialog
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>SIPCommDialog</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger = Logger.getLogger(SIPCommDialog.class);
+
+ /**
+ * The action map of this dialog.
+ */
+ private ActionMap amap;
+
+ /**
+ * The input map of this dialog.
+ */
+ private InputMap imap;
+
+ /**
+ * Indicates if the size and location of this dialog are stored after
+ * closing.
+ */
+ private boolean isSaveSizeAndLocation = true;
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt>.
+ */
+ public SIPCommDialog()
+ {
+ super();
+
+ this.init();
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt> by specifying the
+ * <tt>Dialog</tt>owner of this dialog.
+ * @param owner the owner of this dialog
+ */
+ public SIPCommDialog(Dialog owner)
+ {
+ super(owner);
+
+ this.init();
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt> by specifying the
+ * <tt>Frame</tt> owner.
+ * @param owner the owner of this dialog
+ */
+ public SIPCommDialog(Frame owner)
+ {
+ super(owner);
+
+ this.init();
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt> by specifying explicitly
+ * if the size and location properties are saved. By default size and
+ * location are stored.
+ * @param isSaveSizeAndLocation indicates whether to save the size and
+ * location of this dialog
+ */
+ public SIPCommDialog(boolean isSaveSizeAndLocation)
+ {
+ this();
+
+ this.isSaveSizeAndLocation = isSaveSizeAndLocation;
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt> by specifying the owner
+ * of this dialog and indicating whether to save the size and location
+ * properties.
+ * @param owner the owner of this dialog
+ * @param isSaveSizeAndLocation indicates whether to save the size and
+ * location of this dialog
+ */
+ public SIPCommDialog(Dialog owner, boolean isSaveSizeAndLocation)
+ {
+ this(owner);
+
+ this.isSaveSizeAndLocation = isSaveSizeAndLocation;
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommDialog</tt> by specifying the owner
+ * of this dialog and indicating whether to save the size and location
+ * properties.
+ * @param owner the owner of this dialog
+ * @param isSaveSizeAndLocation indicates whether to save the size and
+ * location of this dialog
+ */
+ public SIPCommDialog(Frame owner, boolean isSaveSizeAndLocation)
+ {
+ this(owner);
+
+ this.isSaveSizeAndLocation = isSaveSizeAndLocation;
+ }
+
+ /**
+ * Initializes this dialog.
+ */
+ private void init()
+ {
+ // If on MacOS we would use the native background.
+ if (!OSUtils.IS_MAC)
+ this.setContentPane(new SIPCommFrame.MainContentPane());
+
+ this.addWindowListener(new DialogWindowAdapter());
+
+ this.initInputMap();
+
+ WindowUtils.addWindow(this);
+ }
+
+ private void initInputMap()
+ {
+ amap = this.getRootPane().getActionMap();
+
+ amap.put("close", new CloseAction());
+
+ imap = this.getRootPane().getInputMap(
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
+
+ // put the defaults for macosx
+ if(OSUtils.IS_MAC)
+ {
+ imap.put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.META_DOWN_MASK),
+ "close");
+ imap.put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK),
+ "close");
+ }
+ }
+
+ /**
+ * The action invoked when user presses Escape key.
+ */
+ private class CloseAction extends UIAction
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if(isSaveSizeAndLocation)
+ saveSizeAndLocation();
+
+ close(true);
+ }
+ }
+
+ /**
+ * Adds a key - action pair for this frame.
+ *
+ * @param keyStroke the key combination
+ * @param action the action which will be executed when user presses the
+ * given key combination
+ */
+ protected void addKeyBinding(KeyStroke keyStroke, Action action)
+ {
+ String actionID = action.getClass().getName();
+
+ amap.put(actionID, action);
+
+ imap.put(keyStroke, actionID);
+ }
+
+ /**
+ * Before closing the application window saves the current size and position
+ * through the <tt>ConfigurationService</tt>.
+ */
+ public class DialogWindowAdapter extends WindowAdapter
+ {
+ /**
+ * Invoked when this window is in the process of being closed.
+ * @param e the <tt>WindowEvent</tt> that notified us
+ */
+ public void windowClosing(WindowEvent e)
+ {
+ if(isSaveSizeAndLocation)
+ saveSizeAndLocation();
+
+ close(false);
+ }
+ }
+
+ /**
+ * Saves the size and the location of this dialog through the
+ * <tt>ConfigurationService</tt>.
+ */
+ private void saveSizeAndLocation()
+ {
+ try
+ {
+ SIPCommFrame.saveSizeAndLocation(this);
+ }
+ catch (ConfigPropertyVetoException e1)
+ {
+ logger.error("The proposed property change "
+ + "represents an unacceptable value");
+ }
+ }
+
+ /**
+ * Sets window size and position.
+ */
+ private void setSizeAndLocation()
+ {
+ ConfigurationService config = DesktopUtilActivator.getConfigurationService();
+ String className = this.getClass().getName().replaceAll("\\$", "_");
+
+ int width = config.getInt(className + ".width", 0);
+ int height = config.getInt(className + ".height", 0);
+
+ String xString = config.getString(className + ".x");
+ String yString = config.getString(className + ".y");
+
+ if(width > 0 && height > 0)
+ this.setSize(width, height);
+
+ if(xString != null && yString != null)
+ {
+ int x = Integer.parseInt(xString);
+ int y = Integer.parseInt(yString);
+ if(ScreenInformation.
+ isTitleOnScreen(new Rectangle(x, y, width, height))
+ || config.getBoolean(
+ SIPCommFrame.PNAME_CALCULATED_POSITIONING, true))
+ {
+ this.setLocation(x, y);
+ }
+ }
+ else
+ this.setCenterLocation();
+ }
+
+ /**
+ * Positions this window in the center of the screen.
+ */
+ private void setCenterLocation()
+ {
+ setLocationRelativeTo(getParent());
+ }
+
+ /**
+ * Checks whether the current component will
+ * exceeds the screen size and if it do will set a default size
+ */
+ private void ensureOnScreenLocationAndSize()
+ {
+ ConfigurationService config = DesktopUtilActivator.getConfigurationService();
+ if(!config.getBoolean(SIPCommFrame.PNAME_CALCULATED_POSITIONING, true))
+ return;
+
+ int x = this.getX();
+ int y = this.getY();
+
+ int width = this.getWidth();
+ int height = this.getHeight();
+
+ Rectangle virtualBounds = ScreenInformation.getScreenBounds();
+
+ // the default distance to the screen border
+ final int borderDistance = 10;
+
+ // in case any of the sizes exceeds the screen size
+ // we set default one
+ // get the left upper point of the window
+ if (!(virtualBounds.contains(x, y)))
+ {
+ // top left exceeds screen bounds
+ if (x < virtualBounds.x)
+ {
+ // window is too far to the left
+ // move it to the right
+ x = virtualBounds.x + borderDistance;
+ } else if (x > virtualBounds.x)
+ {
+ // window is too far to the right
+ // can only occour, when screen resolution is
+ // changed or displayed are disconnected
+
+ // move the window in the bounds to the very right
+ x = virtualBounds.x + virtualBounds.width - width
+ - borderDistance;
+ if (x < virtualBounds.x + borderDistance)
+ {
+ x = virtualBounds.x + borderDistance;
+ }
+ }
+
+ // top left exceeds screen bounds
+ if (y < virtualBounds.y)
+ {
+ // window is too far to the top
+ // move it to the bottom
+ y = virtualBounds.y + borderDistance;
+ } else if (y > virtualBounds.y)
+ {
+ // window is too far to the bottom
+ // can only occour, when screen resolution is
+ // changed or displayed are disconnected
+
+ // move the window in the bounds to the very bottom
+ y = virtualBounds.y + virtualBounds.height - height
+ - borderDistance;
+ if (y < virtualBounds.y + borderDistance)
+ {
+ y = virtualBounds.y + borderDistance;
+ }
+ }
+ this.setLocation(x, y);
+ }
+
+ // check the lower right corder
+ if (!(virtualBounds.contains(x, y, width, height)))
+ {
+ if (x + width > virtualBounds.x + virtualBounds.width)
+ {
+ // location of window is too far to the right, its right
+ // border is out of bounds
+
+ // calculate a new horizontal position
+ // move the whole window to the left
+ x = virtualBounds.x + virtualBounds.width - width
+ - borderDistance;
+ if (x < virtualBounds.x + borderDistance)
+ {
+ // window is already on left side, it is too wide.
+ x = virtualBounds.x + borderDistance;
+ // reduce the width, so it surely fits
+ width = virtualBounds.width - 2 * borderDistance;
+ }
+ }
+ if (y + height > virtualBounds.y + virtualBounds.height)
+ {
+ // location of window is too far to the bottom, its bottom
+ // border is out of bounds
+
+ // calculate a new vertical position
+ // move the whole window to the top
+ y = virtualBounds.y + virtualBounds.height - height
+ - borderDistance;
+ if (y < virtualBounds.y + borderDistance)
+ {
+ // window is already on top, it is too high.
+ y = virtualBounds.y + borderDistance;
+ // reduce the width, so it surely fits
+ height = virtualBounds.height - 2 * borderDistance;
+ }
+ }
+ this.setPreferredSize(new Dimension(width, height));
+ this.setSize(width, height);
+ this.setLocation(x, y);
+ }
+ }
+
+ /**
+ * Overwrites the setVisible method in order to set the size and the
+ * position of this window before showing it.
+ * @param isVisible indicates if the dialog should be visible
+ */
+ public void setVisible(boolean isVisible)
+ {
+ if(isVisible)
+ {
+ this.pack();
+
+ if(isSaveSizeAndLocation)
+ this.setSizeAndLocation();
+ else
+ {
+ this.pack();
+ this.setCenterLocation();
+ }
+
+ ensureOnScreenLocationAndSize();
+
+ JButton button = this.getRootPane().getDefaultButton();
+
+ if(button != null)
+ button.requestFocus();
+ }
+ super.setVisible(isVisible);
+ }
+
+ /**
+ * Overwrites the dispose method in order to save the size and the position
+ * of this window before closing it.
+ */
+ public void dispose()
+ {
+ if(isSaveSizeAndLocation)
+ this.saveSizeAndLocation();
+
+ super.dispose();
+ }
+
+ /**
+ * All functions implemented in this method will be invoked when user
+ * presses the Escape key.
+ *
+ * @param escaped <tt>true</tt> if this frame has been closed by pressing
+ * the Esc key; otherwise, <tt>false</tt>
+ */
+ protected void close(boolean escaped)
+ {
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommFrame.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommFrame.java
new file mode 100644
index 0000000..e3fda87
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommFrame.java
@@ -0,0 +1,835 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.service.keybindings.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.Logger;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
+import org.jitsi.util.*;
+
+/**
+ * A custom frame that remembers its size and location and could have a
+ * semi-transparent background.
+ *
+ * @author Yana Stamcheva
+ * @author Lyubomir Marinov
+ * @author Adam Netocny
+ */
+public class SIPCommFrame
+ extends JFrame
+ implements Observer
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Property that disables the automatic resizing and positioning when a
+ * window's top edge is outside the visible area of the screen.
+ * <p>
+ * <tt>true</tt> use automatic repositioning (default)<br/>
+ * <tt>false</tt> rely on the window manager to place the window
+ */
+ static final String PNAME_CALCULATED_POSITIONING
+ = "net.sip.communicator.util.swing.USE_CALCULATED_POSITIONING";
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>SIPCommFrame</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger = Logger.getLogger(SIPCommFrame.class);
+
+ /**
+ * The action map of this dialog.
+ */
+ private ActionMap amap;
+
+ /**
+ * The input map of this dialog.
+ */
+ private InputMap imap;
+
+ /**
+ * The key bindings set.
+ */
+ private KeybindingSet bindings = null;
+
+ /**
+ * Indicates if the size and location of this dialog are stored after
+ * closing. By default we store window size and location.
+ */
+ private boolean isSaveSizeAndLocation = true;
+
+ /**
+ * Creates a <tt>SIPCommFrame</tt>.
+ */
+ public SIPCommFrame()
+ {
+ // If on MacOS we would use the native background.
+ if (!OSUtils.IS_MAC)
+ setContentPane(new MainContentPane());
+
+ init();
+
+ addWindowListener(new FrameWindowAdapter());
+
+ JRootPane rootPane = getRootPane();
+ amap = rootPane.getActionMap();
+ amap.put("close", new CloseAction());
+ amap.put("closeEsc", new CloseEscAction());
+
+ imap = rootPane.getInputMap(
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+
+ imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closeEsc");
+
+ // put the defaults for macosx
+ if(OSUtils.IS_MAC)
+ {
+ imap.put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.META_DOWN_MASK),
+ "closeEsc");
+ imap.put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK),
+ "closeEsc");
+ }
+
+ WindowUtils.addWindow(this);
+ }
+
+ /**
+ * Validates this container and all of its subcomponents.
+ * <p>
+ * The <code>validate</code> method is used to cause a container
+ * to lay out its subcomponents again. It should be invoked when
+ * this container's subcomponents are modified (added to or
+ * removed from the container, or layout-related information
+ * changed) after the container has been displayed.
+ *
+ * <p>If this {@code Container} is not valid, this method invokes
+ * the {@code validateTree} method and marks this {@code Container}
+ * as valid. Otherwise, no action is performed.
+ *
+ * @see #add(java.awt.Component)
+ * @see Component#invalidate
+ * @see javax.swing.JComponent#revalidate()
+ * @see #validateTree
+ */
+ @Override
+ public void validate()
+ {
+ init();
+ super.validate();
+ }
+
+ /**
+ * Initialize default values.
+ */
+ private void init()
+ {
+ try
+ {
+ Method m = Window.class.getMethod("setIconImages", List.class);
+ List<Image> logos = new ArrayList<Image>(6)
+ {
+ private static final long serialVersionUID = 0L;
+ {
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO"));
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO_20x20"));
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO_32x32"));
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO_45x45"));
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO_64x64"));
+ add(DesktopUtilActivator.getImage(
+ "service.gui.SIP_COMMUNICATOR_LOGO_128x128"));
+ }
+ };
+ m.invoke(this, logos);
+ // In order to have the same icon when using option panes
+ m.invoke(JOptionPane.getRootFrame(), logos);
+ }
+ catch (Exception e)
+ {
+ Image scLogo
+ = DesktopUtilActivator.getImage("service.gui.SIP_COMMUNICATOR_LOGO");
+
+ setIconImage(scLogo);
+ // In order to have the same icon when using option panes
+ JOptionPane.getRootFrame().setIconImage(scLogo);
+ }
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommFrame</tt> by specifying explicitly
+ * if the size and location properties are saved. By default size and
+ * location are stored.
+ * @param isSaveSizeAndLocation indicates whether to save the size and
+ * location of this dialog
+ */
+ public SIPCommFrame(boolean isSaveSizeAndLocation)
+ {
+ this();
+
+ this.isSaveSizeAndLocation = isSaveSizeAndLocation;
+ }
+
+ /**
+ * The action invoked when user presses Ctrl-W and Cmd-W key combination.
+ */
+ private class CloseAction
+ extends UIAction
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if (isSaveSizeAndLocation)
+ saveSizeAndLocation();
+ close(false);
+ }
+ }
+
+ /**
+ * The action invoked when user presses Escape key.
+ */
+ private class CloseEscAction
+ extends UIAction
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if (isSaveSizeAndLocation)
+ saveSizeAndLocation();
+ close(true);
+ }
+ }
+
+ /**
+ * Sets the input map to utilize a given category of keybindings. The frame
+ * is updated to reflect the new bindings when they change. This replaces
+ * any previous bindings that have been added.
+ *
+ * @param category set of keybindings to be utilized
+ */
+ protected void setKeybindingInput(KeybindingSet.Category category)
+ {
+ // Removes old binding set
+ if (bindings != null)
+ {
+ bindings.deleteObserver(this);
+ resetInputMap();
+ }
+
+ // Adds new bindings to input map
+ bindings
+ = DesktopUtilActivator.getKeybindingsService().getBindings(category);
+
+ if (bindings != null)
+ {
+ for (Map.Entry<KeyStroke, String> key2action
+ : bindings.getBindings().entrySet())
+ imap.put(key2action.getKey(), key2action.getValue());
+
+ bindings.addObserver(this);
+ }
+ }
+
+ /**
+ * Bindings the string representation for a keybinding to the action that
+ * will be executed.
+ *
+ * @param binding string representation of action used by input map
+ * @param action the action which will be executed when user presses the
+ * given key combination
+ */
+ protected void addKeybindingAction(String binding, Action action)
+ {
+ amap.put(binding, action);
+ }
+
+ private static class FrameWindowAdapter
+ extends WindowAdapter
+ {
+ @Override
+ public void windowClosing(WindowEvent e)
+ {
+ ((SIPCommFrame) e.getWindow()).windowClosing(e);
+ }
+ }
+
+ /**
+ * Invoked when this window is in the process of being closed. The close
+ * operation can be overridden at this point.
+ * @param e the <tt>WindowEvent</tt> that notified us
+ */
+ protected void windowClosing(WindowEvent e)
+ {
+ /*
+ * Before closing the application window save the current size and
+ * position through the ConfigurationService.
+ */
+ if(isSaveSizeAndLocation)
+ saveSizeAndLocation();
+
+ close(false);
+ }
+
+ /**
+ * Invokes the {@link Window#dispose()} implementation of this instance
+ * thus skipping any overriding that may be in effect for the method in
+ * question by extenders.
+ */
+ protected void windowDispose()
+ {
+ super.dispose();
+ }
+
+ /**
+ * Saves the size and the location of this frame through the
+ * <tt>ConfigurationService</tt>.
+ */
+ private void saveSizeAndLocation()
+ {
+ try
+ {
+ saveSizeAndLocation(this);
+ }
+ catch (ConfigPropertyVetoException e)
+ {
+ logger
+ .error(
+ "Saving the size and the location properties failed",
+ e);
+ }
+ }
+
+ /**
+ * Saves the size and the location of a specific <tt>Component</tt> through
+ * the <tt>ConfigurationService</tt>.
+ *
+ * @param component the <tt>Component</tt> which is to have its size and
+ * location saved through the <tt>ConfigurationService</tt>
+ * @throws ConfigPropertyVetoException if the <tt>ConfigurationService</tt>
+ * does not accept the saving because of objections from its
+ * <tt>PropertyVetoListener</tt>s.
+ */
+ static void saveSizeAndLocation(Component component)
+ throws ConfigPropertyVetoException
+ {
+ Map<String, Object> props = new HashMap<String, Object>();
+ String className
+ = component.getClass().getName().replaceAll("\\$", "_");
+
+ props.put(className + ".width", component.getWidth());
+ props.put(className + ".height", component.getHeight());
+ props.put(className + ".x", component.getX());
+ props.put(className + ".y", component.getY());
+ DesktopUtilActivator.getConfigurationService().setProperties(props);
+ }
+
+ /**
+ * Sets window size and position.
+ */
+ public void setSizeAndLocation()
+ {
+ ConfigurationService configService =
+ DesktopUtilActivator.getConfigurationService();
+ String className = this.getClass().getName();
+ String widthString = configService.getString(className + ".width");
+ String heightString = configService.getString(className + ".height");
+ String xString = configService.getString(className + ".x");
+ String yString = configService.getString(className + ".y");
+
+ int width = 0;
+ int height = 0;
+
+ if (widthString != null && heightString != null)
+ {
+ width = Integer.parseInt(widthString);
+ height = Integer.parseInt(heightString);
+
+ if (width > 0 && height > 0)
+ {
+ Dimension screenSize =
+ Toolkit.getDefaultToolkit().getScreenSize();
+ if (width <= screenSize.width && height <= screenSize.height)
+ this.setSize(width, height);
+ }
+ }
+
+ int x = 0;
+ int y = 0;
+
+ if (xString != null && yString != null)
+ {
+ x = Integer.parseInt(xString);
+ y = Integer.parseInt(yString);
+
+ if(ScreenInformation.
+ isTitleOnScreen(new Rectangle(x, y, width, height))
+ || configService.getBoolean(
+ SIPCommFrame.PNAME_CALCULATED_POSITIONING, true))
+ {
+ this.setLocation(x, y);
+ }
+ }
+ else
+ {
+ this.setCenterLocation();
+ }
+ }
+
+ /**
+ * Positions this window in the center of the screen.
+ */
+ private void setCenterLocation()
+ {
+ setLocationRelativeTo(null);
+ }
+
+ /**
+ * Checks whether the current component will exceeds the screen size and if
+ * it do will set a default size
+ */
+ private void ensureOnScreenLocationAndSize()
+ {
+ ConfigurationService config = DesktopUtilActivator.getConfigurationService();
+ if(!config.getBoolean(SIPCommFrame.PNAME_CALCULATED_POSITIONING, true))
+ return;
+
+ int x = this.getX();
+ int y = this.getY();
+
+ int width = this.getWidth();
+ int height = this.getHeight();
+
+ Rectangle virtualBounds = ScreenInformation.getScreenBounds();
+
+ // the default distance to the screen border
+ final int borderDistance = 10;
+
+ // in case any of the sizes exceeds the screen size
+ // we set default one
+ // get the left upper point of the window
+ if (!(virtualBounds.contains(x, y)))
+ {
+ // top left exceeds screen bounds
+ if (x < virtualBounds.x)
+ {
+ // window is too far to the left
+ // move it to the right
+ x = virtualBounds.x + borderDistance;
+ }
+ else if (x > virtualBounds.x)
+ {
+ // window is too far to the right
+ // can only occour, when screen resolution is
+ // changed or displayed are disconnected
+
+ // move the window in the bounds to the very right
+ x =
+ virtualBounds.x + virtualBounds.width - width
+ - borderDistance;
+ if (x < virtualBounds.x + borderDistance)
+ {
+ x = virtualBounds.x + borderDistance;
+ }
+ }
+
+ // top left exceeds screen bounds
+ if (y < virtualBounds.y)
+ {
+ // window is too far to the top
+ // move it to the bottom
+ y = virtualBounds.y + borderDistance;
+ }
+ else if (y > virtualBounds.y)
+ {
+ // window is too far to the bottom
+ // can only occour, when screen resolution is
+ // changed or displayed are disconnected
+
+ // move the window in the bounds to the very bottom
+ y =
+ virtualBounds.y + virtualBounds.height - height
+ - borderDistance;
+ if (y < virtualBounds.y + borderDistance)
+ {
+ y = virtualBounds.y + borderDistance;
+ }
+ }
+ this.setLocation(x, y);
+ }
+
+ // check the lower right corder
+ if (!(virtualBounds.contains(x + width, y + height)))
+ {
+
+ if (x + width > virtualBounds.x + virtualBounds.width)
+ {
+ // location of window is too far to the right, its right
+ // border is out of bounds
+
+ // calculate a new horizontal position
+ // move the whole window to the left
+ x =
+ virtualBounds.x + virtualBounds.width - width
+ - borderDistance;
+ if (x < virtualBounds.x + borderDistance)
+ {
+ // window is already on left side, it is too wide.
+ x = virtualBounds.x + borderDistance;
+ // reduce the width, so it surely fits
+ width = virtualBounds.width - 2 * borderDistance;
+ }
+ }
+ if (y + height > virtualBounds.y + virtualBounds.height)
+ {
+ // location of window is too far to the bottom, its bottom
+ // border is out of bounds
+
+ // calculate a new vertical position
+ // move the whole window to the top
+ y =
+ virtualBounds.y + virtualBounds.height - height
+ - borderDistance;
+ if (y < virtualBounds.y + borderDistance)
+ {
+ // window is already on top, it is too high.
+ y = virtualBounds.y + borderDistance;
+ // reduce the width, so it surely fits
+ height = virtualBounds.height - 2 * borderDistance;
+ }
+ }
+ this.setPreferredSize(new Dimension(width, height));
+ this.setSize(width, height);
+ this.setLocation(x, y);
+ }
+ }
+
+ /**
+ * Overwrites the setVisible method in order to set the size and the
+ * position of this window before showing it.
+ * @param isVisible indicates if this frame should be visible
+ */
+ @Override
+ public void setVisible(boolean isVisible)
+ {
+ if (isVisible)
+ {
+ this.setSizeAndLocation();
+
+ this.ensureOnScreenLocationAndSize();
+ }
+
+ super.setVisible(isVisible);
+ }
+
+ /**
+ * Overwrites the setVisible method in order to set the size and the
+ * position of this window before showing it.
+ * @param isVisible indicates if this window will be made visible or will
+ * be hidden
+ * @param isPackEnabled indicates if the pack() method should be invoked
+ * before showing this window
+ */
+ public void setVisible(boolean isVisible, boolean isPackEnabled)
+ {
+ if (isVisible)
+ {
+ /*
+ * Since setSizeAndLocation() will use the width and the height,
+ * pack() should be called prior to it. Otherwise, the width and the
+ * height may be zero or may just change after setSizeAndLocation()
+ * during pack().
+ */
+ this.pack();
+ this.setSizeAndLocation();
+ this.ensureOnScreenLocationAndSize();
+ }
+
+ super.setVisible(isVisible);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overwrites the super's <tt>dispose</tt> method in order to save the size
+ * and the position of this <tt>Window</tt> before closing it.
+ */
+ @Override
+ public void dispose()
+ {
+ if (isSaveSizeAndLocation)
+ saveSizeAndLocation();
+
+ /*
+ * The KeybindingsService will outlive us so don't let us retain our
+ * memory.
+ */
+ if (bindings != null)
+ bindings.deleteObserver(this);
+
+ super.dispose();
+ }
+
+ private void resetInputMap()
+ {
+ imap.clear();
+ imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
+ }
+
+ /**
+ * Listens for changes in binding sets so they can be reflected in the input
+ * map.
+ * @param obs the <tt>KeybindingSet</tt> from which to update
+ */
+ public void update(Observable obs, Object arg)
+ {
+ if (obs instanceof KeybindingSet)
+ {
+ KeybindingSet changedBindings = (KeybindingSet) obs;
+
+ resetInputMap();
+ for (Map.Entry<KeyStroke, String> key2action : changedBindings
+ .getBindings().entrySet())
+ {
+ imap.put(key2action.getKey(), key2action.getValue());
+ }
+ }
+ }
+
+ /**
+ * The main content pane.
+ */
+ public static class MainContentPane
+ extends JPanel
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private boolean isColorBgEnabled;
+
+ private boolean isImageBgEnabled;
+
+ private Color bgStartColor;
+
+ private Color bgEndColor;
+
+ private BufferedImage bgImage = null;
+
+ private TexturePaint texture = null;
+
+ /**
+ * Creates an instance of <tt>MainContentPane</tt>.
+ */
+ public MainContentPane()
+ {
+ super(new BorderLayout());
+
+ initColors();
+ initStyles();
+ }
+
+ /**
+ * Validates this container and all of its subcomponents.
+ * <p>
+ * The <code>validate</code> method is used to cause a container
+ * to lay out its subcomponents again. It should be invoked when
+ * this container's subcomponents are modified (added to or
+ * removed from the container, or layout-related information
+ * changed) after the container has been displayed.
+ *
+ * <p>If this {@code Container} is not valid, this method invokes
+ * the {@code validateTree} method and marks this {@code Container}
+ * as valid. Otherwise, no action is performed.
+ *
+ * @see #add(java.awt.Component)
+ * @see Component#invalidate
+ * @see javax.swing.JComponent#revalidate()
+ * @see #validateTree
+ */
+ @Override
+ public void validate()
+ {
+ initStyles();
+ super.validate();
+ }
+
+ /**
+ * Repaints this component.
+ */
+ @Override
+ public void repaint()
+ {
+ initColors();
+ super.repaint();
+ }
+
+ /**
+ * Initialize color values.
+ */
+ private void initColors()
+ {
+ ResourceManagementService resources =
+ DesktopUtilActivator.getResources();
+
+ isColorBgEnabled =
+ new Boolean(resources.getSettingsString(
+ "impl.gui.IS_WINDOW_COLOR_BACKGROUND_ENABLED"))
+ .booleanValue();
+
+ if (isColorBgEnabled)
+ {
+ bgStartColor =
+ new Color(resources.getColor("service.gui.MAIN_BACKGROUND"));
+ bgEndColor =
+ new Color(resources
+ .getColor("service.gui.MAIN_BACKGROUND_GRADIENT"));
+ }
+ else
+ {
+ bgStartColor = null;
+ bgEndColor = null;
+ }
+
+ isImageBgEnabled =
+ new Boolean(resources.getSettingsString(
+ "impl.gui.IS_WINDOW_IMAGE_BACKGROUND_ENABLED"))
+ .booleanValue();
+
+ if (isImageBgEnabled)
+ {
+ final URL bgImagePath
+ = resources.getImageURL("service.gui.WINDOW_TITLE_BAR_BG");
+
+ bgImage = ImageUtils.getBufferedImage(bgImagePath);
+
+ final Rectangle rect =
+ new Rectangle(0, 0, bgImage.getWidth(),
+ bgImage.getHeight());
+
+ texture = new TexturePaint(bgImage, rect);
+ }
+ }
+
+ /**
+ * Initialize style values.
+ */
+ private void initStyles()
+ {
+ ResourceManagementService resources =
+ DesktopUtilActivator.getResources();
+
+ int borderSize =
+ resources
+ .getSettingsInt("impl.gui.MAIN_WINDOW_BORDER_SIZE");
+ this.setBorder(BorderFactory.createEmptyBorder(borderSize,
+ borderSize, borderSize, borderSize));
+ }
+
+ /**
+ * Paints this content pane.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ // If the custom color or image window background is not enabled we
+ // have nothing to do here.
+ if (isColorBgEnabled || isImageBgEnabled)
+ {
+ g = g.create();
+ try
+ {
+ internalPaintComponent(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+ }
+
+ /**
+ * Provides a custom paint if the color or image background properties
+ * are enabled.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ private void internalPaintComponent(Graphics g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ Graphics2D g2 = (Graphics2D) g;
+ int width = getWidth();
+ int height = getHeight();
+
+ if (isColorBgEnabled)
+ {
+ GradientPaint bgGradientColor =
+ new GradientPaint(width / 2, 0, bgStartColor, width / 2, 80,
+ bgEndColor);
+
+ g2.setPaint(bgGradientColor);
+ g2.fillRect(0, 0, width, 80);
+
+ g2.setColor(bgEndColor);
+ g2.fillRect(0, 78, width, height);
+ }
+
+ if (isImageBgEnabled)
+ {
+ if (bgImage != null && texture != null)
+ {
+ g2.setPaint(texture);
+
+ g2.fillRect(0, 0, this.getWidth(), bgImage.getHeight());
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies this instance that it has been requested to close. The default
+ * <tt>SIPCommFrame</tt> implementation does nothing.
+ *
+ * @param escape <tt>true</tt> if the request to close this instance is in
+ * response of a press on the Escape key; otherwise, <tt>false</tt>
+ */
+ protected void close(boolean escape)
+ {
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommHTMLEditorKit.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommHTMLEditorKit.java
new file mode 100644
index 0000000..7a9914f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommHTMLEditorKit.java
@@ -0,0 +1,214 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.text.html.*;
+import javax.swing.text.html.ParagraphView;
+
+/**
+ * The <tt>SIPCommHTMLEditorKit</tt> is an <tt>HTMLEditorKit</tt> which uses
+ * an extended <tt>ParagraphView</tt>.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommHTMLEditorKit extends HTMLEditorKit
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+
+ private final JComponent container;
+
+ /**
+ * Creates an instance of <tt>SIPCommHTMLEditorKit</tt> by specifying the
+ * container, where the editor kit would be used.
+ *
+ * @param container
+ */
+ public SIPCommHTMLEditorKit(JComponent container)
+ {
+ this.container = container;
+ }
+
+ /**
+ * Returns the extended <tt>HTMLFactory</tt> defined here.
+ *
+ * @return the extended view factory
+ */
+ public ViewFactory getViewFactory()
+ {
+ return new HTMLFactoryX();
+ }
+
+ /**
+ * An extended <tt>HTMLFactory</tt> that uses the <tt>SIPCommImageView</tt>
+ * to represent images and the <tt>ParagraphViewX</tt> to represent
+ * paragraphs.
+ */
+ private class HTMLFactoryX extends HTMLFactory
+ implements ViewFactory
+ {
+ public View create(Element elem)
+ {
+ View view = super.create(elem);
+
+ if (view instanceof ParagraphView)
+ {
+ return new ParagraphViewX(elem);
+ }
+ else if (view instanceof ComponentView)
+ {
+ return new MyComponentView(elem);
+ }
+
+ return view;
+ }
+ }
+
+ /**
+ * An extended component view, which provides horizontal and vertical
+ * filling.
+ */
+ private class MyComponentView extends ComponentView
+ {
+ /**
+ * Creates a new ComponentView object.
+ *
+ * @param elem the element to decorate
+ */
+ public MyComponentView(Element elem)
+ {
+ super(elem);
+ }
+
+ /**
+ * Determines the preferred span for this view along an
+ * axis. This is implemented to return the value
+ * returned by Component.getPreferredSize along the
+ * axis of interest.
+ *
+ * @param axis may be either View.X_AXIS or View.Y_AXIS
+ * @return the span the view would like to be rendered into >= 0.
+ * Typically the view is told to render into the span
+ * that is returned, although there is no guarantee.
+ * The parent may choose to resize or break the view.
+ * @exception IllegalArgumentException for an invalid axis
+ */
+ public float getPreferredSpan(int axis)
+ {
+ if ((axis != X_AXIS) && (axis != Y_AXIS))
+ {
+ throw new IllegalArgumentException("Invalid axis: " + axis);
+ }
+ if (getComponent() != null)
+ {
+ Dimension size = getComponent().getPreferredSize();
+ if (axis == View.X_AXIS)
+ {
+ return container.getWidth();
+ }
+ else
+ {
+ return size.height;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Determines the maximum span for this view along an
+ * axis. This is implemented to return the value
+ * returned by Component.getMaximumSize along the
+ * axis of interest.
+ *
+ * @param axis may be either View.X_AXIS or View.Y_AXIS
+ * @return the span the view would like to be rendered into >= 0.
+ * Typically the view is told to render into the span
+ * that is returned, although there is no guarantee.
+ * The parent may choose to resize or break the view.
+ * @exception IllegalArgumentException for an invalid axis
+ */
+ public float getMaximumSpan(int axis)
+ {
+ if ((axis != X_AXIS) && (axis != Y_AXIS))
+ {
+ throw new IllegalArgumentException("Invalid axis: " + axis);
+ }
+ if (getComponent() != null)
+ {
+ Dimension size = getComponent().getMaximumSize();
+ if (axis == View.X_AXIS)
+ {
+ return container.getWidth();
+ }
+ else
+ {
+ return size.height;
+ }
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * The <tt>ParagraphViewX</tt> is created in order to solve the following
+ * problem (Bug ID: 4855207):
+ * <p>
+ * When a paragraph in a JTextPane has a large amount of text the
+ * processing needed to layout the entire paragraph increases as the
+ * paragraph grows.
+ */
+ static class ParagraphViewX extends ParagraphView
+ {
+ /**
+ * Creates an instance of <tt>ParagraphViewX</tt>.
+ *
+ * @param elem the element that this view is responsible for
+ */
+ public ParagraphViewX(Element elem)
+ {
+ super(elem);
+ }
+
+ /**
+ * Calculate requirements along the minor axis. This
+ * is implemented to forward the request to the logical
+ * view by calling getMinimumSpan, getPreferredSpan, and
+ * getMaximumSpan on it.
+ *
+ * @param axis the axis, for which we calculate size requirements
+ * @param sizeRequirements the initial size requirements
+ * @return the recalculated size requirements for the given axis
+ */
+ protected SizeRequirements calculateMinorAxisRequirements (
+ int axis, SizeRequirements sizeRequirements)
+ {
+ if (sizeRequirements == null)
+ {
+ sizeRequirements = new SizeRequirements();
+ }
+
+ float pref = layoutPool.getPreferredSpan(axis);
+ float min = layoutPool.getMinimumSpan(axis);
+
+ // Don't include insets, Box.getXXXSpan will include them.
+ sizeRequirements.minimum = (int)min;
+ sizeRequirements.preferred
+ = Math.max(sizeRequirements.minimum, (int) pref);
+ sizeRequirements.maximum = Short.MAX_VALUE;
+ sizeRequirements.alignment = 0.5f;
+ return sizeRequirements;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommLinkButton.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommLinkButton.java
new file mode 100644
index 0000000..7708e80
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommLinkButton.java
@@ -0,0 +1,279 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.net.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.plugin.desktoputil.plaf.*;
+
+/**
+ * A button which text is a link. The button looks like a link.
+ */
+public class SIPCommLinkButton
+ extends JButton
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Class id key used in UIDefaults.
+ */
+ private static final String UIClassID = "LinkButtonUI";
+
+ /**
+ * Adds the ui class to UIDefaults.
+ */
+ static
+ {
+ UIManager.getDefaults().put(UIClassID,
+ SIPCommLinkButtonUI.class.getName());
+ }
+
+ public static final int ALWAYS_UNDERLINE = 0;
+
+ public static final int HOVER_UNDERLINE = 1;
+
+ public static final int NEVER_UNDERLINE = 2;
+
+ private int linkBehavior;
+
+ private Color linkColor;
+
+ private Color colorPressed;
+
+ private Color visitedLinkColor;
+
+ private Color disabledLinkColor;
+
+ private URL buttonURL;
+
+ private boolean isLinkVisited;
+
+ /**
+ * Created Link Button.
+ */
+ public SIPCommLinkButton()
+ {
+ this(null, null);
+ }
+
+ /**
+ * Created Link Button with text.
+ * @param text
+ */
+ public SIPCommLinkButton(String text)
+ {
+ this(text, null);
+ }
+
+ /**
+ * Created Link Button with url.
+ * @param url
+ */
+ public SIPCommLinkButton(URL url)
+ {
+ this(null, url);
+ }
+
+ /**
+ * Created Link Button with text and url.
+ * @param text
+ * @param url
+ */
+ public SIPCommLinkButton(String text, URL url)
+ {
+ super(text);
+
+ linkBehavior = SIPCommLinkButton.HOVER_UNDERLINE;
+
+ linkColor = Color.blue;
+ colorPressed = Color.red;
+ visitedLinkColor = new Color(128, 0, 128);
+
+ if (text == null && url != null)
+ this.setText(url.toExternalForm());
+ setLinkURL(url);
+
+ this.setBorderPainted(false);
+ this.setContentAreaFilled(false);
+ this.setRolloverEnabled(true);
+ this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ }
+
+ public String getUIClassID()
+ {
+ return SIPCommLinkButton.UIClassID;
+ }
+
+ /**
+ * Setup the tooltip.
+ */
+ protected void setupToolTipText()
+ {
+ String tip = null;
+ if (buttonURL != null)
+ tip = buttonURL.toExternalForm();
+ setToolTipText(tip);
+ }
+
+ /**
+ * Changes link behaviour.
+ * @param bnew the new behaviour. One of ALWAYS_UNDERLINE, HOVER_UNDERLINE
+ * and NEVER_UNDERLINE.
+ */
+ public void setLinkBehavior(int bnew)
+ {
+ if (bnew != ALWAYS_UNDERLINE && bnew != HOVER_UNDERLINE
+ && bnew != NEVER_UNDERLINE)
+ throw new IllegalArgumentException("Not a legal LinkBehavior");
+
+ int old = linkBehavior;
+ linkBehavior = bnew;
+ firePropertyChange("linkBehavior", old, bnew);
+ repaint();
+ }
+
+ /**
+ * Returns the link behaviour.
+ * @return the link behaviour.
+ */
+ public int getLinkBehavior()
+ {
+ return linkBehavior;
+ }
+
+ /**
+ * Sets the link color.
+ * @param color the new color.
+ */
+ public void setLinkColor(Color color)
+ {
+ Color colorOld = linkColor;
+ linkColor = color;
+ firePropertyChange("linkColor", colorOld, color);
+ repaint();
+ }
+
+ /**
+ * Return the link color.
+ * @return link color.
+ */
+ public Color getLinkColor()
+ {
+ return linkColor;
+ }
+
+ /**
+ * Sets the active link color.
+ * @param colorNew the new color.
+ */
+ public void setActiveLinkColor(Color colorNew)
+ {
+ Color colorOld = colorPressed;
+ colorPressed = colorNew;
+ firePropertyChange("activeLinkColor", colorOld, colorNew);
+ repaint();
+ }
+
+ /**
+ * Returns the active link color.
+ * @return the active link color.
+ */
+ public Color getActiveLinkColor()
+ {
+ return colorPressed;
+ }
+
+ /**
+ * Sets disabled link color.
+ * @param color the new color.
+ */
+ public void setDisabledLinkColor(Color color)
+ {
+ Color colorOld = disabledLinkColor;
+ disabledLinkColor = color;
+ firePropertyChange("disabledLinkColor", colorOld, color);
+ if (!isEnabled())
+ repaint();
+ }
+
+ /**
+ * Returns the disabled link color.
+ * @return the disabled link color.
+ */
+ public Color getDisabledLinkColor()
+ {
+ return disabledLinkColor;
+ }
+
+ /**
+ * Set visited link color.
+ * @param colorNew the new visited link color.
+ */
+ public void setVisitedLinkColor(Color colorNew)
+ {
+ Color colorOld = visitedLinkColor;
+ visitedLinkColor = colorNew;
+ firePropertyChange("visitedLinkColor", colorOld, colorNew);
+ repaint();
+ }
+
+ /**
+ * Returns visited link color.
+ * @return visited link color.
+ */
+ public Color getVisitedLinkColor()
+ {
+ return visitedLinkColor;
+ }
+
+ /**
+ * Set a link.
+ * @param url the url.
+ */
+ public void setLinkURL(URL url)
+ {
+ URL urlOld = buttonURL;
+ buttonURL = url;
+ setupToolTipText();
+ firePropertyChange("linkURL", urlOld, url);
+ revalidate();
+ repaint();
+ }
+
+ /**
+ * Returns the url.
+ * @return the link url.
+ */
+ public URL getLinkURL()
+ {
+ return buttonURL;
+ }
+
+ /**
+ * Set a link visited.
+ * @param flagNew is link visited.
+ */
+ public void setLinkVisited(boolean flagNew)
+ {
+ boolean flagOld = isLinkVisited;
+ isLinkVisited = flagNew;
+ firePropertyChange("linkVisited", flagOld, flagNew);
+ repaint();
+ }
+
+ /**
+ * Returns is link visited.
+ * @return is link visited.
+ */
+ public boolean isLinkVisited()
+ {
+ return isLinkVisited;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenu.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenu.java
new file mode 100644
index 0000000..220f87e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenu.java
@@ -0,0 +1,308 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * The <tt>SIPCommMenu</tt> is very similar to a JComboBox. The main
+ * component here is a JLabel only with an icon. When user clicks on the icon a
+ * popup menu is opened, containing a list of icon-text pairs from which the
+ * user could choose one item. When user selects the desired item, the icon of
+ * the selected item is set to the main component label.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommMenu
+ extends JMenu
+{
+ private static final long serialVersionUID = 1L;
+ private Object selectedObject;
+
+ /**
+ * Creates an instance of <tt>SIPCommMenu</tt>.
+ */
+ public SIPCommMenu()
+ {
+ super();
+
+ init();
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommMenu</tt> by specifying
+ * the text and the icon.
+ * @param text the text of the menu
+ * @param defaultIcon the menu icon
+ */
+ public SIPCommMenu(String text, Icon defaultIcon)
+ {
+ super(text);
+
+ this.setIcon(defaultIcon);
+ init();
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommMenu</tt> by specifying the
+ * initialy selected item.
+ *
+ * @param text The item that is initialy selected.
+ */
+ public SIPCommMenu(String text)
+ {
+ super(text);
+ init();
+ }
+
+ private void init()
+ {
+ MouseRolloverHandler mouseHandler = new MouseRolloverHandler();
+
+ this.addMouseListener(mouseHandler);
+ this.addMouseMotionListener(mouseHandler);
+
+ // Hides the popup menu when the parent window loses focus.
+ getPopupMenu().addComponentListener(new ComponentAdapter()
+ {
+ public void componentResized(ComponentEvent evt)
+ {
+ Window parentWindow;
+
+ Component parent = SIPCommMenu.this.getParent();
+
+ // If this is a submenu get the invoker first.
+ if (parent instanceof JPopupMenu)
+ parentWindow = SwingUtilities.getWindowAncestor(
+ ((JPopupMenu) parent).getInvoker());
+ else
+ parentWindow
+ = SwingUtilities.getWindowAncestor(SIPCommMenu.this);
+
+ if (!parentWindow.isActive())
+ {
+ getPopupMenu().setVisible(false);
+ }
+
+ parentWindow.addWindowListener(new WindowAdapter()
+ {
+ public void windowDeactivated(WindowEvent e)
+ {
+ JPopupMenu popupMenu = getPopupMenu();
+
+ if (popupMenu != null && popupMenu.isVisible())
+ popupMenu.setVisible(false);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Adds an item to the "choice list" of this selector box.
+ *
+ * @param text The text of the item.
+ * @param icon The icon of the item.
+ * @param actionListener The <tt>ActionListener</tt>, which handles the
+ * case, when the item is selected.
+ */
+ public void addItem(String text, Icon icon, ActionListener actionListener)
+ {
+ JMenuItem item = new JMenuItem(text, icon);
+
+ item.addActionListener(actionListener);
+
+ this.add(item);
+ }
+
+ /**
+ * Selects the given item.
+ *
+ * @param selectedObject The object to select.
+ */
+ public void setSelected(SelectedObject selectedObject)
+ {
+ if (selectedObject.getIcon() != null)
+ this.setIcon(selectedObject.getIcon());
+
+ if (selectedObject.getText() != null)
+ this.setText(selectedObject.getText());
+
+ if (selectedObject.getObject() != null)
+ this.setSelectedObject(selectedObject.getObject());
+ }
+
+ /**
+ * Selects the given object.
+ *
+ * @param o The <tt>Object</tt> to select.
+ */
+ public void setSelectedObject(Object o)
+ {
+ this.selectedObject = o;
+ }
+
+ /**
+ * Returns the selected object.
+ *
+ * @return the selected object.
+ */
+ public Object getSelectedObject()
+ {
+ return this.selectedObject;
+ }
+
+ /**
+ * Sets the isMouseOver property value and repaints this component.
+ *
+ * @param isMouseOver <code>true</code> to indicate that the mouse is over
+ * this component, <code>false</code> - otherwise.
+ */
+ public void setMouseOver(boolean isMouseOver)
+ {
+ this.repaint();
+ }
+
+ /**
+ * Paints this component.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ public void paintComponent(Graphics g)
+ {
+ Graphics g2 = g.create();
+ try
+ {
+ internalPaintComponent(g2);
+ }
+ finally
+ {
+ g2.dispose();
+ }
+ super.paintComponent(g);
+ }
+
+ /**
+ * Paints a rollover effect when the mouse is over this menu.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ private void internalPaintComponent(Graphics g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ // Paint a roll over fade out.
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = getModel().isRollover() ? 1.0f : 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ }
+
+ visibility /= 2;
+
+ g.setColor(new Color(1.0f, 1.0f, 1.0f, visibility));
+
+ g.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 20, 20);
+
+ g.setColor(UIManager.getColor("Menu.foreground"));
+ }
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class ButtonRepaintCallback implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ SIPCommMenu.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ /**
+ * Perform a fade animation on mouse over.
+ */
+ private class MouseRolloverHandler
+ implements MouseListener,
+ MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(false);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeOut(FadeKind.ROLLOVER,
+ SIPCommMenu.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(true);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ SIPCommMenu.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenuBar.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenuBar.java
new file mode 100644
index 0000000..c08e5a7
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommMenuBar.java
@@ -0,0 +1,71 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.plugin.desktoputil.plaf.*;
+import net.java.sip.communicator.util.skin.*;
+/**
+ * The SIPCommMenuBar is a <tt>JMenuBar</tt> without border decoration that can
+ * be used as a container for other components, like selector boxes that won't
+ * need a menu decoration.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommMenuBar
+ extends JMenuBar
+ implements Skinnable
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Class id key used in UIDefaults.
+ */
+ private static final String UIClassID = "SIPCommMenuBarUI";
+
+ /**
+ * Adds the ui class to UIDefaults.
+ */
+ static
+ {
+ UIManager.getDefaults().put(UIClassID,
+ SIPCommMenuBarUI.class.getName());
+ }
+
+ /**
+ * Creates an instance of <tt>SIPCommMenuBar</tt>.
+ */
+ public SIPCommMenuBar()
+ {
+ loadSkin();
+ }
+
+ /**
+ * Reload UI defs.
+ */
+ public void loadSkin()
+ {
+ this.setBorder(BorderFactory.createEmptyBorder());
+ }
+
+ /**
+ * Returns the name of the L&F class that renders this component.
+ *
+ * @return the string "TreeUI"
+ * @see JComponent#getUIClassID
+ * @see UIDefaults#getUI
+ */
+ public String getUIClassID()
+ {
+ return UIClassID;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommPopupMenu.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommPopupMenu.java
new file mode 100644
index 0000000..0ecba98
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommPopupMenu.java
@@ -0,0 +1,67 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+/**
+ * A custom popup menu that detects parent focus lost.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommPopupMenu
+ extends JPopupMenu
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Constructor.
+ */
+ public SIPCommPopupMenu()
+ {
+ // Hides the popup menu when the parent window loses focus.
+ addComponentListener(new ComponentAdapter()
+ {
+ public void componentResized(ComponentEvent evt)
+ {
+ final Window parentWindow;
+
+ Component parent = getParent();
+
+ // If this is a submenu get the invoker first.
+ if (parent instanceof JPopupMenu)
+ parentWindow = SwingUtilities.getWindowAncestor(
+ ((JPopupMenu) parent).getInvoker());
+ else
+ parentWindow
+ = SwingUtilities.getWindowAncestor(getInvoker());
+
+ if (parentWindow != null)
+ {
+ if (!parentWindow.isActive())
+ setVisible(false);
+
+ parentWindow.addWindowListener(new WindowAdapter()
+ {
+ public void windowDeactivated(WindowEvent e)
+ {
+ if (SIPCommPopupMenu.this != null
+ && SIPCommPopupMenu.this.isVisible())
+ SIPCommPopupMenu.this.setVisible(false);
+ }
+ });
+ }
+ }
+ });
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommRadioButton.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommRadioButton.java
new file mode 100644
index 0000000..ca71cb7
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommRadioButton.java
@@ -0,0 +1,48 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+import org.jitsi.util.*;
+
+/**
+ * @author Ingo Bauersachs
+ */
+public class SIPCommRadioButton
+ extends JRadioButton
+{
+ private static final long serialVersionUID = 0L;
+
+ private static final boolean setContentAreaFilled = (OSUtils.IS_WINDOWS
+ || OSUtils.IS_LINUX);
+
+ public SIPCommRadioButton()
+ {
+ init();
+ }
+
+ public SIPCommRadioButton(String text)
+ {
+ super(text);
+
+ init();
+ }
+
+ public SIPCommRadioButton(String text, boolean selected)
+ {
+ super(text, selected);
+
+ init();
+ }
+
+ private void init()
+ {
+ if (setContentAreaFilled)
+ setContentAreaFilled(false);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommScrollPane.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommScrollPane.java
new file mode 100644
index 0000000..2eb3b1b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommScrollPane.java
@@ -0,0 +1,236 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.beans.*;
+import java.lang.reflect.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+import org.jitsi.util.*;
+
+/**
+ * The SCScrollPane is a JScrollPane with a custom viewport that allows to
+ * set an image as a background. Depending on the
+ * "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED" property we'll be setting a
+ * single image or a texture of images.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommScrollPane
+ extends JScrollPane
+ implements Skinnable
+{
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates an <tt>SCSCrollPane</tt>.
+ */
+ public SIPCommScrollPane()
+ {
+ this.setBorder(BorderFactory.createMatteBorder(
+ 1, 0, 1, 0, Color.GRAY));
+
+ this.setViewport(new SCViewport());
+
+ this.getVerticalScrollBar().setUnitIncrement(100);
+ }
+
+ /**
+ * Sets the view of this JViewport.
+ *
+ * @param view the view to set.
+ */
+ @Override
+ public void setViewportView(Component view)
+ {
+ if (view instanceof JComponent)
+ {
+ JComponent viewAsJComponent = (JComponent) view;
+
+ viewAsJComponent.setBorder(
+ BorderFactory.createEmptyBorder(3, 3, 3, 3));
+ viewAsJComponent.setOpaque(false);
+ }
+
+ super.setViewportView(view);
+ }
+
+ /**
+ * Reloads skin information in viewport.
+ */
+ public void loadSkin()
+ {
+ ((SCViewport) getViewport()).loadSkin();
+ }
+
+ /**
+ * The <tt>SCViewport</tt> used as viewport in this scrollpane.
+ */
+ private static class SCViewport
+ extends JViewport
+ implements Skinnable
+ {
+ private static final long serialVersionUID = 1L;
+
+ private BufferedImage bgImage;
+
+ private Color color;
+
+ private TexturePaint texture;
+
+ /**
+ * Creates the <tt>SCViewport</tt>.
+ */
+ public SCViewport()
+ {
+ this.setBackground(Color.WHITE);
+
+ loadSkin();
+ }
+
+ /**
+ * Returns the boolean value of the property given by <tt>key</tt>.
+ * @param key the key of the property we look for
+ * @return the boolean value of the searched property
+ */
+ private boolean getSettingsBoolean(String key)
+ {
+ return
+ Boolean.parseBoolean(
+ DesktopUtilActivator.getResources().getSettingsString(key));
+ }
+
+ /**
+ * Paints this viewport.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ g = g.create();
+ try
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ Graphics2D g2 = (Graphics2D) g;
+ int width = getWidth();
+ int height = getHeight();
+
+ // paint the image
+ if (bgImage != null)
+ {
+ if (texture != null)
+ {
+ g2.setPaint(texture);
+
+ g2.fillRect(0, 0, width, height);
+ }
+ else
+ {
+ g.setColor(color);
+
+ // paint the background with the chosen color
+ g.fillRect(0, 0, width, height);
+
+ g2.drawImage(bgImage, width - bgImage.getWidth(),
+ height - bgImage.getHeight(), this);
+ }
+ }
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ /**
+ * Reloads background.
+ */
+ public void loadSkin()
+ {
+ if(getSettingsBoolean("impl.gui.IS_CONTACT_LIST_IMG_BG_ENABLED"))
+ {
+ bgImage =
+ DesktopUtilActivator.getImage("service.gui.MAIN_WINDOW_BACKGROUND");
+
+ if (getSettingsBoolean(
+ "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED")
+ && (bgImage != null))
+ {
+ texture =
+ new TexturePaint(bgImage, new Rectangle(0, 0, bgImage
+ .getWidth(null), bgImage.getHeight(null)));
+
+ color = null;
+ }
+ else
+ {
+ texture = null;
+ color =
+ new Color(DesktopUtilActivator.getResources().getColor(
+ "service.gui.CONTACT_LIST_BACKGROUND"));
+ }
+ }
+ else
+ {
+ bgImage = null;
+ texture = null;
+ color = null;
+ }
+ }
+ }
+
+ /**
+ * Releases the resources allocated by this instance throughout its lifetime
+ * and prepares it for garbage collection.
+ */
+ public void dispose()
+ {
+ if(OSUtils.IS_MAC)
+ {
+ // Apple introduced a memory leak in JViewport class -
+ // they add a PropertyChangeListeners to the CToolkit
+ try
+ {
+ Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
+ PropertyChangeListener[] pcl
+ = defaultToolkit.getPropertyChangeListeners(
+ "apple.awt.contentScaleFactor");
+
+ for(PropertyChangeListener pc : pcl)
+ {
+ // find the reference to the object created the listener
+ Field f = pc.getClass().getDeclaredField("this$0");
+
+ f.setAccessible(true);
+ // If we are the parent, clean up.
+ if(f.get(pc).equals(this.getViewport()))
+ {
+ defaultToolkit.removePropertyChangeListener(
+ "apple.awt.contentScaleFactor",
+ pc);
+ break;
+ }
+ }
+ }
+ catch(Throwable t)
+ {
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTabbedPane.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTabbedPane.java
new file mode 100644
index 0000000..b41ee9f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTabbedPane.java
@@ -0,0 +1,512 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+/*
+ * The following code borrowed from David Bismut, davidou@mageos.com Intern,
+ * SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004 Ecole des Mines de
+ * Nantes, France
+ */
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.plugin.desktoputil.event.*;
+import net.java.sip.communicator.plugin.desktoputil.plaf.*;
+import net.java.sip.communicator.util.skin.*;
+
+/**
+ * A JTabbedPane with some added UI functionalities. A close and max/detach
+ * icons are added to every tab, typically to let the user close or detach the
+ * tab by clicking on these icons.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommTabbedPane
+ extends JTabbedPane
+ implements ChangeListener,
+ Skinnable
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private int overTabIndex = -1;
+
+ private int lastSelectedIndex;
+
+ public SIPCommTabbedPane()
+ {
+ this(false, false);
+ }
+
+ /**
+ * Creates the <code>CloseAndMaxTabbedPane</code> with an enhanced UI if
+ * <code>enhancedUI</code> parameter is set to <code>true</code>.
+ *
+ * @param closingTabs support for closable tabs
+ * @param maximizingTabs support for maximisable tabs
+ */
+ public SIPCommTabbedPane(boolean closingTabs, boolean maximizingTabs)
+ {
+ super.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
+
+ UIManager.getDefaults()
+ .put("TabbedPane.tabAreaInsets", new Insets(0, 5, 0, 0));
+
+ UIManager.getDefaults()
+ .put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
+
+ this.setForeground(
+ new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE")));
+
+ this.setUI(new SIPCommTabbedPaneEnhancedUI());
+
+ if(closingTabs)
+ this.setCloseIcon(true);
+
+ if(maximizingTabs)
+ this.setMaxIcon(true);
+
+ this.addChangeListener(this);
+ }
+
+ /**
+ * Returns the index of the last tab on which the mouse did an action.
+ *
+ * @return
+ */
+ public int getOverTabIndex()
+ {
+ return overTabIndex;
+ }
+
+ /**
+ * Returns <code>true</code> if the close icon is enabled.
+ *
+ * @return
+ */
+ public boolean isCloseEnabled()
+ {
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
+ return ui.isCloseEnabled();
+ }
+
+ /**
+ * Returns <code>true</code> if the max/detach icon is enabled.
+ *
+ * @return
+ */
+ public boolean isMaxEnabled()
+ {
+ return ((SIPCommTabbedPaneUI) getUI()).isMaxEnabled();
+ }
+
+ /**
+ * Override JTabbedPane method. Does nothing.
+ * @param tabLayoutPolicy The tab layout policy.
+ */
+ @Override
+ public void setTabLayoutPolicy(int tabLayoutPolicy)
+ {
+ }
+
+ /**
+ * Override JTabbedPane method. Does nothing.
+ * @param tabPlacement The tab placement.
+ */
+ @Override
+ public void setTabPlacement(int tabPlacement)
+ {
+ }
+
+ /**
+ * Sets whether the tabbedPane should have a close icon or not.
+ *
+ * @param b whether the tabbedPane should have a close icon or not
+ */
+ public void setCloseIcon(boolean b)
+ {
+ ((SIPCommTabbedPaneUI) getUI()).setCloseIcon(b);
+ }
+
+ /**
+ * Sets whether the tabbedPane should have a max/detach icon or not.
+ *
+ * @param b whether the tabbedPane should have a max/detach icon or not
+ */
+ public void setMaxIcon(boolean b)
+ {
+ ((SIPCommTabbedPaneUI) getUI()).setMaxIcon(b);
+ }
+
+ /**
+ * Detaches the <code>index</code> tab in a separate frame. When the frame
+ * is closed, the tab is automatically reinserted into the tabbedPane.
+ *
+ * @param index index of the tabbedPane to be detached
+ */
+ public void detachTab(int index)
+ {
+ if (index < 0 || index >= getTabCount())
+ return;
+
+ final int tabIndex = index;
+ final JComponent c = (JComponent) getComponentAt(tabIndex);
+
+ final Icon icon = getIconAt(tabIndex);
+ final String title = getTitleAt(tabIndex);
+ final String toolTip = getToolTipTextAt(tabIndex);
+ final Border border = c.getBorder();
+
+ final JFrame frame = new SIPCommFrame()
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ protected void close(boolean isEscaped)
+ {
+ if (isEscaped)
+ return;
+
+ dispose();
+
+ insertTab(title, icon, c, toolTip, Math.min(tabIndex,
+ getTabCount()));
+
+ c.setBorder(border);
+ setSelectedComponent(c);
+ }
+ };
+
+ Window parentWindow = SwingUtilities.windowForComponent(this);
+
+ removeTabAt(index);
+
+ c.setPreferredSize(c.getSize());
+
+ frame.setTitle(title);
+ frame.getContentPane().add(c);
+ frame.setLocation(parentWindow.getLocation());
+ frame.pack();
+
+ WindowFocusListener windowFocusListener = new WindowFocusListener() {
+ long start;
+
+ long end;
+
+ public void windowGainedFocus(WindowEvent e) {
+ start = System.currentTimeMillis();
+ }
+
+ public void windowLostFocus(WindowEvent e) {
+ end = System.currentTimeMillis();
+ long elapsed = end - start;
+
+ if (elapsed < 100)
+ frame.toFront();
+
+ frame.removeWindowFocusListener(this);
+ }
+ };
+
+ /*
+ * This is a small hack to avoid Windows GUI bug, that prevent a new
+ * window from stealing focus (without this windowFocusListener, most of
+ * the time the new frame would just blink from foreground to
+ * background). A windowFocusListener is added to the frame, and if the
+ * time between the frame beeing in foreground and the frame beeing in
+ * background is less that 100ms, it just brings the windows to the
+ * front once again. Then it removes the windowFocusListener. Note that
+ * this hack would not be required on Linux or UNIX based systems.
+ */
+
+ frame.addWindowFocusListener(windowFocusListener);
+
+ // frame.show();
+ frame.setVisible(true);
+ frame.toFront();
+
+ }
+
+ /**
+ * Adds a <code>CloseListener</code> to the tabbedPane.
+ *
+ * @param l the <code>CloseListener</code> to add
+ * @see #fireCloseTabEvent
+ * @see #removeCloseListener
+ */
+ public synchronized void addCloseListener(CloseListener l)
+ {
+ listenerList.add(CloseListener.class, l);
+ }
+
+ /**
+ * Adds a <code>MaxListener</code> to the tabbedPane.
+ *
+ * @param l the <code>MaxListener</code> to add
+ * @see #fireMaxTabEvent
+ * @see #removeMaxListener
+ */
+ public synchronized void addMaxListener(MaxListener l)
+ {
+ listenerList.add(MaxListener.class, l);
+ }
+
+ /**
+ * Adds a <code>DoubleClickListener</code> to the tabbedPane.
+ *
+ * @param l the <code>DoubleClickListener</code> to add
+ * @see #fireDoubleClickTabEvent
+ * @see #removeDoubleClickListener
+ */
+ public synchronized void addDoubleClickListener(DoubleClickListener l)
+ {
+ listenerList.add(DoubleClickListener.class, l);
+ }
+
+ /**
+ * Adds a <code>PopupOutsideListener</code> to the tabbedPane.
+ *
+ * @param l the <code>PopupOutsideListener</code> to add
+ * @see #firePopupOutsideTabEvent
+ * @see #removePopupOutsideListener
+ */
+ public synchronized void addPopupOutsideListener(PopupOutsideListener l)
+ {
+ listenerList.add(PopupOutsideListener.class, l);
+ }
+
+ /**
+ * Removes a <code>CloseListener</code> from this tabbedPane.
+ *
+ * @param l the <code>CloseListener</code> to remove
+ * @see #fireCloseTabEvent
+ * @see #addCloseListener
+ */
+ public synchronized void removeCloseListener(CloseListener l)
+ {
+ listenerList.remove(CloseListener.class, l);
+ }
+
+ /**
+ * Removes a <code>MaxListener</code> from this tabbedPane.
+ *
+ * @param l the <code>MaxListener</code> to remove
+ * @see #fireMaxTabEvent
+ * @see #addMaxListener
+ */
+ public synchronized void removeMaxListener(MaxListener l)
+ {
+ listenerList.remove(MaxListener.class, l);
+ }
+
+ /**
+ * Removes a <code>DoubleClickListener</code> from this tabbedPane.
+ *
+ * @param l
+ * the <code>DoubleClickListener</code> to remove
+ * @see #fireDoubleClickTabEvent
+ * @see #addDoubleClickListener
+ */
+ public synchronized void removeDoubleClickListener(DoubleClickListener l)
+ {
+ listenerList.remove(DoubleClickListener.class, l);
+ }
+
+ /**
+ * Removes a <code>PopupOutsideListener</code> from this tabbedPane.
+ *
+ * @param l
+ * the <code>PopupOutsideListener</code> to remove
+ * @see #firePopupOutsideTabEvent
+ * @see #addPopupOutsideListener
+ */
+ public synchronized void removePopupOutsideListener(
+ PopupOutsideListener l)
+ {
+ listenerList.remove(PopupOutsideListener.class, l);
+ }
+
+ /**
+ * Sends a <code>MouseEvent</code>, whose source is this tabbedpane, to
+ * every <code>CloseListener</code>. The method also updates the
+ * <code>overTabIndex</code> of the tabbedPane with a value coming from
+ * the UI. This method method is called each time a <code>MouseEvent</code>
+ * is received from the UI when the user clicks on the close icon of the tab
+ * which index is <code>overTabIndex</code>.
+ *
+ * @param e
+ * the <code>MouseEvent</code> to be sent
+ * @param overTabIndex
+ * the index of a tab, usually the tab over which the mouse is
+ *
+ * @see #addCloseListener
+ */
+ public void fireCloseTabEvent(MouseEvent e, int overTabIndex)
+ {
+ this.overTabIndex = overTabIndex;
+
+ EventListener[] closeListeners = getListeners(CloseListener.class);
+ for (int i = 0; i < closeListeners.length; i++)
+ {
+ ((CloseListener) closeListeners[i]).closeOperation(e);
+ }
+ }
+
+ /**
+ * Sends a <code>MouseEvent</code>, whose source is this tabbedpane, to
+ * every <code>MaxListener</code>. The method also updates the
+ * <code>overTabIndex</code> of the tabbedPane with a value coming from
+ * the UI. This method method is called each time a <code>MouseEvent</code>
+ * is received from the UI when the user clicks on the max icon of the tab
+ * which index is <code>overTabIndex</code>.
+ *
+ * @param e
+ * the <code>MouseEvent</code> to be sent
+ * @param overTabIndex
+ * the index of a tab, usually the tab over which the mouse is
+ *
+ * @see #addMaxListener
+ */
+ public void fireMaxTabEvent(MouseEvent e, int overTabIndex)
+ {
+ this.overTabIndex = overTabIndex;
+
+ EventListener[] maxListeners = getListeners(MaxListener.class);
+ for (int i = 0; i < maxListeners.length; i++)
+ {
+ ((MaxListener) maxListeners[i]).maxOperation(e);
+ }
+ }
+
+ /**
+ * Sends a <code>MouseEvent</code>, whose source is this tabbedpane, to
+ * every <code>DoubleClickListener</code>. The method also updates the
+ * <code>overTabIndex</code> of the tabbedPane with a value coming from
+ * the UI. This method method is called each time a <code>MouseEvent</code>
+ * is received from the UI when the user double-clicks on the tab which
+ * index is <code>overTabIndex</code>.
+ *
+ * @param e
+ * the <code>MouseEvent</code> to be sent
+ * @param overTabIndex
+ * the index of a tab, usually the tab over which the mouse is
+ *
+ * @see #addDoubleClickListener
+ */
+ public void fireDoubleClickTabEvent(MouseEvent e, int overTabIndex)
+ {
+ this.overTabIndex = overTabIndex;
+
+ EventListener[] dClickListeners
+ = getListeners(DoubleClickListener.class);
+ for (int i = 0; i < dClickListeners.length; i++)
+ {
+ ((DoubleClickListener) dClickListeners[i]).doubleClickOperation(e);
+ }
+ }
+
+ /**
+ * Sends a <code>MouseEvent</code>, whose source is this tabbedpane, to
+ * every <code>PopupOutsideListener</code>. The method also sets the
+ * <code>overTabIndex</code> to -1. This method method is called each time
+ * a <code>MouseEvent</code> is received from the UI when the user
+ * right-clicks on the inactive part of a tabbedPane.
+ *
+ * @param e
+ * the <code>MouseEvent</code> to be sent
+ *
+ * @see #addPopupOutsideListener
+ */
+ public void firePopupOutsideTabEvent(MouseEvent e)
+ {
+ this.overTabIndex = -1;
+
+ EventListener[] popupListeners
+ = getListeners(PopupOutsideListener.class);
+ for (int i = 0; i < popupListeners.length; i++)
+ {
+ ((PopupOutsideListener) popupListeners[i]).popupOutsideOperation(e);
+ }
+ }
+
+ /**
+ * Overrides setSelectedIndex in JTabbedPane in order to remove the
+ * highlight if the tab which is selected.
+ * @param tabIndex The index of the tab to be selected.
+ */
+ @Override
+ public void setSelectedIndex(int tabIndex)
+ {
+ SIPCommTabbedPaneEnhancedUI ui
+ = (SIPCommTabbedPaneEnhancedUI) this.getUI();
+ if (ui.isTabHighlighted(tabIndex))
+ {
+ ui.tabRemoveHighlight(tabIndex);
+ }
+ super.setSelectedIndex(tabIndex);
+ }
+
+ /**
+ * Highlights the tab with the given index.
+ *
+ * @param tabIndex The tab index.
+ */
+ public void highlightTab(int tabIndex)
+ {
+ SIPCommTabbedPaneEnhancedUI ui
+ = (SIPCommTabbedPaneEnhancedUI) this.getUI();
+
+ if (!ui.isTabHighlighted(tabIndex)
+ && this.getSelectedIndex() != tabIndex)
+ ui.tabAddHightlight(tabIndex);
+
+ this.repaint();
+ }
+
+ @Override
+ public void removeTabAt(int index)
+ {
+ if (index < lastSelectedIndex)
+ {
+ this.setSelectedIndex(lastSelectedIndex - 1);
+ }
+ else if (index > lastSelectedIndex)
+ {
+ this.setSelectedIndex(lastSelectedIndex);
+ }
+
+ super.removeTabAt(index);
+ }
+
+ public void stateChanged(ChangeEvent e)
+ {
+ lastSelectedIndex = this.getSelectedIndex();
+ }
+
+ /**
+ * Reloads skin information.
+ */
+ public void loadSkin()
+ {
+ this.setForeground(
+ new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE")));
+
+ ((SIPCommTabbedPaneEnhancedUI)this.getUI()).loadSkin();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextButton.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextButton.java
new file mode 100644
index 0000000..a348c5d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextButton.java
@@ -0,0 +1,279 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.plaf.basic.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * A custom JButton that contains only text. A custom background could be set,
+ * which will result in a round cornered background behind the text. Note that
+ * you can also set a semi-transparent background. The button also supports a
+ * rollover effect.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommTextButton extends JButton
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Class id key used in UIDefaults.
+ */
+ private static final String UIClassID = "BasicButtonUI";
+
+ /**
+ * Adds the ui class to UIDefaults.
+ */
+ static
+ {
+ UIManager.getDefaults().put(UIClassID,
+ BasicButtonUI.class.getName());
+ }
+
+ private final float[] borderColor
+ = Color.DARK_GRAY.getRGBComponents(null);
+
+ private Image bgImage;
+
+ /**
+ * Creates a <tt>SIPCommTextButton</tt>.
+ */
+ public SIPCommTextButton()
+ {
+ this("", null);
+ }
+
+ /**
+ * Creates a <tt>SIPCommTextButton</tt>
+ * @param text the text of the button
+ */
+ public SIPCommTextButton(String text)
+ {
+ this(text, null);
+ }
+
+ public SIPCommTextButton(String text, Image bgImage)
+ {
+ super(text);
+
+ this.bgImage = bgImage;
+
+ MouseRolloverHandler mouseHandler = new MouseRolloverHandler();
+
+ this.addMouseListener(mouseHandler);
+ this.addMouseMotionListener(mouseHandler);
+
+ this.setIcon(null);
+ this.setIconTextGap(0);
+
+ /*
+ * Explicitly remove all borders that may be set from the current look
+ * and feel.
+ */
+ this.setContentAreaFilled(false);
+ }
+
+ public void setBgImage(Image image)
+ {
+ this.bgImage = image;
+ }
+
+ /**
+ * Return the background image.
+ *
+ * @return the background image of this button
+ */
+ public Image getBgImage()
+ {
+ return bgImage;
+ }
+
+ /**
+ * Overrides the <code>paintComponent</code> method of <tt>JButton</tt> to
+ * paint the button background and icon, and all additional effects of this
+ * configurable button.
+ *
+ * @param g The Graphics object.
+ */
+ protected void paintComponent(Graphics g)
+ {
+ Graphics2D g1 = (Graphics2D) g.create();
+ try
+ {
+ internalPaintComponent(g1);
+ }
+ finally
+ {
+ g1.dispose();
+ }
+
+ super.paintComponent(g);
+ }
+
+ /**
+ * Paints this button.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ private void internalPaintComponent(Graphics2D g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ // Paint a roll over fade out.
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = this.getModel().isRollover() ? 1.0f : 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ }
+
+ visibility /= 2;
+
+ if (visibility != 0.0f)
+ {
+ g.setColor(new Color(borderColor[0], borderColor[1],
+ borderColor[2], visibility));
+
+ if (bgImage != null)
+ g.fillRoundRect((this.getWidth() - bgImage.getWidth(null))/2,
+ (this.getHeight() - bgImage.getHeight(null))/2,
+ bgImage.getWidth(null) - 1,
+ bgImage.getHeight(null) - 1,
+ 20, 20);
+ else
+ g.fillRoundRect(0, 0,
+ this.getWidth() - 1, this.getHeight() - 1,
+ 20, 20);
+ }
+
+ if (bgImage != null)
+ {
+ g.drawImage(bgImage,
+ (this.getWidth() - bgImage.getWidth(null))/2,
+ (this.getHeight() - bgImage.getHeight(null))/2, null);
+ }
+ else
+ {
+ g.setColor(getBackground());
+ g.fillRoundRect(1, 1,
+ this.getWidth() - 2, this.getHeight() - 2,
+ 20, 20);
+ }
+
+ }
+
+ /**
+ * Returns the name of the L&F class that renders this component.
+ *
+ * @return the string "TreeUI"
+ * @see JComponent#getUIClassID
+ * @see UIDefaults#getUI
+ */
+ public String getUIClassID()
+ {
+ return UIClassID;
+ }
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class ButtonRepaintCallback implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ SIPCommTextButton.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ /**
+ * Perform a fade animation on mouse over.
+ */
+ private class MouseRolloverHandler
+ implements MouseListener,
+ MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(false);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeOut(FadeKind.ROLLOVER,
+ SIPCommTextButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(true);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ SIPCommTextButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextField.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextField.java
new file mode 100644
index 0000000..80b39dc
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommTextField.java
@@ -0,0 +1,287 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.plugin.desktoputil.event.*;
+
+/**
+ * The <tt>SIPCommTextField</tt> is a <tt>JTextField</tt> that offers the
+ * possibility to specify a default (tip) text that explains what is the
+ * required data.
+ * @author Yana Stamcheva
+ */
+public class SIPCommTextField
+ extends JTextField
+ implements MouseListener,
+ FocusListener,
+ KeyListener,
+ DocumentListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The default text.
+ */
+ private String defaultText;
+
+ /**
+ * A list of all listeners registered for text field change events.
+ */
+ private Collection<TextFieldChangeListener> changeListeners
+ = new LinkedList<TextFieldChangeListener>();
+
+ /**
+ * Indicates if the default text is currently visible.
+ */
+ private boolean isDefaultTextVisible;
+
+ /**
+ * The color of the foreground.
+ */
+ private Color foregroundColor = Color.BLACK;
+
+ /**
+ * The foreground color of the default text.
+ */
+ private Color defaultTextColor = Color.GRAY;
+
+ /**
+ * Creates an instance of <tt>SIPCommTextField</tt> by specifying the text
+ * we would like to show by default in it.
+ * @param text the text we would like to enter by default
+ */
+ public SIPCommTextField(String text)
+ {
+ super(text);
+
+ if (text != null && text.length() > 0)
+ {
+ this.defaultText = text;
+ isDefaultTextVisible = true;
+ }
+
+ this.setFont(getFont().deriveFont(10f));
+ this.setForeground(defaultTextColor);
+
+ this.addMouseListener(this);
+ this.addFocusListener(this);
+
+ this.addKeyListener(this);
+ this.getDocument().addDocumentListener(this);
+ }
+
+ /**
+ * Indicates that the mouse button was pressed on this component. Hides
+ * the default text when user clicks on the text field.
+ * @param e the <tt>MouseEvent</tt> that notified us
+ */
+ public void mousePressed(MouseEvent e)
+ {
+ if (getText() == null)
+ {
+ clearDefaultText();
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {}
+
+ public void mouseEntered(MouseEvent e) {}
+
+ public void mouseExited(MouseEvent e) {}
+
+ public void mouseReleased(MouseEvent e) {}
+
+ /**
+ * Selects the user text when this text field gains the focus.
+ * @param e the <tt>FocusEvent</tt> that notified us
+ */
+ public void focusGained(FocusEvent e)
+ {
+ clearDefaultText();
+ }
+
+ /**
+ * Sets the default text when the field looses focus.
+ * @param e the <tt>FocusEvent</tt> that notified us
+ */
+ public void focusLost(FocusEvent e)
+ {
+ if (getText() == null || getText().length() == 0)
+ {
+ setDefaultText();
+ }
+ }
+
+ /**
+ * Returns the text contained in this field.
+ * @return the text contained in this field
+ */
+ public String getText()
+ {
+ if (!super.getText().equals(defaultText))
+ return super.getText();
+
+ return null;
+ }
+
+ /**
+ * Sets the text of this text field.
+ * @param text the text to show in this text field
+ */
+ public void setText(String text)
+ {
+ if ((text == null || text.length() == 0) && !isFocusOwner())
+ setDefaultText();
+ else
+ {
+ this.setForeground(foregroundColor);
+ super.setText(text);
+ }
+ }
+
+ /**
+ * Sets the default text.
+ */
+ private void setDefaultText()
+ {
+ super.setText(defaultText);
+ this.setForeground(defaultTextColor);
+ this.setCaretPosition(0);
+ }
+
+ /**
+ * Clears the default text.
+ */
+ private void clearDefaultText()
+ {
+ if (super.getText().equals(defaultText))
+ {
+ super.setText("");
+ this.setForeground(foregroundColor);
+ }
+ }
+
+ /**
+ * Clears the default text when a key pressed event is received.
+ * @param e the <tt>KeyEvent</tt> that notified us
+ */
+ public void keyPressed(KeyEvent e)
+ {
+ clearDefaultText();
+ }
+
+ /**
+ * Clears the default text when a key typed event is received.
+ * @param e the <tt>KeyEvent</tt> that notified us
+ */
+ public void keyTyped(KeyEvent e)
+ {
+ clearDefaultText();
+ }
+
+ public void keyReleased(KeyEvent e){}
+
+ /**
+ * Adds the given <tt>TextFieldChangeListener</tt> to the list of listeners
+ * notified on changes of the text contained in this field.
+ * @param l the <tt>TextFieldChangeListener</tt> to add
+ */
+ public void addTextChangeListener(TextFieldChangeListener l)
+ {
+ synchronized (changeListeners)
+ {
+ changeListeners.add(l);
+ }
+ }
+
+ /**
+ * Removes the given <tt>TextFieldChangeListener</tt> from the list of
+ * listeners notified on changes of the text contained in this field.
+ * @param l the <tt>TextFieldChangeListener</tt> to add
+ */
+ public void removeTextChangeListener(TextFieldChangeListener l)
+ {
+ synchronized (changeListeners)
+ {
+ changeListeners.remove(l);
+ }
+ }
+
+ public void changedUpdate(DocumentEvent e) {}
+
+ /**
+ * Handles the change when a char has been inserted in the field.
+ * @param e the <tt>DocumentEvent</tt> that notified us
+ */
+ public void insertUpdate(DocumentEvent e)
+ {
+ if(!super.getText().equals(defaultText))
+ fireTextFieldChangeListener(0);
+ else
+ isDefaultTextVisible = true;
+ }
+
+ /**
+ * Handles the change when a char has been removed from the field.
+ * @param e the <tt>DocumentEvent</tt> that notified us
+ */
+ public void removeUpdate(DocumentEvent e)
+ {
+ if (!isDefaultTextVisible)
+ fireTextFieldChangeListener(1);
+ else
+ isDefaultTextVisible = false;
+ }
+
+ /**
+ * Sets the foreground color.
+ *
+ * @param c the color to set for the text field foreground
+ */
+ public void setForegroundColor(Color c)
+ {
+ foregroundColor = c;
+ }
+
+ /**
+ * Sets the foreground color of the default text shown in this text field.
+ *
+ * @param c the color to set
+ */
+ public void setDefaultTextColor(Color c)
+ {
+ defaultTextColor = c;
+
+ if (isDefaultTextVisible)
+ setForeground(defaultTextColor);
+ }
+
+ /**
+ * Notifies all registered <tt>TextFieldChangeListener</tt>s that a change
+ * has occurred in the text contained in this field.
+ * @param eventType the type of the event to transfer
+ */
+ private void fireTextFieldChangeListener(int eventType)
+ {
+ for (TextFieldChangeListener l : changeListeners)
+ switch (eventType)
+ {
+ case 0: l.textInserted(); break;
+ case 1: l.textRemoved(); break;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SIPCommToggleButton.java b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommToggleButton.java
new file mode 100644
index 0000000..e730341
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SIPCommToggleButton.java
@@ -0,0 +1,444 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import org.jvnet.lafwidget.animation.*;
+
+/**
+ * The <tt>SIPCommToggleButton</tt> is a flexible <tt>JToggleButton</tt> that
+ * allows to configure its background, its icon, the look when a mouse is over
+ * it, etc.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommToggleButton
+ extends JToggleButton
+ implements OrderedComponent
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The background image shown in normal button state.
+ */
+ private Image bgImage;
+
+ /**
+ * The background image shown in rollover button state.
+ */
+ private Image bgRolloverImage;
+
+ /**
+ * The icon image shown in normal (non-pressed) button state.
+ */
+ private Image iconImage;
+
+ /**
+ * The background image shown in pressed button state.
+ */
+ private Image pressedImage;
+
+ /**
+ * The icon image shown in pressed button state.
+ */
+ private Image pressedIconImage;
+
+ /**
+ * The index of the button, used when we want to order our buttons.
+ */
+ private int index = -1;
+
+ /**
+ * Creates an instance of <tt>SIPCommToggleButton</tt>.
+ */
+ public SIPCommToggleButton()
+ {
+ // Explicitly remove all borders that may be set from the current
+ // look and feel.
+ this.setBorder(null);
+
+ MouseRolloverHandler mouseHandler = new MouseRolloverHandler();
+
+ this.addMouseListener(mouseHandler);
+ this.addMouseMotionListener(mouseHandler);
+ }
+
+ /**
+ * Creates a button with custom background image and rollover image.
+ *
+ * @param bgImage the background button image
+ * @param rolloverImage the rollover button image
+ */
+ public SIPCommToggleButton(Image bgImage, Image rolloverImage)
+ {
+ this(bgImage, rolloverImage, null, null);
+ }
+
+ /**
+ * Creates a button with custom background image, rollover image and
+ * icon image.
+ *
+ * @param bgImage The background image.
+ * @param rolloverImage The roll over image.
+ * @param iconImage The icon.
+ * @param pressedImage The image used to paint the pressed state.
+ */
+ public SIPCommToggleButton( Image bgImage,
+ Image rolloverImage,
+ Image iconImage,
+ Image pressedImage)
+ {
+ this(bgImage, rolloverImage, iconImage, pressedImage, null);
+ }
+
+ /**
+ * Creates a button with custom background image, rollover image and
+ * icon image.
+ *
+ * @param bgImage the background image
+ * @param rolloverImage the roll over image
+ * @param iconImage the icon
+ * @param pressedImage the image used to paint the pressed state
+ * @param pressedIconImage the icon image in a pressed state
+ */
+ public SIPCommToggleButton( Image bgImage,
+ Image rolloverImage,
+ Image iconImage,
+ Image pressedImage,
+ Image pressedIconImage)
+ {
+ this();
+
+ this.bgImage = bgImage;
+ this.bgRolloverImage = rolloverImage;
+ this.iconImage = iconImage;
+ this.pressedImage = pressedImage;
+ this.pressedIconImage = pressedIconImage;
+
+ this.setPreferredSize(
+ new Dimension( this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+
+ if (iconImage != null)
+ this.setIcon(new ImageIcon(this.iconImage));
+ }
+
+ /**
+ * Overrides the <code>paintComponent</code> method of <tt>JButton</tt>
+ * to paint the button background and icon, and all additional effects
+ * of this configurable button.
+ *
+ * @param g the Graphics object
+ */
+
+ public void paintComponent(Graphics g)
+ {
+ g = g.create();
+ try
+ {
+ internalPaintComponent(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ /**
+ * Paints this button.
+ *
+ * @param g the Graphics object
+ */
+ private void internalPaintComponent(Graphics g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ if (this.bgImage != null)
+ {
+ // If there's no icon, we make grey the backgroundImage
+ // when disabled.
+ if (!isEnabled())
+ {
+ Image disabledImage = new ImageIcon(LightGrayFilter
+ .createDisabledImage(bgImage)).getImage();
+
+ g.drawImage(disabledImage, 0, 0, this);
+ }
+ else {
+ g.drawImage(this.bgImage, 0, 0, this);
+ }
+ }
+
+ // Paint the roll over image.
+ if (getModel().isRollover() && bgRolloverImage != null)
+ {
+ g.drawImage(bgRolloverImage, 0, 0, this);
+ }
+
+ // Paint the pressed image.
+ if (getModel().isSelected() && pressedImage != null)
+ {
+ g.drawImage(pressedImage, 0, 0, this);
+ }
+
+ // Paint a roll over fade out.
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ float visibility = getModel().isRollover() ? 1.0f : 0.0f;
+ if (fadeTracker.isTracked(this, FadeKind.ROLLOVER))
+ {
+ visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER);
+ }
+ visibility /= 2;
+
+ g.setColor(new Color(1.0f, 1.0f, 1.0f, visibility));
+
+ if (bgImage != null)
+ {
+ g.fillRoundRect(this.getWidth() / 2 - this.bgImage.getWidth(null)
+ / 2, this.getHeight() / 2 - this.bgImage.getHeight(null) / 2,
+ bgImage.getWidth(null), bgImage.getHeight(null), 10, 10);
+ }
+ else if (isContentAreaFilled() || (visibility != 0.0f))
+ {
+ g.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 10, 10);
+ }
+
+ // Paint the icon image.
+ Image iconImageFinal = null;
+ if (getModel().isSelected() && pressedIconImage != null)
+ {
+ iconImageFinal = pressedIconImage;
+ }
+ else if (iconImage != null)
+ {
+ if (!isEnabled())
+ {
+ iconImageFinal = new ImageIcon(LightGrayFilter
+ .createDisabledImage(iconImage)).getImage();
+ }
+ else
+ {
+ iconImageFinal = iconImage;
+ }
+ }
+
+ int bgWidth = (bgImage != null)
+ ? bgImage.getWidth(null)
+ : getWidth();
+ int bgHeight = (bgImage != null)
+ ? bgImage.getHeight(null)
+ : getHeight();
+
+ if (iconImageFinal != null)
+ g.drawImage(iconImageFinal,
+ (bgWidth - iconImageFinal.getWidth(null)) / 2,
+ (bgHeight - iconImageFinal.getHeight(null)) / 2, this);
+ }
+
+ /**
+ * Returns the background image of this button.
+ *
+ * @return the background image of this button
+ */
+ public Image getBgImage()
+ {
+ return bgImage;
+ }
+
+ /**
+ * Sets the background image to this button.
+ *
+ * @param bgImage the background image to set
+ */
+ public void setBgImage(Image bgImage)
+ {
+ this.bgImage = bgImage;
+
+ this.setPreferredSize(new Dimension(this.bgImage.getWidth(null),
+ this.bgImage.getHeight(null)));
+ }
+
+ /**
+ * Returns the background rollover image of this button.
+ *
+ * @return the background rollover image of this button
+ */
+ public Image getBgRolloverImage()
+ {
+ return bgRolloverImage;
+ }
+
+ /**
+ * Sets the background rollover image to this button.
+ *
+ * @param bgRolloverImage the background rollover image to set
+ */
+ public void setBgRolloverImage(Image bgRolloverImage)
+ {
+ this.bgRolloverImage = bgRolloverImage;
+ }
+
+ /**
+ * Returns the icon image of this button.
+ *
+ * @return the icon image of this button
+ */
+ public Image getIconImage()
+ {
+ return iconImage;
+ }
+
+ /**
+ * Sets the icon image to this button.
+ *
+ * @param iconImage the icon image to set
+ */
+ public void setIconImage(Image iconImage)
+ {
+ this.iconImage = iconImage;
+ this.repaint();
+ }
+
+ /**
+ * Sets the icon image for the pressed state of this button.
+ *
+ * @param iconImage the icon image to set
+ */
+ public void setPressedIconImage(Image iconImage)
+ {
+ this.pressedIconImage = iconImage;
+ this.repaint();
+ }
+
+ /**
+ * Sets the image representing the pressed state of this button.
+ *
+ * @param pressedImage the image representing the pressed state of this
+ * button
+ */
+ public void setPressedImage(Image pressedImage)
+ {
+ this.pressedImage = pressedImage;
+ this.repaint();
+ }
+
+ /**
+ * Change buttons index when we want to order it.
+ * @param index the button index.
+ */
+ public void setIndex(int index)
+ {
+ this.index = index;
+ }
+
+ /**
+ * Returns the current button index we have set, or -1 if none used.
+ * @return
+ */
+ public int getIndex()
+ {
+ return this.index;
+ }
+
+ /**
+ * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button
+ * when the fade animation is performed.
+ */
+ private class ButtonRepaintCallback implements FadeTrackerCallback
+ {
+ public void fadeEnded(FadeKind arg0)
+ {
+ repaintLater();
+ }
+
+ public void fadePerformed(FadeKind arg0, float arg1)
+ {
+ repaintLater();
+ }
+
+ private void repaintLater()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ SIPCommToggleButton.this.repaint();
+ }
+ });
+ }
+
+ public void fadeReversed(FadeKind arg0, boolean arg1, float arg2)
+ {
+ }
+ }
+
+ /**
+ * Perform a fade animation on mouse over.
+ */
+ private class MouseRolloverHandler
+ implements MouseListener,
+ MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(false);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeOut(FadeKind.ROLLOVER,
+ SIPCommToggleButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ }
+
+ public void mouseEntered(MouseEvent e)
+ {
+ if (isEnabled())
+ {
+ getModel().setRollover(true);
+
+ FadeTracker fadeTracker = FadeTracker.getInstance();
+
+ fadeTracker.trackFadeIn(FadeKind.ROLLOVER,
+ SIPCommToggleButton.this,
+ true,
+ new ButtonRepaintCallback());
+ }
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/ScreenInformation.java b/src/net/java/sip/communicator/plugin/desktoputil/ScreenInformation.java
new file mode 100644
index 0000000..192fc6b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/ScreenInformation.java
@@ -0,0 +1,68 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+/**
+ * A class which reads the screen bounds and provides this information.
+ *
+ * @author Ingo Bauersachs
+ */
+public class ScreenInformation
+{
+ /**
+ * Calculates the bounding box of all available screens. This method is
+ * highly inaccurate when screens of different sizes are used or not evenly
+ * aligned. A correct implementation should generate a polygon.
+ *
+ * @return A polygon of the usable screen area.
+ */
+ public static Rectangle getScreenBounds()
+ {
+ final GraphicsEnvironment ge = GraphicsEnvironment
+ .getLocalGraphicsEnvironment();
+
+ Rectangle bounds = new Rectangle();
+ for(GraphicsDevice gd : ge.getScreenDevices())
+ {
+ GraphicsConfiguration gc = gd.getDefaultConfiguration();
+ bounds = bounds.union(gc.getBounds());
+ }
+ return bounds;
+ }
+
+ /**
+ * Checks whether the top edge of the rectangle is contained in any of the
+ * available screens.
+ *
+ * @param window The bounding box of the window.
+ * @return True when the top edge is in a visible screen area; false
+ * otherwise
+ */
+ public static boolean isTitleOnScreen(Rectangle window)
+ {
+ final GraphicsEnvironment ge = GraphicsEnvironment
+ .getLocalGraphicsEnvironment();
+
+ boolean leftInside = false;
+ boolean rightInside = false;
+ Point left = new Point(window.x, window.y);
+ Point right = new Point(window.x, window.y + window.width);
+ for(GraphicsDevice gd : ge.getScreenDevices())
+ {
+ GraphicsConfiguration gc = gd.getDefaultConfiguration();
+ if(gc.getBounds().contains(left))
+ leftInside = true;
+ if(gc.getBounds().contains(right))
+ rightInside = true;
+ if(leftInside && rightInside)
+ return true;
+ }
+ return leftInside && rightInside;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SelectedObject.java b/src/net/java/sip/communicator/plugin/desktoputil/SelectedObject.java
new file mode 100644
index 0000000..aae3c0a
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SelectedObject.java
@@ -0,0 +1,80 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+/**
+ * A convenience class used to store combobox complex objects.
+ * The <tt>SelectedObject</tt> is used for all account and status combo boxes
+ * throughout this gui implementation.
+ *
+ * @author Yana Stamcheva
+ */
+public class SelectedObject
+{
+ private String text;
+
+ private Icon icon;
+
+ private Object object;
+
+ /**
+ * Creates an instance of <tt>SelectedObject</tt> by specifying the text,
+ * icon and object associated with it.
+ *
+ * @param text The text.
+ * @param icon The icon.
+ * @param object The object.
+ */
+ public SelectedObject(String text, Icon icon, Object object)
+ {
+ this.text = text;
+ this.icon = icon;
+ this.object = object;
+ }
+
+ /**
+ * Creates an instance of <tt>SelectedObject</tt> by specifying the
+ * icon and object associated with it.
+ *
+ * @param icon The icon.
+ * @param object The object.
+ */
+ public SelectedObject(Icon icon, Object object)
+ {
+ this.icon = icon;
+ this.object = object;
+ }
+
+ /**
+ * Returns the text of this <tt>SelectedObject</tt>.
+ * @return the text of this <tt>SelectedObject</tt>.
+ */
+ public String getText()
+ {
+ return text;
+ }
+
+ /**
+ * Returns the icon of this <tt>SelectedObject</tt>.
+ * @return the icon of this <tt>SelectedObject</tt>.
+ */
+ public Icon getIcon()
+ {
+ return icon;
+ }
+
+ /**
+ * Returns the real object behind this <tt>SelectedObject</tt>.
+ * @return the real object behind this <tt>SelectedObject</tt>.
+ */
+ public Object getObject()
+ {
+ return object;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooser.java b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooser.java
new file mode 100644
index 0000000..6948f1e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooser.java
@@ -0,0 +1,99 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.io.*;
+
+/**
+ * The purpose of this interface is to provide an unique way to access to the
+ * methods of JFileChooser (javax.swing) or FileDialog (java.awt).
+ *
+ * It's interesting to use FileDialog under Mac OS X because it uses the native
+ * user interface for file selection provided by Mac OS which is more practical
+ * than the user interface performed by a JFileChooser (on Mac).
+ *
+ * Therefore, under other platforms (Microsoft Windows, Linux), the use of
+ * JFileChooser instead of FileDialog performs a better user interface for
+ * browsing among a file hierarchy.
+ *
+ * @author Valentin Martinet
+ */
+public interface SipCommFileChooser
+{
+
+ /**
+ * Allows to request a 'load file' dialog (optional)
+ */
+ public static int LOAD_FILE_OPERATION = 0;
+
+ /**
+ * Allows to request a 'save file' dialog (optional)
+ */
+ public static int SAVE_FILE_OPERATION = 1;
+
+ /**
+ * Instruction to display only files.
+ */
+ public static final int FILES_ONLY = 0;
+
+ /**
+ * Instruction to display only directories in
+ * file chooser dialog.
+ */
+ public static final int DIRECTORIES_ONLY = 1;
+
+ /**
+ * Change the selection mode for the file choose.
+ * Possible values are DIRECTORIES_ONLY or FILES_ONLY, default is
+ * FILES_ONLY.
+ *
+ * @param mode the mode to use.
+ */
+ public void setSelectionMode(int mode);
+
+ /**
+ * Returns the selected file by the user from the dialog.
+ *
+ * @return File the selected file from the dialog
+ */
+ public File getApprovedFile();
+
+ /**
+ * Sets the default path to be considered for browsing among files.
+ *
+ * @param path the default start path for this dialog
+ */
+ public void setStartPath(String path);
+
+ /**
+ * Shows the dialog and returns the selected file.
+ *
+ * @return File the selected file in this dialog
+ */
+ public File getFileFromDialog();
+
+ /**
+ * Adds a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void addFilter(SipCommFileFilter filter);
+
+ /**
+ * Sets a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void setFileFilter(SipCommFileFilter filter);
+
+ /**
+ * Returns the filter the user has chosen for saving a file.
+ *
+ * @return SipCommFileFilter the used filter when saving a file
+ */
+ public SipCommFileFilter getUsedFilter();
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooserImpl.java b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooserImpl.java
new file mode 100644
index 0000000..60c09ac
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileChooserImpl.java
@@ -0,0 +1,163 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.io.*;
+
+import javax.swing.*;
+
+/**
+ * Implements <tt>SipCommFileChooser</tt> for Swing's <tt>JFileChooser</tt>.
+ *
+ * @author Valentin Martinet
+ */
+public class SipCommFileChooserImpl
+ extends JFileChooser
+ implements SipCommFileChooser
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Parent component of this dialog (JFrame, Frame, etc)
+ */
+ private Component parent;
+
+ /**
+ * Constructor
+ *
+ * @param title title for this dialog
+ * @param operation 'Save file' or 'Load file' operation
+ */
+ public SipCommFileChooserImpl(String title, int operation)
+ {
+ super();
+
+ this.setDialogTitle(title);
+ this.setDialogType(operation);
+ }
+
+ /**
+ * Initializes a new <tt>SipCommFileChooserImpl</tt> instance.
+ *
+ * @param parent
+ * @param path
+ * @param title
+ * @param operation
+ */
+ public SipCommFileChooserImpl(
+ Component parent, String path, String title, int operation)
+ {
+ this(title, operation);
+
+ this.parent = parent;
+ this.setStartPath(path);
+ }
+
+ /**
+ * Returns the selected file by the user from the dialog.
+ *
+ * @return File the selected file from the dialog
+ */
+ public File getApprovedFile()
+ {
+ return this.getSelectedFile();
+ }
+
+ /**
+ * Sets the default path to be considered for browsing among files.
+ *
+ * @param path the default start path for this dialog
+ */
+ public void setStartPath(String path)
+ {
+ // Passing null makes JFileChooser points to user's default dir.
+ File file = (path == null) ? null : new File(path);
+
+ setCurrentDirectory(file);
+
+ /*
+ * If the path doesn't exist, the intention of the caller may have been
+ * to also set a default file name.
+ */
+ if ((file != null) && !file.isDirectory())
+ setSelectedFile(file);
+ }
+
+ /**
+ * Shows the dialog and returns the selected file.
+ *
+ * @return File the selected file in this dialog
+ */
+ public File getFileFromDialog()
+ {
+ int choice = -1;
+
+ if(this.getDialogType() == JFileChooser.OPEN_DIALOG)
+ choice = this.showOpenDialog(this.getParentComponent());
+ else
+ choice = this.showSaveDialog(this.getParentComponent());
+
+ return
+ (choice == JFileChooser.APPROVE_OPTION) ? getSelectedFile() : null;
+ }
+
+ /**
+ * Returns the parent component of this dialog
+ *
+ * @return Component dialog's parent component
+ */
+ public Component getParentComponent()
+ {
+ return this.parent;
+ }
+
+ /**
+ * Adds a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void addFilter(SipCommFileFilter filter)
+ {
+ this.addChoosableFileFilter(filter);
+ }
+
+ /**
+ * Sets a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void setFileFilter(SipCommFileFilter filter)
+ {
+ super.setFileFilter(filter);
+ }
+
+ /**
+ * Returns the filter the user has chosen for saving a file.
+ *
+ * @return SipCommFileFilter the used filter when saving a file
+ */
+ public SipCommFileFilter getUsedFilter()
+ {
+ return (SipCommFileFilter)this.getFileFilter();
+ }
+
+ /**
+ * Change the selection mode for the file choose.
+ * Possible values are DIRECTORIES_ONLY or FILES_ONLY, default is
+ * FILES_ONLY.
+ *
+ * @param mode the mode to use.
+ */
+ public void setSelectionMode(int mode)
+ {
+ super.setFileSelectionMode(mode);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileDialogImpl.java b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileDialogImpl.java
new file mode 100644
index 0000000..cf963b0
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileDialogImpl.java
@@ -0,0 +1,162 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.io.*;
+
+import org.jitsi.util.*;
+
+/**
+ * Implements <tt>SipCommFileChooser</tt> for AWT's <tt>FileDialog</tt>.
+ *
+ * @author Valentin Martinet
+ */
+public class SipCommFileDialogImpl
+ extends FileDialog
+ implements SipCommFileChooser
+{
+ /**
+ * The serialization-related version of the <tt>SipCommFileDialogImpl</tt>
+ * class explicitly defined to silence a related warning (e.g. in Eclipse
+ * IDE) since the <tt>SipCommFileDialogImpl</tt> class does not add instance
+ * fields.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The selection mode, the default is files only, can be changed to
+ * DIRECTORIES_ONLY.
+ */
+ private int selectionMode = FILES_ONLY;
+
+ /**
+ * Constructor
+ *
+ * @param parent the parent frame of this dialog
+ * @param title the title for this dialog
+ */
+ public SipCommFileDialogImpl(Frame parent, String title)
+ {
+ super(parent, title);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param parent the parent frame of this dialog
+ * @param title the title for this dialog
+ * @param fileOperation request a 'load file' or 'save file' dialog
+ */
+ public SipCommFileDialogImpl(Frame parent, String title, int fileOperation)
+ {
+ super(parent, title, fileOperation);
+ }
+
+ /**
+ * Returns the selected file by the user from the dialog.
+ *
+ * @return File the selected file from the dialog
+ */
+ public File getApprovedFile()
+ {
+ String file = getFile();
+
+ return (file != null) ? new File(getDirectory(), file) : null;
+ }
+
+ /**
+ * Sets the default path to be considered for browsing among files.
+ *
+ * @param path the default start path for this dialog
+ */
+ public void setStartPath(String path)
+ {
+ File file = (path == null) ? null : new File(path);
+
+ if ((file != null) && !file.isDirectory())
+ {
+ setDirectory(file.getParent());
+ setFile(file.getName());
+ }
+ else
+ setDirectory(path);
+ }
+
+ /**
+ * Shows the dialog and returns the selected file.
+ *
+ * @return File the selected file in this dialog
+ */
+ public File getFileFromDialog()
+ {
+ this.setVisible(true);
+
+ return this.getApprovedFile();
+ }
+
+ /**
+ * Adds a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void addFilter(SipCommFileFilter filter)
+ {
+ this.setFilenameFilter(filter);
+ }
+
+ /**
+ * Sets a file filter to this dialog.
+ *
+ * @param filter the filter to add
+ */
+ public void setFileFilter(SipCommFileFilter filter)
+ {
+ this.setFilenameFilter(filter);
+ }
+
+ /**
+ * Returns the filter the user has chosen for saving a file.
+ *
+ * @return SipCommFileFilter the used filter when saving a file
+ */
+ public SipCommFileFilter getUsedFilter()
+ {
+ return (SipCommFileFilter)this.getFilenameFilter();
+ }
+
+ /**
+ * Change the selection mode for the file choose.
+ * Possible values are DIRECTORIES_ONLY or FILES_ONLY, default is
+ * FILES_ONLY.
+ *
+ * @param mode the mode to use.
+ */
+ public void setSelectionMode(int mode)
+ {
+ this.selectionMode = mode;
+ }
+
+ /**
+ * Shows or hides the file chooser dialog.
+ * @param b if <code>true</code>, shows the dialog;
+ * otherwise, hides it
+ */
+ public void setVisible(boolean b)
+ {
+ // workaround to make sure we choose only folders on macosx
+ if(OSUtils.IS_MAC && selectionMode == DIRECTORIES_ONLY)
+ System.setProperty(
+ "apple.awt.fileDialogForDirectories", "true");
+
+ super.setVisible(b);
+
+ if(OSUtils.IS_MAC && selectionMode == DIRECTORIES_ONLY)
+ System.setProperty(
+ "apple.awt.fileDialogForDirectories", "false");
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileFilter.java b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileFilter.java
new file mode 100644
index 0000000..47137cd
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SipCommFileFilter.java
@@ -0,0 +1,52 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.io.*;
+
+import javax.swing.filechooser.FileFilter;
+
+
+/**
+ * The purpose of this interface is to provide an generic file filter type for
+ * the SipCommFileChooser, which is used either as an AWT FileDialog, either as
+ * a Swing JFileChooser.
+ *
+ * Both of these dialogs use their own filter type, FileFilter (class) for
+ * JFileChooser and FilenameFilter (interface) for FileDialog.
+ *
+ * SipCommFileFilter acts as both an implementation and an heritage from these
+ * two filters. To use a your own file filter with a SipCommFileChooser, you
+ * just have to extend from SipCommFileFilter and redefine at least the method
+ * 'public boolean accept(File f)' which is described in the Java FileFilter
+ * class.
+ *
+ * You won't have to redefine 'public boolean accept(File dir, String name)'
+ * from the Java FilenameFilter interface since it's done here: the method is
+ * transfered toward the accept method of Java FileFilter class.
+ *
+ * @author Valentin Martinet
+ */
+public abstract class SipCommFileFilter
+ extends FileFilter
+ implements FilenameFilter
+{
+
+ /**
+ * Avoid to be obliged to implement
+ * 'public boolean accept(File dir, String name)'
+ * in your own file filter.
+ *
+ * @param dir file's parent directory
+ * @param name file's name
+ * @return boolean if the file is accepted or not
+ */
+ public boolean accept(File dir, String name)
+ {
+ return accept(new File(dir.getAbsolutePath(), name));
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SoundLevelIndicator.java b/src/net/java/sip/communicator/plugin/desktoputil/SoundLevelIndicator.java
new file mode 100644
index 0000000..b3a85c0
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SoundLevelIndicator.java
@@ -0,0 +1,402 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+import org.jitsi.service.resources.*;
+
+/**
+ * Represents the sound level indicator for a particular peer.
+ *
+ * @author Dilshan Amadoru
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ * @author Lyubomir Marinov
+ */
+public class SoundLevelIndicator
+ extends TransparentPanel
+ implements Skinnable
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private static final String SOUND_LEVEL_ACTIVE_LEFT
+ = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT";
+
+ private static final String SOUND_LEVEL_ACTIVE_LEFT_GRADIENT
+ = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT_GRADIENT";
+
+ private static final String SOUND_LEVEL_ACTIVE_MIDDLE
+ = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_MIDDLE";
+
+ private static final String SOUND_LEVEL_ACTIVE_RIGHT
+ = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT";
+
+ private static final String SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT
+ = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT";
+
+ private static final String SOUND_LEVEL_INACTIVE_LEFT
+ = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_LEFT";
+
+ private static final String SOUND_LEVEL_INACTIVE_MIDDLE
+ = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_MIDDLE";
+
+ private static final String SOUND_LEVEL_INACTIVE_RIGHT
+ = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_RIGHT";
+
+ /**
+ * The maximum possible sound level.
+ */
+ private final int maxSoundLevel;
+
+ /**
+ * The minimum possible sound level.
+ */
+ private final int minSoundLevel;
+
+ /**
+ * The number of (distinct) sound bars displayed by this instance.
+ */
+ private int soundBarCount;
+
+ /**
+ * The sound level which is currently depicted by this
+ * <tt>SoundLevelIndicator</tt>.
+ */
+ private int soundLevel;
+
+ /**
+ * Image when a sound level block is active
+ */
+ private ImageIcon soundLevelActiveImageLeft;
+
+ /**
+ * Image when a sound level block is active
+ */
+ private ImageIcon soundLevelActiveImageLeftGradient;
+
+ /**
+ * Image when a sound level block is active
+ */
+ private ImageIcon soundLevelActiveImageMiddle;
+
+ /**
+ * Image when a sound level block is active
+ */
+ private ImageIcon soundLevelActiveImageRight;
+
+ /**
+ * Image when a sound level block is active
+ */
+ private ImageIcon soundLevelActiveImageRightGradient;
+
+ /**
+ * Image when a sound level block is not active
+ */
+ private ImageIcon soundLevelInactiveImageLeft;
+
+ /**
+ * Image when a sound level block is not active
+ */
+ private ImageIcon soundLevelInactiveImageMiddle;
+
+ /**
+ * Image when a sound level block is not active
+ */
+ private ImageIcon soundLevelInactiveImageRight;
+
+ /**
+ * A runnable that will be used to update the sound level.
+ */
+ private LevelUpdate levelUpdate = new LevelUpdate();
+
+ /**
+ * Initializes a new <tt>SoundLevelIndicator</tt> instance.
+ *
+ * @param minSoundLevel the minimum possible sound level
+ * @param maxSoundLevel the maximum possible sound level
+ */
+ public SoundLevelIndicator(int minSoundLevel, int maxSoundLevel)
+ {
+ this.minSoundLevel = minSoundLevel;
+ this.maxSoundLevel = maxSoundLevel;
+ this.soundLevel = minSoundLevel;
+
+ loadSkin();
+
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+ }
+
+ /**
+ * Update the sound level indicator component to fit the given values.
+ *
+ * @param soundLevel the sound level to show
+ */
+ public void updateSoundLevel(int soundLevel)
+ {
+ levelUpdate.setSoundLevel(soundLevel);
+ LowPriorityEventQueue.invokeLater(levelUpdate);
+ }
+
+ /**
+ * Update the sound level indicator component to fit the given values.
+ *
+ * @param soundLevel the sound level to show
+ */
+ private void updateSoundLevelInternal(int soundLevel)
+ {
+ int range = 1;
+
+ // Check if the given range values are correct.
+ if ((minSoundLevel > -1)
+ && (maxSoundLevel > -1)
+ && (minSoundLevel < maxSoundLevel))
+ {
+ range = maxSoundLevel - minSoundLevel;
+
+ if (soundLevel < 40 /* A WHISPER */)
+ soundLevel = minSoundLevel;
+ else if (soundLevel > 85 /* BEGINNING OF HEARING DAMAGE */)
+ soundLevel = maxSoundLevel;
+ else
+ {
+ /*
+ * Depict the range between "A WHISPER" and "BEGINNING OF
+ * HEARING DAMAGE".
+ */
+ soundLevel = (int) (((soundLevel - 40.0) / 45.0) * range);
+ if (soundLevel < minSoundLevel)
+ soundLevel = minSoundLevel;
+ else if (soundLevel > maxSoundLevel)
+ soundLevel = maxSoundLevel;
+ }
+ }
+
+ /*
+ * Audacity uses 0.9 for this.soundLevel and, consequently, 0.1 for
+ * soundLevel but that makes the animation too slow.
+ */
+ this.soundLevel = (int) (this.soundLevel * 0.8 + soundLevel * 0.2);
+
+ int activeSoundBarCount
+ = Math.round(this.soundLevel * soundBarCount / (float) range);
+
+ /*
+ * We cannot use getComponentCount() and then call getComponent(int)
+ * because there are multiple threads involved and the code bellow is
+ * not executed on the UI thread i.e. ArrayIndexOutOfBounds may and do
+ * happen.
+ */
+ Component[] components = getComponents();
+
+ for (int i = 0; i < components.length; i++)
+ {
+ Component c = getComponent(i);
+
+ if (c instanceof JLabel)
+ {
+ Icon activeIcon = null;
+ Icon inactiveIcon = null;
+ if (i == 0)
+ {
+ if (activeSoundBarCount == 1)
+ activeIcon = soundLevelActiveImageLeftGradient;
+ else
+ {
+ activeIcon = soundLevelActiveImageLeft;
+ inactiveIcon = soundLevelInactiveImageLeft;
+ }
+ }
+ else if (i == activeSoundBarCount - 1)
+ {
+ if (i == components.length - 1)
+ activeIcon = soundLevelActiveImageRight;
+ else
+ activeIcon = soundLevelActiveImageRightGradient;
+ }
+ else if (i == components.length - 1)
+ {
+ inactiveIcon = soundLevelInactiveImageRight;
+ }
+ else
+ {
+ activeIcon = soundLevelActiveImageMiddle;
+ inactiveIcon = soundLevelInactiveImageMiddle;
+ }
+
+ ((JLabel) c).setIcon(
+ (i < activeSoundBarCount)
+ ? activeIcon
+ : inactiveIcon);
+ }
+ }
+
+ repaint();
+ }
+
+ public void resetSoundLevel()
+ {
+ soundLevel = minSoundLevel;
+ updateSoundLevel(minSoundLevel);
+ }
+
+ @Override
+ public void setBounds(int x, int y, int width, int height)
+ {
+ super.setBounds(x, y, width, height);
+
+ int newSoundBarCount = getSoundBarCount(getWidth());
+
+ if (newSoundBarCount > 0)
+ {
+ while (newSoundBarCount < soundBarCount)
+ {
+ for (int i = getComponentCount() - 1; i >= 0; i--)
+ {
+ Component c = getComponent(i);
+
+ if (c instanceof JLabel)
+ {
+ remove(c);
+ soundBarCount--;
+ break;
+ }
+ }
+ }
+ while (soundBarCount < newSoundBarCount)
+ {
+ JLabel soundBar;
+ if (soundBarCount == 0)
+ soundBar = new JLabel(soundLevelInactiveImageLeft);
+ else if (soundBarCount == newSoundBarCount - 1)
+ soundBar = new JLabel(soundLevelInactiveImageRight);
+ else
+ soundBar = new JLabel(soundLevelInactiveImageMiddle);
+
+ soundBar.setVerticalAlignment(JLabel.CENTER);
+ add(soundBar);
+ soundBarCount++;
+ }
+ }
+
+ updateSoundLevel(soundLevel);
+ revalidate();
+ repaint();
+ }
+
+ /**
+ * Returns the number of sound level bars that we could currently show in
+ * this panel.
+ *
+ * @param width the current width of the call window
+ * @return the number of sound level bars that we could currently show in
+ * this panel
+ */
+ private int getSoundBarCount(int width)
+ {
+ int soundBarWidth = soundLevelActiveImageLeft.getIconWidth();
+
+ return width / soundBarWidth;
+ }
+
+ /**
+ * Reloads icons.
+ */
+ public void loadSkin()
+ {
+ ResourceManagementService resources = DesktopUtilActivator.getResources();
+
+ soundLevelActiveImageLeft
+ = resources.getImage(SOUND_LEVEL_ACTIVE_LEFT);
+ soundLevelActiveImageLeftGradient
+ = resources.getImage(SOUND_LEVEL_ACTIVE_LEFT_GRADIENT);
+ soundLevelActiveImageMiddle
+ = resources.getImage(SOUND_LEVEL_ACTIVE_MIDDLE);
+ soundLevelActiveImageRight
+ = resources.getImage(SOUND_LEVEL_ACTIVE_RIGHT);
+ soundLevelActiveImageRightGradient
+ = resources.getImage(SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT);
+
+ soundLevelInactiveImageLeft
+ = resources.getImage(SOUND_LEVEL_INACTIVE_LEFT);
+ soundLevelInactiveImageMiddle
+ = resources.getImage(SOUND_LEVEL_INACTIVE_MIDDLE);
+ soundLevelInactiveImageRight
+ = resources.getImage(SOUND_LEVEL_INACTIVE_RIGHT);
+
+ if (!isPreferredSizeSet())
+ {
+ int preferredHeight = 0;
+ int preferredWidth = 0;
+
+ if (soundLevelActiveImageLeft != null)
+ {
+ int height = soundLevelActiveImageLeft.getIconHeight();
+ int width = soundLevelActiveImageLeft.getIconWidth();
+
+ if (preferredHeight < height)
+ preferredHeight = height;
+ if (preferredWidth < width)
+ preferredWidth = width;
+ }
+ if (soundLevelInactiveImageLeft != null)
+ {
+ int height = soundLevelInactiveImageLeft.getIconHeight();
+ int width = soundLevelInactiveImageLeft.getIconWidth();
+
+ if (preferredHeight < height)
+ preferredHeight = height;
+ if (preferredWidth < width)
+ preferredWidth = width;
+ }
+ if ((preferredHeight > 0) && (preferredWidth > 0))
+ setPreferredSize(
+ new Dimension(
+ 10 * preferredWidth,
+ preferredHeight));
+ }
+
+ updateSoundLevel(soundLevel);
+ }
+
+ /**
+ * Runnable used to update sound levels.
+ */
+ private class LevelUpdate
+ implements Runnable
+ {
+ /**
+ * The current sound level to update.
+ */
+ private int soundLevel;
+
+ /**
+ * Update.
+ */
+ public void run()
+ {
+ updateSoundLevelInternal(soundLevel);
+ }
+
+ /**
+ * Changes the sound level.
+ * @param soundLevel changes the sound level.
+ */
+ public void setSoundLevel(int soundLevel)
+ {
+ this.soundLevel = soundLevel;
+ }
+ };
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/StyledHTMLEditorPane.java b/src/net/java/sip/communicator/plugin/desktoputil/StyledHTMLEditorPane.java
new file mode 100644
index 0000000..b81ea01
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/StyledHTMLEditorPane.java
@@ -0,0 +1,108 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.io.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.text.html.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * A custom styled HTML editor pane.
+ *
+ * @author Yana Stamcheva
+ */
+public class StyledHTMLEditorPane
+ extends JEditorPane
+{
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The logger for this class.
+ */
+ private final Logger logger = Logger.getLogger(StyledHTMLEditorPane.class);
+
+ /**
+ * The editor kit of this editor pane.
+ */
+ private final HTMLEditorKit editorKit;
+
+ /**
+ * The document of this editor pane.
+ */
+ private final HTMLDocument document;
+
+ /**
+ * Creates an instance of <tt>StyledHTMLEditorPane</tt>.
+ */
+ public StyledHTMLEditorPane()
+ {
+ editorKit = new SIPCommHTMLEditorKit(this);
+
+ this.document = (HTMLDocument) editorKit.createDefaultDocument();
+
+ this.setContentType("text/html");
+ this.setEditorKitForContentType("text/html", editorKit);
+ this.setEditorKit(editorKit);
+ this.setDocument(document);
+
+ putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
+ }
+
+ /**
+ * Appends text to end of the editor pane.
+ *
+ * @param text the text to append
+ */
+ public void appendToEnd(String text)
+ {
+ Element root = document.getDefaultRootElement();
+ try
+ {
+ document.insertAfterEnd(root
+ .getElement(root.getElementCount() - 1), text);
+ }
+ catch (BadLocationException e)
+ {
+ logger.error("Insert in the HTMLDocument failed.", e);
+ }
+ catch (IOException e)
+ {
+ logger.error("Insert in the HTMLDocument failed.", e);
+ }
+ }
+
+ /**
+ * Inserts the given text in the beginning of the editor pane.
+ *
+ * @param text the text to insert
+ */
+ public void insertAfterStart(String text)
+ {
+ Element root = this.document.getDefaultRootElement();
+
+ try
+ {
+ this.document.insertBeforeStart(root
+ .getElement(0), text);
+ }
+ catch (BadLocationException e)
+ {
+ logger.error("Insert in the HTMLDocument failed.", e);
+ }
+ catch (IOException e)
+ {
+ logger.error("Insert in the HTMLDocument failed.", e);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/SwingWorker.java b/src/net/java/sip/communicator/plugin/desktoputil/SwingWorker.java
new file mode 100644
index 0000000..7f64b84
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/SwingWorker.java
@@ -0,0 +1,229 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * Based on the 3rd version of SwingWorker (also known as SwingWorker 3), an
+ * abstract class that you subclass to perform GUI-related work in a dedicated
+ * thread. For instructions on using this class, see:
+ *
+ * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
+ *
+ * Note that the API changed slightly in the 3rd version:
+ * You must now invoke start() on the SwingWorker after
+ * creating it.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.util.concurrent.*;
+
+import javax.swing.*;
+
+/**
+ * Utility class based on the javax.swing.SwingWorker. <tt>SwingWorker</tt> is
+ * an abstract class that you subclass to perform GUI-related work in a
+ * dedicated thread. In addition to the original SwingWorker this class takes
+ * care of exceptions occurring during the execution of the separate thread. It
+ * will call a catchException() method in the Swing thread if an exception
+ * occurs.
+ *
+ * @author Yana Stamcheva
+ * @author Lyubomir Marinov
+ */
+public abstract class SwingWorker
+{
+ /**
+ * The <tt>ExecutorService</tt> which is shared by the <tt>SwingWorker</tt>
+ * instances for the purposes of controlling the use of <tt>Thread</tt>s.
+ */
+ private static ExecutorService executorService;
+
+ /**
+ * The <tt>Callable</tt> implementation which is (to be) submitted to
+ * {@link #executorService} and invokes {@link #construct()} on behalf of
+ * this <tt>SwingWorker</tt>.
+ */
+ private final Callable<Object> callable;
+
+ /**
+ * The <tt>Future</tt> instance which represents the state and the return
+ * value of the execution of {@link #callable} i.e. {@link #construct()}.
+ */
+ private Future<?> future;
+
+ /**
+ * Start a thread that will call the <code>construct</code> method
+ * and then exit.
+ */
+ public SwingWorker()
+ {
+ callable
+ = new Callable<Object>()
+ {
+ public Object call()
+ {
+ Object value = null;
+
+ try
+ {
+ value = construct();
+ }
+ catch (final Throwable t)
+ {
+ if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ else
+ {
+ // catchException
+ SwingUtilities.invokeLater(
+ new Runnable()
+ {
+ public void run()
+ {
+ catchException(t);
+ }
+ });
+ }
+ }
+
+ // We only want to perform the finished if the thread hasn't
+ // been interrupted.
+ if (!Thread.currentThread().isInterrupted())
+ // finished
+ SwingUtilities.invokeLater(
+ new Runnable()
+ {
+ public void run()
+ {
+ finished();
+ }
+ });
+
+ return value;
+ }
+ };
+ }
+
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * if an exception has occurred during the <code>construct</code> method.
+ *
+ * @param exception the exception that has occurred
+ */
+ protected void catchException(Throwable exception)
+ {
+ }
+
+ /**
+ * Computes the value to be returned by {@link #get()}.
+ */
+ protected abstract Object construct()
+ throws Exception;
+
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * after the <code>construct</code> method has returned.
+ */
+ protected void finished()
+ {
+ }
+
+ /**
+ * Return the value created by the <code>construct</code> method.
+ * Returns null if either the constructing thread or the current
+ * thread was interrupted before a value was produced.
+ *
+ * @return the value created by the <code>construct</code> method
+ */
+ public Object get()
+ {
+ Future<?> future;
+
+ synchronized (this)
+ {
+ /*
+ * SwingWorker assigns a value to the future field only once and we
+ * do not want to invoke Future#cancel(true) while holding a lock.
+ */
+ future = this.future;
+ }
+
+ Object value = null;
+
+ if (future != null)
+ {
+ boolean interrupted = false;
+
+ do
+ {
+ try
+ {
+ value = future.get();
+ break;
+ }
+ catch (CancellationException ce)
+ {
+ break;
+ }
+ catch (ExecutionException ee)
+ {
+ break;
+ }
+ catch (InterruptedException ie)
+ {
+ interrupted = true;
+ }
+ }
+ while (true);
+ if (interrupted) // propagate
+ Thread.currentThread().interrupt();
+ }
+
+ return value;
+ }
+
+ /**
+ * A new method that interrupts the worker thread. Call this method
+ * to force the worker to stop what it's doing.
+ */
+ public void interrupt()
+ {
+ Future<?> future;
+
+ synchronized (this)
+ {
+ /*
+ * SwingWorker assigns a value to the future field only once and we
+ * do not want to invoke Future#cancel(true) while holding a lock.
+ */
+ future = this.future;
+ }
+
+ if (future != null)
+ future.cancel(true);
+ }
+
+ /**
+ * Start the worker thread.
+ */
+ public void start()
+ {
+ ExecutorService executorService;
+
+ synchronized (SwingWorker.class)
+ {
+ if (SwingWorker.executorService == null)
+ SwingWorker.executorService = Executors.newCachedThreadPool();
+ executorService = SwingWorker.executorService;
+ }
+
+ synchronized (this)
+ {
+ if (future == null || future.isDone())
+ future = executorService.submit(callable);
+ else
+ throw new IllegalStateException("future");
+ }
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/TransparentPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/TransparentPanel.java
new file mode 100644
index 0000000..5b3f41e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/TransparentPanel.java
@@ -0,0 +1,30 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+
+/**
+ * Provides compatibility with source code written prior to the inception of
+ * libjitsi.
+ *
+ * @author Lyubomir Marinov
+ */
+public class TransparentPanel
+ extends org.jitsi.util.swing.TransparentPanel
+{
+ private static final long serialVersionUID = 0L;
+
+ public TransparentPanel()
+ {
+ }
+
+ public TransparentPanel(LayoutManager layout)
+ {
+ super(layout);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/TrimTextField.java b/src/net/java/sip/communicator/plugin/desktoputil/TrimTextField.java
new file mode 100644
index 0000000..5b837c3
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/TrimTextField.java
@@ -0,0 +1,36 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+/**
+ * A custom JTextField that trims the contents before returns it.
+ *
+ * @author Damian Minkov
+ */
+public class TrimTextField
+ extends JTextField
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Returns the trimmed value of the text contained in the field.
+ * @return the trimmed value of the field.
+ */
+ public String getText()
+ {
+ String txt = super.getText();
+ if(txt != null)
+ return txt.trim();
+ else
+ return null;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/UIAction.java b/src/net/java/sip/communicator/plugin/desktoputil/UIAction.java
new file mode 100644
index 0000000..2852acc
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/UIAction.java
@@ -0,0 +1,26 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import javax.swing.*;
+
+/**
+ * A wrapper around AbstractAction, so we can differ our Actions.
+ * Used when adding actions to the action map,
+ * and actions will be triggered by keystrokes from the inputMap of the RootPane.
+ *
+ * @author Damian Minkov
+ */
+public abstract class UIAction
+ extends AbstractAction
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/WindowUtils.java b/src/net/java/sip/communicator/plugin/desktoputil/WindowUtils.java
new file mode 100644
index 0000000..3ff5a77
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/WindowUtils.java
@@ -0,0 +1,158 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * Utility class for awt windows management.
+ *
+ * @author Yana Stamcheva
+ */
+public class WindowUtils
+{
+ /**
+ * The list of all <tt>Window</tt>s owned by this application.
+ */
+ private static final List<Window> WINDOW_LIST;
+
+ static
+ {
+ /*
+ * WINDOW_LIST is flawed because there are more calls to addWindow than
+ * to removeWindow. Java 6 has introduced Window#getWindows so try to
+ * use it instead.
+ */
+ Method Window_getWindows = null;
+
+ try
+ {
+ Window_getWindows = Window.class.getMethod("getWindows");
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ /*
+ * Ignore the exception because we are just checking whether the
+ * method exists.
+ */
+ }
+ catch (SecurityException se)
+ {
+ }
+ WINDOW_LIST
+ = (Window_getWindows == null) ? new ArrayList<Window>() : null;
+ }
+
+ /**
+ * Returns an array of all {@code Window}s, both owned and ownerless,
+ * created by this application.
+ * If called from an applet, the array includes only the {@code Window}s
+ * accessible by that applet.
+ * <p>
+ * <b>Warning:</b> this method may return system created windows, such
+ * as a print dialog. Applications should not assume the existence of
+ * these dialogs, nor should an application assume anything about these
+ * dialogs such as component positions, <code>LayoutManager</code>s
+ * or serialization.
+ *
+ * @return Returns an array of all {@code Window}s.
+ */
+ public static Window[] getWindows()
+ {
+ if (WINDOW_LIST == null)
+ {
+ Method Window_getWindows = null;
+
+ try
+ {
+ Window_getWindows = Window.class.getMethod("getWindows");
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ /* Ignore it because we cannot really do anything useful. */
+ }
+ catch (SecurityException se)
+ {
+ }
+
+ Object windows = null;
+
+ if (Window_getWindows != null)
+ {
+ try
+ {
+ windows = Window_getWindows.invoke(null);
+ }
+ catch (ExceptionInInitializerError eiie)
+ {
+ /* Ignore it because we cannot really do anything useful. */
+ }
+ catch (IllegalAccessException iae)
+ {
+ }
+ catch (IllegalArgumentException iae)
+ {
+ }
+ catch (InvocationTargetException ite)
+ {
+ }
+ catch (NullPointerException npe)
+ {
+ }
+ }
+
+ return
+ (windows instanceof Window[])
+ ? (Window[]) windows
+ : new Window[0];
+ }
+ else
+ {
+ synchronized (WINDOW_LIST)
+ {
+ return WINDOW_LIST.toArray(new Window[WINDOW_LIST.size()]);
+ }
+ }
+ }
+
+ /**
+ * Adds a {@link Window} into window list
+ *
+ * @param w {@link Window} to be added.
+ */
+ public static void addWindow(Window w)
+ {
+ if (WINDOW_LIST != null)
+ {
+ synchronized (WINDOW_LIST)
+ {
+ if (!WINDOW_LIST.contains(w))
+ WINDOW_LIST.add(w);
+ }
+ }
+ }
+
+ /**
+ * Removes a {@link Window} into window list
+ *
+ * @param w {@link Window} to be removed.
+ */
+ public static void removeWindow(Window w)
+ {
+ if (WINDOW_LIST != null)
+ {
+ synchronized (WINDOW_LIST)
+ {
+ WINDOW_LIST.remove(w);
+ }
+ }
+ }
+
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/X509CertificatePanel.java b/src/net/java/sip/communicator/plugin/desktoputil/X509CertificatePanel.java
new file mode 100644
index 0000000..e60c71c
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/X509CertificatePanel.java
@@ -0,0 +1,423 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil;
+
+import java.awt.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.interfaces.*;
+import java.text.*;
+import java.util.*;
+
+import javax.naming.*;
+import javax.naming.ldap.*;
+import javax.security.auth.x500.*;
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.resources.*;
+
+/**
+ * Panel that shows the content of an X509Certificate.
+ */
+public class X509CertificatePanel
+ extends TransparentPanel
+{
+ private static final long serialVersionUID = -8368302061995971947L;
+
+ /**
+ * Constructs a X509 certificate panel.
+ *
+ * @param certificate <tt>X509Certificate</tt> object
+ */
+ public X509CertificatePanel(X509Certificate certificate)
+ {
+ ResourceManagementService R = DesktopUtilActivator.getResources();
+ DateFormat dateFormatter = DateFormat
+ .getDateInstance(DateFormat.MEDIUM);
+
+ Insets valueInsets = new Insets(2,10,0,0);
+ Insets titleInsets = new Insets(10,5,0,0);
+
+ setLayout(new GridBagLayout());
+
+ int currentRow = 0;
+
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.insets = new Insets(2,5,0,0);
+ constraints.gridx = 0;
+ constraints.weightx = 0;
+ constraints.weighty = 0;
+ constraints.gridy = currentRow++;
+
+ X500Principal issuer = certificate.getIssuerX500Principal();
+ X500Principal subject = certificate.getSubjectX500Principal();
+
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_ISSUED_TO")),
+ constraints);
+
+ // subject
+ constraints.insets = valueInsets;
+ try
+ {
+ for(Rdn name : new LdapName(subject.getName()).getRdns())
+ {
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ String lbl =
+ R.getI18NString("service.gui.CERT_INFO_" + name.getType());
+ if (lbl
+ .equals("!service.gui.CERT_INFO_" + name.getType() + "!"))
+ lbl = name.getType();
+ add(new JLabel(lbl), constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(
+ name.getValue() instanceof byte[] ?
+ getHex((byte[])name.getValue()) + " ("
+ + new String((byte[]) name.getValue()) + ")"
+ : name.getValue().toString()),
+ constraints);
+ }
+ }
+ catch (InvalidNameException e1)
+ {
+ constraints.gridy = currentRow++;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_CN")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(subject.getName()),
+ constraints);
+ }
+
+ // issuer
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.insets = titleInsets;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_ISSUED_BY")),
+ constraints);
+ constraints.insets = valueInsets;
+ try
+ {
+ for(Rdn name : new LdapName(issuer.getName()).getRdns())
+ {
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.gridx = 0;
+ String lbl =
+ R.getI18NString("service.gui.CERT_INFO_" + name.getType());
+ if (lbl
+ .equals("!service.gui.CERT_INFO_" + name.getType() + "!"))
+ lbl = name.getType();
+ add(new JLabel(lbl), constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(
+ name.getValue() instanceof byte[] ?
+ getHex((byte[])name.getValue()) + " ("
+ + new String((byte[]) name.getValue()) + ")"
+ : name.getValue().toString()),
+ constraints);
+ }
+ }
+ catch (InvalidNameException e1)
+ {
+ constraints.gridy = currentRow++;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_CN")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(issuer.getName()),
+ constraints);
+ }
+
+ // validity
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.insets = titleInsets;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_VALIDITY")),
+ constraints);
+ constraints.insets = valueInsets;
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_ISSUED_ON")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(dateFormatter.format(certificate.getNotBefore())),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_EXPIRES_ON")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(dateFormatter.format(certificate.getNotAfter())),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.insets = titleInsets;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_FINGERPRINTS")),
+ constraints);
+ constraints.insets = valueInsets;
+
+ try
+ {
+ String sha1String = getThumbprint(certificate, "SHA1");
+ String md5String = getThumbprint(certificate, "MD5");
+
+ JTextArea sha1Area = new JTextArea(sha1String);
+ sha1Area.setLineWrap(false);
+ sha1Area.setOpaque(false);
+ sha1Area.setWrapStyleWord(true);
+ sha1Area.setEditable(false);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel("SHA1:"),
+ constraints);
+
+ constraints.gridx = 1;
+ add(
+ sha1Area,
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel("MD5:"),
+ constraints);
+
+ JTextArea md5Area = new JTextArea(md5String);
+ md5Area.setLineWrap(false);
+ md5Area.setOpaque(false);
+ md5Area.setWrapStyleWord(true);
+ md5Area.setEditable(false);
+
+ constraints.gridx = 1;
+ add(
+ md5Area,
+ constraints);
+ }
+ catch (Exception e)
+ {
+ // do nothing as we cannot show this value
+ }
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.insets = titleInsets;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_CERT_DETAILS")),
+ constraints);
+ constraints.insets = valueInsets;
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_SER_NUM")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(certificate.getSerialNumber().toString()),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_VER")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(String.valueOf(certificate.getVersion())),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_SIGN_ALG")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(String.valueOf(certificate.getSigAlgName())),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ constraints.insets = titleInsets;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_PUB_KEY_INFO")),
+ constraints);
+ constraints.insets = valueInsets;
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_ALG")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(certificate.getPublicKey().getAlgorithm()),
+ constraints);
+
+ if(certificate.getPublicKey().getAlgorithm().equals("RSA"))
+ {
+ RSAPublicKey key = (RSAPublicKey)certificate.getPublicKey();
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_PUB_KEY")),
+ constraints);
+
+ JTextArea pubkeyArea = new JTextArea(
+ R.getI18NString(
+ "service.gui.CERT_INFO_KEY_BYTES_PRINT",
+ new String[]{
+ String.valueOf(key.getModulus().toByteArray().length-1),
+ key.getModulus().toString(16)
+ }));
+ pubkeyArea.setLineWrap(false);
+ pubkeyArea.setOpaque(false);
+ pubkeyArea.setWrapStyleWord(true);
+ pubkeyArea.setEditable(false);
+
+ constraints.gridx = 1;
+ add(
+ pubkeyArea,
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_EXP")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(key.getPublicExponent().toString()),
+ constraints);
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_KEY_SIZE")),
+ constraints);
+ constraints.gridx = 1;
+ add(
+ new JLabel(R.getI18NString(
+ "service.gui.CERT_INFO_KEY_BITS_PRINT",
+ new String[]{
+ String.valueOf(key.getModulus().bitLength())})),
+ constraints);
+ }
+ else if(certificate.getPublicKey().getAlgorithm().equals("DSA"))
+ {
+ DSAPublicKey key =
+ (DSAPublicKey)certificate.getPublicKey();
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel("Y:"), constraints);
+
+ JTextArea yArea = new JTextArea(key.getY().toString(16));
+ yArea.setLineWrap(false);
+ yArea.setOpaque(false);
+ yArea.setWrapStyleWord(true);
+ yArea.setEditable(false);
+
+ constraints.gridx = 1;
+ add(
+ yArea,
+ constraints);
+ }
+
+ constraints.gridy = currentRow++;
+ constraints.gridx = 0;
+ add(new JLabel(
+ R.getI18NString("service.gui.CERT_INFO_SIGN")),
+ constraints);
+
+ JTextArea signArea = new JTextArea(
+ R.getI18NString(
+ "service.gui.CERT_INFO_KEY_BYTES_PRINT",
+ new String[]{
+ String.valueOf(certificate.getSignature().length),
+ getHex(certificate.getSignature())
+ }));
+ signArea.setLineWrap(false);
+ signArea.setOpaque(false);
+ signArea.setWrapStyleWord(true);
+ signArea.setEditable(false);
+
+ constraints.gridx = 1;
+ add(
+ signArea,
+ constraints);
+ }
+
+ /**
+ * Converts the byte array to hex string.
+ * @param raw the data.
+ * @return the hex string.
+ */
+ private String getHex( byte [] raw )
+ {
+ if (raw == null)
+ return null;
+
+ StringBuilder hex = new StringBuilder(2 * raw.length);
+ Formatter f = new Formatter(hex);
+ for (byte b : raw)
+ {
+ f.format("%02x", b);
+ }
+ return hex.toString();
+ } /**
+ * Calculates the hash of the certificate known as the "thumbprint"
+ * and returns it as a string representation.
+ *
+ * @param cert The certificate to hash.
+ * @param algorithm The hash algorithm to use.
+ * @return The SHA-1 hash of the certificate.
+ * @throws CertificateException
+ */
+ private static String getThumbprint(X509Certificate cert, String algorithm)
+ throws CertificateException
+ {
+ MessageDigest digest;
+ try
+ {
+ digest = MessageDigest.getInstance(algorithm);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CertificateException(e);
+ }
+ byte[] encodedCert = cert.getEncoded();
+ StringBuilder sb = new StringBuilder(encodedCert.length * 2);
+ Formatter f = new Formatter(sb);
+ for (byte b : digest.digest(encodedCert))
+ {
+ f.format("%02x", b);
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/border/ExtendedEtchedBorder.java b/src/net/java/sip/communicator/plugin/desktoputil/border/ExtendedEtchedBorder.java
new file mode 100644
index 0000000..62b5afe
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/border/ExtendedEtchedBorder.java
@@ -0,0 +1,127 @@
+package net.java.sip.communicator.plugin.desktoputil.border;
+
+import java.awt.*;
+
+import javax.swing.border.*;
+
+public class ExtendedEtchedBorder
+ extends EtchedBorder
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Thickness of the top line.
+ */
+ private final int top;
+
+ /**
+ * Thickness of the left line.
+ */
+ private final int left;
+
+ /**
+ * Thickness of the bottom line.
+ */
+ private final int bottom;
+
+ /**
+ * Thickness of the right line.
+ */
+ private final int right;
+
+ /**
+ * Creates an etched border with the specified etch-type and specified
+ * thickness of each border: top, left, bottom, right.
+ *
+ * @param etchType the type of etch to be drawn by the border
+ * @param top the thickness of the top border
+ * @param left the thickness of the left border
+ * @param bottom the thickness of the bottom border
+ * @param right the thickness of the right border
+ */
+ public ExtendedEtchedBorder(int etchType,
+ int top,
+ int left,
+ int bottom,
+ int right)
+ {
+ super(etchType, null, null);
+
+ this.top = top;
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ }
+
+ /**
+ * Paints the border for the specified component with the
+ * specified position and size.
+ * @param c the component for which this border is being painted
+ * @param g the paint graphics
+ * @param x the x position of the painted border
+ * @param y the y position of the painted border
+ * @param width the width of the painted border
+ * @param height the height of the painted border
+ */
+ public void paintBorder(Component c,
+ Graphics g,
+ int x,
+ int y,
+ int width,
+ int height)
+ {
+ int w = width;
+ int h = height;
+
+ Graphics2D g2 = (Graphics2D) g;
+
+ g2.translate(x, y);
+
+ g2.setColor(etchType == LOWERED ? getShadowColor(c)
+ : getHighlightColor(c));
+
+ if (top > 0)
+ {
+ g2.setStroke(new BasicStroke(top));
+ g2.drawLine(0, 0, w-2, 0);
+ }
+
+ if (left > 0)
+ {
+ g2.setStroke(new BasicStroke(left));
+ g2.drawLine(0, 0, 0, h-2);
+ }
+
+ if (bottom > 0)
+ {
+ g2.setStroke(new BasicStroke(bottom));
+ g2.drawLine(0, h-2, w-2, h-2);
+ }
+
+ if (right > 0)
+ {
+ g2.setStroke(new BasicStroke(right));
+ g2.drawLine(w-2, 0, w-2, h-2);
+ }
+
+ g2.setColor(etchType == LOWERED ? getHighlightColor(c)
+ : getShadowColor(c));
+
+ if (top > 0)
+ g2.drawLine(1, 1, w-3, 1);
+
+ if (left > 0)
+ g2.drawLine(1, h-3, 1, 1);
+
+ if (right > 0)
+ g2.drawLine(0, h-1, w-1, h-1);
+
+ if (bottom > 0)
+ g2.drawLine(w-1, h-1, w-1, 0);
+
+ g2.translate(-x, -y);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf b/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf
new file mode 100644
index 0000000..52b31ca
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf
@@ -0,0 +1,64 @@
+Bundle-Activator: net.java.sip.communicator.plugin.desktoputil.DesktopUtilActivator
+Bundle-Name: Jitsi Swing Utility Packages
+Bundle-Description: A bundle that export packages with swing related utility classes.
+Bundle-Vendor: jitsi.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: com.sun.awt,
+ javax.imageio,
+ javax.naming,
+ javax.naming.directory,
+ javax.naming.ldap,
+ javax.net,
+ javax.net.ssl,
+ javax.security.auth.x500,
+ javax.swing,
+ javax.swing.border,
+ javax.swing.event,
+ javax.swing.filechooser,
+ javax.swing.plaf,
+ javax.swing.plaf.basic,
+ javax.swing.plaf.metal,
+ javax.swing.table,
+ javax.swing.text,
+ javax.swing.text.html,
+ javax.swing.text.html.parser,
+ javax.swing.tree,
+ javax.xml.parsers,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.skin,
+ net.java.sip.communicator.plugin.desktoputil.dns,
+ net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.resources,
+ net.java.sip.communicator.service.keybindings,
+ net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.netaddr.event,
+ net.java.sip.communicator.service.contactlist,
+ net.java.sip.communicator.service.browserlauncher,
+ net.java.sip.communicator.service.protocol,
+ org.apache.xml.serialize,
+ org.jitsi.service.configuration,
+ org.jitsi.service.neomedia,
+ org.jitsi.service.neomedia.codec,
+ org.jitsi.service.resources,
+ org.jitsi.service.fileaccess,
+ org.jitsi.util,
+ org.jitsi.util.event,
+ org.jitsi.util.swing,
+ org.osgi.framework,
+ org.w3c.dom,
+ org.xbill.DNS,
+ org.xml.sax,
+ sun.awt.shell,
+ sun.net.dns,
+ sun.net.util
+Export-Package: net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.border,
+ net.java.sip.communicator.plugin.desktoputil.event,
+ net.java.sip.communicator.plugin.desktoputil.plaf,
+ net.java.sip.communicator.plugin.desktoputil.transparent,
+ net.java.sip.communicator.plugin.desktoputil.wizard,
+ org.xbill.DNS \ No newline at end of file
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/ConfigurableDnssecResolver.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/ConfigurableDnssecResolver.java
new file mode 100644
index 0000000..d2f4fce
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/ConfigurableDnssecResolver.java
@@ -0,0 +1,356 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.service.notification.*;
+import net.java.sip.communicator.util.Logger;
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
+import org.jitsi.util.*;
+import org.xbill.DNS.*;
+
+/**
+ * Resolver that wraps a DNSSEC capable resolver and handles validation
+ * failures according to the user's settings.
+ *
+ * @author Ingo Bauersachs
+ */
+public class ConfigurableDnssecResolver
+ extends UnboundResolver
+{
+ private final static Logger logger
+ = Logger.getLogger(ConfigurableDnssecResolver.class);
+
+ /**
+ * Name of the property that defines the default DNSSEC validation
+ * behavior.
+ */
+ public final static String PNAME_DNSSEC_VALIDATION_MODE
+ = "net.java.sip.communicator.util.dns.DNSSEC_VALIDATION_MODE";
+
+ /**
+ * Default value of {@link #PNAME_DNSSEC_VALIDATION_MODE}
+ */
+ public final static String PNAME_BASE_DNSSEC_PIN
+ = "net.java.sip.communicator.util.dns.pin";
+
+ final static String EVENT_TYPE = "DNSSEC_NOTIFICATION";
+
+ private ConfigurationService config
+ = DnsUtilActivator.getConfigurationService();
+ private ResourceManagementService R
+ = DnsUtilActivator.getResources();
+ private Map<String, Date> lastNotifications
+ = new HashMap<String, Date>();
+
+ /**
+ * Creates a new instance of this class. Tries to use the system's
+ * default forwarders.
+ */
+ public ConfigurableDnssecResolver()
+ {
+ super();
+ String forwarders = DnsUtilActivator.getConfigurationService()
+ .getString(DnsUtilActivator.PNAME_DNSSEC_NAMESERVERS);
+ if(!StringUtils.isNullOrEmpty(forwarders, true))
+ {
+ if(logger.isTraceEnabled())
+ {
+ logger.trace("Setting DNSSEC forwarders to: "
+ + Arrays.toString(forwarders.split(",")));
+ }
+ super.setForwarders(forwarders.split(","));
+ }
+ DnsUtilActivator.getNotificationService().
+ registerDefaultNotificationForEvent(
+ ConfigurableDnssecResolver.EVENT_TYPE,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null, null);
+ }
+
+ /**
+ * Inspects a DNS answer message and handles validation results according to
+ * the user's preferences.
+ *
+ * @throws DnssecRuntimeException when the validation failed and the user
+ * did not choose to ignore it.
+ */
+ @Override
+ protected void validateMessage(SecureMessage msg)
+ throws DnssecRuntimeException
+ {
+ //---------------------------------------------------------------------
+ // || 1 | 2 | 3 | 4 | 5
+ //---------------------------------------------------------------------
+ // Sec. | Bog. || Ign. | Sec.Only | Sec.Or.Unsig | Warn.Bog | WarnAll
+ //---------------------------------------------------------------------
+ //a) 1 | 0 || ok | ok | ok | ok | ok
+ //b) 0 | 1 || ok | nok | nok | ask | ask
+ //c) 0 | 0 || ok | nok | ok | ok | ask
+ //---------------------------------------------------------------------
+
+ String fqdn = msg.getQuestion().getName().toString();
+ String type = Type.string(msg.getQuestion().getType());
+ String propName = createPropNameUnsigned(fqdn, type);
+ SecureResolveMode defaultAction = Enum.valueOf(SecureResolveMode.class,
+ config.getString(
+ PNAME_DNSSEC_VALIDATION_MODE,
+ SecureResolveMode.WarnIfBogus.name()
+ )
+ );
+ SecureResolveMode pinned = Enum.valueOf(SecureResolveMode.class,
+ config.getString(
+ propName,
+ defaultAction.name()
+ )
+ );
+
+ //create default entry
+ if(pinned == defaultAction)
+ config.setProperty(propName, pinned.name());
+
+ //check domain policy
+
+ //[abc]1, a[2-5]
+ if(pinned == SecureResolveMode.IgnoreDnssec || msg.isSecure())
+ return;
+
+ if(
+ //b2, c2
+ (pinned == SecureResolveMode.SecureOnly && !msg.isSecure())
+ ||
+ //b3
+ (pinned == SecureResolveMode.SecureOrUnsigned && msg.isBogus())
+ )
+ {
+ String text = getExceptionMessage(msg);
+ Date last = lastNotifications.get(text);
+ if(last == null
+ //wait at least 5 minutes before showing the same info again
+ || last.before(new Date(new Date().getTime() - 1000*60*5)))
+ {
+ DnsUtilActivator.getNotificationService().fireNotification(
+ EVENT_TYPE,
+ R.getI18NString("util.dns.INSECURE_ANSWER_TITLE"),
+ text,
+ null);
+ lastNotifications.put(text, new Date());
+ }
+ throw new DnssecRuntimeException(text);
+ }
+
+ //c3
+ if(pinned == SecureResolveMode.SecureOrUnsigned && !msg.isBogus())
+ return;
+
+ //c4
+ if(pinned == SecureResolveMode.WarnIfBogus && !msg.isBogus())
+ return;
+
+ //b4, b5, c5
+ String reason = msg.isBogus()
+ ? R.getI18NString("util.dns.DNSSEC_ADVANCED_REASON_BOGUS",
+ new String[]{fqdn, msg.getBogusReason()})
+ : R.getI18NString("util.dns.DNSSEC_ADVANCED_REASON_UNSIGNED",
+ new String[]{type, fqdn});
+ DnssecDialog dlg = new DnssecDialog(fqdn, reason);
+ dlg.setVisible(true);
+ DnssecDialogResult result = dlg.getResult();
+ switch(result)
+ {
+ case Accept:
+ break;
+ case Deny:
+ throw new DnssecRuntimeException(getExceptionMessage(msg));
+ case AlwaysAccept:
+ if(msg.isBogus())
+ config.setProperty(propName,
+ SecureResolveMode.IgnoreDnssec.name());
+ else
+ config.setProperty(propName,
+ SecureResolveMode.WarnIfBogus.name());
+ break;
+ case AlwaysDeny:
+ config.setProperty(propName, SecureResolveMode.SecureOnly);
+ throw new DnssecRuntimeException(getExceptionMessage(msg));
+ }
+ }
+
+ /**
+ * Defines the return code from the DNSSEC verification dialog.
+ */
+ private enum DnssecDialogResult
+ {
+ /** The DNS result shall be accepted. */
+ Accept,
+ /** The result shall be rejected. */
+ Deny,
+ /** The result shall be accepted permanently. */
+ AlwaysAccept,
+ /**
+ * The result shall be rejected automatically unless it is valid
+ * according to DNSSEC.
+ */
+ AlwaysDeny
+ }
+
+ /**
+ * Dialog to ask and warn the user if he wants to continue to accept an
+ * invalid dnssec result.
+ */
+ private class DnssecDialog extends SIPCommDialog implements ActionListener
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ //UI controls
+ private JPanel pnlAdvanced;
+ private JPanel pnlStandard;
+ private final String domain;
+ private final String reason;
+ private JButton cmdAck;
+ private JButton cmdShowDetails;
+
+ //state
+ private DnssecDialogResult result = DnssecDialogResult.Deny;
+
+ /**
+ * Creates a new instance of this class.
+ * @param domain The FQDN of the domain that failed.
+ * @param reason String describing why the validation failed.
+ */
+ public DnssecDialog(String domain, String reason)
+ {
+ super(false);
+ setModal(true);
+ this.domain = domain;
+ this.reason = reason;
+ initComponents();
+ }
+
+ /**
+ * Creates the UI controls
+ */
+ private void initComponents()
+ {
+ setLayout(new BorderLayout(15, 15));
+ setTitle(R.getI18NString("util.dns.INSECURE_ANSWER_TITLE"));
+
+ // warning text
+ JLabel imgWarning =
+ new JLabel(R.getImage("service.gui.icons.WARNING_ICON"));
+ imgWarning.setBorder(BorderFactory
+ .createEmptyBorder(10, 10, 10, 10));
+ add(imgWarning, BorderLayout.WEST);
+ JLabel lblWarning = new JLabel(
+ R.getI18NString("util.dns.DNSSEC_WARNING", new String[]{
+ R.getSettingsString("service.gui.APPLICATION_NAME"),
+ domain
+ })
+ );
+ add(lblWarning, BorderLayout.CENTER);
+
+ //standard panel (deny option)
+ cmdAck = new JButton(R.getI18NString("service.gui.OK"));
+ cmdAck.addActionListener(this);
+
+ cmdShowDetails = new JButton(
+ R.getI18NString("util.dns.DNSSEC_ADVANCED_OPTIONS"));
+ cmdShowDetails.addActionListener(this);
+
+ pnlStandard = new TransparentPanel(new BorderLayout());
+ pnlStandard.setBorder(BorderFactory
+ .createEmptyBorder(10, 10, 10, 10));
+ pnlStandard.add(cmdShowDetails, BorderLayout.WEST);
+ pnlStandard.add(cmdAck, BorderLayout.EAST);
+ add(pnlStandard, BorderLayout.SOUTH);
+
+ //advanced panel
+ pnlAdvanced = new TransparentPanel(new BorderLayout());
+ JPanel pnlAdvancedButtons = new TransparentPanel(
+ new FlowLayout(FlowLayout.RIGHT));
+ pnlAdvancedButtons.setBorder(BorderFactory
+ .createEmptyBorder(10, 10, 10, 10));
+ pnlAdvanced.add(pnlAdvancedButtons, BorderLayout.EAST);
+ for(DnssecDialogResult r : DnssecDialogResult.values())
+ {
+ JButton cmd = new JButton(R.getI18NString(
+ DnssecDialogResult.class.getName() + "." + r.name()));
+ cmd.setActionCommand(r.name());
+ cmd.addActionListener(this);
+ pnlAdvancedButtons.add(cmd);
+ }
+ JLabel lblReason = new JLabel(reason);
+ lblReason.setBorder(BorderFactory
+ .createEmptyBorder(10, 10, 10, 10));
+ pnlAdvanced.add(lblReason, BorderLayout.NORTH);
+ }
+
+ /**
+ * Handles the events coming from the buttons.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if(e.getSource() == cmdAck)
+ {
+ result = DnssecDialogResult.Deny;
+ dispose();
+ }
+ else if(e.getSource() == cmdShowDetails)
+ {
+ getContentPane().remove(pnlStandard);
+ add(pnlAdvanced, BorderLayout.SOUTH);
+ pack();
+ }
+ else
+ {
+ result = Enum.valueOf(DnssecDialogResult.class,
+ e.getActionCommand());
+ dispose();
+ }
+ }
+
+ /**
+ * Gets the option that user has chosen.
+ * @return the option that user has chosen.
+ */
+ public DnssecDialogResult getResult()
+ {
+ return result;
+ }
+ }
+
+ private String getExceptionMessage(SecureMessage msg)
+ {
+ return msg.getBogusReason() == null
+ ? R.getI18NString(
+ "util.dns.INSECURE_ANSWER_MESSAGE_NO_REASON",
+ new String[]{msg.getQuestion().getName().toString()}
+ )
+ : R.getI18NString(
+ "util.dns.INSECURE_ANSWER_MESSAGE_REASON",
+ new String[]{msg.getQuestion().getName().toString(),
+ //TODO parse bogus reason text and translate
+ msg.getBogusReason()}
+ );
+ }
+
+ private String createPropNameUnsigned(String fqdn, String type)
+ {
+ return PNAME_BASE_DNSSEC_PIN + "." + fqdn.replace(".", "__");
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/DnsUtilActivator.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnsUtilActivator.java
new file mode 100644
index 0000000..9253701
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnsUtilActivator.java
@@ -0,0 +1,181 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import net.java.sip.communicator.service.notification.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
+import org.osgi.framework.*;
+import org.xbill.DNS.*;
+
+/**
+ * The DNS Util activator registers the DNSSEC resolver if enabled.
+ *
+ * @author Emil Ivov
+ * @author Ingo Bauersachs
+ */
+public class DnsUtilActivator
+ implements BundleActivator
+{
+ /**
+ * The name of the property that enables or disables the DNSSEC resolver
+ * (instead of a normal, non-validating local resolver).
+ */
+ public static final String PNAME_DNSSEC_RESOLVER_ENABLED
+ = "net.java.sip.communicator.util.dns.DNSSEC_ENABLED";
+
+ /**
+ * Default value of @see PNAME_DNSSEC_RESOLVER_ENABLED.
+ */
+ public static final boolean PDEFAULT_DNSSEC_RESOLVER_ENABLED = false;
+
+ /**
+ * The name of the property that sets custom nameservers to use for all DNS
+ * lookups when DNSSEC is enabled. Multiple servers are separated by a comma
+ * (,).
+ */
+ public static final String PNAME_DNSSEC_NAMESERVERS
+ = "net.java.sip.communicator.util.dns.DNSSEC_NAMESERVERS";
+
+ /**
+ * The <tt>Logger</tt> used by the <tt>UtilActivator</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(DnsUtilActivator.class);
+
+ private static ConfigurationService configurationService;
+ private static NotificationService notificationService;
+ private static ResourceManagementService resourceService;
+ private static BundleContext bundleContext;
+
+ /**
+ * Calls <tt>Thread.setUncaughtExceptionHandler()</tt>
+ *
+ * @param context The execution context of the bundle being started
+ * (unused).
+ * @throws Exception If this method throws an exception, this bundle is
+ * marked as stopped and the Framework will remove this bundle's
+ * listeners, unregister all services registered by this bundle, and
+ * release all services used by this bundle.
+ */
+ public void start(BundleContext context)
+ throws Exception
+ {
+ bundleContext = context;
+
+ if(getConfigurationService().getBoolean(
+ PNAME_DNSSEC_RESOLVER_ENABLED,
+ PDEFAULT_DNSSEC_RESOLVER_ENABLED))
+ {
+ getNotificationService().
+ registerDefaultNotificationForEvent(
+ ConfigurableDnssecResolver.EVENT_TYPE,
+ NotificationAction.ACTION_POPUP_MESSAGE,
+ null, null);
+ }
+ refreshResolver();
+ }
+
+ /**
+ * Sets a DNSSEC resolver as default resolver on lookup when DNSSEC is
+ * enabled; creates a standard lookup otherwise.
+ */
+ public static void refreshResolver()
+ {
+ if(getConfigurationService().getBoolean(
+ PNAME_DNSSEC_RESOLVER_ENABLED,
+ PDEFAULT_DNSSEC_RESOLVER_ENABLED))
+ {
+ logger.trace("DNSSEC is enabled");
+ ConfigurableDnssecResolver res = new ConfigurableDnssecResolver();
+ for(int i = 1;;i++)
+ {
+ String anchor = getResources().getSettingsString(
+ "net.java.sip.communicator.util.dns.DS_ROOT." + i);
+ if(anchor == null)
+ break;
+ res.addTrustAnchor(anchor);
+ if(logger.isTraceEnabled())
+ logger.trace("Loaded trust anchor " + anchor);
+ }
+ Lookup.setDefaultResolver(res);
+ }
+ else
+ {
+ logger.trace("DNSSEC is disabled, refresh default config");
+ Lookup.refreshDefault();
+ }
+ }
+
+ /**
+ * Doesn't do anything.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the bundle is
+ * still marked as stopped, and the Framework will remove the bundle's
+ * listeners, unregister all services registered by the bundle, and
+ * release all services used by the bundle.
+ */
+ public void stop(BundleContext context)
+ throws Exception
+ {
+ }
+
+ /**
+ * Returns the <tt>ConfigurationService</tt> obtained from the bundle
+ * context.
+ * @return the <tt>ConfigurationService</tt> obtained from the bundle
+ * context
+ */
+ public static ConfigurationService getConfigurationService()
+ {
+ if (configurationService == null)
+ {
+ configurationService
+ = ServiceUtils.getService(
+ bundleContext,
+ ConfigurationService.class);
+ }
+ return configurationService;
+ }
+
+ /**
+ * Returns the <tt>NotificationService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>NotificationService</tt> obtained from the bundle context
+ */
+ public static NotificationService getNotificationService()
+ {
+ if (notificationService == null)
+ {
+ notificationService
+ = ServiceUtils.getService(
+ bundleContext,
+ NotificationService.class);
+ }
+ return notificationService;
+ }
+
+ /**
+ * Returns the service giving access to all application resources.
+ *
+ * @return the service giving access to all application resources.
+ */
+ public static ResourceManagementService getResources()
+ {
+ if (resourceService == null)
+ {
+ resourceService
+ = ResourceManagementServiceUtils.getService(bundleContext);
+ }
+ return resourceService;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecException.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecException.java
new file mode 100644
index 0000000..565a08a
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecException.java
@@ -0,0 +1,30 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+/**
+ * Checked DNSSEC exception for code that knows how to deal with it.
+ *
+ * @author Ingo Bauersachs
+ */
+public class DnssecException
+ extends Exception
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new instance of this class.
+ * @param e the DNSSEC runtime exception to encapsulate.
+ */
+ public DnssecException(DnssecRuntimeException e)
+ {
+ super(e);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecRuntimeException.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecRuntimeException.java
new file mode 100644
index 0000000..b06ba5b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/DnssecRuntimeException.java
@@ -0,0 +1,35 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import java.net.*;
+
+/**
+ * Runtime exception that is thrown when a DNSSEC validation failure occurred.
+ * This is not a checked exception or a derivative of
+ * {@link UnknownHostException} so that existing code does not retry the lookup
+ * (potentially in a loop).
+ *
+ * @author Ingo Bauersachs
+ */
+public class DnssecRuntimeException
+ extends RuntimeException
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new instance of this class.
+ * @param message The reason why this exception is thrown.
+ */
+ public DnssecRuntimeException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/ParallelResolver.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/ParallelResolver.java
new file mode 100644
index 0000000..105e49d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/ParallelResolver.java
@@ -0,0 +1,694 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.util.*;
+
+import org.xbill.DNS.*;
+
+/**
+ * The purpose of this class is to help avoid the significant delays that occur
+ * in networks where DNS servers would ignore SRV, NAPTR, and sometimes even
+ * A/AAAA queries (i.e. without even sending an error response). We also try to
+ * handle cases where DNS servers may return empty responses to some records.
+ * <p>
+ * We achieve this by entering a redundant mode whenever we detect an abnormal
+ * delay (longer than <tt>DNS_PATIENCE</tt>) while waiting for a DNS resonse,
+ * or when that response is not considered satisfying.
+ * <p>
+ * Once we enter redundant mode, we start duplicating all queries and sending
+ * them to both our primary and backup resolvers (in case we have any). We then
+ * always return the first response we get, regardless of who sent it.
+ * <p>
+ * We exit redundant mode after receiving <tt>DNS_REDEMPTION</tt> consecutive
+ * timely and correct responses from our primary resolver.
+ *
+ * @author Emil Ivov
+ */
+public class ParallelResolver implements Resolver
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>ParallelResolver</tt>
+ * class and its instances for logging output.
+ */
+ private static final Logger logger = Logger
+ .getLogger(ParallelResolver.class.getName());
+
+ /**
+ * Indicates whether we are currently in a mode where all DNS queries are
+ * sent to both the primary and the backup DNS servers.
+ */
+ private static boolean redundantMode = false;
+
+ /**
+ * The default number of milliseconds it takes us to get into redundant
+ * mode while waiting for a DNS query response.
+ */
+ public static final int DNS_PATIENCE = 1500;
+
+ /**
+ * The name of the property that allows us to override the default
+ * <tt>DNS_PATIENCE</tt> value.
+ */
+ public static final String PNAME_DNS_PATIENCE
+ = "net.java.sip.communicator.util.dns.DNS_PATIENCE";
+
+ /**
+ * The currently configured number of milliseconds that we need to wait
+ * before entering redundant mode.
+ */
+ private static long currentDnsPatience = DNS_PATIENCE;
+
+ /**
+ * The default number of times that the primary DNS would have to provide a
+ * faster response than the backup resolver before we consider it safe
+ * enough to exit redundant mode.
+ */
+ public static final int DNS_REDEMPTION = 3;
+
+ /**
+ * The name of the property that allows us to override the default
+ * <tt>DNS_REDEMPTION</tt> value.
+ */
+ public static final String PNAME_DNS_REDEMPTION
+ = "net.java.sip.communicator.util.dns.DNS_REDEMPTION";
+
+ /**
+ * The currently configured number of times that the primary DNS would have
+ * to provide a faster response than the backup resolver before we consider
+ * it safe enough to exit redundant mode.
+ */
+ public static int currentDnsRedemption = DNS_REDEMPTION;
+
+ /**
+ * The number of fast responses that we need to get from the primary
+ * resolver before we exit redundant mode. <tt>0</tt> indicates that we are
+ * no longer in redundant mode
+ */
+ private static int redemptionStatus = 0;
+
+ /**
+ * A lock that we use while determining whether we've completed redemption
+ * and can exit redundant mode.
+ */
+ private final static Object redemptionLock = new Object();
+
+ /**
+ * The default resolver that we use if everything works properly.
+ */
+ private static Resolver defaultResolver;
+
+ static
+ {
+ try
+ {
+ defaultResolver = new ExtendedResolver();
+ }
+ catch (UnknownHostException e)
+ {
+ //should never happen
+ throw new RuntimeException("Failed to initialize resolver");
+ }
+
+ initProperties();
+ }
+
+ /**
+ * Default resolver property initialisation
+ */
+ private static void initProperties()
+ {
+ try
+ {
+ currentDnsPatience = DesktopUtilActivator.getConfigurationService()
+ .getLong(PNAME_DNS_PATIENCE, DNS_PATIENCE);
+ currentDnsRedemption
+ = DesktopUtilActivator.getConfigurationService()
+ .getInt(PNAME_DNS_REDEMPTION, DNS_REDEMPTION);
+ }
+ catch(Throwable t)
+ {
+ //we don't want messed up properties to screw up DNS resolution
+ //so we just log.
+ logger.info("Failed to initialize DNS resolver properties", t);
+ }
+
+ }
+
+ /**
+ * Replaces the default resolver used by this class. Mostly meant for
+ * debugging.
+ *
+ * @param resolver the resolver we'd like to use by default from now on.
+ */
+ public static void setDefaultResolver(Resolver resolver)
+ {
+ defaultResolver = resolver;
+ }
+
+ /**
+ * Returns the default resolver used by this class. Mostly meant for
+ * debugging.
+ *
+ * @return the resolver this class consults first.
+ */
+ public static Resolver getDefaultResolver()
+ {
+ return defaultResolver;
+ }
+
+ /**
+ * An extended resolver that would be encapsulating all backup resolvers.
+ */
+ private final ExtendedResolver backupResolver;
+
+ /**
+ * Creates a <tt>ParallelResolver</tt> that would use the specified array
+ * of <tt>backupServers</tt> if the default DNS doesn't seem to be doing
+ * that well.
+ *
+ * @param backupServers the list of backup DNS servers that we should use
+ * if, and only if, the default servers don't seem to work that well.
+ */
+ public ParallelResolver(InetSocketAddress[] backupServers)
+ {
+ try
+ {
+ backupResolver = new ExtendedResolver(new SimpleResolver[]{});
+ for(InetSocketAddress backupServer : backupServers )
+ {
+ SimpleResolver sr = new SimpleResolver();
+ sr.setAddress(backupServer);
+
+ backupResolver.addResolver(sr);
+ }
+ }
+ catch (UnknownHostException e)
+ {
+ //this shouldn't be thrown since we don't do any DNS querying
+ //in here. this is why we take an InetSocketAddress as a param.
+ throw new IllegalStateException("The impossible just happened: "
+ +"we could not initialize our backup DNS resolver");
+ }
+ }
+
+ /**
+ * Sends a message and waits for a response.
+ *
+ * @param query The query to send.
+ * @return The response
+ *
+ * @throws IOException An error occurred while sending or receiving.
+ */
+ public Message send(Message query)
+ throws IOException
+ {
+
+ ParallelResolution resolution = new ParallelResolution(query);
+
+ resolution.sendFirstQuery();
+
+ //make a copy of the redundant mode variable in case we are currently
+ //completed a redemption that started earlier.
+ boolean redundantModeCopy;
+
+ synchronized(redemptionLock)
+ {
+ redundantModeCopy = redundantMode;
+ }
+
+ //if we are not in redundant mode we should wait a bit and see how this
+ //goes. if we get a reply we could return bravely.
+ if(!redundantModeCopy)
+ {
+ if(resolution.waitForResponse(currentDnsPatience))
+ {
+ //we are done.
+ return resolution.returnResponseOrThrowUp();
+ }
+ else
+ {
+ synchronized(redemptionLock)
+ {
+ redundantMode = true;
+ redemptionStatus = currentDnsRedemption;
+ logger.info("Primary DNS seems laggy as we got no "
+ +"response for " + currentDnsPatience + "ms. "
+ + "Enabling redundant mode.");
+ }
+ }
+ }
+
+ //we are definitely in redundant mode now
+ resolution.sendBackupQueries();
+
+ resolution.waitForResponse(0);
+
+ //check if it is time to end redundant mode.
+ synchronized(redemptionLock)
+ {
+ if(!resolution.primaryResolverRespondedFirst)
+ {
+ //primary DNS is still feeling shaky. we reinit redemption
+ //status in case we were about to cut the server some slack
+ redemptionStatus = currentDnsRedemption;
+ }
+ else
+ {
+ //primary server replied first. we let him redeem some dignity
+ redemptionStatus --;
+
+ //yup, it's now time to end DNS redundant mode;
+ if(redemptionStatus <= 0)
+ {
+ redundantMode = false;
+ logger.info("Primary DNS seems back in biz. "
+ + "Disabling redundant mode.");
+ }
+ }
+ }
+
+ return resolution.returnResponseOrThrowUp();
+ }
+
+ /**
+ * Supposed to asynchronously send messages but not currently implemented.
+ *
+ * @param query The query to send
+ * @param listener The object containing the callbacks.
+ * @return An identifier, which is also a parameter in the callback
+ */
+ public Object sendAsync(final Message query, final ResolverListener listener)
+ {
+ return null;
+ }
+
+ /**
+ * Sets the port to communicate on with the default servers.
+ *
+ * @param port The port to send messages to
+ */
+ public void setPort(int port)
+ {
+ defaultResolver.setPort(port);
+ }
+
+ /**
+ * Sets whether TCP connections will be sent by default with the default
+ * resolver. Backup servers would always be contacted the same way.
+ *
+ * @param flag Indicates whether TCP connections are made
+ */
+ public void setTCP(boolean flag)
+ {
+ defaultResolver.setTCP(flag);
+ }
+
+ /**
+ * Sets whether truncated responses will be ignored. If not, a truncated
+ * response over UDP will cause a retransmission over TCP. Backup servers
+ * would always be contacted the same way.
+ *
+ * @param flag Indicates whether truncated responses should be ignored.
+ */
+ public void setIgnoreTruncation(boolean flag)
+ {
+ defaultResolver.setIgnoreTruncation(flag);
+ }
+
+ /**
+ * Sets the EDNS version used on outgoing messages.
+ *
+ * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no
+ * EDNS.
+ * @throws IllegalArgumentException An invalid level was indicated.
+ */
+ public void setEDNS(int level)
+ {
+ defaultResolver.setEDNS(level);
+ }
+
+ /**
+ * Sets the EDNS information on outgoing messages.
+ *
+ * @param level The EDNS level to use. 0 indicates EDNS0 and -1 indicates no
+ * EDNS.
+ * @param payloadSize The maximum DNS packet size that this host is capable
+ * of receiving over UDP. If 0 is specified, the default (1280) is used.
+ * @param flags EDNS extended flags to be set in the OPT record.
+ * @param options EDNS options to be set in the OPT record, specified as a
+ * List of OPTRecord.Option elements.
+ *
+ * @throws IllegalArgumentException An invalid field was specified.
+ * @see OPTRecord
+ */
+ @SuppressWarnings("rawtypes") // that's the way it is in dnsjava
+ public void setEDNS(int level, int payloadSize, int flags, List options)
+ {
+ defaultResolver.setEDNS(level, payloadSize, flags, options);
+ }
+
+ /**
+ * Specifies the TSIG key that messages will be signed with
+ * @param key The key
+ */
+ public void setTSIGKey(TSIG key)
+ {
+ defaultResolver.setTSIGKey(key);
+ }
+
+ /**
+ * Sets the amount of time to wait for a response before giving up.
+ *
+ * @param secs The number of seconds to wait.
+ * @param msecs The number of milliseconds to wait.
+ */
+ public void setTimeout(int secs, int msecs)
+ {
+ defaultResolver.setTimeout(secs, msecs);
+ }
+
+ /**
+ * Sets the amount of time to wait for a response before giving up.
+ *
+ * @param secs The number of seconds to wait.
+ */
+ public void setTimeout(int secs)
+ {
+ defaultResolver.setTimeout(secs);
+ }
+
+ /**
+ * Resets resolver configuration and populate our default resolver
+ * with the newly configured servers.
+ */
+ public void reset()
+ {
+ ExtendedResolver resolver = (ExtendedResolver)defaultResolver;
+
+ // remove old ones
+ for(Resolver r : resolver.getResolvers())
+ {
+ resolver.deleteResolver(r);
+ }
+
+ // populate with new servers after refreshing configuration
+ try
+ {
+ String [] servers = ResolverConfig.getCurrentConfig().servers();
+ if (servers != null)
+ {
+ for (int i = 0; i < servers.length; i++)
+ {
+ Resolver r = new SimpleResolver(servers[i]);
+ //r.setTimeout(quantum);
+ resolver.addResolver(r);
+ }
+ }
+ else
+ resolver.addResolver(new SimpleResolver());
+ }
+ catch (UnknownHostException e)
+ {
+ //should never happen
+ throw new RuntimeException("Failed to initialize resolver");
+ }
+ }
+
+ /**
+ * Determines if <tt>response</tt> can be considered a satisfactory DNS
+ * response and returns accordingly.
+ * <p>
+ * We consider non-satisfactory responses that may indicate that the local
+ * DNS does not work properly and that we may hence need to fall back to
+ * the backup resolver.
+ * <p>
+ * Basically the goal here is to be able to go into redundant mode when we
+ * come across DNS servers that send empty responses to SRV and NAPTR
+ * requests.
+ *
+ * @param response the dnsjava {@link Message} that we'd like to inspect.
+ *
+ * @return <tt>true</tt> if <tt>response</tt> appears as a satisfactory
+ * response and <tt>false</tt> otherwise.
+ */
+ private boolean isResponseSatisfactory(Message response)
+ {
+ if ( response == null )
+ return false;
+
+ Record[] answerRR = response.getSectionArray(Section.ANSWER);
+ Record[] authorityRR = response.getSectionArray(Section.AUTHORITY);
+ Record[] additionalRR = response.getSectionArray(Section.ADDITIONAL);
+
+ if ( (answerRR != null && answerRR.length > 0)
+ || (authorityRR != null && authorityRR.length > 0)
+ || (additionalRR != null && additionalRR.length > 0))
+ {
+ return true;
+ }
+
+ //we didn't find any responses and unless the answer is NXDOMAIN then
+ //we may want to check with the backup resolver for a second opinion
+ if(response.getRcode() == Rcode.NXDOMAIN)
+ return true;
+
+ //if we received NODATA (same as NOERROR and no response records) for
+ // an AAAA or a NAPTR query then it makes sense since many existing
+ //domains come without those two.
+ if( response.getRcode() == Rcode.NOERROR
+ && (response.getQuestion().getType() == Type.AAAA
+ || response.getQuestion().getType() == Type.NAPTR))
+ {
+ return true;
+ }
+
+ //nope .. this doesn't make sense ...
+ return false;
+ }
+
+ /**
+ * The class that listens for responses to any of the queries we send to
+ * our default and backup servers and returns as soon as we get one or until
+ * our default resolver fails.
+ */
+ private class ParallelResolution extends Thread
+ {
+ /**
+ * The query that we have sent to the default and backup DNS servers.
+ */
+ private final Message query;
+
+ /**
+ * The field where we would store the first incoming response to our
+ * query.
+ */
+ public Message response;
+
+ /**
+ * The field where we would store the first error we receive from a DNS
+ * or a backup resolver.
+ */
+ private Throwable exception;
+
+ /**
+ * Indicates whether we are still waiting for an answer from someone
+ */
+ private boolean done = false;
+
+ /**
+ * Indicates that a response was received from the primary resolver.
+ */
+ private boolean primaryResolverRespondedFirst = true;
+
+ /**
+ * Creates a {@link ParallelResolution} for the specified <tt>query</tt>
+ *
+ * @param query the DNS query that we'd like to send to our primary
+ * and backup resolvers.
+ */
+ public ParallelResolution(final Message query)
+ {
+ super("ParallelResolutionThread");
+ this.query = query;
+ }
+
+ /**
+ * Starts this collector which would cause it to send its query to the
+ * default resolver.
+ */
+ public void sendFirstQuery()
+ {
+ start();
+ }
+
+ /**
+ * Sends this collector's query to the default resolver.
+ */
+ public void run()
+ {
+ Message localResponse = null;
+ try
+ {
+ localResponse = defaultResolver.send(query);
+ }
+ catch (Throwable exc)
+ {
+ logger.info("Exception occurred during parallel DNS resolving" +
+ exc, exc);
+ this.exception = exc;
+ }
+ synchronized(this)
+ {
+ //if the backup resolvers had already replied we ignore the
+ //reply of the primary one whatever it was.
+ if(done)
+ return;
+
+ //if there was a response we're only done if it is satisfactory
+ if( localResponse != null
+ && isResponseSatisfactory(localResponse))
+ {
+ response = localResponse;
+ done = true;
+ }
+ notify();
+ }
+ }
+
+ /**
+ * Asynchronously sends this collector's query to all backup resolvers.
+ */
+ public void sendBackupQueries()
+ {
+ logger.info("Send DNS queries to backup resolvers");
+
+ //yes. a second thread in the thread ... it's ugly but it works
+ //and i do want to keep code simple to read ... this whole parallel
+ //resolving is complicated enough as it is.
+ new Thread(){
+ public void run()
+ {
+ synchronized(ParallelResolution.this)
+ {
+ if (done)
+ return;
+ Message localResponse = null;
+ try
+ {
+ localResponse = backupResolver.send(query);
+ }
+ catch (Throwable exc)
+ {
+ logger.info("Exception occurred during backup "
+ +"DNS resolving" + exc);
+
+ //keep this so that we can rethrow it
+ exception = exc;
+ }
+ //if the default resolver has already replied we
+ //ignore the reply of the backup ones.
+ if(done)
+ return;
+
+ //contrary to responses from the primary resolver,
+ //in this case we don't care whether the response is
+ //satisfying: if it isn't, there's nothing we can do
+ response = localResponse;
+ done = true;
+
+ ParallelResolution.this.notify();
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * Waits for a response or an error to occur during <tt>waitFor</tt>
+ * milliseconds.If neither happens, we return false.
+ *
+ * @param waitFor the number of milliseconds to wait for a response or
+ * an error or <tt>0</tt> if we'd like to wait until either of these
+ * happen.
+ *
+ * @return <tt>true</tt> if we returned because we received a response
+ * from a resolver or errors from everywhere, and <tt>false</tt> that
+ * didn't happen.
+ */
+ public boolean waitForResponse(long waitFor)
+ {
+ synchronized(this)
+ {
+ if(done)
+ return done;
+ try
+ {
+ wait(waitFor);
+ }
+ catch (InterruptedException e)
+ {
+ //we don't care
+ }
+
+ return done;
+ }
+ }
+
+ /**
+ * Waits for resolution to complete (if necessary) and then either
+ * returns the response we received or throws whatever exception we
+ * saw.
+ *
+ * @return the response {@link Message} we received from the DNS.
+ *
+ * @throws IOException if this resolution ended badly because of a
+ * network IO error
+ * @throws RuntimeException if something unexpected happened
+ * during resolution.
+ * @throws IllegalArgumentException if something unexpected happened
+ * during resolution or if there was no response.
+ */
+ public Message returnResponseOrThrowUp()
+ throws IOException, RuntimeException, IllegalArgumentException
+ {
+ if(!done)
+ waitForResponse(0);
+
+ if(response != null)
+ {
+ return response;
+ }
+ else if (exception instanceof IOException)
+ {
+ logger.warn("IO exception while using DNS resolver", exception);
+ throw (IOException) exception;
+ }
+ else if (exception instanceof RuntimeException)
+ {
+ logger.warn("RunTimeException while using DNS resolver",
+ exception);
+ throw (RuntimeException) exception;
+ }
+ else if (exception instanceof Error)
+ {
+ logger.warn("Error while using DNS resolver", exception);
+ throw (Error) exception;
+ }
+ else
+ {
+ logger.warn("Received a bad response from primary DNS resolver",
+ exception);
+ throw new IllegalStateException("ExtendedResolver failure");
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureMessage.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureMessage.java
new file mode 100644
index 0000000..28f8fcb
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureMessage.java
@@ -0,0 +1,93 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import java.io.*;
+
+import org.xbill.DNS.*;
+
+/**
+ * DNS Message that adds DNSSEC validation information.
+ *
+ * @author Ingo Bauersachs
+ */
+public class SecureMessage
+ extends Message
+{
+ private boolean secure;
+ private boolean bogus;
+ private String bogusReason;
+
+ /**
+ * Creates a new instance of this class based on data received from an
+ * Unbound resolve.
+ *
+ * @param msg The answer of the Unbound resolver.
+ * @throws IOException
+ */
+ public SecureMessage(UnboundResult msg) throws IOException
+ {
+ super(msg.answerPacket);
+ secure = msg.secure;
+ bogus = msg.bogus;
+ bogusReason = msg.whyBogus;
+ }
+
+ /**
+ * Indicates whether the answer is secure.
+ * @return True, if the result is validated securely.
+ */
+ public boolean isSecure()
+ {
+ return secure;
+ }
+
+ /**
+ * Indicates if there was a validation failure.
+ *
+ * @return If the result was not secure (secure == false), and this result
+ * is due to a security failure, bogus is true.
+ */
+ public boolean isBogus()
+ {
+ return bogus;
+ }
+
+ /**
+ * If the result is bogus this contains a string that describes the failure.
+ *
+ * @return string that describes the failure.
+ */
+ public String getBogusReason()
+ {
+ return bogusReason;
+ }
+
+ /**
+ * Converts the Message to a String. The fields secure, bogus and whyBogus
+ * are append as a comment.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder s = new StringBuilder(super.toString());
+ s.append('\n');
+ s.append(";; Secure: ");
+ s.append(secure);
+ s.append('\n');
+ s.append(";; Bogus: ");
+ s.append(bogus);
+ s.append('\n');
+ if(bogus)
+ {
+ s.append(";; Reason: ");
+ s.append(bogusReason);
+ s.append('\n');
+ }
+ return s.toString();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureResolveMode.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureResolveMode.java
new file mode 100644
index 0000000..77c21d9
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/SecureResolveMode.java
@@ -0,0 +1,43 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+/**
+ * Defines how DNSSEC validation errors should be handled.
+ *
+ * @author Ingo Bauersachs
+ */
+public enum SecureResolveMode
+{
+ /**
+ * Any DNSSEC data is completely ignored.
+ */
+ IgnoreDnssec,
+
+ /**
+ * The result of a query is only returned if it validated successfully.
+ */
+ SecureOnly,
+
+ /**
+ * The result of a query is returned if it validated successfully or when
+ * the zone is unsigned.
+ */
+ SecureOrUnsigned,
+
+ /**
+ * If the result of a query is bogus (manipulated, incorrect), the user is
+ * to be asked how to proceed.
+ */
+ WarnIfBogus,
+
+ /**
+ * If the result of a query is bogus (manipulated, incorrect) or if the zone
+ * is unsigned, the user is to be asked how to proceed.
+ */
+ WarnIfBogusOrUnsigned
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundApi.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundApi.java
new file mode 100644
index 0000000..bd53010
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundApi.java
@@ -0,0 +1,228 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+/**
+ * Wrapper for the JUnbound JNI wrapper.
+ * <p>
+ * The JavaDoc of these methods is directly copied from libunbound, licensed as
+ * follows:
+ * <p>
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Ingo Bauersachs
+ */
+public class UnboundApi
+{
+ private static boolean isAvailable;
+ private static final Object syncRoot = new Object();
+
+ static
+ {
+ tryLoadUnbound();
+ }
+
+ /**
+ * Attempts to load the Unbound native library. When successful,
+ * {@link #isAvailable()} returns true.
+ */
+ public static void tryLoadUnbound()
+ {
+ synchronized(syncRoot)
+ {
+ try
+ {
+ System.loadLibrary("junbound");
+ isAvailable = true;
+ }
+ catch(UnsatisfiedLinkError e)
+ {
+ isAvailable = false;
+ }
+ }
+ }
+
+ /**
+ * Indicates whether the Unbound library is loaded.
+ * @return True when the JNI wrapper could be loaded, false otherwise.
+ */
+ public static boolean isAvailable()
+ {
+ return isAvailable;
+ }
+
+ /**
+ * Set debug verbosity for the context. Output is directed to stderr. Higher
+ * debug level gives more output.
+ *
+ * @param context context.
+ * @param level The debug level.
+ */
+ public static native void setDebugLevel(long context, int level);
+
+ /**
+ * Create a resolving and validation context.
+ * @return a new context. default initialization. returns NULL on error.
+ */
+ public static native long createContext();
+
+ /**
+ * Destroy a validation context and free all its resources. Outstanding
+ * async queries are killed and callbacks are not called for them.
+ *
+ * @param context context to delete
+ */
+ public static native void deleteContext(long context);
+
+ /**
+ * Set machine to forward DNS queries to, the caching resolver to use.
+ * <p>
+ * IP4 or IP6 address. Forwards all DNS requests to that machine, which is
+ * expected to run a recursive resolver. If the proxy is not DNSSEC-capable,
+ * validation may fail. Can be called several times, in that case the
+ * addresses are used as backup servers.
+ *
+ * @param context context. At this time it is only possible to set
+ * configuration before the first resolve is done.
+ * @param server address, IP4 or IP6 in string format. If the server is
+ * NULL, forwarding is disabled.
+ */
+ public static native void setForwarder(long context, String server);
+
+ /**
+ * Add a trust anchor to the given context.
+ * <p>
+ * The trust anchor is a string, on one line, that holds a valid DNSKEY or
+ * DS RR.
+ *
+ * @param context context. At this time it is only possible to add trusted
+ * keys before the first resolve is done.
+ * @param anchor string, with zone-format RR on one line. [domainname] [TTL
+ * optional] [type] [class optional] [rdata contents]
+ */
+ public static native void addTrustAnchor(long context, String anchor);
+
+ /**
+ * Perform resolution and validation of the target name.
+ *
+ * @param context context. The context is finalized, and can no longer
+ * accept config changes.
+ * @param name domain name in text format (a zero terminated text string).
+ * @param rrtype type of RR in host order, 1 is A (address).
+ * @param rrclass class of RR in host order, 1 is IN (for internet).
+ * @return the result data is returned in a newly allocated result
+ * structure. May be NULL on return, return value is set to an error
+ * in that case (out of memory).
+ * @throws UnboundException when an error occurred.
+ */
+ public static native UnboundResult resolve(long context, String name,
+ int rrtype, int rrclass) throws UnboundException;
+
+ /**
+ * Perform resolution and validation of the target name.
+ * <p>
+ * Asynchronous, after a while, the callback will be called with your data
+ * and the result.
+ *
+ * @param context context. If no thread or process has been created yet to
+ * perform the work in the background, it is created now. The
+ * context is finalized, and can no longer accept config changes.
+ * @param name domain name in text format (a string).
+ * @param rrtype type of RR in host order, 1 is A.
+ * @param rrclass class of RR in host order, 1 is IN (for internet).
+ * @param data this data is your own data (you can pass null), and is passed
+ * on to the callback function.
+ * @param cb this is called on completion of the resolution.
+ * @return an identifier number is returned for the query as it is in
+ * progress. It can be used to cancel the query.
+ * @throws UnboundException when an error occurred.
+ */
+ public static native int resolveAsync(long context, String name,
+ int rrtype, int rrclass, Object data, UnboundCallback cb)
+ throws UnboundException;
+
+ /**
+ * Cancel an async query in progress. Its callback will not be called.
+ *
+ * @param context context.
+ * @param asyncId which query to cancel.
+ * @throws UnboundException This routine can error if the async_id passed
+ * does not exist or has already been delivered. If another
+ * thread is processing results at the same time, the result may
+ * be delivered at the same time and the cancel fails with an
+ * error. Also the cancel can fail due to a system error, no
+ * memory or socket failures.
+ */
+ public static native void cancelAsync(long context, int asyncId)
+ throws UnboundException;
+
+ /**
+ * Convert error value to a human readable string.
+ *
+ * @param code error code from one of the Unbound functions.
+ * @return text string of the error code.
+ */
+ public static native String errorCodeToString(int code);
+
+ /**
+ * Wait for a context to finish with results. Call this routine to continue
+ * processing results from the validating resolver. After the wait, there
+ * are no more outstanding asynchronous queries.
+ *
+ * @param context context.
+ * @throws UnboundException when an error occurred.
+ */
+ public static native void processAsync(long context)
+ throws UnboundException;
+
+ /**
+ * Interface for the async resolve callback.
+ */
+ public interface UnboundCallback
+ {
+ /**
+ * Called on completion of the async resolution.
+ *
+ * @param data the same object as passed to
+ * {@link UnboundApi#resolveAsync(long, String, int, int,
+ * Object, UnboundCallback)}
+ * @param err 0 when a result has been found, an Unbound error code
+ * otherwise
+ * @param result a newly allocated result structure. The result may be
+ * null, in that case err is set.
+ */
+ public void UnboundResolveCallback(Object data, int err,
+ UnboundResult result);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundException.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundException.java
new file mode 100644
index 0000000..0367e2f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundException.java
@@ -0,0 +1,31 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+/**
+ * Exception that is being thrown when native Unbound code resulted in an error.
+ *
+ * @author Ingo Bauersachs
+ */
+public class UnboundException
+ extends Exception
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates a new instance of this class.
+ *
+ * @param message the detail message.
+ */
+ public UnboundException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResolver.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResolver.java
new file mode 100644
index 0000000..abeb6ba
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResolver.java
@@ -0,0 +1,384 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.util.*;
+
+import org.xbill.DNS.*;
+
+/**
+ * Implementation of the {@link Resolver} interface, wrapping the native NLnet
+ * Labs Unbound resolver. Only the basic methods for queries are supported.
+ *
+ * @author Ingo Bauersachs
+ */
+public class UnboundResolver
+ implements Resolver
+{
+ private final static Logger logger =
+ Logger.getLogger(UnboundResolver.class);
+
+ /**
+ * Helper class to synchronize on asynchronous queries.
+ */
+ private static class CallbackData
+ {
+ /**
+ * The resolver consumer that wishes to be informed when the request
+ * completed.
+ */
+ ResolverListener listener;
+
+ /**
+ * The unbound session context.
+ */
+ long context;
+
+ /**
+ * The ID of the unbound async query.
+ */
+ int asyncId;
+
+ /**
+ * Java synchronization on top of unbound.
+ */
+ CountDownLatch sync = new CountDownLatch(1);
+ }
+
+ /**
+ * Timeout for DNS queries.
+ */
+ private int timeout = 10000;
+
+ /**
+ * The recursive DNS servers answering our queries.
+ */
+ private String[] forwarders;
+
+ /**
+ * DNSSEC trust anchors for signed zones (usually for the root zone).
+ */
+ private List<String> trustAnchors = new LinkedList<String>();
+
+ /**
+ * Pool that executes our queries.
+ */
+ private ExecutorService threadPool;
+
+ /**
+ * Creates a new instance of this class.
+ */
+ public UnboundResolver()
+ {
+ threadPool = Executors.newCachedThreadPool();
+ }
+
+ /**
+ * Sets a list of forwarders to use instead of the system default.
+ *
+ * @param forwarders list of servers to use for our queries.
+ */
+ public void setForwarders(String[] forwarders)
+ {
+ this.forwarders = forwarders;
+ }
+
+ /**
+ * Adds a DNSSEC trust anchor validation of the DNSKEYs.
+ *
+ * @param anchor trust anchor in the form of
+ * "'zone' IN DS 'key tag' 'algorithm' 'digest type' 'digest'"
+ */
+ public void addTrustAnchor(String anchor)
+ {
+ trustAnchors.add(anchor);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SecureMessage send(final Message query) throws IOException
+ {
+ Future<SecureMessage> future = threadPool.submit(
+ new Callable<SecureMessage>()
+ {
+ public SecureMessage call() throws Exception
+ {
+ if(logger.isDebugEnabled())
+ logger.debug(query);
+
+ SecureMessage secureMessage = null;
+ final long context = prepareContext();
+ try
+ {
+ UnboundResult result = UnboundApi.resolve(
+ context,
+ query.getQuestion().getName().toString(),
+ query.getQuestion().getType(),
+ query.getQuestion().getDClass()
+ );
+ secureMessage = new SecureMessage(result);
+ validateMessage(secureMessage);
+ }
+ finally
+ {
+ UnboundApi.deleteContext(context);
+ if(logger.isDebugEnabled() && secureMessage != null)
+ logger.debug(secureMessage);
+ }
+
+ return secureMessage;
+ }
+ });
+ try
+ {
+ return future.get(timeout, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ logger.error(e);
+ throw new IOException(e.getMessage());
+ }
+ catch (ExecutionException e)
+ {
+ if(e.getCause() instanceof DnssecRuntimeException)
+ throw new DnssecRuntimeException(e.getCause().getMessage());
+ logger.error(e);
+ throw new IOException(e.getMessage());
+ }
+ catch (TimeoutException e)
+ {
+ throw new SocketTimeoutException(e.getMessage());
+ }
+ }
+
+ /**
+ * Method to allow overriders to inspect the message. This class'
+ * implementation does nothing.
+ *
+ * @param msg The message to inspect.
+ * @throws DnssecRuntimeException if the inspector does not want the code to
+ * continue normal processing of the answer.
+ */
+ protected void validateMessage(SecureMessage msg)
+ throws DnssecRuntimeException
+ {
+ }
+
+ /**
+ * Prepares a unbound session context initialized with forwarders and trust
+ * anchors.
+ *
+ * @return The context id
+ */
+ private long prepareContext()
+ {
+ final long context = UnboundApi.createContext();
+ if(logger.isTraceEnabled())
+ UnboundApi.setDebugLevel(context, 100);
+ for(String fwd : forwarders == null
+ ? ResolverConfig.getCurrentConfig().servers()
+ : forwarders)
+ {
+ fwd = fwd.trim();
+ if(NetworkUtils.isValidIPAddress(fwd))
+ {
+ if(fwd.startsWith("["))
+ fwd = fwd.substring(1, fwd.length() - 1);
+ UnboundApi.setForwarder(context, fwd);
+ }
+ }
+ for(String anchor : trustAnchors)
+ {
+ UnboundApi.addTrustAnchor(context, anchor);
+ }
+ return context;
+ }
+
+ /**
+ * Cleans up an Unbound session context.
+ *
+ * @param cbData The helper object of the asynchronous call.
+ * @param cancelAsync Whether an outstanding asynchronous unbound query
+ * should be canceled.
+ */
+ private static synchronized void deleteContext(CallbackData cbData,
+ boolean cancelAsync)
+ {
+ if(cbData.context == 0)
+ return;
+
+ if(cancelAsync)
+ {
+ try
+ {
+ UnboundApi.cancelAsync(cbData.context, cbData.asyncId);
+ }
+ catch (UnboundException ignore)
+ {}
+ }
+ UnboundApi.deleteContext(cbData.context);
+ cbData.context = 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xbill.DNS.Resolver#sendAsync(org.xbill.DNS.Message,
+ * org.xbill.DNS.ResolverListener)
+ */
+ public CallbackData sendAsync(Message query, ResolverListener listener)
+ {
+ if(listener == null)
+ throw new IllegalArgumentException("listener cannot be null");
+
+ final long context = prepareContext();
+ final CallbackData cbData = new CallbackData();
+ cbData.listener = listener;
+ cbData.context = context;
+ int asyncId;
+ try
+ {
+ asyncId = UnboundApi.resolveAsync(
+ context,
+ query.getQuestion().getName().toString(),
+ query.getQuestion().getType(),
+ query.getQuestion().getDClass(),
+ cbData,
+ new UnboundApi.UnboundCallback()
+ {
+ public void UnboundResolveCallback(Object data, int err,
+ UnboundResult result)
+ {
+ CallbackData cbData = (CallbackData)data;
+ deleteContext(cbData, false);
+
+ ResolverListener l = cbData.listener;
+ if(err == 0)
+ {
+ try
+ {
+ l.receiveMessage(data,
+ new SecureMessage(result));
+ }
+ catch (IOException e)
+ {
+ l.handleException(data, e);
+ }
+ }
+ else
+ l.handleException(data,
+ new Exception(
+ UnboundApi.errorCodeToString(err)));
+
+ cbData.sync.countDown();
+ }
+ }
+ );
+ }
+ catch (UnboundException e)
+ {
+ listener.handleException(null, e);
+ return null;
+ }
+ cbData.asyncId = asyncId;
+ threadPool.execute(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ UnboundApi.processAsync(context);
+ }
+ catch(UnboundException ex)
+ {
+ cbData.listener.handleException(this, ex);
+ deleteContext(cbData, false);
+ cbData.sync.countDown();
+ }
+ }
+ });
+ return cbData;
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ public void setEDNS(int level)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ @SuppressWarnings("rawtypes")
+ public void setEDNS(int level, int payloadSize, int flags, List options)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ public void setIgnoreTruncation(boolean flag)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ public void setPort(int port)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ public void setTCP(boolean flag)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ * @throws UnsupportedOperationException
+ */
+ public void setTSIGKey(TSIG key)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see org.xbill.DNS.Resolver#setTimeout(int)
+ */
+ public void setTimeout(int secs)
+ {
+ timeout = secs * 1000;
+ }
+
+ /* (non-Javadoc)
+ * @see org.xbill.DNS.Resolver#setTimeout(int, int)
+ */
+ public void setTimeout(int secs, int msecs)
+ {
+ timeout = secs * 1000 + msecs;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResult.java b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResult.java
new file mode 100644
index 0000000..0be905d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/UnboundResult.java
@@ -0,0 +1,117 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.dns;
+
+/**
+ * Class that contains the answer to query processed by the native Unbound
+ * resolver. Corresponds to the <a
+ * href="http://unbound.net/documentation/doxygen/structub__result.html"
+ * >ub_result</a> data structure.
+ *
+ * The fields {@link #data} and {@link #canonname} are not filled.
+ * <p>
+ * The JavaDoc of these fields is directly copied from libunbound, licensed as
+ * follows:
+ * <p>
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * @author Ingo Bauersachs
+ */
+public class UnboundResult
+{
+ /**
+ * The original question, name text string.
+ */
+ String qname;
+
+ /**
+ * the type asked for
+ */
+ int qtype;
+
+ /**
+ * the type asked for
+ */
+ int qclass;
+
+
+ /**
+ * a list of network order DNS rdata items, terminated with a NULL pointer,
+ * so that data[0] is the first result entry, data[1] the second, and the
+ * last entry is NULL.
+ */
+ byte[][] data;
+
+ /**
+ * canonical name for the result (the final cname).
+ */
+ String canonname;
+
+ /**
+ * DNS RCODE for the result.
+ */
+ int rcode;
+
+ /**
+ * The DNS answer packet.
+ */
+ byte[] answerPacket;
+
+
+ /**
+ * If there is any data, this is true.
+ */
+ boolean haveData;
+
+ /**
+ * If there was no data, and the domain did not exist, this is true.
+ */
+ boolean nxDomain;
+
+ /**
+ * True, if the result is validated securely.
+ */
+ boolean secure;
+
+ /**
+ * If the result was not secure ({@link #secure} == false), and this result
+ * is due to a security failure, bogus is true.
+ */
+ boolean bogus;
+
+ /**
+ * If the result is bogus this contains a string (zero terminated) that
+ * describes the failure.
+ */
+ String whyBogus;
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/dns/desktoputil.dns.manifest.mf b/src/net/java/sip/communicator/plugin/desktoputil/dns/desktoputil.dns.manifest.mf
new file mode 100644
index 0000000..e289126
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/dns/desktoputil.dns.manifest.mf
@@ -0,0 +1,19 @@
+Bundle-Activator: net.java.sip.communicator.plugin.desktoputil.dns.DnsUtilActivator
+Bundle-Name: SIP Communicator DNS Utility Packages
+Bundle-SymbolicName: net.java.sip.communicator.plugin.desktoputil.dns
+Bundle-Description: A bundle that export packages with DNS utility classes.
+Bundle-Vendor: jitsi.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: org.jitsi.util,
+ org.osgi.framework,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.plugin.desktoputil,
+ org.jitsi.service.resources,
+ net.java.sip.communicator.service.resources,
+ org.jitsi.service.configuration,
+ net.java.sip.communicator.service.notification,
+ sun.net.dns,
+ org.xbill.DNS,
+ javax.swing
+Export-Package: net.java.sip.communicator.plugin.desktoputil.dns
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/event/CloseListener.java b/src/net/java/sip/communicator/plugin/desktoputil/event/CloseListener.java
new file mode 100644
index 0000000..a79b99e
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/event/CloseListener.java
@@ -0,0 +1,22 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.event;
+
+/*
+ * The content of this file was based on code borrowed from David Bismut,
+ * davidou@mageos.com Intern, SETLabs, Infosys Technologies Ltd. May 2004 - Jul
+ * 2004 Ecole des Mines de Nantes, France
+ */
+import java.awt.event.*;
+import java.util.*;
+
+/**
+ * @author Yana Stamcheva
+ */
+public interface CloseListener extends EventListener {
+ public void closeOperation(MouseEvent e);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/event/DoubleClickListener.java b/src/net/java/sip/communicator/plugin/desktoputil/event/DoubleClickListener.java
new file mode 100644
index 0000000..8e84bf9
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/event/DoubleClickListener.java
@@ -0,0 +1,22 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.event;
+
+/*
+ * The following code borrowed from David Bismut, davidou@mageos.com Intern,
+ * SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004 Ecole des Mines de
+ * Nantes, France
+ */
+import java.awt.event.*;
+import java.util.*;
+
+/**
+ * @author Yana Stamcheva
+ */
+public interface DoubleClickListener extends EventListener {
+ public void doubleClickOperation(MouseEvent e);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/event/MaxListener.java b/src/net/java/sip/communicator/plugin/desktoputil/event/MaxListener.java
new file mode 100644
index 0000000..e5791e7
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/event/MaxListener.java
@@ -0,0 +1,22 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.event;
+
+/*
+ * The following code borrowed from David Bismut, davidou@mageos.com Intern,
+ * SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004 Ecole des Mines de
+ * Nantes, France
+ */
+import java.awt.event.*;
+import java.util.*;
+
+/**
+ * @author Yana Stamcheva
+ */
+public interface MaxListener extends EventListener {
+ public void maxOperation(MouseEvent e);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/event/PopupOutsideListener.java b/src/net/java/sip/communicator/plugin/desktoputil/event/PopupOutsideListener.java
new file mode 100644
index 0000000..3cbb040
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/event/PopupOutsideListener.java
@@ -0,0 +1,22 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.event;
+
+/*
+ * The following code borrowed from David Bismut, davidou@mageos.com Intern,
+ * SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004 Ecole des Mines de
+ * Nantes, France
+ */
+import java.awt.event.*;
+import java.util.*;
+
+/**
+ * @author Yana Stamcheva
+ */
+public interface PopupOutsideListener extends EventListener {
+ public void popupOutsideOperation(MouseEvent e);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/event/TextFieldChangeListener.java b/src/net/java/sip/communicator/plugin/desktoputil/event/TextFieldChangeListener.java
new file mode 100644
index 0000000..214d5b3
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/event/TextFieldChangeListener.java
@@ -0,0 +1,27 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.event;
+
+/**
+ * The <tt>TextFieldChangeListener</tt> listens for any changes in the text
+ * contained in a <tt>SIPCommTextField</tt>. It is notified every time a char
+ * is inserted or removed from the field.
+ *
+ * @author Yana Stamcheva
+ */
+public interface TextFieldChangeListener
+{
+ /**
+ * Indicates that a text has been removed from the text field.
+ */
+ public void textRemoved();
+
+ /**
+ * Indicates that a text has been inserted to the text field.
+ */
+ public void textInserted();
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommLinkButtonUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommLinkButtonUI.java
new file mode 100644
index 0000000..ce54319
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommLinkButtonUI.java
@@ -0,0 +1,75 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+/**
+ * The SIPCommLinkButtonUI implementation.
+ * @author ROTH Damien
+ */
+public class SIPCommLinkButtonUI
+ extends BasicButtonUI
+{
+ private static final SIPCommLinkButtonUI ui = new SIPCommLinkButtonUI();
+
+ public static ComponentUI createUI(JComponent jcomponent)
+ {
+ return ui;
+ }
+
+ protected void paintText(
+ Graphics g, JComponent com, Rectangle rect, String s)
+ {
+ SIPCommLinkButton bn = (SIPCommLinkButton) com;
+
+ ButtonModel bnModel = bn.getModel();
+ if (bnModel.isEnabled())
+ {
+ if (bnModel.isPressed())
+ bn.setForeground(bn.getActiveLinkColor());
+ else if (bn.isLinkVisited())
+ bn.setForeground(bn.getVisitedLinkColor());
+ else
+ bn.setForeground(bn.getLinkColor());
+ }
+ else
+ {
+ if (bn.getDisabledLinkColor() != null)
+ bn.setForeground(bn.getDisabledLinkColor());
+ }
+
+ super.paintText(g, com, rect, s);
+ int behaviour = bn.getLinkBehavior();
+
+ if (!(behaviour == SIPCommLinkButton.HOVER_UNDERLINE
+ && bnModel.isRollover())
+ && behaviour != SIPCommLinkButton.ALWAYS_UNDERLINE)
+ return;
+
+ FontMetrics fm = g.getFontMetrics();
+ int x = rect.x + getTextShiftOffset();
+ int y = (rect.y + fm.getAscent()
+ + fm.getDescent() + getTextShiftOffset()) - 1;
+ if (bnModel.isEnabled())
+ {
+ g.setColor(bn.getForeground());
+ g.drawLine(x, y, (x + rect.width) - 1, y);
+ }
+ else
+ {
+ g.setColor(bn.getBackground().brighter());
+ g.drawLine(x, y, (x + rect.width) - 1, y);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommMenuBarUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommMenuBarUI.java
new file mode 100644
index 0000000..b3b0727
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommMenuBarUI.java
@@ -0,0 +1,33 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+
+/**
+ * @author Yana Stamcheva
+ */
+public class SIPCommMenuBarUI
+ extends BasicMenuBarUI
+{
+ /**
+ * Creates a new SIPCommMenuUI instance.
+ */
+ public static ComponentUI createUI(JComponent x)
+ {
+ return new SIPCommMenuBarUI();
+ }
+
+ protected void installDefaults()
+ {
+ super.installDefaults();
+
+ LookAndFeel.installProperty(menuBar, "opaque", Boolean.FALSE);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneEnhancedUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneEnhancedUI.java
new file mode 100644
index 0000000..119335b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneEnhancedUI.java
@@ -0,0 +1,477 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+/*
+ * The content of this file was based on code borrowed from David Bismut,
+ * davidou@mageos.com Intern, SETLabs, Infosys Technologies Ltd. May 2004 - Jul
+ * 2004 Ecole des Mines de Nantes, France
+ */
+
+import java.awt.*;
+import java.awt.image.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.text.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+/**
+ * This UI displays a different interface, which is independent from the look
+ * and feel.
+ *
+ * @author David Bismut, davidou@mageos.com
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommTabbedPaneEnhancedUI
+ extends SIPCommTabbedPaneUI
+ implements Skinnable
+{
+ private static Color TAB_HIGHLIGHT_FOREGROUND_COLOR
+ = new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE_HIGHLIGHT"));
+
+ private static Color TAB_SELECTED_FOREGROUND_COLOR
+ = new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE_SELECTED"));
+
+ private static final int TAB_OVERLAP
+ = Integer.parseInt(DesktopUtilActivator.getResources().
+ getSettingsString("impl.gui.TAB_OVERLAP"));
+
+ private static final int PREFERRED_WIDTH = 150;
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a selected tab.
+ */
+ private static final String SELECTED_TAB_LEFT_BG =
+ "service.gui.lookandfeel.SELECTED_TAB_LEFT_BG";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a selected tab.
+ */
+ private static final String SELECTED_TAB_MIDDLE_BG =
+ "service.gui.lookandfeel.SELECTED_TAB_MIDDLE_BG";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a selected tab.
+ */
+ private static final String SELECTED_TAB_RIGHT_BG =
+ "service.gui.lookandfeel.SELECTED_TAB_RIGHT_BG";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a tab.
+ */
+ private static final String TAB_LEFT_BG =
+ "service.gui.lookandfeel.TAB_LEFT_BG";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a tab.
+ */
+ private static final String TAB_MIDDLE_BG =
+ "service.gui.lookandfeel.TAB_MIDDLE_BG";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background
+ * of a tab.
+ */
+ private static final String TAB_RIGHT_BG =
+ "service.gui.lookandfeel.TAB_RIGHT_BG";
+
+ protected final java.util.List<Integer> highlightedTabs
+ = new Vector<Integer>();
+
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new SIPCommTabbedPaneEnhancedUI();
+ }
+
+ protected void paintFocusIndicator(Graphics g, int tabPlacement,
+ Rectangle[] rects, int tabIndex, Rectangle iconRect,
+ Rectangle textRect, boolean isSelected) {}
+
+ /**
+ * Overriden to paint nothing.
+ */
+ protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
+ int x, int y, int w, int h, boolean isSelected) {}
+
+ protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y, int w, int h)
+ {
+ if (tabPane.getTabCount() < 1)
+ return;
+
+ g.setColor(shadow);
+ g.drawLine(x, y, x + w - 2, y);
+ }
+
+ protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y, int w, int h)
+ {
+ if (tabPane.getTabCount() < 1)
+ return;
+
+ g.setColor(shadow);
+
+ g.drawLine(x, y, x, y + h - 3);
+ }
+
+ protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y, int w, int h)
+ {
+ if (tabPane.getTabCount() < 1)
+ return;
+
+ g.setColor(shadow);
+ g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3);
+ g.drawLine(x + 1, y + h - 2, x + w - 2, y + h - 2);
+ g.setColor(shadow.brighter());
+ g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+
+ }
+
+ protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y, int w, int h)
+ {
+ if (tabPane.getTabCount() < 1)
+ return;
+
+ g.setColor(shadow);
+
+ g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 3);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 3);
+ g.setColor(shadow.brighter());
+ g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 2);
+
+ }
+
+ protected void paintTabBackground(Graphics g, int tabPlacement,
+ int tabIndex, int x, int y, int w, int h, boolean isSelected)
+ {
+ g = g.create();
+ try
+ {
+ internalPaintTabBackground(g, tabPlacement, tabIndex, x, y, w, h,
+ isSelected);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ private void internalPaintTabBackground(Graphics g, int tabPlacement,
+ int tabIndex, int x, int y, int w, int h, boolean isSelected)
+ {
+ BufferedImage leftImg = null;
+ BufferedImage middleImg = null;
+ BufferedImage rightImg = null;
+
+ Graphics2D g2 = (Graphics2D) g;
+
+ AntialiasingManager.activateAntialiasing(g2);
+
+ int tabOverlap = 0;
+
+ if (isSelected)
+ {
+ if (tabPane.isEnabledAt(tabIndex))
+ {
+ leftImg = DesktopUtilActivator.getImage(SELECTED_TAB_LEFT_BG);
+ middleImg = DesktopUtilActivator.getImage(SELECTED_TAB_MIDDLE_BG);
+ rightImg = DesktopUtilActivator.getImage(SELECTED_TAB_RIGHT_BG);
+
+ tabOverlap = TAB_OVERLAP;
+ }
+ else
+ {
+ leftImg = DesktopUtilActivator.getImage(TAB_LEFT_BG);
+ middleImg = DesktopUtilActivator.getImage(TAB_MIDDLE_BG);
+ rightImg = DesktopUtilActivator.getImage(TAB_RIGHT_BG);
+ }
+ }
+ else
+ {
+ leftImg = DesktopUtilActivator.getImage(TAB_LEFT_BG);
+ middleImg = DesktopUtilActivator.getImage(TAB_MIDDLE_BG);
+ rightImg = DesktopUtilActivator.getImage(TAB_RIGHT_BG);
+ }
+
+ // Remove the existing gap between the tabs and the panel, which is due
+ // to the removal of the tabbed pane border.
+ y++;
+ // If the current tab is not the selected tab we paint it 2 more pixels
+ // to the bottom in order to create the disabled look.
+ if (!isSelected)
+ y+=2;
+
+ g2.drawImage(leftImg, x, y, null);
+ g2.drawImage(middleImg, x + leftImg.getWidth(), y,
+ w - leftImg.getWidth() - rightImg.getWidth() + tabOverlap,
+ leftImg.getHeight(), null);
+ g2.drawImage(rightImg, x + w - rightImg.getWidth() + tabOverlap, y, null);
+ }
+
+ protected void paintText(Graphics g, int tabPlacement, Font font,
+ FontMetrics metrics, int tabIndex, String title,
+ Rectangle textRect, boolean isSelected)
+ {
+ g.setFont(font);
+
+ int titleWidth = SwingUtilities.computeStringWidth(metrics, title);
+
+ int preferredWidth = 0;
+ if (isOneActionButtonEnabled()) {
+ preferredWidth = calculateTabWidth(tabPlacement, tabIndex, metrics)
+ - WIDTHDELTA - 15;
+
+ if (isCloseEnabled())
+ preferredWidth -= BUTTONSIZE;
+
+ if (isMaxEnabled())
+ preferredWidth -= BUTTONSIZE;
+ }
+ else
+ {
+ preferredWidth = titleWidth;
+ }
+
+ while (titleWidth > preferredWidth)
+ {
+ if (title.endsWith("..."))
+ title = title.substring(0, title.indexOf("...") - 1)
+ .concat("...");
+ else
+ title = title.substring(0, title.length() - 4)
+ .concat("...");
+
+ titleWidth = SwingUtilities.computeStringWidth(metrics, title);
+ }
+
+ textRect.width = titleWidth;
+
+ View v = getTextViewForTab(tabIndex);
+ if (v != null)
+ {
+ // html
+ v.paint(g, textRect);
+ }
+ else
+ {
+ // plain text
+ int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
+
+ if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex))
+ {
+ if (isSelected)
+ g.setColor(TAB_SELECTED_FOREGROUND_COLOR);
+ else
+ {
+ if (this.isTabHighlighted(tabIndex))
+ {
+ g.setColor(TAB_HIGHLIGHT_FOREGROUND_COLOR);
+ }
+ else
+ g.setColor(tabPane.getForegroundAt(tabIndex));
+ }
+
+ BasicGraphicsUtils
+ .drawString(g, title, mnemIndex,
+ textRect.x, textRect.y + metrics.getAscent());
+ }
+ else
+ { // tab disabled
+ g.setColor(tabPane.getBackgroundAt(tabIndex).brighter());
+ BasicGraphicsUtils
+ .drawStringUnderlineCharAt(g, title, mnemIndex,
+ textRect.x, textRect.y + metrics.getAscent());
+
+ g.setColor(tabPane.getBackgroundAt(tabIndex).darker());
+ BasicGraphicsUtils.drawStringUnderlineCharAt(g, title,
+ mnemIndex, textRect.x - 1, textRect.y
+ + metrics.getAscent() - 1);
+ }
+ }
+ }
+
+ protected class ScrollableTabButton extends
+ SIPCommTabbedPaneUI.ScrollableTabButton
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public ScrollableTabButton(int direction)
+ {
+ super(direction);
+ setRolloverEnabled(true);
+ }
+
+ public Dimension getPreferredSize()
+ {
+ return new Dimension(16, calculateMaxTabHeight(0));
+ }
+
+ public void paint(Graphics g)
+ {
+ Color origColor;
+ boolean isPressed, isRollOver, isEnabled;
+ int w, h, size;
+
+ w = getWidth();
+ h = getHeight();
+ origColor = g.getColor();
+ isPressed = getModel().isPressed();
+ isRollOver = getModel().isRollover();
+ isEnabled = isEnabled();
+
+ g.setColor(getBackground());
+ g.fillRect(0, 0, w, h);
+
+ g.setColor(shadow);
+ // Using the background color set above
+ if (direction == WEST) {
+ g.drawLine(0, 0, 0, h - 1); // left
+ g.drawLine(w - 1, 0, w - 1, 0); // right
+ } else
+ g.drawLine(w - 2, h - 1, w - 2, 0); // right
+
+ g.drawLine(0, 0, w - 2, 0); // top
+
+ if (isRollOver)
+ {
+ // do highlights or shadows
+ Color color1;
+ Color color2;
+
+ if (isPressed)
+ {
+ color2 = Color.WHITE;
+ color1 = shadow;
+ }
+ else
+ {
+ color1 = Color.WHITE;
+ color2 = shadow;
+ }
+
+ g.setColor(color1);
+
+ if (direction == WEST) {
+ g.drawLine(1, 1, 1, h - 1); // left
+ g.drawLine(1, 1, w - 2, 1); // top
+ g.setColor(color2);
+ g.drawLine(w - 1, h - 1, w - 1, 1); // right
+ } else {
+ g.drawLine(0, 1, 0, h - 1);
+ g.drawLine(0, 1, w - 3, 1); // top
+ g.setColor(color2);
+ g.drawLine(w - 3, h - 1, w - 3, 1); // right
+ }
+
+ }
+
+ // g.drawLine(0, h - 1, w - 1, h - 1); //bottom
+
+ // If there's no room to draw arrow, bail
+ if (h < 5 || w < 5) {
+ g.setColor(origColor);
+ return;
+ }
+
+ if (isPressed) {
+ g.translate(1, 1);
+ }
+
+ // Draw the arrow
+ size = Math.min((h - 4) / 3, (w - 4) / 3);
+ size = Math.max(size, 2);
+ paintTriangle(g, (w - size) / 2, (h - size) / 2, size, direction,
+ isEnabled);
+
+ // Reset the Graphics back to it's original settings
+ if (isPressed) {
+ g.translate(-1, -1);
+ }
+ g.setColor(origColor);
+
+ }
+
+ }
+
+ protected SIPCommTabbedPaneUI.ScrollableTabButton createScrollableTabButton(
+ int direction)
+ {
+ return new ScrollableTabButton(direction);
+ }
+
+
+ protected int calculateTabWidth(int tabPlacement, int tabIndex,
+ FontMetrics metrics)
+ {
+ int width = super.calculateTabWidth(tabPlacement, tabIndex, metrics);
+
+ if (isOneActionButtonEnabled())
+ {
+ if(width > PREFERRED_WIDTH)
+ width = PREFERRED_WIDTH;
+ }
+
+ return width + WIDTHDELTA;
+ }
+
+ public void tabAddHightlight(int tabIndex)
+ {
+ this.highlightedTabs.add(tabIndex);
+ }
+
+ public void tabRemoveHighlight(int tabIndex)
+ {
+ Iterator<Integer> highlightedIter = highlightedTabs.iterator();
+
+ while (highlightedIter.hasNext())
+ {
+ if (highlightedIter.next().intValue() == tabIndex)
+ {
+ highlightedIter.remove();
+ break;
+ }
+ }
+ }
+
+ public boolean isTabHighlighted(int tabIndex)
+ {
+ return highlightedTabs.contains(tabIndex);
+ }
+
+ /**
+ * Reloads color info.
+ */
+ public void loadSkin()
+ {
+ super.loadSkin();
+
+ TAB_HIGHLIGHT_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE_HIGHLIGHT"));
+
+ TAB_SELECTED_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources()
+ .getColor("service.gui.TAB_TITLE_SELECTED"));
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneUI.java
new file mode 100644
index 0000000..072ff51
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTabbedPaneUI.java
@@ -0,0 +1,1770 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+/*
+ * The content of this file was based on code borrowed from David Bismut,
+ * davidou@mageos.com Intern, SETLabs, Infosys Technologies Ltd. May 2004 - Jul
+ * 2004 Ecole des Mines de Nantes, France
+ */
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.text.*;
+
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+/**
+ * SIPCommTabbedPaneUI implementation.
+ */
+public class SIPCommTabbedPaneUI
+ extends BasicTabbedPaneUI
+ implements Skinnable
+{
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint a close
+ * button on a tab.
+ */
+ private static final String CLOSE_TAB_ICON =
+ "service.gui.lookandfeel.CLOSE_TAB_ICON";
+
+ /**
+ * The image used in the <tt>SIPCommLookAndFeel</tt> to paint a rollover
+ * close button on a tab.
+ */
+ //private static final String CLOSE_TAB_SELECTED_ICON =
+ // "service.gui.lookandfeel.CLOSE_TAB_SELECTED_ICON";
+
+ // Instance variables initialized at installation
+ private ContainerListener containerListener;
+
+ private Vector<View> htmlViews;
+
+ private Map<Integer, Integer> mnemonicToIndexMap;
+
+ /**
+ * InputMap used for mnemonics. Only non-null if the JTabbedPane has
+ * mnemonics associated with it. Lazily created in initMnemonics.
+ */
+ private InputMap mnemonicInputMap;
+
+ // For use when tabLayoutPolicy = SCROLL_TAB_LAYOUT
+ protected ScrollableTabSupport tabScroller;
+
+ private int tabCount;
+
+ protected MyMouseMotionListener motionListener;
+
+ // UI creation
+
+ private static final int INACTIVE = 0;
+
+ private static final int OVER = 1;
+
+ private static final int PRESSED = 2;
+
+ public static final int BUTTONSIZE = 15;
+
+ public static final int WIDTHDELTA = 1;
+
+ private static final Border PRESSEDBORDER = new SoftBevelBorder(
+ SoftBevelBorder.LOWERED);
+
+ private static final Border OVERBORDER = new SoftBevelBorder(
+ SoftBevelBorder.RAISED);
+
+ //private Image closeImgB;
+
+ //private BufferedImage maxImgB;
+
+ private Image closeImgI;
+
+ private BufferedImage maxImgI;
+
+ private int overTabIndex = -1;
+
+ private int closeIndexStatus = INACTIVE;
+
+ private int maxIndexStatus = INACTIVE;
+
+ private boolean mousePressed = false;
+
+ private boolean isCloseButtonEnabled = false;
+
+ private boolean isMaxButtonEnabled = false;
+
+ protected JPopupMenu actionPopupMenu;
+
+ protected JMenuItem maxItem;
+
+ protected JMenuItem closeItem;
+
+ public SIPCommTabbedPaneUI()
+ {
+ //closeImgB = SwingSwingUtilActivator.getImage(CLOSE_TAB_SELECTED_ICON);
+
+ //maxImgB = new BufferedImage(BUTTONSIZE, BUTTONSIZE,
+ // BufferedImage.TYPE_4BYTE_ABGR);
+
+ loadSkin();
+
+ actionPopupMenu = new JPopupMenu();
+
+ maxItem = new JMenuItem("Detach");
+ closeItem = new JMenuItem("Close");
+
+ maxItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ ((SIPCommTabbedPane) tabPane).fireMaxTabEvent(null, tabPane
+ .getSelectedIndex());
+ }
+ });
+
+ closeItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ ((SIPCommTabbedPane) tabPane).fireCloseTabEvent(null, tabPane
+ .getSelectedIndex());
+ }
+ });
+
+ setPopupMenu();
+ }
+
+ protected boolean isOneActionButtonEnabled()
+ {
+ return isCloseButtonEnabled || isMaxButtonEnabled;
+ }
+
+ public boolean isCloseEnabled()
+ {
+ return isCloseButtonEnabled;
+ }
+
+ public boolean isMaxEnabled()
+ {
+ return isMaxButtonEnabled;
+ }
+
+ public void setCloseIcon(boolean b)
+ {
+ isCloseButtonEnabled = b;
+ setPopupMenu();
+ }
+
+ public void setMaxIcon(boolean b)
+ {
+ isMaxButtonEnabled = b;
+ setPopupMenu();
+ }
+
+ private void setPopupMenu()
+ {
+ actionPopupMenu.removeAll();
+ if (isMaxButtonEnabled)
+ actionPopupMenu.add(maxItem);
+ if (isMaxButtonEnabled && isCloseButtonEnabled)
+ actionPopupMenu.addSeparator();
+ if (isCloseButtonEnabled)
+ actionPopupMenu.add(closeItem);
+ }
+
+ protected int calculateTabWidth(int tabPlacement, int tabIndex,
+ FontMetrics metrics)
+ {
+ int delta = 0;
+
+ Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
+
+ if (isOneActionButtonEnabled())
+ {
+ tabInsets.right = 0;
+
+ if (isCloseButtonEnabled)
+ delta += BUTTONSIZE;
+ if (isMaxButtonEnabled)
+ delta += BUTTONSIZE;
+ }
+
+ return super.calculateTabWidth(tabPlacement, tabIndex, metrics) + delta;
+ }
+
+ protected int calculateTabHeight(int tabPlacement, int tabIndex,
+ int fontHeight)
+ {
+ return super.calculateTabHeight(tabPlacement, tabIndex, fontHeight + 4);
+ }
+
+ protected void layoutLabel(int tabPlacement, FontMetrics metrics,
+ int tabIndex, String title, Icon icon, Rectangle tabRect,
+ Rectangle iconRect, Rectangle textRect, boolean isSelected)
+ {
+ textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
+
+ View v = getTextViewForTab(tabIndex);
+ if (v != null) {
+ tabPane.putClientProperty("html", v);
+ }
+
+ SwingUtilities.layoutCompoundLabel((JComponent) tabPane,
+ metrics,
+ title,
+ icon,
+ SwingUtilities.CENTER,
+ SwingUtilities.LEFT,
+ SwingUtilities.CENTER,
+ SwingUtilities.CENTER,
+ tabRect,
+ iconRect,
+ textRect,
+ 0);
+
+ tabPane.putClientProperty("html", null);
+
+ if (icon != null)
+ {
+ iconRect.y = iconRect.y + 2;
+ iconRect.x = tabRect.x + 7;
+ }
+
+ textRect.y = textRect.y + 2;
+
+ if (icon != null)
+ textRect.x = iconRect.x + iconRect.width + 5;
+ else
+ textRect.x = textRect.x + 8;
+ }
+
+ protected MouseListener createMouseListener()
+ {
+ return new MyMouseHandler();
+ }
+
+ protected ScrollableTabButton createScrollableTabButton(int direction)
+ {
+ return new ScrollableTabButton(direction);
+ }
+
+ protected Rectangle newCloseRect(Rectangle rect)
+ {
+ int dx = rect.x + rect.width - BUTTONSIZE - WIDTHDELTA;
+ int dy = rect.y + (rect.height - BUTTONSIZE) / 2 + 2;
+
+ return new Rectangle(dx, dy, BUTTONSIZE, BUTTONSIZE);
+ }
+
+ protected Rectangle newMaxRect(Rectangle rect)
+ {
+ int dx = rect.x + rect.width - BUTTONSIZE - WIDTHDELTA;
+ int dy = rect.y + (rect.height - BUTTONSIZE) / 2 + 2;
+
+ if (isCloseButtonEnabled)
+ dx -= BUTTONSIZE;
+
+ return new Rectangle(dx, dy, BUTTONSIZE, BUTTONSIZE);
+ }
+
+ protected void updateOverTab(int x, int y)
+ {
+ int overTabIndex = getTabAtLocation(x, y);
+ if (this.overTabIndex != overTabIndex)
+ {
+ this.overTabIndex = overTabIndex;
+ tabScroller.tabPanel.repaint();
+ }
+ }
+
+ protected void updateCloseIcon(int x, int y)
+ {
+ if (overTabIndex != -1) {
+ int newCloseIndexStatus = INACTIVE;
+
+ Rectangle closeRect = newCloseRect(rects[overTabIndex]);
+ if (closeRect.contains(x, y))
+ newCloseIndexStatus = mousePressed ? PRESSED : OVER;
+
+ if (closeIndexStatus != newCloseIndexStatus)
+ {
+ closeIndexStatus = newCloseIndexStatus;
+ tabScroller.tabPanel.repaint();
+ }
+ }
+ }
+
+ protected void updateMaxIcon(int x, int y)
+ {
+ if (overTabIndex != -1)
+ {
+ int newMaxIndexStatus = INACTIVE;
+
+ Rectangle maxRect = newMaxRect(rects[overTabIndex]);
+
+ if (maxRect.contains(x, y))
+ newMaxIndexStatus = mousePressed ? PRESSED : OVER;
+
+ if (maxIndexStatus != newMaxIndexStatus)
+ {
+ maxIndexStatus = newMaxIndexStatus;
+ tabScroller.tabPanel.repaint();
+ }
+ }
+ }
+
+ private void setTabIcons(int x, int y)
+ {
+ // if the mouse isPressed
+ if (!mousePressed)
+ updateOverTab(x, y);
+
+ if (isCloseButtonEnabled)
+ updateCloseIcon(x, y);
+ if (isMaxButtonEnabled)
+ updateMaxIcon(x, y);
+ }
+
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new SIPCommTabbedPaneUI();
+ }
+
+ /**
+ * Invoked by <code>installUI</code> to create a layout manager object to
+ * manage the <code>JTabbedPane</code>.
+ *
+ * @return a layout manager object
+ *
+ * @see javax.swing.JTabbedPane#getTabLayoutPolicy
+ */
+ protected LayoutManager createLayoutManager()
+ {
+ return new TabbedPaneScrollLayout();
+ }
+
+ /*
+ * In an attempt to preserve backward compatibility for programs which have
+ * extended BasicTabbedPaneUI to do their own layout, the UI uses the
+ * installed layoutManager (and not tabLayoutPolicy) to determine if
+ * scrollTabLayout is enabled.
+ */
+
+ /**
+ * Creates and installs any required subcomponents for the JTabbedPane.
+ * Invoked by installUI.
+ *
+ * @since 1.4
+ */
+ protected void installComponents()
+ {
+ if (tabScroller == null)
+ {
+ tabScroller = new ScrollableTabSupport(tabPane.getTabPlacement());
+ tabPane.add(tabScroller.viewport);
+ tabPane.add(tabScroller.scrollForwardButton);
+ tabPane.add(tabScroller.scrollBackwardButton);
+ }
+ }
+
+ /**
+ * Removes any installed subcomponents from the JTabbedPane. Invoked by
+ * uninstallUI.
+ *
+ * @since 1.4
+ */
+ protected void uninstallComponents()
+ {
+ tabPane.remove(tabScroller.viewport);
+ tabPane.remove(tabScroller.scrollForwardButton);
+ tabPane.remove(tabScroller.scrollBackwardButton);
+ tabScroller = null;
+ }
+
+ protected void installListeners()
+ {
+ if ((propertyChangeListener = createPropertyChangeListener()) != null)
+ {
+ tabPane.addPropertyChangeListener(propertyChangeListener);
+ }
+ if ((tabChangeListener = createChangeListener()) != null)
+ {
+ tabPane.addChangeListener(tabChangeListener);
+ }
+ if ((mouseListener = createMouseListener()) != null)
+ {
+ tabScroller.tabPanel.addMouseListener(mouseListener);
+ }
+
+ if ((focusListener = createFocusListener()) != null)
+ {
+ tabPane.addFocusListener(focusListener);
+ }
+
+ // PENDING(api) : See comment for ContainerHandler
+ if ((containerListener = new ContainerHandler()) != null)
+ {
+ tabPane.addContainerListener(containerListener);
+ if (tabPane.getTabCount() > 0)
+ {
+ htmlViews = createHTMLVector();
+ }
+ }
+
+ if ((motionListener = new MyMouseMotionListener()) != null)
+ {
+ tabScroller.tabPanel.addMouseMotionListener(motionListener);
+ }
+
+ }
+
+ protected void uninstallListeners()
+ {
+ if (mouseListener != null)
+ {
+ tabScroller.tabPanel.removeMouseListener(mouseListener);
+ mouseListener = null;
+ }
+
+ if (motionListener != null)
+ {
+ tabScroller.tabPanel.removeMouseMotionListener(motionListener);
+ motionListener = null;
+ }
+
+ if (focusListener != null)
+ {
+ tabPane.removeFocusListener(focusListener);
+ focusListener = null;
+ }
+
+ // PENDING(api): See comment for ContainerHandler
+ if (containerListener != null)
+ {
+ tabPane.removeContainerListener(containerListener);
+ containerListener = null;
+ if (htmlViews != null)
+ {
+ htmlViews.removeAllElements();
+ htmlViews = null;
+ }
+ }
+ if (tabChangeListener != null)
+ {
+ tabPane.removeChangeListener(tabChangeListener);
+ tabChangeListener = null;
+ }
+ if (propertyChangeListener != null)
+ {
+ tabPane.removePropertyChangeListener(propertyChangeListener);
+ propertyChangeListener = null;
+ }
+
+ }
+
+ protected ChangeListener createChangeListener()
+ {
+ return new TabSelectionHandler();
+ }
+
+ protected void installKeyboardActions()
+ {
+ InputMap km
+ = getMyInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+
+ SwingUtilities.replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
+ km = getMyInputMap(JComponent.WHEN_FOCUSED);
+ SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, km);
+
+ ActionMap am = createMyActionMap();
+
+ SwingUtilities.replaceUIActionMap(tabPane, am);
+
+ tabScroller.scrollForwardButton.setAction(am
+ .get("scrollTabsForwardAction"));
+ tabScroller.scrollBackwardButton.setAction(am
+ .get("scrollTabsBackwardAction"));
+
+ }
+
+ InputMap getMyInputMap(int condition)
+ {
+ if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
+ {
+ return (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
+ }
+ else if (condition == JComponent.WHEN_FOCUSED)
+ {
+ return (InputMap) UIManager.get("TabbedPane.focusInputMap");
+ }
+ return null;
+ }
+
+ ActionMap createMyActionMap()
+ {
+ ActionMap map = new ActionMapUIResource();
+ map.put("navigateNext", new DirectionAction(NEXT));
+ map.put("navigatePrevious", new DirectionAction(PREVIOUS));
+ map.put("navigateRight", new DirectionAction(EAST));
+ map.put("navigateLeft", new DirectionAction(WEST));
+ map.put("navigateUp", new DirectionAction(NORTH));
+ map.put("navigateDown", new DirectionAction(SOUTH));
+ map.put("navigatePageUp", new PageAction(true));
+ map.put("navigatePageDown", new PageAction(false));
+ map.put("requestFocus", new RequestFocusAction());
+ map.put("requestFocusForVisibleComponent",
+ new RequestFocusForVisibleAction());
+ map.put("setSelectedIndex", new SetSelectedIndexAction());
+ map.put("scrollTabsForwardAction", new ScrollTabsForwardAction());
+ map.put("scrollTabsBackwardAction", new ScrollTabsBackwardAction());
+ return map;
+ }
+
+ protected void uninstallKeyboardActions()
+ {
+ SwingUtilities.replaceUIActionMap(tabPane, null);
+ SwingUtilities.replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities
+ .replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
+ }
+
+ /**
+ * Reloads the mnemonics. This should be invoked when a memonic changes,
+ * when the title of a mnemonic changes, or when tabs are added/removed.
+ */
+ private void updateMnemonics()
+ {
+ resetMnemonics();
+ for (int counter = tabPane.getTabCount() - 1; counter >= 0; counter--)
+ {
+ int mnemonic = tabPane.getMnemonicAt(counter);
+
+ if (mnemonic > 0)
+ {
+ addMnemonic(counter, mnemonic);
+ }
+ }
+ }
+
+ /**
+ * Resets the mnemonics bindings to an empty state.
+ */
+ private void resetMnemonics()
+ {
+ if (mnemonicToIndexMap != null)
+ {
+ mnemonicToIndexMap.clear();
+ mnemonicInputMap.clear();
+ }
+ }
+
+ /**
+ * Adds the specified mnemonic at the specified index.
+ */
+ private void addMnemonic(int index, int mnemonic)
+ {
+ if (mnemonicToIndexMap == null)
+ {
+ initMnemonics();
+ }
+
+ mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK),
+ "setSelectedIndex");
+
+ mnemonicToIndexMap.put(mnemonic, index);
+ }
+
+ /**
+ * Installs the state needed for mnemonics.
+ */
+ private void initMnemonics()
+ {
+ mnemonicToIndexMap = new Hashtable<Integer, Integer>();
+ mnemonicInputMap = new InputMapUIResource();
+ mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
+ SwingUtilities
+ .replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ mnemonicInputMap);
+ }
+
+ // UI Rendering
+
+ public void paint(Graphics g, JComponent c)
+ {
+ int tc = tabPane.getTabCount();
+
+ if (tabCount != tc) {
+ tabCount = tc;
+ updateMnemonics();
+ }
+
+ int selectedIndex = tabPane.getSelectedIndex();
+ int tabPlacement = tabPane.getTabPlacement();
+
+ ensureCurrentLayout();
+
+ // Paint content border
+ paintContentBorder(g, tabPlacement, selectedIndex);
+ }
+
+ protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
+ int tabIndex, Rectangle iconRect, Rectangle textRect)
+ {
+ Rectangle tabRect = rects[tabIndex];
+ int selectedIndex = tabPane.getSelectedIndex();
+ boolean isSelected = selectedIndex == tabIndex;
+ boolean isOver = overTabIndex == tabIndex;
+ Graphics2D g2 = null;
+ Shape save = null;
+ boolean cropShape = false;
+ int cropx = 0;
+ int cropy = 0;
+
+ if (g instanceof Graphics2D)
+ {
+ g2 = (Graphics2D) g;
+
+ AntialiasingManager.activateAntialiasing(g2);
+
+ // Render visual for cropped tab edge...
+ Rectangle viewRect = tabScroller.viewport.getViewRect();
+ int cropline;
+
+ cropline = viewRect.x + viewRect.width;
+ if ((tabRect.x < cropline)
+ && (tabRect.x + tabRect.width > cropline))
+ {
+
+ cropx = cropline - 1;
+ cropy = tabRect.y;
+ cropShape = true;
+ }
+
+ if (cropShape)
+ {
+ save = g2.getClip();
+ g2.clipRect(tabRect.x, tabRect.y, tabRect.width,
+ tabRect.height);
+ }
+ }
+
+ paintTabBackground(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
+ tabRect.width, tabRect.height, isSelected);
+
+ paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
+ tabRect.width, tabRect.height, isSelected);
+
+ String title = tabPane.getTitleAt(tabIndex);
+ Font font = tabPane.getFont();
+ FontMetrics metrics = g.getFontMetrics(font);
+ Icon icon = getIconForTab(tabIndex);
+
+ layoutLabel(tabPlacement, metrics, tabIndex, title, icon, tabRect,
+ iconRect, textRect, isSelected);
+
+ paintText(g, tabPlacement, font, metrics, tabIndex, title, textRect,
+ isSelected);
+
+ paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
+
+ paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect,
+ textRect, isSelected);
+
+ if (cropShape)
+ {
+ paintCroppedTabEdge(g, tabPlacement, tabIndex, isSelected, cropx,
+ cropy);
+ g2.setClip(save);
+ }
+ else if (isOver || isSelected)
+ {
+ Rectangle closeRect = newCloseRect(tabRect);
+
+ int dx = closeRect.x;
+ int dy = closeRect.y;
+
+ if (isCloseButtonEnabled)
+ paintCloseIcon(g2, dx, dy, isOver);
+ if (isMaxButtonEnabled)
+ paintMaxIcon(g2, dx, dy, isOver);
+ }
+
+ }
+
+ protected void paintCloseIcon(Graphics g, int dx, int dy, boolean isOver)
+ {
+ // paintActionButton(g, dx, dy, closeIndexStatus, isOver, closeB,
+ // closeImgB);
+ g.drawImage(closeImgI, dx, dy + 1, null);
+ }
+
+ protected void paintMaxIcon(Graphics g, int dx, int dy, boolean isOver)
+ {
+ if (isCloseButtonEnabled)
+ dx -= BUTTONSIZE;
+
+ // paintActionButton(g, dx, dy, maxIndexStatus, isOver, maxB, maxImgB);
+ g.drawImage(maxImgI, dx, dy + 1, null);
+ }
+
+ protected void paintActionButton(Graphics g, int dx, int dy, int status,
+ boolean isOver, JButton button, Image image)
+ {
+ button.setBorder(null);
+
+ if (isOver) {
+ switch (status) {
+ case OVER:
+ button.setBorder(OVERBORDER);
+ break;
+ case PRESSED:
+ button.setBorder(PRESSEDBORDER);
+ break;
+ }
+ }
+
+ button.setBackground(tabScroller.tabPanel.getBackground());
+ button.paint(image.getGraphics());
+ g.drawImage(image, dx, dy, null);
+ }
+
+ /*
+ * This method will create and return a polygon shape for the given tab
+ * rectangle which has been cropped at the specified cropline with a torn
+ * edge visual. e.g. A "File" tab which has cropped been cropped just after
+ * the "i": ------------- | ..... | | . | | ... . | | . . | | . . | | . . |
+ * --------------
+ *
+ * The x, y arrays below define the pattern used to create a "torn" edge
+ * segment which is repeated to fill the edge of the tab. For tabs placed on
+ * TOP and BOTTOM, this righthand torn edge is created by line segments
+ * which are defined by coordinates obtained by subtracting xCropLen[i] from
+ * (tab.x + tab.width) and adding yCroplen[i] to (tab.y). For tabs placed on
+ * LEFT or RIGHT, the bottom torn edge is created by subtracting xCropLen[i]
+ * from (tab.y + tab.height) and adding yCropLen[i] to (tab.x).
+ */
+
+ //private static final int CROP_SEGMENT = 12;
+
+ private void paintCroppedTabEdge(Graphics g, int tabPlacement,
+ int tabIndex, boolean isSelected, int x, int y)
+ {
+ g.setColor(shadow);
+ g.drawLine(x, y, x, y + rects[tabIndex].height);
+
+ }
+
+ private void ensureCurrentLayout()
+ {
+ if (!tabPane.isValid())
+ {
+ tabPane.validate();
+ }
+ /*
+ * If tabPane doesn't have a peer yet, the validate() call will silently
+ * fail. We handle that by forcing a layout if tabPane is still invalid.
+ * See bug 4237677.
+ */
+ if (!tabPane.isValid())
+ {
+ TabbedPaneLayout layout = (TabbedPaneLayout) tabPane.getLayout();
+ layout.calculateLayoutInfo();
+ }
+ }
+
+ /**
+ * Returns the bounds of the specified tab in the coordinate space of the
+ * JTabbedPane component. This is required because the tab rects are by
+ * default defined in the coordinate space of the component where they are
+ * rendered, which could be the JTabbedPane (for WRAP_TAB_LAYOUT) or a
+ * ScrollableTabPanel (SCROLL_TAB_LAYOUT). This method should be used
+ * whenever the tab rectangle must be relative to the JTabbedPane itself and
+ * the result should be placed in a designated Rectangle object (rather than
+ * instantiating and returning a new Rectangle each time). The tab index
+ * parameter must be a valid tabbed pane tab index (0 to tab count - 1,
+ * inclusive). The destination rectangle parameter must be a valid
+ * <code>Rectangle</code> instance. The handling of invalid parameters is
+ * unspecified.
+ *
+ * @param tabIndex
+ * the index of the tab
+ * @param dest
+ * the rectangle where the result should be placed
+ * @return the resulting rectangle
+ *
+ * @since 1.4
+ */
+
+ protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
+ {
+ dest.width = rects[tabIndex].width;
+ dest.height = rects[tabIndex].height;
+
+ Point vpp = tabScroller.viewport.getLocation();
+ Point viewp = tabScroller.viewport.getViewPosition();
+ dest.x = rects[tabIndex].x + vpp.x - viewp.x;
+ dest.y = rects[tabIndex].y + vpp.y - viewp.y;
+
+ return dest;
+ }
+
+ private int getTabAtLocation(int x, int y)
+ {
+ ensureCurrentLayout();
+
+ int tabCount = tabPane.getTabCount();
+ for (int i = 0; i < tabCount; i++)
+ {
+ if (rects[i].contains(x, y))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int getOverTabIndex()
+ {
+ return overTabIndex;
+ }
+
+ /**
+ * Returns the index of the tab closest to the passed in location, note that
+ * the returned tab may not contain the location x,y.
+ */
+ private int getClosestTab(int x, int y)
+ {
+ int min = 0;
+ int tabCount = Math.min(rects.length, tabPane.getTabCount());
+ int max = tabCount;
+ int tabPlacement = tabPane.getTabPlacement();
+ boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM);
+ int want = (useX) ? x : y;
+
+ while (min != max)
+ {
+ int current = (max + min) / 2;
+ int minLoc;
+ int maxLoc;
+
+ if (useX)
+ {
+ minLoc = rects[current].x;
+ maxLoc = minLoc + rects[current].width;
+ }
+ else
+ {
+ minLoc = rects[current].y;
+ maxLoc = minLoc + rects[current].height;
+ }
+ if (want < minLoc)
+ {
+ max = current;
+ if (min == max)
+ {
+ return Math.max(0, current - 1);
+ }
+ }
+ else if (want >= maxLoc)
+ {
+ min = current;
+ if (max - min <= 1)
+ {
+ return Math.max(current + 1, tabCount - 1);
+ }
+ }
+ else
+ {
+ return current;
+ }
+ }
+ return min;
+ }
+
+ /**
+ * Returns a point which is translated from the specified point in the
+ * JTabbedPane's coordinate space to the coordinate space of the
+ * ScrollableTabPanel. This is used for SCROLL_TAB_LAYOUT ONLY.
+ */
+ private Point translatePointToTabPanel(int srcx, int srcy, Point dest)
+ {
+ Point vpp = tabScroller.viewport.getLocation();
+ Point viewp = tabScroller.viewport.getViewPosition();
+ dest.x = srcx + vpp.x + viewp.x;
+ dest.y = srcy + vpp.y + viewp.y;
+ return dest;
+ }
+
+ // BasicTabbedPaneUI methods
+
+ // Tab Navigation methods
+
+ // REMIND(aim,7/29/98): This method should be made
+ // protected in the next release where
+ // API changes are allowed
+ //
+ boolean requestMyFocusForVisibleComponent()
+ {
+ Component visibleComponent = getVisibleComponent();
+ if (visibleComponent.isFocusable())
+ {
+ visibleComponent.requestFocus();
+ return true;
+ }
+ else if (visibleComponent instanceof JComponent)
+ {
+ if (((JComponent) visibleComponent).requestFocusInWindow())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static class DirectionAction
+ extends AbstractAction
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private final int direction;
+
+ public DirectionAction(int direction)
+ {
+ this.direction = direction;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = (JTabbedPane) e.getSource();
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+ ui.navigateSelectedTab(direction);
+ }
+ };
+
+ private static class PageAction
+ extends AbstractAction
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private final boolean up;
+
+ public PageAction(boolean up)
+ {
+ this.up = up;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = (JTabbedPane) e.getSource();
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+ int tabPlacement = pane.getTabPlacement();
+ if (tabPlacement == TOP || tabPlacement == BOTTOM)
+ {
+ ui.navigateSelectedTab(up ? WEST : EAST);
+ }
+ else
+ {
+ ui.navigateSelectedTab(up ? NORTH : SOUTH);
+ }
+ }
+ };
+
+ private static class RequestFocusAction
+ extends AbstractAction
+ {
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = (JTabbedPane) e.getSource();
+ pane.requestFocus();
+ }
+ };
+
+ private static class RequestFocusForVisibleAction
+ extends AbstractAction
+ {
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = (JTabbedPane) e.getSource();
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+ ui.requestMyFocusForVisibleComponent();
+ }
+ };
+
+ /**
+ * Selects a tab in the JTabbedPane based on the String of the action
+ * command. The tab selected is based on the first tab that has a mnemonic
+ * matching the first character of the action command.
+ */
+ private static class SetSelectedIndexAction
+ extends AbstractAction
+ {
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = (JTabbedPane) e.getSource();
+
+ if (pane != null && (pane.getUI() instanceof SIPCommTabbedPaneUI))
+ {
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+ String command = e.getActionCommand();
+
+ if (command != null && command.length() > 0)
+ {
+ int mnemonic = e.getActionCommand().charAt(0);
+ if (mnemonic >= 'a' && mnemonic <= 'z')
+ {
+ mnemonic -= ('a' - 'A');
+ }
+
+ Integer index = ui.mnemonicToIndexMap.get(mnemonic);
+ if (index != null && pane.isEnabledAt(index.intValue()))
+ {
+ pane.setSelectedIndex(index.intValue());
+ }
+ }
+ }
+ }
+ };
+
+ private static class ScrollTabsForwardAction
+ extends AbstractAction
+ {
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = null;
+ Object src = e.getSource();
+ if (src instanceof JTabbedPane)
+ {
+ pane = (JTabbedPane) src;
+ }
+ else if (src instanceof ScrollableTabButton)
+ {
+ pane = (JTabbedPane) ((ScrollableTabButton) src).getParent();
+ }
+ else
+ {
+ return; // shouldn't happen
+ }
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+
+ ui.tabScroller.scrollForward(pane.getTabPlacement());
+ }
+ }
+
+ private static class ScrollTabsBackwardAction
+ extends AbstractAction
+ {
+ private static final long serialVersionUID = 0L;
+
+ public void actionPerformed(ActionEvent e)
+ {
+ JTabbedPane pane = null;
+ Object src = e.getSource();
+ if (src instanceof JTabbedPane)
+ {
+ pane = (JTabbedPane) src;
+ }
+ else if (src instanceof ScrollableTabButton)
+ {
+ pane = (JTabbedPane) ((ScrollableTabButton) src).getParent();
+ }
+ else
+ {
+ return; // shouldn't happen
+ }
+ SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) pane.getUI();
+
+ ui.tabScroller.scrollBackward(pane.getTabPlacement());
+ }
+ }
+
+ /**
+ * This inner class is marked &quot;public&quot; due to a compiler bug. This
+ * class should be treated as a &quot;protected&quot; inner class.
+ * Instantiate it only within subclasses of BasicTabbedPaneUI.
+ */
+ private class TabbedPaneScrollLayout
+ extends TabbedPaneLayout
+ {
+
+ protected int preferredTabAreaHeight(int tabPlacement, int width)
+ {
+ return calculateMaxTabHeight(tabPlacement);
+ }
+
+ protected int preferredTabAreaWidth(int tabPlacement, int height)
+ {
+ return calculateMaxTabWidth(tabPlacement);
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ int tabPlacement = tabPane.getTabPlacement();
+ int tabCount = tabPane.getTabCount();
+ Insets insets = tabPane.getInsets();
+ int selectedIndex = tabPane.getSelectedIndex();
+ Component visibleComponent = getVisibleComponent();
+
+ calculateLayoutInfo();
+
+ if (selectedIndex < 0)
+ {
+ if (visibleComponent != null)
+ {
+ // The last tab was removed, so remove the component
+ setVisibleComponent(null);
+ }
+ }
+ else
+ {
+ Component selectedComponent =
+ tabPane.getComponentAt(selectedIndex);
+ boolean shouldChangeFocus = false;
+
+ // In order to allow programs to use a single component
+ // as the display for multiple tabs, we will not change
+ // the visible component if the currently selected tab
+ // has a null component. This is a bit dicey, as we don't
+ // explicitly state we support this in the spec, but since
+ // programs are now depending on this, we're making it work.
+ //
+ if (selectedComponent != null)
+ {
+ if (selectedComponent != visibleComponent
+ && visibleComponent != null)
+ {
+ if (KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .getFocusOwner() != null)
+ {
+ shouldChangeFocus = true;
+ }
+ }
+ setVisibleComponent(selectedComponent);
+ }
+ int tx, ty, tw, th; // tab area bounds
+ int cx, cy, cw, ch; // content area bounds
+ Insets contentInsets = getContentBorderInsets(tabPlacement);
+ Rectangle bounds = tabPane.getBounds();
+ int numChildren = tabPane.getComponentCount();
+
+ if (numChildren > 0)
+ {
+
+ // calculate tab area bounds
+ tw = bounds.width - insets.left - insets.right;
+ th =
+ calculateTabAreaHeight(tabPlacement, runCount,
+ maxTabHeight);
+ tx = insets.left;
+ ty = insets.top;
+
+ // calculate content area bounds
+ cx = tx + contentInsets.left;
+ cy = ty + th + contentInsets.top;
+ cw =
+ bounds.width - insets.left - insets.right
+ - contentInsets.left - contentInsets.right;
+ ch =
+ bounds.height - insets.top - insets.bottom - th
+ - contentInsets.top - contentInsets.bottom;
+
+ for (int i = 0; i < numChildren; i++)
+ {
+ Component child = tabPane.getComponent(i);
+
+ if (child instanceof ScrollableTabViewport)
+ {
+ JViewport viewport = (JViewport) child;
+ Rectangle viewRect = viewport.getViewRect();
+ int vw = tw;
+ int vh = th;
+
+ int totalTabWidth =
+ rects[tabCount - 1].x
+ + rects[tabCount - 1].width;
+ if (totalTabWidth > tw)
+ {
+ // Need to allow space for scrollbuttons
+ vw = Math.max(tw - 36, 36);
+ ;
+ if (totalTabWidth - viewRect.x <= vw)
+ {
+ // Scrolled to the end, so ensure the
+ // viewport size is
+ // such that the scroll offset aligns with a
+ // tab
+ vw = totalTabWidth - viewRect.x;
+ }
+ }
+
+ child.setBounds(tx, ty, vw, vh);
+
+ }
+ else if (child instanceof ScrollableTabButton)
+ {
+ ScrollableTabButton scrollbutton =
+ (ScrollableTabButton) child;
+ Dimension bsize = scrollbutton.getPreferredSize();
+ int bx = 0;
+ int by = 0;
+ int bw = bsize.width;
+ int bh = bsize.height;
+ boolean visible = false;
+
+ int totalTabWidth =
+ rects[tabCount - 1].x
+ + rects[tabCount - 1].width;
+
+ if (totalTabWidth > tw)
+ {
+ int dir =
+ scrollbutton.scrollsForward() ? EAST : WEST;
+ scrollbutton.setDirection(dir);
+ visible = true;
+ bx =
+ dir == EAST ? bounds.width - insets.left
+ - bsize.width : bounds.width
+ - insets.left - 2 * bsize.width;
+ by =
+ (tabPlacement == TOP ? ty + th
+ - bsize.height : ty);
+ }
+
+ child.setVisible(visible);
+ if (visible)
+ {
+ child.setBounds(bx, by, bw, bh);
+ }
+
+ }
+ else
+ {
+ // All content children...
+ child.setBounds(cx, cy, cw, ch);
+ }
+ }
+ if (shouldChangeFocus)
+ {
+ if (!requestMyFocusForVisibleComponent())
+ {
+ tabPane.requestFocus();
+ }
+ }
+ }
+ }
+ }
+
+ protected void calculateTabRects(int tabPlacement, int tabCount)
+ {
+ FontMetrics metrics = getFontMetrics();;
+ Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+ int i;
+
+ int x = tabAreaInsets.left - 2;
+ int y = tabAreaInsets.top;
+ int totalWidth = 0;
+ int totalHeight = 0;
+
+ //
+ // Calculate bounds within which a tab run must fit
+ //
+ maxTabHeight = calculateMaxTabHeight(tabPlacement);
+
+ runCount = 0;
+ selectedRun = -1;
+
+ if (tabCount == 0)
+ return;
+
+ selectedRun = 0;
+ runCount = 1;
+
+ // Run through tabs and lay them out in a single run
+ Rectangle rect;
+ for (i = 0; i < tabCount; i++)
+ {
+ rect = rects[i];
+
+ if (i > 0)
+ {
+ rect.x = rects[i - 1].x + rects[i - 1].width - 1;
+ }
+ else
+ {
+ tabRuns[0] = 0;
+ maxTabWidth = 0;
+ totalHeight += maxTabHeight;
+ rect.x = x;
+ }
+ rect.width = calculateTabWidth(tabPlacement, i, metrics);
+ totalWidth = rect.x + rect.width;
+ maxTabWidth = Math.max(maxTabWidth, rect.width);
+
+ rect.y = y;
+ rect.height = maxTabHeight /* - 2 */;
+ }
+
+ // tabPanel.setSize(totalWidth, totalHeight);
+ tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth,
+ totalHeight));
+ }
+ }
+
+ private class ScrollableTabSupport implements ChangeListener
+ {
+ public ScrollableTabViewport viewport;
+
+ public ScrollableTabPanel tabPanel;
+
+ public ScrollableTabButton scrollForwardButton;
+
+ public ScrollableTabButton scrollBackwardButton;
+
+ public int leadingTabIndex;
+
+ private Point tabViewPosition = new Point(0, 0);
+
+ ScrollableTabSupport(int tabPlacement)
+ {
+ viewport = new ScrollableTabViewport();
+ tabPanel = new ScrollableTabPanel();
+ viewport.setView(tabPanel);
+ viewport.addChangeListener(this);
+
+ scrollForwardButton = createScrollableTabButton(EAST);
+ scrollBackwardButton = createScrollableTabButton(WEST);
+ // scrollForwardButton = new ScrollableTabButton(EAST);
+ // scrollBackwardButton = new ScrollableTabButton(WEST);
+ }
+
+ public void scrollForward(int tabPlacement)
+ {
+ Dimension viewSize = viewport.getViewSize();
+ Rectangle viewRect = viewport.getViewRect();
+
+ if (tabPlacement == TOP || tabPlacement == BOTTOM)
+ {
+ if (viewRect.width >= viewSize.width - viewRect.x)
+ return; // no room left to scroll
+ }
+ else
+ { // tabPlacement == LEFT || tabPlacement == RIGHT
+ if (viewRect.height >= viewSize.height - viewRect.y)
+ return;
+ }
+ setLeadingTabIndex(tabPlacement, leadingTabIndex + 1);
+ }
+
+ public void scrollBackward(int tabPlacement)
+ {
+ if (leadingTabIndex == 0)
+ return; // no room left to scroll
+
+ setLeadingTabIndex(tabPlacement, leadingTabIndex - 1);
+ }
+
+ public void setLeadingTabIndex(int tabPlacement, int index)
+ {
+ leadingTabIndex = index;
+ Dimension viewSize = viewport.getViewSize();
+ Rectangle viewRect = viewport.getViewRect();
+
+ tabViewPosition.x = leadingTabIndex == 0 ? 0
+ : rects[leadingTabIndex].x;
+
+ if ((viewSize.width - tabViewPosition.x) < viewRect.width)
+ {
+ // We've scrolled to the end, so adjust the viewport size
+ // to ensure the view position remains aligned on a tab boundary
+ Dimension extentSize = new Dimension(viewSize.width
+ - tabViewPosition.x, viewRect.height);
+ viewport.setExtentSize(extentSize);
+ }
+
+ viewport.setViewPosition(tabViewPosition);
+ }
+
+ public void stateChanged(ChangeEvent e)
+ {
+ JViewport viewport = (JViewport) e.getSource();
+ int tabPlacement = tabPane.getTabPlacement();
+ int tabCount = tabPane.getTabCount();
+ Rectangle vpRect = viewport.getBounds();
+ Dimension viewSize = viewport.getViewSize();
+ Rectangle viewRect = viewport.getViewRect();
+
+ leadingTabIndex = getClosestTab(viewRect.x, viewRect.y);
+
+ // If the tab isn't right aligned, adjust it.
+ if (leadingTabIndex + 1 < tabCount)
+ {
+
+ if (rects[leadingTabIndex].x < viewRect.x)
+ leadingTabIndex++;
+ }
+ Insets contentInsets = getContentBorderInsets(tabPlacement);
+
+ tabPane.repaint(vpRect.x, vpRect.y + vpRect.height, vpRect.width,
+ contentInsets.top);
+ scrollBackwardButton.setEnabled(viewRect.x > 0);
+ scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1
+ && viewSize.width - viewRect.x > viewRect.width);
+
+ }
+
+ public String toString()
+ {
+ return new String("viewport.viewSize=" + viewport.getViewSize()
+ + "\n" + "viewport.viewRectangle=" + viewport.getViewRect()
+ + "\n" + "leadingTabIndex=" + leadingTabIndex + "\n"
+ + "tabViewPosition=" + tabViewPosition);
+ }
+
+ }
+
+ private static class ScrollableTabViewport
+ extends JViewport
+ implements UIResource
+ {
+ private static final long serialVersionUID = 0L;
+
+ public ScrollableTabViewport()
+ {
+ setOpaque(false);
+ setScrollMode(SIMPLE_SCROLL_MODE);
+ }
+ }
+
+ private class ScrollableTabPanel
+ extends TransparentPanel
+ implements UIResource
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ public ScrollableTabPanel()
+ {
+ setLayout(null);
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ SIPCommTabbedPaneUI.this.paintTabArea(g, tabPane.getTabPlacement(),
+ tabPane.getSelectedIndex());
+ }
+ }
+
+ protected static class ScrollableTabButton
+ extends BasicArrowButton
+ implements UIResource, SwingConstants
+ {
+ private static final long serialVersionUID = 0L;
+
+ public ScrollableTabButton(int direction)
+ {
+ super(direction, UIManager.getColor("TabbedPane.selected"),
+ UIManager.getColor("TabbedPane.shadow"), UIManager
+ .getColor("TabbedPane.darkShadow"), UIManager
+ .getColor("TabbedPane.highlight"));
+ }
+
+ public boolean scrollsForward()
+ {
+ return direction == EAST || direction == SOUTH;
+ }
+ }
+
+ /**
+ * This inner class is marked &quot;public&quot; due to a compiler bug. This
+ * class should be treated as a &quot;protected&quot; inner class.
+ * Instantiate it only within subclasses of BasicTabbedPaneUI.
+ */
+ private class TabSelectionHandler implements ChangeListener
+ {
+ public void stateChanged(ChangeEvent e)
+ {
+ JTabbedPane tabPane = (JTabbedPane) e.getSource();
+ tabPane.revalidate();
+ tabPane.repaint();
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ {
+ int index = tabPane.getSelectedIndex();
+
+ if (index < rects.length && index != -1)
+ tabScroller.tabPanel.scrollRectToVisible(rects[index]);
+ }
+ }
+ }
+
+ /**
+ * This inner class is marked &quot;public&quot; due to a compiler bug. This
+ * class should be treated as a &quot;protected&quot; inner class.
+ * Instantiate it only within subclasses of BasicTabbedPaneUI.
+ */
+
+ /*
+ * GES 2/3/99: The container listener code was added to support HTML
+ * rendering of tab titles.
+ *
+ * Ideally, we would be able to listen for property changes when a tab is
+ * added or its text modified. At the moment there are no such events
+ * because the Beans spec doesn't allow 'indexed' property changes (i.e. tab
+ * 2's text changed from A to B).
+ *
+ * In order to get around this, we listen for tabs to be added or removed by
+ * listening for the container events. we then queue up a runnable (so the
+ * component has a chance to complete the add) which checks the tab title of
+ * the new component to see if it requires HTML rendering.
+ *
+ * The Views (one per tab title requiring HTML rendering) are stored in the
+ * htmlViews Vector, which is only allocated after the first time we run
+ * into an HTML tab. Note that this vector is kept in step with the number
+ * of pages, and nulls are added for those pages whose tab title do not
+ * require HTML rendering.
+ *
+ * This makes it easy for the paint and layout code to tell whether to
+ * invoke the HTML engine without having to check the string during
+ * time-sensitive operations.
+ *
+ * When we have added a way to listen for tab additions and changes to tab
+ * text, this code should be removed and replaced by something which uses
+ * that.
+ */
+ private class ContainerHandler implements ContainerListener
+ {
+ public void componentAdded(ContainerEvent e)
+ {
+ JTabbedPane tp = (JTabbedPane) e.getContainer();
+ Component child = e.getChild();
+ if (child instanceof UIResource)
+ return;
+
+ int index = tp.indexOfComponent(child);
+ String title = tp.getTitleAt(index);
+
+ boolean isHTML = BasicHTML.isHTMLString(title);
+ if (isHTML)
+ {
+ if (htmlViews == null)
+ { // Initialize vector
+ htmlViews = createHTMLVector();
+ }
+ else
+ { // Vector already exists
+ View v = BasicHTML.createHTMLView(tp, title);
+ htmlViews.insertElementAt(v, index);
+ }
+ }
+ else
+ { // Not HTML
+ if (htmlViews != null)
+ { // Add placeholder
+ htmlViews.insertElementAt(null, index);
+ } // else nada!
+ }
+ }
+
+ public void componentRemoved(ContainerEvent e)
+ {
+ JTabbedPane tp = (JTabbedPane) e.getContainer();
+ Component child = e.getChild();
+ if (child instanceof UIResource)
+ return;
+
+ // NOTE 4/15/2002 (joutwate):
+ // This fix is implemented using client properties since there is
+ // currently no IndexPropertyChangeEvent. Once
+ // IndexPropertyChangeEvents have been added this code should be
+ // modified to use it.
+ Integer indexObj = (Integer) tp
+ .getClientProperty("__index_to_remove__");
+ if (indexObj != null)
+ {
+ int index = indexObj.intValue();
+ if (htmlViews != null && htmlViews.size() >= index)
+ {
+ htmlViews.removeElementAt(index);
+ }
+ }
+ }
+ }
+
+ private Vector<View> createHTMLVector()
+ {
+ Vector<View> htmlViews = new Vector<View>();
+ int count = tabPane.getTabCount();
+ if (count > 0) {
+ for (int i = 0; i < count; i++)
+ {
+ String title = tabPane.getTitleAt(i);
+ if (BasicHTML.isHTMLString(title))
+ {
+ htmlViews.addElement(BasicHTML.createHTMLView(tabPane,
+ title));
+ }
+ else
+ {
+ htmlViews.addElement(null);
+ }
+ }
+ }
+ return htmlViews;
+ }
+
+ private class MyMouseHandler extends MouseHandler
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ if (closeIndexStatus == OVER)
+ {
+ closeIndexStatus = PRESSED;
+ tabScroller.tabPanel.repaint();
+ }
+ else if (maxIndexStatus == OVER)
+ {
+ maxIndexStatus = PRESSED;
+ tabScroller.tabPanel.repaint();
+ }
+ else
+ {
+ super.mousePressed(e);
+ }
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() > 1 && overTabIndex != -1)
+ {
+ ((SIPCommTabbedPane) tabPane).fireDoubleClickTabEvent(e,
+ overTabIndex);
+ }
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ updateOverTab(e.getX(), e.getY());
+
+ if (overTabIndex == -1) {
+ if (e.isPopupTrigger())
+ ((SIPCommTabbedPane) tabPane).firePopupOutsideTabEvent(e);
+ return;
+ }
+
+ if (isOneActionButtonEnabled() && e.isPopupTrigger())
+ {
+ super.mousePressed(e);
+
+ closeIndexStatus = INACTIVE; // Prevent undesired action when
+ maxIndexStatus = INACTIVE; // right-clicking on icons
+
+ actionPopupMenu.show(tabScroller.tabPanel, e.getX(), e.getY());
+ return;
+ }
+
+ if (closeIndexStatus == PRESSED)
+ {
+ closeIndexStatus = OVER;
+ tabScroller.tabPanel.repaint();
+ ((SIPCommTabbedPane) tabPane)
+ .fireCloseTabEvent(e, overTabIndex);
+ return;
+ }
+
+ if (maxIndexStatus == PRESSED)
+ {
+ maxIndexStatus = OVER;
+ tabScroller.tabPanel.repaint();
+ ((SIPCommTabbedPane) tabPane).fireMaxTabEvent(e, overTabIndex);
+ return;
+ }
+
+ // Allow tabs closing with mouse middle button
+ if (e.getButton() == MouseEvent.BUTTON2)
+ ((SIPCommTabbedPane) tabPane).fireCloseTabEvent(e, overTabIndex);
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ if (!mousePressed)
+ {
+ overTabIndex = -1;
+ tabScroller.tabPanel.repaint();
+ }
+ }
+
+ }
+
+ private class MyMouseMotionListener
+ implements MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ if (actionPopupMenu.isVisible())
+ return; // No updates when popup is visible
+ mousePressed = false;
+ setTabIcons(e.getX(), e.getY());
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ if (actionPopupMenu.isVisible())
+ return; // No updates when popup is visible
+ mousePressed = true;
+ setTabIcons(e.getX(), e.getY());
+ }
+ }
+
+ /**
+ * We don't want to have a content border.
+ */
+ protected void paintContentBorder( Graphics g,
+ int tabPlacement,
+ int selectedIndex)
+ {}
+
+ /**
+ * Reloads close icon.
+ */
+ public void loadSkin()
+ {
+ closeImgI = DesktopUtilActivator.getImage(CLOSE_TAB_ICON);
+
+ maxImgI = new BufferedImage(BUTTONSIZE, BUTTONSIZE,
+ BufferedImage.TYPE_4BYTE_ABGR);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTextFieldUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTextFieldUI.java
new file mode 100644
index 0000000..ce4c56f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTextFieldUI.java
@@ -0,0 +1,513 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.metal.*;
+import javax.swing.text.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.util.skin.*;
+
+/**
+ * SIPCommTextFieldUI implementation.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ */
+public class SIPCommTextFieldUI
+ extends MetalTextFieldUI
+ implements Skinnable,
+ MouseMotionListener,
+ MouseListener
+{
+ /**
+ * Indicates if the mouse is currently over the delete button.
+ */
+ protected boolean isDeleteMouseOver = false;
+
+ /**
+ * Indicates if the mouse is currently pressed on the delete button.
+ */
+ protected boolean isDeleteMousePressed = false;
+
+ /**
+ * The gap between the delete button and the text in the field.
+ */
+ protected static int BUTTON_GAP = 5;
+
+ /**
+ * The image of the delete text button.
+ */
+ private Image deleteButtonImg;
+
+ /**
+ * The rollover image of the delete text button.
+ */
+ private Image deleteButtonRolloverImg;
+
+ /**
+ * The image for the pressed state of the delete text button.
+ */
+ private Image deleteButtonPressedImg;
+
+ /**
+ * Indicates if the text field contains a
+ * delete button allowing to delete all the content at once.
+ */
+ private boolean isDeleteButtonEnabled = false;
+
+ /**
+ * The delete text button shown on the right of the field.
+ */
+ protected SIPCommButton deleteButton;
+
+ /**
+ * Indicates if the delete icon is visible.
+ */
+ private boolean isDeleteIconVisible = false;
+
+ /**
+ * The start background gradient color.
+ */
+ private Color bgStartColor
+ = new Color(DesktopUtilActivator.getResources().getColor(
+ "service.gui.SEARCH_BACKGROUND"));
+
+ /**
+ * The end background gradient color.
+ */
+ private Color bgEndColor
+ = new Color(DesktopUtilActivator.getResources().getColor(
+ "service.gui.SEARCH_GRADIENT"));
+
+ /**
+ * The start background gradient color.
+ */
+ private Color bgBorderStartColor
+ = new Color(DesktopUtilActivator.getResources().getColor(
+ "service.gui.SEARCH_BORDER"));
+
+ /**
+ * The end background gradient color.
+ */
+ private Color bgBorderEndColor
+ = new Color(DesktopUtilActivator.getResources().getColor(
+ "service.gui.SEARCH_BORDER_GRADIENT"));
+
+ /**
+ * Creates a <tt>SIPCommTextFieldUI</tt>.
+ */
+ public SIPCommTextFieldUI()
+ {
+ loadSkin();
+ }
+
+ /**
+ * Returns <code>true</code> if the delete buttons is enabled and false -
+ * otherwise.
+ * @return <code>true</code> if the delete buttons is enabled and false -
+ * otherwise
+ */
+ public boolean isDeleteButtonEnabled()
+ {
+ return isDeleteButtonEnabled;
+ }
+
+ /**
+ * Updates the isDeleteButtonEnabled field.
+ *
+ * @param isDeleteButtonEnabled indicates if the delete buttons is enabled
+ * or not
+ */
+ public void setDeleteButtonEnabled(boolean isDeleteButtonEnabled)
+ {
+ this.isDeleteButtonEnabled = isDeleteButtonEnabled;
+ }
+
+ /**
+ * Adds the custom mouse listeners defined in this class to the installed
+ * listeners.
+ */
+ protected void installListeners()
+ {
+ super.installListeners();
+
+ getComponent().addMouseListener(this);
+
+ getComponent().addMouseMotionListener(this);
+ }
+
+ /**
+ * Uninstalls listeners for the UI.
+ */
+ protected void uninstallListeners()
+ {
+ super.uninstallListeners();
+
+ getComponent().removeMouseListener(this);
+ getComponent().removeMouseMotionListener(this);
+ }
+
+ /**
+ * Paints the background of the associated component.
+ * @param g the <tt>Graphics</tt> object used for painting
+ */
+ protected void customPaintBackground(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g.create();
+
+ try
+ {
+ String roundedSet = DesktopUtilActivator.getResources().
+ getSettingsString(
+ "impl.gui.IS_SIP_COMM_TEXT_FIELD_ROUNDED");
+
+ boolean isRounded = true;
+
+ if(roundedSet != null)
+ {
+ isRounded = new Boolean(roundedSet)
+ .booleanValue();
+ }
+
+ AntialiasingManager.activateAntialiasing(g2);
+ JTextComponent c = this.getComponent();
+
+ GradientPaint bgGradientColor =
+ new GradientPaint( c.getWidth() / 2, 0,
+ bgStartColor,
+ c.getWidth() / 2, c.getHeight(),
+ bgEndColor);
+
+ g2.setPaint(bgGradientColor);
+
+ if(isRounded)
+ {
+ g2.fillRoundRect(1, 1, c.getWidth() - 1, c.getHeight() - 1,
+ 8, 8);
+ }
+ else
+ {
+ g2.fillRect(1, 1, c.getWidth() - 1, c.getHeight() - 1);
+ }
+
+ Rectangle deleteButtonRect = getDeleteButtonRect();
+
+ if(deleteButtonRect != null)
+ {
+ int dx = deleteButtonRect.x;
+ int dy = deleteButtonRect.y;
+
+ if (c.getText() != null
+ && c.getText().length() > 0
+ && isDeleteButtonEnabled)
+ {
+ if (isDeleteMousePressed)
+ g2.drawImage(deleteButtonPressedImg, dx, dy, null);
+ if (isDeleteMouseOver)
+ g2.drawImage(deleteButtonRolloverImg, dx, dy, null);
+ else
+ g2.drawImage(deleteButtonImg, dx, dy, null);
+
+ isDeleteIconVisible = true;
+ }
+ else
+ isDeleteIconVisible = false;
+ }
+ else
+ isDeleteIconVisible = false;
+
+ g2.setStroke(new BasicStroke(1f));
+ GradientPaint bgBorderGradientColor
+ = new GradientPaint( c.getWidth() / 2, 0,
+ bgBorderStartColor,
+ c.getWidth() / 2, c.getHeight(),
+ bgBorderEndColor);
+
+ g2.setPaint(bgBorderGradientColor);
+
+ if(isRounded)
+ {
+ g2.drawRoundRect(
+ 0, 0, c.getWidth() - 1, c.getHeight() - 1, 8, 8);
+ }
+ else
+ {
+ g2.drawRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);
+ }
+ }
+ finally
+ {
+ g2.dispose();
+ }
+ }
+
+ /**
+ * Updates the delete icon, changes the cursor and deletes the content of
+ * the associated text component when the mouse is pressed over the delete
+ * icon.
+ *
+ * @param evt the mouse event that has prompted us to update the delete
+ * icon.
+ */
+ protected void updateDeleteIcon(MouseEvent evt)
+ {
+ // If the component is null we have nothing more to do here. Fixes a
+ // NullPointerException in getDeleteButtonRectangle().
+ if (getComponent() == null)
+ return;
+
+ int x = evt.getX();
+ int y = evt.getY();
+
+ if (!isDeleteButtonEnabled)
+ return;
+
+ Rectangle deleteRect = getDeleteButtonRect();
+
+ if (isDeleteIconVisible && deleteRect.contains(x, y))
+ {
+ if (evt.getID() == MouseEvent.MOUSE_PRESSED)
+ {
+ isDeleteMouseOver = false;
+ isDeleteMousePressed = true;
+ }
+ else
+ {
+ isDeleteMouseOver = true;
+ isDeleteMousePressed = false;
+ }
+
+ getComponent().setCursor(Cursor.getDefaultCursor());
+
+ if (evt.getID() == MouseEvent.MOUSE_CLICKED)
+ getComponent().setText("");
+ }
+ else
+ {
+ isDeleteMouseOver = false;
+ isDeleteMousePressed = false;
+ }
+
+ getComponent().repaint();
+ }
+
+ /**
+ * Calculates the delete button rectangle.
+ *
+ * @return the delete button rectangle
+ */
+ protected Rectangle getDeleteButtonRect()
+ {
+ JTextComponent c = getComponent();
+
+ if(c == null)
+ return null;
+
+ Rectangle rect = c.getBounds();
+
+ int dx = rect.width - deleteButton.getWidth() - BUTTON_GAP;
+ int dy = rect.height / 2 - deleteButton.getHeight()/2;
+
+ return new Rectangle( dx,
+ dy,
+ deleteButton.getWidth(),
+ deleteButton.getHeight());
+ }
+
+ /**
+ * If we are in the case of disabled delete button, we simply call the
+ * parent implementation of this method, otherwise we recalculate the editor
+ * rectangle in order to leave place for the delete button.
+ * @return the visible editor rectangle
+ */
+ protected Rectangle getVisibleEditorRect()
+ {
+ if (!isDeleteIconVisible)
+ {
+ return super.getVisibleEditorRect();
+ }
+
+ JTextComponent c = getComponent();
+
+ if(c == null)
+ return null;
+
+ Rectangle alloc = c.getBounds();
+
+ if ((alloc.width > 0) && (alloc.height > 0))
+ {
+ alloc.x = alloc.y = 0;
+ Insets insets = c.getInsets();
+ alloc.x += insets.left;
+ alloc.y += insets.top;
+ alloc.width -= insets.left + insets.right
+ + getDeleteButtonRect().getWidth();
+ alloc.height -= insets.top + insets.bottom;
+ return alloc;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param bgStartColor the bgStartColor to set
+ */
+ public void setBgStartColor(Color bgStartColor)
+ {
+ this.bgStartColor = bgStartColor;
+ }
+
+ /**
+ * @param bgEndColor the bgEndColor to set
+ */
+ public void setBgEndColor(Color bgEndColor)
+ {
+ this.bgEndColor = bgEndColor;
+ }
+
+ /**
+ * @param bgBorderStartColor the bgBorderStartColor to set
+ */
+ public void setBgBorderStartColor(Color bgBorderStartColor)
+ {
+ this.bgBorderStartColor = bgBorderStartColor;
+ }
+
+ /**
+ * @param bgBorderEndColor the bgBorderEndColor to set
+ */
+ public void setBgBorderEndColor(Color bgBorderEndColor)
+ {
+ this.bgBorderEndColor = bgBorderEndColor;
+ }
+
+ /**
+ * Reloads skin information.
+ */
+ public void loadSkin()
+ {
+ deleteButtonImg = DesktopUtilActivator.getResources()
+ .getImage("service.gui.lookandfeel.DELETE_TEXT_ICON").getImage();
+
+ deleteButtonRolloverImg = DesktopUtilActivator.getResources()
+ .getImage("service.gui.lookandfeel.DELETE_TEXT_ROLLOVER_ICON")
+ .getImage();
+
+ deleteButtonPressedImg = DesktopUtilActivator.getResources()
+ .getImage("service.gui.lookandfeel.DELETE_TEXT_PRESSED_ICON")
+ .getImage();
+
+ if(deleteButton != null)
+ {
+ deleteButton.setBackgroundImage(deleteButtonImg);
+ deleteButton.setRolloverImage(deleteButtonRolloverImg);
+ deleteButton.setPressedImage(deleteButtonPressedImg);
+ }
+ else
+ {
+ deleteButton = new SIPCommButton(
+ deleteButtonImg,
+ deleteButtonRolloverImg,
+ deleteButtonPressedImg,
+ null, null, null);
+ }
+
+ deleteButton.setSize ( deleteButtonImg.getWidth(null),
+ deleteButtonImg.getHeight(null));
+ }
+
+ /**
+ * Updates the delete icon when the mouse was clicked.
+ * @param e the <tt>MouseEvent</tt> that notified us of the click
+ */
+ public void mouseClicked(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ updateCursor(e);
+ }
+
+ /**
+ * Updates the delete icon when the mouse is enters the component area.
+ * @param e the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseEntered(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ updateCursor(e);
+ }
+
+ /**
+ * Updates the delete icon when the mouse exits the component area.
+ * @param e the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseExited(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ updateCursor(e);
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ }
+
+ /**
+ * Updates the delete icon when the mouse is dragged over.
+ * @param e the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseDragged(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ updateCursor(e);
+ }
+
+ /**
+ * Updates the delete icon when the mouse is moved over.
+ * @param e the <tt>MouseEvent</tt> that notified us
+ */
+ public void mouseMoved(MouseEvent e)
+ {
+ updateDeleteIcon(e);
+ updateCursor(e);
+ }
+
+ /**
+ * Updates the cursor type depending on a given <tt>MouseEvent</tt>.
+ *
+ * @param mouseEvent the <tt>MouseEvent</tt> on which the cursor depends
+ */
+ private void updateCursor(MouseEvent mouseEvent)
+ {
+ Rectangle rect = getVisibleEditorRect();
+ if (rect != null && rect.contains(mouseEvent.getPoint()))
+ {
+ getComponent().setCursor(
+ Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+ }
+ }
+
+ /**
+ * Creates a UI for a SIPCommTextFieldUI.
+ *
+ * @param c the text field
+ * @return the UI
+ */
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new SIPCommTextFieldUI();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTreeUI.java b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTreeUI.java
new file mode 100644
index 0000000..1cb9386
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/plaf/SIPCommTreeUI.java
@@ -0,0 +1,258 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.plaf;
+
+import java.awt.*;
+import java.awt.Container;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.tree.*;
+
+/**
+ * SIPCommTreeUI implementation.
+ *
+ * @author Yana Stamcheva
+ */
+public class SIPCommTreeUI
+ extends BasicTreeUI
+ implements HierarchyListener,
+ TreeSelectionListener
+{
+ private static JTree tree;
+
+ private JViewport parentViewport;
+
+ private VariableLayoutCache layoutCache;
+
+ /**
+ * Last selected index.
+ */
+ private int lastSelectedIndex;
+
+ /**
+ * Creates the UI for the given component.
+ * @param c the component for which we're create an UI
+ * @return this UI implementation
+ */
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new SIPCommTreeUI();
+ }
+
+ /**
+ * Installs this UI to the given component.
+ * @param c the component to which to install this UI
+ */
+ public void installUI(JComponent c)
+ {
+ if ( c == null )
+ throw new NullPointerException(
+ "null component passed to BasicTreeUI.installUI()" );
+
+ tree = (JTree)c;
+
+ JViewport v = getFirstParentViewport(tree);
+ if(v != null)
+ this.parentViewport = v;
+ else
+ tree.addHierarchyListener(this);
+
+ tree.getSelectionModel().addTreeSelectionListener(this);
+
+ super.installUI(c);
+ }
+
+ /**
+ * Returns the first parent view port found.
+ * @param c the component parents we search
+ * @return the first parent view port found.
+ */
+ private JViewport getFirstParentViewport(Container c)
+ {
+ if(c == null)
+ return null;
+ else
+ if(c instanceof JViewport)
+ return (JViewport)c;
+ else
+ return getFirstParentViewport(c.getParent());
+ }
+
+ /**
+ * On uninstalling the ui remove the listeners.
+ * @param c
+ */
+ public void uninstallUI(JComponent c)
+ {
+ tree.getSelectionModel().clearSelection();
+ tree.getSelectionModel().removeTreeSelectionListener(this);
+ tree.removeHierarchyListener(this);
+
+ super.uninstallUI(c);
+ }
+
+ /**
+ * HierarchyListener's method.
+ * @param e the event.
+ */
+ public void hierarchyChanged(HierarchyEvent e)
+ {
+ if (e.getID() == HierarchyEvent.HIERARCHY_CHANGED
+ && (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0
+ && e.getChangedParent() instanceof JViewport)
+ {
+ parentViewport = (JViewport) e.getChangedParent();
+ }
+ }
+
+ /**
+ * The TreeSelectionListener's method.
+ * @param e the event.
+ */
+ public void valueChanged(TreeSelectionEvent e)
+ {
+ // Update cell size.
+ selectionChanged( e.getOldLeadSelectionPath(),
+ e.getNewLeadSelectionPath());
+ }
+
+ /**
+ * Installs the defaults of this UI.
+ */
+ protected void installDefaults()
+ {
+ if(tree.getBackground() == null ||
+ tree.getBackground() instanceof UIResource) {
+ tree.setBackground(UIManager.getColor("Tree.background"));
+ }
+ if(getHashColor() == null || getHashColor() instanceof UIResource) {
+ setHashColor(UIManager.getColor("Tree.hash"));
+ }
+ if (tree.getFont() == null || tree.getFont() instanceof UIResource)
+ tree.setFont( UIManager.getFont("Tree.font") );
+ // JTree's original row height is 16. To correctly display the
+ // contents on Linux we should have set it to 18, Windows 19 and
+ // Solaris 20. As these values vary so much it's too hard to
+ // be backward compatable and try to update the row height, we're
+ // therefor NOT going to adjust the row height based on font. If the
+ // developer changes the font, it's there responsibility to update
+ // the row height.
+
+ setExpandedIcon(null);
+ setCollapsedIcon(null);
+
+ setLeftChildIndent(0);
+ setRightChildIndent(0);
+
+ LookAndFeel.installProperty(tree, "rowHeight",
+ UIManager.get("Tree.rowHeight"));
+
+ largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0);
+
+ Object scrollsOnExpand = UIManager.get("Tree.scrollsOnExpand");
+ if (scrollsOnExpand != null) {
+ LookAndFeel.installProperty(
+ tree, "scrollsOnExpand", scrollsOnExpand);
+ }
+
+ UIManager.getDefaults().put("Tree.paintLines", false);
+ UIManager.getDefaults().put("Tree.lineTypeDashed", false);
+ }
+
+ /**
+ * Creates the object responsible for managing what is expanded, as
+ * well as the size of nodes.
+ * @return the created layout cache
+ */
+ protected AbstractLayoutCache createLayoutCache()
+ {
+ layoutCache = new VariableLayoutCache();
+ return layoutCache;
+ }
+
+ /**
+ * Do not select the <tt>ShowMoreContact</tt>.
+ *
+ * @param path the <tt>TreePath</tt> to select
+ * @param event the <tt>MouseEvent</tt> that provoked the select
+ */
+ protected void selectPathForEvent(TreePath path, MouseEvent event)
+ {
+ super.selectPathForEvent(path, event);
+ }
+
+ /**
+ * A custom layout cache that recalculates the width of the cell the match
+ * the width of the tree (i.e. expands the cell to the right).
+ */
+ private class VariableLayoutCache extends VariableHeightLayoutCache
+ {
+ /**
+ * Returns the preferred width of the receiver.
+ * @param path the path, which bounds we obtain
+ * @param placeIn the initial rectangle of the path
+ * @return the bounds of the path
+ */
+ public Rectangle getBounds(TreePath path, Rectangle placeIn)
+ {
+ Rectangle rect = super.getBounds(path, placeIn);
+
+ if (rect != null && parentViewport != null)
+ {
+ rect.width = parentViewport.getWidth() - 2;
+ }
+
+ return rect;
+ }
+ }
+
+ /**
+ * Ensures the tree size.
+ */
+ private void ensureTreeSize()
+ {
+ // Update tree height.
+ updateSize();
+
+ // Finally repaint in order the change to take place.
+ tree.repaint();
+ }
+
+ /**
+ * Refreshes row sizes corresponding to the given paths.
+ *
+ * @param oldPath the old selection path
+ * @param newPath the new selection path
+ */
+ public void selectionChanged(TreePath oldPath, TreePath newPath)
+ {
+ if (oldPath != null)
+ layoutCache.invalidatePathBounds(oldPath);
+
+ if (newPath != null)
+ {
+ layoutCache.invalidatePathBounds(newPath);
+ lastSelectedIndex = tree.getRowForPath(newPath);
+ }
+ // If the selection has disappeared, for example when the selected row
+ // has been removed, refresh the previously selected row.
+ else
+ {
+ int nextRow = (tree.getRowCount() > lastSelectedIndex)
+ ? lastSelectedIndex : tree.getRowCount() - 1;
+
+ layoutCache.invalidatePathBounds(
+ tree.getPathForRow(nextRow));
+ }
+
+ ensureTreeSize();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/transparent/AWTUtilitiesWrapper.java b/src/net/java/sip/communicator/plugin/desktoputil/transparent/AWTUtilitiesWrapper.java
new file mode 100644
index 0000000..0cc9a72
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/transparent/AWTUtilitiesWrapper.java
@@ -0,0 +1,161 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * Based on the code of Anthony Petrov
+ * http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/
+ */
+package net.java.sip.communicator.plugin.desktoputil.transparent;
+
+import java.awt.*;
+import java.lang.reflect.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ *
+ * @author Yana Stamcheva
+ */
+public class AWTUtilitiesWrapper
+{
+ private static final Logger logger
+ = Logger.getLogger(AWTUtilitiesWrapper.class);
+
+ private static Class<?> awtUtilitiesClass;
+ private static Class<?> translucencyClass;
+ private static Method mIsTranslucencySupported, mIsTranslucencyCapable,
+ mSetWindowShape, mSetWindowOpacity, mSetWindowOpaque;
+
+ public static Object PERPIXEL_TRANSPARENT, TRANSLUCENT, PERPIXEL_TRANSLUCENT;
+
+ static void init()
+ {
+ try
+ {
+ awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities");
+ translucencyClass
+ = Class.forName("com.sun.awt.AWTUtilities$Translucency");
+
+ if (translucencyClass.isEnum())
+ {
+ Object[] kinds = translucencyClass.getEnumConstants();
+ if (kinds != null)
+ {
+ PERPIXEL_TRANSPARENT = kinds[0];
+ TRANSLUCENT = kinds[1];
+ PERPIXEL_TRANSLUCENT = kinds[2];
+ }
+ }
+ mIsTranslucencySupported = awtUtilitiesClass.getMethod(
+ "isTranslucencySupported", translucencyClass);
+ mIsTranslucencyCapable = awtUtilitiesClass.getMethod(
+ "isTranslucencyCapable", GraphicsConfiguration.class);
+ mSetWindowShape = awtUtilitiesClass.getMethod(
+ "setWindowShape", Window.class, Shape.class);
+ mSetWindowOpacity = awtUtilitiesClass.getMethod(
+ "setWindowOpacity", Window.class, float.class);
+ mSetWindowOpaque = awtUtilitiesClass.getMethod(
+ "setWindowOpaque", Window.class, boolean.class);
+ }
+ catch (NoSuchMethodException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (SecurityException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (ClassNotFoundException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ }
+
+ static
+ {
+ init();
+ }
+
+ private static boolean isSupported(Method method, Object kind)
+ {
+ if (awtUtilitiesClass == null || method == null)
+ {
+ return false;
+ }
+ try
+ {
+ Object ret = method.invoke(null, kind);
+ if (ret instanceof Boolean)
+ {
+ return ((Boolean)ret).booleanValue();
+ }
+ }
+ catch (IllegalAccessException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (IllegalArgumentException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (InvocationTargetException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ return false;
+ }
+
+ public static boolean isTranslucencySupported(Object kind)
+ {
+ if (translucencyClass == null)
+ return false;
+
+ return isSupported(mIsTranslucencySupported, kind);
+ }
+
+ public static boolean isTranslucencyCapable(GraphicsConfiguration gc)
+ {
+ return isSupported(mIsTranslucencyCapable, gc);
+ }
+
+ private static void set(Method method, Window window, Object value)
+ {
+ if (awtUtilitiesClass == null || method == null)
+ {
+ return;
+ }
+ try
+ {
+ method.invoke(null, window, value);
+ }
+ catch (IllegalAccessException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (IllegalArgumentException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ catch (InvocationTargetException ex)
+ {
+ logger.info("Not available transparent windows.");
+ }
+ }
+
+ public static void setWindowShape(Window window, Shape shape)
+ {
+ set(mSetWindowShape, window, shape);
+ }
+
+ public static void setWindowOpacity(Window window, float opacity)
+ {
+ set(mSetWindowOpacity, window, Float.valueOf(opacity));
+ }
+
+ public static void setWindowOpaque(Window window, boolean opaque)
+ {
+ set(mSetWindowOpaque, window, Boolean.valueOf(opaque));
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/transparent/TransparentFrame.java b/src/net/java/sip/communicator/plugin/desktoputil/transparent/TransparentFrame.java
new file mode 100644
index 0000000..95947da
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/transparent/TransparentFrame.java
@@ -0,0 +1,102 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.transparent;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ *
+ * @author Yana Stamcheva
+ */
+public class TransparentFrame
+ extends JFrame
+ implements RootPaneContainer
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Indicates if the transparency is supported from the current graphics
+ * environment.
+ */
+ public static boolean isTranslucencySupported;
+
+ /**
+ * Creates a transparent undecorated frame. If the transparency is not
+ * supported creates a normal undecorated frame.
+ *
+ * @return the created frame
+ */
+ public static TransparentFrame createTransparentFrame()
+ {
+ isTranslucencySupported
+ = AWTUtilitiesWrapper.isTranslucencySupported(
+ AWTUtilitiesWrapper.PERPIXEL_TRANSLUCENT);
+
+ GraphicsConfiguration translucencyCapableGC
+ = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDefaultConfiguration();
+
+ if (!AWTUtilitiesWrapper.isTranslucencyCapable(translucencyCapableGC))
+ {
+ translucencyCapableGC = null;
+
+ GraphicsEnvironment env
+ = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice[] devices = env.getScreenDevices();
+
+ for (int i = 0; i < devices.length
+ && translucencyCapableGC == null; i++)
+ {
+ GraphicsConfiguration[] configs = devices[i].getConfigurations();
+ for (int j = 0; j < configs.length
+ && translucencyCapableGC == null; j++)
+ {
+ if (AWTUtilitiesWrapper.isTranslucencyCapable(configs[j]))
+ {
+ translucencyCapableGC = configs[j];
+ }
+ }
+ }
+ if (translucencyCapableGC == null)
+ {
+ isTranslucencySupported = false;
+ }
+ }
+
+ if (isTranslucencySupported)
+ return new TransparentFrame(translucencyCapableGC);
+
+ return new TransparentFrame();
+ }
+
+ /**
+ * Creates an undecorated transparent frame.
+ *
+ * @param gc the <tt>GraphicsConfiguration</tt> to use
+ */
+ private TransparentFrame(GraphicsConfiguration gc)
+ {
+ super(gc);
+
+ setUndecorated(true);
+ AWTUtilitiesWrapper.setWindowOpaque(this, false);
+ AWTUtilitiesWrapper.setWindowOpacity(this, 1f);
+ }
+
+ /**
+ * Creates an undecorated frame.
+ */
+ private TransparentFrame()
+ {
+ setUndecorated(true);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsPanel.java
new file mode 100644
index 0000000..97c9275
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsPanel.java
@@ -0,0 +1,227 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.wizard;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.codec.*;
+import org.jitsi.service.resources.*;
+
+
+/**
+ * The encodings configuration panel (used in the account configuration wizards)
+ *
+ * @author Boris Grozev
+ */
+public class EncodingsPanel extends TransparentPanel
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>EncodingsPanel</tt> class for
+ * logging output.
+ */
+ private static final Logger logger = Logger.getLogger(EncodingsPanel.class);
+
+ /**
+ * The <tt>ResourceManagementService</tt> used by this class
+ */
+ private static ResourceManagementService resourceService
+ = UtilActivator.getResources();
+
+ /**
+ * The "override global settings" checkbox.
+ */
+ private final JCheckBox overrideCheckBox;
+
+ /**
+ * The <tt>MediaConfiguration</tt> instance we'll use to obtain most of the
+ * <tt>Component</tt>s for the panel
+ */
+ private final MediaConfigurationService mediaConfiguration;
+
+ /**
+ * A panel to hold the audio encodings table
+ */
+ private JPanel audioPanel;
+
+ /**
+ * The audio encodings table (and "up"/"down" buttons)
+ */
+ private Component audioControls;
+
+ /**
+ * A panel to hold the video encodings table
+ */
+ private JPanel videoPanel;
+
+ /**
+ * The video encodings table (and "up"/"down" buttons)
+ */
+ private Component videoControls;
+
+ /**
+ * Holds the properties we need to get/set for the encoding preferences
+ */
+ private Map<String, String> encodingProperties
+ = new HashMap<String, String>();
+
+ /**
+ * An <tt>EncodingConfiguration</tt> we'll be using to manage preferences
+ * for us
+ */
+ private EncodingConfiguration encodingConfiguration;
+
+ /**
+ * The "reset" button
+ */
+ private JButton resetButton = new JButton(resourceService.getI18NString(
+ "plugin.jabberaccregwizz.RESET"));
+
+ /**
+ * Builds an object, loads the tables with the global configuration..
+ */
+ public EncodingsPanel()
+ {
+ super(new BorderLayout());
+
+ overrideCheckBox = new SIPCommCheckBox(resourceService.
+ getI18NString("plugin.jabberaccregwizz.OVERRIDE_ENCODINGS"),
+ false);
+ overrideCheckBox.addChangeListener(new ChangeListener()
+ {
+ public void stateChanged(ChangeEvent e)
+ {
+ updateTableState();
+ }
+ });
+
+ mediaConfiguration
+ = UtilActivator.getMediaConfiguration();
+
+ //by default (on account creation) use an <tt>EncodingConfiguration</tt>
+ //loaded with the global preferences. But make a new instance, because
+ //we do not want to change the current one
+ encodingConfiguration = mediaConfiguration.getMediaService()
+ .createEmptyEncodingConfiguration();
+ encodingConfiguration.loadEncodingConfiguration(mediaConfiguration
+ .getMediaService().getCurrentEncodingConfiguration());
+
+ audioControls = mediaConfiguration.
+ createEncodingControls(MediaType.AUDIO, encodingConfiguration);
+ videoControls = mediaConfiguration.
+ createEncodingControls(MediaType.VIDEO, encodingConfiguration);
+
+ JPanel mainPanel = new TransparentPanel();
+ mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+ add(mainPanel, BorderLayout.NORTH);
+
+ JPanel checkBoxPanel
+ = new TransparentPanel(new BorderLayout());
+ checkBoxPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ checkBoxPanel.add(overrideCheckBox,BorderLayout.WEST);
+ resetButton.setToolTipText(resourceService.getI18NString(
+ "plugin.jabberaccregwizz.RESET_DESCRIPTION"));
+ checkBoxPanel.add(resetButton,BorderLayout.EAST);
+ resetButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ encodingConfiguration.loadEncodingConfiguration(
+ mediaConfiguration.getMediaService()
+ .getCurrentEncodingConfiguration());
+ encodingConfiguration.storeProperties(encodingProperties,
+ ProtocolProviderFactory.ENCODING_PROP_PREFIX+".");
+ resetTables();
+ }
+ });
+
+ audioPanel = new TransparentPanel(new BorderLayout(10, 10));
+ audioPanel.setBorder(BorderFactory.createTitledBorder(
+ resourceService.getI18NString("plugin.jabberaccregwizz.AUDIO")));
+ audioPanel.add(audioControls);
+
+ videoPanel = new TransparentPanel(new BorderLayout(10, 10));
+ videoPanel.setBorder(BorderFactory.createTitledBorder(
+ resourceService.getI18NString("plugin.jabberaccregwizz.VIDEO")));
+ videoPanel.add(videoControls);
+
+ mainPanel.add(checkBoxPanel);
+ mainPanel.add(audioPanel);
+ mainPanel.add(videoPanel);
+ }
+
+ /**
+ * Saves the settings we hold in <tt>registration</tt>
+ * @param registration the <tt>EncodingsRegistration</tt> to use
+ */
+ public void commitPanel(EncodingsRegistration registration)
+ {
+ registration.setOverrideEncodings(overrideCheckBox.isSelected());
+
+ encodingConfiguration.storeProperties(encodingProperties,
+ ProtocolProviderFactory.ENCODING_PROP_PREFIX+".");
+
+ registration.setEncodingProperties(encodingProperties);
+ }
+
+ /**
+ * Checks the given <tt>accountProperties</tt> for encoding configuration
+ * and loads it.
+ * @param accountProperties the properties to use.
+ */
+ public void loadAccount(Map<String, String> accountProperties)
+ {
+ String overrideEncodings = accountProperties.get(
+ ProtocolProviderFactory.OVERRIDE_ENCODINGS);
+ boolean isOverrideEncodings = Boolean.parseBoolean(overrideEncodings);
+ overrideCheckBox.setSelected(isOverrideEncodings);
+
+ encodingConfiguration = mediaConfiguration.getMediaService()
+ .createEmptyEncodingConfiguration();
+ encodingConfiguration.loadProperties(accountProperties,
+ ProtocolProviderFactory.ENCODING_PROP_PREFIX);
+ encodingConfiguration.storeProperties(encodingProperties,
+ ProtocolProviderFactory.ENCODING_PROP_PREFIX+".");
+
+ resetTables();
+
+ }
+
+ /**
+ * Recreates the audio and video controls. Necessary when
+ * our encodingConfiguration reference has changed.
+ */
+ private void resetTables()
+ {
+ audioPanel.remove(audioControls);
+ videoPanel.remove(videoControls);
+ audioControls = mediaConfiguration.
+ createEncodingControls(MediaType.AUDIO, encodingConfiguration);
+ videoControls = mediaConfiguration.
+ createEncodingControls(MediaType.VIDEO, encodingConfiguration);
+
+ audioPanel.add(audioControls);
+ videoPanel.add(videoControls);
+ updateTableState();
+ }
+
+ /**
+ * Enables or disables the encodings tables based on the override checkbox.
+ */
+ private void updateTableState()
+ {
+ audioControls.setEnabled(overrideCheckBox.isSelected());
+ videoControls.setEnabled(overrideCheckBox.isSelected());
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsRegistration.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsRegistration.java
new file mode 100644
index 0000000..fa3f2f4
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncodingsRegistration.java
@@ -0,0 +1,41 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.wizard;
+
+import java.util.*;
+
+/**
+ * An interface to get/set settings in the encodings panel.
+ *
+ * @author Boris Grozev
+ */
+public interface EncodingsRegistration
+{
+ /**
+ * Get the stored encoding properties
+ * @return The stored encoding properties.
+ */
+ Map<String, String> getEncodingProperties();
+
+ /**
+ * Set the encoding properties
+ * @param encodingProperties The encoding properties to set.
+ */
+ void setEncodingProperties(Map<String, String> encodingProperties);
+
+ /**
+ * Whether override encodings is enabled
+ * @return Whether override encodings is enabled
+ */
+ boolean isOverrideEncodings();
+
+ /**
+ * Set the override encodings setting to <tt>override</tt>
+ * @param override The value to set the override encoding settings to.
+ */
+ void setOverrideEncodings(boolean override);
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncryptionConfigurationTableModel.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncryptionConfigurationTableModel.java
new file mode 100644
index 0000000..be32b11
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/EncryptionConfigurationTableModel.java
@@ -0,0 +1,223 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.wizard;
+
+import java.util.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+/**
+ * Implements {@link TableModel} for encryption configuration (ZRTP, SDES and
+ * MIKEY).
+ *
+ * @author Lyubomir Marinov
+ * @author Vincent Lucas
+ */
+public class EncryptionConfigurationTableModel
+ extends MoveableTableModel
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The encryption protocol names.
+ */
+ private String[] encryptionProtocols;
+
+ /**
+ * The encryption protocol status (enabled / disabled).
+ */
+ private boolean[] encryptionProtocolStatus;
+
+ /**
+ * Creates a new table model in order to manage the encryption protocols and
+ * the corresponding priority.
+ *
+ * @param encryptionProtocols The encryption protocol names.
+ * @param encryptionProtocolStatuss The encryption protocol status (enabled
+ * / disabled).
+ */
+ public EncryptionConfigurationTableModel(
+ String[] encryptionProtocols,
+ boolean[] encryptionProtocolStatus)
+ {
+ this.init(encryptionProtocols, encryptionProtocolStatus);
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex)
+ {
+ return
+ (columnIndex == 0)
+ ? Boolean.class
+ : super.getColumnClass(columnIndex);
+ }
+
+ public int getColumnCount()
+ {
+ return 2;
+ }
+
+ /**
+ * Returns the number of row in this table model.
+ *
+ * @return the number of row in this table model.
+ */
+ public int getRowCount()
+ {
+ return encryptionProtocols.length;
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ return (columnIndex == 0);
+ }
+
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ return encryptionProtocolStatus[rowIndex];
+ case 1:
+ return encryptionProtocols[rowIndex];
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void setValueAt(Object value, int rowIndex, int columnIndex)
+ {
+ if ((columnIndex == 0) && (value instanceof Boolean))
+ {
+ this.encryptionProtocolStatus[rowIndex]
+ = ((Boolean) value).booleanValue();
+
+ // We fire the update event before setting the configuration
+ // property in order to have more reactive user interface.
+ fireTableCellUpdated(rowIndex, columnIndex);
+ }
+ }
+
+ /**
+ * Move the row.
+ *
+ * @param rowIndex index of the row
+ * @param up true to move up, false to move down
+ * @return the next row index
+ */
+ public int move(int rowIndex, boolean up)
+ {
+ int toRowIndex;
+ if (up)
+ {
+ toRowIndex = rowIndex - 1;
+ if (toRowIndex < 0)
+ throw new IllegalArgumentException("rowIndex");
+ }
+ else
+ {
+ toRowIndex = rowIndex + 1;
+ if (toRowIndex >= getRowCount())
+ throw new IllegalArgumentException("rowIndex");
+ }
+
+ // Swaps the selection list.
+ boolean tmpSelectionItem = this.encryptionProtocolStatus[rowIndex];
+ this.encryptionProtocolStatus[rowIndex]
+ = this.encryptionProtocolStatus[toRowIndex];
+ this.encryptionProtocolStatus[toRowIndex] = tmpSelectionItem;
+
+ // Swaps the label list.
+ String tmpLabel = this.encryptionProtocols[rowIndex];
+ this.encryptionProtocols[rowIndex]
+ = this.encryptionProtocols[toRowIndex];
+ this.encryptionProtocols[toRowIndex] = tmpLabel;
+
+ fireTableRowsUpdated(rowIndex, toRowIndex);
+ return toRowIndex;
+ }
+
+ /**
+ * Returns the map between encryption protocol names and their priority
+ * order.
+ *
+ * @return The map between encryption protocol names and their priority
+ * order.
+ */
+ public Map<String, Integer> getEncryptionProtocols()
+ {
+ Map<String, Integer> encryptionProtocolMap
+ = new HashMap<String, Integer>(this.encryptionProtocols.length);
+ for(int i = 0; i < this.encryptionProtocols.length; ++i)
+ {
+ encryptionProtocolMap.put(
+ this.encryptionProtocols[i],
+ new Integer(i));
+ }
+ return encryptionProtocolMap;
+ }
+
+ /**
+ * Returns the map between encryption protocol names and their status.
+ *
+ * @return The map between encryption protocol names and their status.
+ */
+ public Map<String, Boolean> getEncryptionProtocolStatus()
+ {
+ Map<String, Boolean> encryptionProtocolStatusMap
+ = new HashMap<String, Boolean>(
+ this.encryptionProtocolStatus.length);
+ for(int i = 0; i < this.encryptionProtocolStatus.length; ++i)
+ {
+ encryptionProtocolStatusMap.put(
+ encryptionProtocols[i],
+ new Boolean(encryptionProtocolStatus[i]));
+ }
+ return encryptionProtocolStatusMap;
+ }
+
+ /**
+ * Returns if the label is enabled or disabled.
+ *
+ * @param label The label to be determined as enabled or disabled.
+ *
+ * @return True if the label given in parameter is enabled. False,
+ * otherwise.
+ */
+ public boolean isEnabledLabel(String label)
+ {
+ for(int i = 0; i < this.encryptionProtocols.length; ++i)
+ {
+ if(this.encryptionProtocols[i].equals(label))
+ {
+ return this.encryptionProtocolStatus[i];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Initiates this table model in order to manage the encryption protocols
+ * and the corresponding priority.
+ *
+ * @param encryptionProtocols The encryption protocol names.
+ * @param encryptionProtocolStatuss The encryption protocol status (enabled
+ * / disabled).
+ */
+ public void init(
+ String[] encryptionProtocols,
+ boolean[] encryptionProtocolStatus)
+ {
+ this.encryptionProtocols = encryptionProtocols;
+ this.encryptionProtocolStatus = encryptionProtocolStatus;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityAccountRegistration.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityAccountRegistration.java
new file mode 100644
index 0000000..4c88ded
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityAccountRegistration.java
@@ -0,0 +1,253 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.wizard;
+
+import net.java.sip.communicator.service.protocol.*;
+
+import java.util.*;
+
+/**
+ * The <tt>SecurityAccountRegistration</tt> is used to determine security
+ * options for different registration protocol (Jabber, SIP). Useful fot the
+ * SecurityPanel.
+ *
+ * @author Vincent Lucas
+ */
+public abstract class SecurityAccountRegistration
+{
+ /**
+ * Enables support to encrypt calls.
+ */
+ private boolean defaultEncryption = true;
+
+ /**
+ * Enqbles ZRTP encryption.
+ */
+ private boolean sipZrtpAttribute = true;
+
+ /**
+ * Tells if SDES is enabled for this account.
+ */
+ private boolean sdesEnabled = false;
+
+ /**
+ * The list of cipher suites enabled for SDES.
+ */
+ private String sdesCipherSuites = null;
+
+ /**
+ * The map between encryption protocols and their priority order.
+ */
+ private Map<String, Integer> encryptionProtocols;
+
+ /**
+ * The map between encryption protocols and their status (enabled or
+ * disabled).
+ */
+ private Map<String, Boolean> encryptionProtocolStatus;
+
+ /**
+ * Initializes the security account registration properties with the default
+ * values.
+ */
+ public SecurityAccountRegistration()
+ {
+ // Sets the default values.
+ this.encryptionProtocols = new HashMap<String, Integer>(1);
+ this.encryptionProtocols.put(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".ZRTP",
+ 0);
+ this.encryptionProtocolStatus = new HashMap<String, Boolean>(1);
+ this.encryptionProtocolStatus.put(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS + ".ZRTP",
+ true);
+ }
+
+ /**
+ * If default call encryption is enabled
+ *
+ * @return If default call encryption is enabled
+ */
+ public boolean isDefaultEncryption()
+ {
+ return defaultEncryption;
+ }
+
+ /**
+ * Sets default call encryption
+ *
+ * @param defaultEncryption if we want to set call encryption on as default
+ */
+ public void setDefaultEncryption(boolean defaultEncryption)
+ {
+ this.defaultEncryption = defaultEncryption;
+ }
+
+ /**
+ * Check if to include the ZRTP attribute to SIP/SDP or to Jabber/IQ
+ *
+ * @return include the ZRTP attribute to SIP/SDP or to Jabber/IQ
+ */
+ public boolean isSipZrtpAttribute()
+ {
+ return sipZrtpAttribute;
+ }
+
+ /**
+ * Sets ZRTP attribute support
+ *
+ * @param sipZrtpAttribute include the ZRTP attribute to SIP/SDP or to
+ * Jabber/IQ
+ */
+ public void setSipZrtpAttribute(boolean sipZrtpAttribute)
+ {
+ this.sipZrtpAttribute = sipZrtpAttribute;
+ }
+
+ /**
+ * Tells if SDES is enabled for this account.
+ *
+ * @return True if SDES is enabled. False, otherwise.
+ */
+ public boolean isSDesEnabled()
+ {
+ return sdesEnabled;
+ }
+
+ /**
+ * Enables or disables SDES for this account.
+ *
+ * @param sdesEnabled True to enable SDES. False, otherwise.
+ */
+ public void setSDesEnabled(boolean sdesEnabled)
+ {
+ this.sdesEnabled = sdesEnabled;
+ }
+
+ /**
+ * Returns the list of cipher suites enabled for SDES.
+ *
+ * @return The list of cipher suites enabled for SDES. Null if no cipher
+ * suite is enabled.
+ */
+ public String getSDesCipherSuites()
+ {
+ return sdesCipherSuites;
+ }
+
+ /**
+ * Sets the list of cipher suites enabled for SDES.
+ *
+ * @param The list of cipher suites enabled for SDES. Null if no cipher
+ * suite is enabled.
+ */
+ public void setSDesCipherSuites(String cipherSuites)
+ {
+ this.sdesCipherSuites = cipherSuites;
+ }
+
+ /**
+ * Sets the method used for RTP/SAVP indication.
+ */
+ public abstract void setSavpOption(int savpOption);
+
+ /**
+ * Returns the map between the encryption protocols and their priority
+ * order.
+ *
+ * @return The map between the encryption protocols and their priority
+ * order.
+ */
+ public Map<String, Integer> getEncryptionProtocols()
+ {
+ return encryptionProtocols;
+ }
+
+ /**
+ * Sets the map between the encryption protocols and their priority order.
+ *
+ * @param encryptionProtools The map between the encryption protocols and
+ * their priority order.
+ */
+ public void setEncryptionProtocols(
+ Map<String, Integer> encryptionProtocols)
+ {
+ this.encryptionProtocols = encryptionProtocols;
+ }
+
+ /**
+ * Returns the map between the encryption protocols and their status.
+ *
+ * @return The map between the encryption protocols and their status.
+ */
+ public Map<String, Boolean> getEncryptionProtocolStatus()
+ {
+ return encryptionProtocolStatus;
+ }
+
+ /**
+ * Sets the map between the encryption protocols and their status.
+ *
+ * @param encryptionProtools The map between the encryption protocols and
+ * their status.
+ */
+ public void setEncryptionProtocolStatus(
+ Map<String, Boolean> encryptionProtocolStatus)
+ {
+ this.encryptionProtocolStatus = encryptionProtocolStatus;
+ }
+
+ /**
+ * Adds the ordered encryption protocol names to the property list given in
+ * parameter.
+ *
+ * @param properties The property list to fill in.
+ */
+ public void addEncryptionProtocolsToProperties(
+ Map<String, String> properties)
+ {
+ Map<String, Integer> encryptionProtocols
+ = this.getEncryptionProtocols();
+ Iterator<String> encryptionProtocolIterator
+ = encryptionProtocols.keySet().iterator();
+ String encryptionProtocol;
+ while(encryptionProtocolIterator.hasNext())
+ {
+ encryptionProtocol = encryptionProtocolIterator.next();
+ properties.put(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL
+ + "."
+ + encryptionProtocol,
+ encryptionProtocols.get(encryptionProtocol).toString());
+ }
+ }
+
+ /**
+ * Adds the encryption protocol status to the property list given in
+ * parameter.
+ *
+ * @param properties The property list to fill in.
+ */
+ public void addEncryptionProtocolStatusToProperties(
+ Map<String, String> properties)
+ {
+ Map<String, Boolean> encryptionProtocolStatus
+ = this.getEncryptionProtocolStatus();
+ Iterator<String> encryptionProtocolStatusIterator
+ = encryptionProtocolStatus.keySet().iterator();
+ String encryptionProtocol;
+ while(encryptionProtocolStatusIterator.hasNext())
+ {
+ encryptionProtocol = encryptionProtocolStatusIterator.next();
+ properties.put(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS
+ + "."
+ + encryptionProtocol,
+ encryptionProtocolStatus.get(encryptionProtocol)
+ .toString());
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java
new file mode 100644
index 0000000..aa0fb81
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java
@@ -0,0 +1,591 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.desktoputil.wizard;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.table.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+import org.jitsi.service.neomedia.*;
+
+import ch.imvs.sdes4j.srtp.*;
+
+/**
+ * Contains the security settings for SIP media encryption.
+ *
+ * @author Ingo Bauersachs
+ * @author Vincent Lucas
+ */
+public class SecurityPanel
+ extends TransparentPanel
+ implements ActionListener,
+ TableModelListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private final SecurityAccountRegistration regform;
+
+ private JPanel pnlAdvancedSettings;
+ private JCheckBox enableDefaultEncryption;
+ private JCheckBox enableSipZrtpAttribute;
+ private JComboBox cboSavpOption;
+ private JTable tabCiphers;
+ private CipherTableModel cipherModel;
+ private JLabel cmdExpandAdvancedSettings;
+
+ /**
+ * The TableModel used to configure the encryption protocols preferences.
+ */
+ private EncryptionConfigurationTableModel encryptionConfigurationTableModel;
+
+ /**
+ * JTable with 2 buttons (up and down) which able to enable encryption
+ * protocols and to choose their priority order.
+ */
+ private PriorityTable encryptionProtocolPreferences;
+
+ /**
+ * The encryption protocols managed by this SecurityPanel.
+ */
+ private static final String[] encryptionProtocols = {"ZRTP", "SDES"};
+
+ /**
+ * Boolean used to display or not the SAVP options (only useful for SIP, not
+ * for XMPP).
+ */
+ private boolean displaySavpOtions;
+
+ private static class SavpOption
+ {
+ int option;
+
+ SavpOption(int option)
+ {
+ this.option = option;
+ }
+
+ @Override
+ public String toString()
+ {
+ return UtilActivator.getResources().getI18NString(
+ "plugin.sipaccregwizz.SAVP_OPTION_" + option);
+ }
+ }
+
+ private static class Entry
+ {
+ String cipher;
+ Boolean enabled;
+
+ public Entry(String cipher, boolean enabled)
+ {
+ this.cipher = cipher;
+ this.enabled = enabled;
+ }
+ }
+
+ private static class CipherTableModel extends AbstractTableModel
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ private List<Entry> data = new ArrayList<Entry>();
+ private final String defaultCiphers = UtilActivator.getResources()
+ .getSettingsString(SDesControl.SDES_CIPHER_SUITES);
+
+ CipherTableModel(String ciphers)
+ {
+ loadData(ciphers);
+ }
+
+ public void loadData(String ciphers)
+ {
+ data.clear();
+
+ if(defaultCiphers == null)
+ return;
+
+ if(ciphers == null)
+ ciphers = defaultCiphers;
+ //TODO the available ciphers should come from SDesControlImpl
+ data.add(new Entry(SrtpCryptoSuite.AES_CM_128_HMAC_SHA1_80, ciphers
+ .contains(SrtpCryptoSuite.AES_CM_128_HMAC_SHA1_80)));
+ data.add(new Entry(SrtpCryptoSuite.AES_CM_128_HMAC_SHA1_32, ciphers
+ .contains(SrtpCryptoSuite.AES_CM_128_HMAC_SHA1_32)));
+ data.add(new Entry(SrtpCryptoSuite.F8_128_HMAC_SHA1_80, ciphers
+ .contains(SrtpCryptoSuite.F8_128_HMAC_SHA1_80)));
+ fireTableDataChanged();
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex)
+ {
+ switch(columnIndex)
+ {
+ case 0:
+ return Boolean.class;
+ case 1:
+ return String.class;
+ }
+ return null;
+ }
+
+ public int getRowCount()
+ {
+ return data.size();
+ }
+
+ public int getColumnCount()
+ {
+ return 2;
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ return (columnIndex == 0);
+ }
+
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ Entry e = data.get(rowIndex);
+ switch(columnIndex)
+ {
+ case 0:
+ return e.enabled;
+ case 1:
+ return e.cipher;
+ }
+ return null;
+ }
+
+ @Override
+ public void setValueAt(Object value, int rowIndex, int columnIndex)
+ {
+ if ((columnIndex == 0) && (value instanceof Boolean))
+ {
+ Entry e = data.get(rowIndex);
+ e.enabled = (Boolean)value;
+ fireTableCellUpdated(rowIndex, columnIndex);
+ }
+ }
+
+ String getEnabledCiphers()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Entry e : data)
+ {
+ if(e.enabled)
+ {
+ sb.append(e.cipher);
+ sb.append(',');
+ }
+ }
+ if(sb.length() == 0)
+ {
+ return sb.toString();
+ }
+ else
+ {
+ return sb.substring(0, sb.length()-1);
+ }
+ }
+ }
+
+ /**
+ * Initiates a panel to configure the security (ZRTP and SDES) for SIP or
+ * XMPP protocols.
+ *
+ * @param regform The registration form of the account to configure.
+ * @param displaySavpOptions Boolean used to display or not the SAVP options
+ * (only useful for SIP, not for XMPP).
+ */
+ public SecurityPanel(
+ SecurityAccountRegistration regform,
+ boolean displaySavpOptions)
+ {
+ super(new BorderLayout(10, 10));
+
+ this.regform = regform;
+ this.displaySavpOtions = displaySavpOptions;
+ initComponents();
+ }
+
+ private void initComponents()
+ {
+ setLayout(new BorderLayout());
+ final JPanel mainPanel = new TransparentPanel();
+ add(mainPanel, BorderLayout.NORTH);
+
+ mainPanel.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ //general encryption option
+ enableDefaultEncryption = new SIPCommCheckBox(UtilActivator
+ .getResources()
+ .getI18NString("plugin.sipaccregwizz.ENABLE_DEFAULT_ENCRYPTION"),
+ regform.isDefaultEncryption());
+ enableDefaultEncryption.addActionListener(this);
+ mainPanel.add(enableDefaultEncryption, c);
+
+ //warning message and button to show advanced options
+ JLabel lblWarning = new JLabel();
+ lblWarning.setBorder(new EmptyBorder(10, 5, 10, 0));
+ lblWarning.setText(UtilActivator.getResources().getI18NString(
+ "plugin.sipaccregwizz.SECURITY_WARNING",
+ new String[]{
+ UtilActivator.getResources().getSettingsString(
+ "service.gui.APPLICATION_NAME")
+ }
+ ));
+ c.gridy++;
+ mainPanel.add(lblWarning, c);
+
+ cmdExpandAdvancedSettings = new JLabel();
+ cmdExpandAdvancedSettings.setBorder(new EmptyBorder(0, 5, 0, 0));
+ cmdExpandAdvancedSettings.setIcon(UtilActivator.getResources()
+ .getImage("service.gui.icons.RIGHT_ARROW_ICON"));
+ cmdExpandAdvancedSettings.setText(UtilActivator.getResources()
+ .getI18NString("plugin.sipaccregwizz.SHOW_ADVANCED"));
+ cmdExpandAdvancedSettings.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ cmdExpandAdvancedSettings.setIcon(
+ UtilActivator.getResources().getImage(
+ pnlAdvancedSettings.isVisible()
+ ? "service.gui.icons.RIGHT_ARROW_ICON"
+ : "service.gui.icons.DOWN_ARROW_ICON"));
+
+ pnlAdvancedSettings.setVisible(
+ !pnlAdvancedSettings.isVisible());
+
+ pnlAdvancedSettings.revalidate();
+ }
+ });
+ c.gridy++;
+ mainPanel.add(cmdExpandAdvancedSettings, c);
+
+ pnlAdvancedSettings = new TransparentPanel();
+ pnlAdvancedSettings.setLayout(new GridBagLayout());
+ pnlAdvancedSettings.setVisible(false);
+ c.gridy++;
+ mainPanel.add(pnlAdvancedSettings, c);
+
+
+ c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 2;
+ c.gridheight = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ pnlAdvancedSettings.add(new JSeparator(), c);
+
+ // Encryption protcol preferences.
+ JLabel lblEncryptionProtocolPreferences = new JLabel();
+ lblEncryptionProtocolPreferences.setText(UtilActivator.getResources()
+ .getI18NString(
+ "plugin.sipaccregwizz.ENCRYPTION_PROTOCOL_PREFERENCES"));
+ c.gridy++;
+ pnlAdvancedSettings.add(lblEncryptionProtocolPreferences, c);
+
+ int nbEncryptionProtocols = this.encryptionProtocols.length;
+ String[] encryptions = new String[nbEncryptionProtocols];
+ boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols];
+
+ this.encryptionConfigurationTableModel
+ = new EncryptionConfigurationTableModel(
+ encryptions,
+ selectedEncryptions);
+ this.encryptionProtocolPreferences = new PriorityTable(
+ this.encryptionConfigurationTableModel,
+ 60);
+ this.encryptionConfigurationTableModel.addTableModelListener(this);
+ c.gridy++;
+ pnlAdvancedSettings.add(this.encryptionProtocolPreferences, c);
+
+ //ZRTP
+ JLabel lblZrtpOption = new JLabel();
+ lblZrtpOption.setBorder(new EmptyBorder(5, 5, 5, 0));
+ lblZrtpOption.setText(UtilActivator.getResources()
+ .getI18NString("plugin.sipaccregwizz.ZRTP_OPTION"));
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 1;
+ pnlAdvancedSettings.add(lblZrtpOption, c);
+ c.gridx = 1;
+ pnlAdvancedSettings.add(new JSeparator(), c);
+
+ enableSipZrtpAttribute = new SIPCommCheckBox(
+ UtilActivator.getResources()
+ .getI18NString("plugin.sipaccregwizz.ENABLE_SIPZRTP_ATTRIBUTE"),
+ regform.isSipZrtpAttribute());
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 2;
+ pnlAdvancedSettings.add(enableSipZrtpAttribute, c);
+
+ //SDES
+ JLabel lblSDesOption = new JLabel();
+ lblSDesOption.setBorder(new EmptyBorder(5, 5, 5, 0));
+ lblSDesOption.setText( UtilActivator.getResources().getI18NString(
+ "plugin.sipaccregwizz.SDES_OPTION"));
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 1;
+ pnlAdvancedSettings.add(lblSDesOption, c);
+ c.gridx = 1;
+ pnlAdvancedSettings.add(new JSeparator(), c);
+
+ JLabel lblCipherInfo = new JLabel();
+ lblCipherInfo.setText(UtilActivator.getResources()
+ .getI18NString("plugin.sipaccregwizz.CIPHER_SUITES"));
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 2;
+ pnlAdvancedSettings.add(lblCipherInfo, c);
+
+ cipherModel = new CipherTableModel(regform.getSDesCipherSuites());
+ tabCiphers = new JTable(cipherModel);
+ tabCiphers.setShowGrid(false);
+ tabCiphers.setTableHeader(null);
+ TableColumnModel tableColumnModel = tabCiphers.getColumnModel();
+ TableColumn tableColumn = tableColumnModel.getColumn(0);
+ tableColumn.setMaxWidth(tableColumn.getMinWidth());
+ JScrollPane scrollPane = new JScrollPane(tabCiphers);
+ scrollPane.setPreferredSize(new Dimension(tabCiphers.getWidth(), 100));
+ c.gridy++;
+ pnlAdvancedSettings.add(scrollPane, c);
+
+ //SAVP selection
+ c.gridx = 0;
+ c.gridwidth = 1;
+ JLabel lblSavpOption = new JLabel();
+ lblSavpOption.setBorder(new EmptyBorder(5, 5, 5, 0));
+ lblSavpOption.setText( UtilActivator.getResources().getI18NString(
+ "plugin.sipaccregwizz.SAVP_OPTION"));
+ if(this.displaySavpOtions)
+ {
+ c.gridy++;
+ pnlAdvancedSettings.add(lblSavpOption, c);
+ }
+ c.gridx = 1;
+ if(this.displaySavpOtions)
+ {
+ pnlAdvancedSettings.add(new JSeparator(), c);
+ }
+
+ cboSavpOption = new JComboBox(new SavpOption[]{
+ new SavpOption(0),
+ new SavpOption(1),
+ new SavpOption(2)
+ });
+ c.gridx = 0;
+ c.gridwidth = 2;
+ c.insets = new Insets(0, 20, 0, 0);
+ if(this.displaySavpOtions)
+ {
+ c.gridy++;
+ pnlAdvancedSettings.add(cboSavpOption, c);
+ }
+ }
+
+ /**
+ * Saves the user input when the "Next" wizard buttons is clicked.
+ *
+ * @param registration the SIPAccountRegistration
+ * @return
+ */
+ public boolean commitPanel(SecurityAccountRegistration registration)
+ {
+ registration.setDefaultEncryption(enableDefaultEncryption.isSelected());
+ registration.setEncryptionProtocols(
+ encryptionConfigurationTableModel.getEncryptionProtocols());
+ registration.setEncryptionProtocolStatus(
+ encryptionConfigurationTableModel
+ .getEncryptionProtocolStatus());
+ registration.setSipZrtpAttribute(enableSipZrtpAttribute.isSelected());
+ registration.setSavpOption(((SavpOption) cboSavpOption
+ .getSelectedItem()).option);
+ registration.setSDesCipherSuites(cipherModel.getEnabledCiphers());
+
+ return true;
+ }
+
+ /**
+ * Loads the account with the given identifier.
+ * @param accountID the account identifier
+ */
+ public void loadAccount(AccountID accountID)
+ {
+ enableDefaultEncryption.setSelected(
+ accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true));
+
+ Map<String, Integer> encryptionProtocols
+ = accountID.getIntegerPropertiesByPrefix(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL,
+ true);
+ Map<String, Boolean> encryptionProtocolStatus
+ = accountID.getBooleanPropertiesByPrefix(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS,
+ true,
+ false);
+ this.loadEncryptionProtocols(
+ encryptionProtocols,
+ encryptionProtocolStatus);
+
+ enableSipZrtpAttribute.setSelected(
+ accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_SIPZRTP_ATTRIBUTE,
+ true));
+ cboSavpOption.setSelectedIndex(
+ accountID.getAccountPropertyInt(
+ ProtocolProviderFactory.SAVP_OPTION,
+ ProtocolProviderFactory.SAVP_OFF));
+ cipherModel.loadData(
+ accountID.getAccountPropertyString(
+ ProtocolProviderFactory.SDES_CIPHER_SUITES));
+ loadStates();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if(e.getSource() == enableDefaultEncryption)
+ {
+ loadStates();
+ }
+ else if(e.getSource() == cmdExpandAdvancedSettings)
+ {
+ pnlAdvancedSettings.setVisible(!pnlAdvancedSettings.isVisible());
+ }
+ }
+
+ public void tableChanged(TableModelEvent e)
+ {
+ if(e.getSource() == this.encryptionConfigurationTableModel)
+ {
+ loadStates();
+ }
+ }
+
+ private void loadStates()
+ {
+ boolean b = enableDefaultEncryption.isSelected();
+ cboSavpOption.setEnabled(b);
+ this.encryptionProtocolPreferences.setEnabled(b);
+ enableSipZrtpAttribute.setEnabled(
+ b
+ && this.encryptionConfigurationTableModel
+ .isEnabledLabel("ZRTP"));
+ tabCiphers.setEnabled(
+ b
+ && this.encryptionConfigurationTableModel
+ .isEnabledLabel("SDES"));
+ }
+
+ /**
+ * Loads the list of enabled and disabled encryption protocols with their
+ * priority.
+ *
+ * @param enabledEncryptionProtocols The list of enabled encryption protocol
+ * available for this account.
+ * @param disabledEncryptionProtocols The list of disabled encryption protocol
+ * available for this account.
+ */
+ private void loadEncryptionProtocols(
+ Map<String, Integer> encryptionProtocols,
+ Map<String, Boolean> encryptionProtocolStatus)
+ {
+ int nbEncryptionProtocols = this.encryptionProtocols.length;
+ String[] encryptions = new String[nbEncryptionProtocols];
+ boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols];
+
+ // Load stored values.
+ int prefixeLength
+ = ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1;
+ String encryptionProtocolPropertyName;
+ String name;
+ int index;
+ boolean enabled;
+ Iterator<String> encryptionProtocolNames
+ = encryptionProtocols.keySet().iterator();
+ while(encryptionProtocolNames.hasNext())
+ {
+ encryptionProtocolPropertyName = encryptionProtocolNames.next();
+ index = encryptionProtocols.get(encryptionProtocolPropertyName);
+ // If the property is set.
+ if(index != -1)
+ {
+ name = encryptionProtocolPropertyName.substring(prefixeLength);
+ enabled = encryptionProtocolStatus.get(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS
+ + "."
+ + name);
+ encryptions[index] = name;
+ selectedEncryptions[index] = enabled;
+ }
+ }
+
+ // Load default values.
+ String encryptionProtocol;
+ boolean set;
+ int j = 0;
+ for(int i = 0; i < this.encryptionProtocols.length; ++i)
+ {
+ encryptionProtocol = this.encryptionProtocols[i];
+ // Specify a default value only if there is no specific value set.
+ if(!encryptionProtocols.containsKey(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL
+ + "."
+ + encryptionProtocol))
+ {
+ set = false;
+ // Search for the first empty element.
+ while(j < encryptions.length && !set)
+ {
+ if(encryptions[j] == null)
+ {
+ encryptions[j] = encryptionProtocol;
+ // By default only ZRTP is set to true.
+ selectedEncryptions[j]
+ = encryptionProtocol.equals("ZRTP");
+ set = true;
+ }
+ ++j;
+ }
+
+ }
+ }
+
+ this.encryptionConfigurationTableModel.init(
+ encryptions,
+ selectedEncryptions);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java
index 3e2b3b9..1e78af0 100644
--- a/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java
@@ -13,9 +13,9 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.dict4j.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the host,
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/ProgressPanel.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/ProgressPanel.java
index d8f265e..0f71c64 100755
--- a/src/net/java/sip/communicator/plugin/dictaccregwizz/ProgressPanel.java
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/ProgressPanel.java
@@ -10,7 +10,7 @@ import java.awt.event.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Panel showing the current status of the search of the strategies
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf
index ebf4a69..a6e842a 100644
--- a/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/dnsconfig/DnsContainerPanel.java b/src/net/java/sip/communicator/plugin/dnsconfig/DnsContainerPanel.java
index ff55fbc..1d2bb9c 100644
--- a/src/net/java/sip/communicator/plugin/dnsconfig/DnsContainerPanel.java
+++ b/src/net/java/sip/communicator/plugin/dnsconfig/DnsContainerPanel.java
@@ -6,8 +6,8 @@
*/
package net.java.sip.communicator.plugin.dnsconfig;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.resources.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/dnsconfig/DnssecPanel.java b/src/net/java/sip/communicator/plugin/dnsconfig/DnssecPanel.java
index b4f741a..2d44a21 100644
--- a/src/net/java/sip/communicator/plugin/dnsconfig/DnssecPanel.java
+++ b/src/net/java/sip/communicator/plugin/dnsconfig/DnssecPanel.java
@@ -14,9 +14,9 @@ import javax.swing.*;
import javax.swing.plaf.basic.*;
import javax.swing.table.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.dns.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.dns.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
@@ -28,7 +28,8 @@ import org.osgi.framework.*;
* @author Ingo Bauersachs
*/
public class DnssecPanel
- extends TransparentPanel implements ActionListener, FocusListener
+ extends TransparentPanel
+ implements ActionListener, FocusListener
{
/**
* Serial version UID.
diff --git a/src/net/java/sip/communicator/plugin/dnsconfig/DnssecTableModel.java b/src/net/java/sip/communicator/plugin/dnsconfig/DnssecTableModel.java
index 424ee7c..6ebb319 100644
--- a/src/net/java/sip/communicator/plugin/dnsconfig/DnssecTableModel.java
+++ b/src/net/java/sip/communicator/plugin/dnsconfig/DnssecTableModel.java
@@ -13,7 +13,7 @@ import java.util.List;
import javax.swing.table.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.dns.*;
+import net.java.sip.communicator.plugin.desktoputil.dns.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/dnsconfig/ParallelDnsPanel.java b/src/net/java/sip/communicator/plugin/dnsconfig/ParallelDnsPanel.java
index aeeb5a0..8315a2f 100644
--- a/src/net/java/sip/communicator/plugin/dnsconfig/ParallelDnsPanel.java
+++ b/src/net/java/sip/communicator/plugin/dnsconfig/ParallelDnsPanel.java
@@ -6,19 +6,19 @@
*/
package net.java.sip.communicator.plugin.dnsconfig;
-import static net.java.sip.communicator.util.NetworkUtils.DEFAULT_BACKUP_RESOLVER;
-import static net.java.sip.communicator.util.NetworkUtils.PDEFAULT_BACKUP_RESOLVER_ENABLED;
-import static net.java.sip.communicator.util.NetworkUtils.PNAME_BACKUP_RESOLVER;
-import static net.java.sip.communicator.util.NetworkUtils.PNAME_BACKUP_RESOLVER_ENABLED;
-import static net.java.sip.communicator.util.NetworkUtils.PNAME_BACKUP_RESOLVER_FALLBACK_IP;
-import static net.java.sip.communicator.util.NetworkUtils.PNAME_BACKUP_RESOLVER_PORT;
-import static net.java.sip.communicator.util.NetworkUtils.getDefaultDnsPort;
-import static net.java.sip.communicator.util.NetworkUtils.isIPv4Address;
-import static net.java.sip.communicator.util.NetworkUtils.isIPv6Address;
-import static net.java.sip.communicator.util.dns.ParallelResolver.DNS_PATIENCE;
-import static net.java.sip.communicator.util.dns.ParallelResolver.DNS_REDEMPTION;
-import static net.java.sip.communicator.util.dns.ParallelResolver.PNAME_DNS_PATIENCE;
-import static net.java.sip.communicator.util.dns.ParallelResolver.PNAME_DNS_REDEMPTION;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.DEFAULT_BACKUP_RESOLVER;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.PDEFAULT_BACKUP_RESOLVER_ENABLED;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.PNAME_BACKUP_RESOLVER;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.PNAME_BACKUP_RESOLVER_ENABLED;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.PNAME_BACKUP_RESOLVER_FALLBACK_IP;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.PNAME_BACKUP_RESOLVER_PORT;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.getDefaultDnsPort;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.isIPv4Address;
+import static net.java.sip.communicator.plugin.desktoputil.NetworkUtils.isIPv6Address;
+import static net.java.sip.communicator.plugin.desktoputil.dns.ParallelResolver.DNS_PATIENCE;
+import static net.java.sip.communicator.plugin.desktoputil.dns.ParallelResolver.DNS_REDEMPTION;
+import static net.java.sip.communicator.plugin.desktoputil.dns.ParallelResolver.PNAME_DNS_PATIENCE;
+import static net.java.sip.communicator.plugin.desktoputil.dns.ParallelResolver.PNAME_DNS_REDEMPTION;
import java.awt.*;
import java.awt.event.*;
@@ -29,9 +29,9 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.dns.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.dns.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/dnsconfig/dnsconfig.manifest.mf b/src/net/java/sip/communicator/plugin/dnsconfig/dnsconfig.manifest.mf
index b6a4bc3..1961b0b 100644
--- a/src/net/java/sip/communicator/plugin/dnsconfig/dnsconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/dnsconfig/dnsconfig.manifest.mf
@@ -11,8 +11,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.dns,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil.dns,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/exampleplugin/PluginDialog.java b/src/net/java/sip/communicator/plugin/exampleplugin/PluginDialog.java
index bf2946e..0549766 100644
--- a/src/net/java/sip/communicator/plugin/exampleplugin/PluginDialog.java
+++ b/src/net/java/sip/communicator/plugin/exampleplugin/PluginDialog.java
@@ -10,8 +10,8 @@ import java.awt.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.contactlist.*;
-import net.java.sip.communicator.util.swing.*;
/**
* A plugin dialog that is open through the right button menu over a contact and
diff --git a/src/net/java/sip/communicator/plugin/exampleplugin/exampleplugin.manifest.mf b/src/net/java/sip/communicator/plugin/exampleplugin/exampleplugin.manifest.mf
index f683c87..87ac64f 100644
--- a/src/net/java/sip/communicator/plugin/exampleplugin/exampleplugin.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/exampleplugin/exampleplugin.manifest.mf
@@ -11,7 +11,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/facebookaccregwizz/facebookaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/facebookaccregwizz/facebookaccregwizz.manifest.mf
index a6143fe..b83b304 100644
--- a/src/net/java/sip/communicator/plugin/facebookaccregwizz/facebookaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/facebookaccregwizz/facebookaccregwizz.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.jabberaccregwizz,
javax.accessibility,
javax.imageio,
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java
index 7960da7..4941f29 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java
@@ -13,12 +13,12 @@ import javax.swing.*;
import javax.swing.border.*;
import net.java.sip.communicator.plugin.generalconfig.autoaway.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
index 34b2ea5..6bb6522 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java
@@ -16,10 +16,10 @@ import javax.swing.border.*;
import javax.swing.event.*;
import net.java.sip.communicator.plugin.generalconfig.autoaway.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.util.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/OpusConfigForm.java b/src/net/java/sip/communicator/plugin/generalconfig/OpusConfigForm.java
index 48fae73..1cb1675 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/OpusConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/OpusConfigForm.java
@@ -6,8 +6,8 @@
*/
package net.java.sip.communicator.plugin.generalconfig;
+import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.neomedia.codec.*;
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/SIPConfigForm.java b/src/net/java/sip/communicator/plugin/generalconfig/SIPConfigForm.java
index b7a5e91..c2a63f5 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/SIPConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/SIPConfigForm.java
@@ -12,9 +12,9 @@ import java.util.List;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
/**
* Implementation of the configuration form.
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/SilkConfigForm.java b/src/net/java/sip/communicator/plugin/generalconfig/SilkConfigForm.java
index 3f00ec4..c287519 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/SilkConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/SilkConfigForm.java
@@ -6,8 +6,8 @@
*/
package net.java.sip.communicator.plugin.generalconfig;
+import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.neomedia.codec.*;
@@ -23,8 +23,6 @@ import java.awt.event.*;
public class SilkConfigForm
extends TransparentPanel
{
-
-
/**
* The default value for the SAT setting
*/
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/autoaway/AutoAwayConfigurationPanel.java b/src/net/java/sip/communicator/plugin/generalconfig/autoaway/AutoAwayConfigurationPanel.java
index 3c5a144..a0160d8 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/autoaway/AutoAwayConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/generalconfig/autoaway/AutoAwayConfigurationPanel.java
@@ -14,7 +14,7 @@ import javax.swing.event.*;
import javax.swing.text.*;
import net.java.sip.communicator.plugin.generalconfig.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf b/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf
index 20e945e..5aa2084 100644
--- a/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.service.sysactivity,
net.java.sip.communicator.service.sysactivity.event,
com.sun.jna.win32,
diff --git a/src/net/java/sip/communicator/plugin/gibberishaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/gibberishaccregwizz/FirstWizardPage.java
index bd54660..3736744 100644
--- a/src/net/java/sip/communicator/plugin/gibberishaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/gibberishaccregwizz/FirstWizardPage.java
@@ -11,9 +11,9 @@ import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
diff --git a/src/net/java/sip/communicator/plugin/gibberishaccregwizz/gibberishaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/gibberishaccregwizz/gibberishaccregwizz.manifest.mf
index 88de8d4..501cedc 100644
--- a/src/net/java/sip/communicator/plugin/gibberishaccregwizz/gibberishaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/gibberishaccregwizz/gibberishaccregwizz.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/globalproxyconfig/GlobalProxyConfigForm.java b/src/net/java/sip/communicator/plugin/globalproxyconfig/GlobalProxyConfigForm.java
index 819b7e6..e8c3562 100644
--- a/src/net/java/sip/communicator/plugin/globalproxyconfig/GlobalProxyConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/globalproxyconfig/GlobalProxyConfigForm.java
@@ -10,8 +10,8 @@ import java.awt.event.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.configuration.*;
diff --git a/src/net/java/sip/communicator/plugin/globalproxyconfig/globalproxyconfig.manifest.mf b/src/net/java/sip/communicator/plugin/globalproxyconfig/globalproxyconfig.manifest.mf
index 58d2153..9e1cc68 100644
--- a/src/net/java/sip/communicator/plugin/globalproxyconfig/globalproxyconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/globalproxyconfig/globalproxyconfig.manifest.mf
@@ -6,7 +6,7 @@ Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.protocol,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
diff --git a/src/net/java/sip/communicator/plugin/googletalkaccregwizz/googletalkaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/googletalkaccregwizz/googletalkaccregwizz.manifest.mf
index 248077b..1d0fcb2 100644
--- a/src/net/java/sip/communicator/plugin/googletalkaccregwizz/googletalkaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/googletalkaccregwizz/googletalkaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.jabberaccregwizz,
javax.naming,
javax.naming.directory,
diff --git a/src/net/java/sip/communicator/plugin/icqaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/icqaccregwizz/FirstWizardPage.java
index 23518be..351b438 100644
--- a/src/net/java/sip/communicator/plugin/icqaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/icqaccregwizz/FirstWizardPage.java
@@ -11,9 +11,9 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
diff --git a/src/net/java/sip/communicator/plugin/icqaccregwizz/icqaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/icqaccregwizz/icqaccregwizz.manifest.mf
index d22b94b..1a85969 100644
--- a/src/net/java/sip/communicator/plugin/icqaccregwizz/icqaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/icqaccregwizz/icqaccregwizz.manifest.mf
@@ -16,7 +16,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/ippiaccregwizz/CreateIppiAccountForm.java b/src/net/java/sip/communicator/plugin/ippiaccregwizz/CreateIppiAccountForm.java
index cb454d1..45de648 100644
--- a/src/net/java/sip/communicator/plugin/ippiaccregwizz/CreateIppiAccountForm.java
+++ b/src/net/java/sip/communicator/plugin/ippiaccregwizz/CreateIppiAccountForm.java
@@ -16,8 +16,8 @@ import javax.swing.*;
import javax.swing.text.*;
import net.java.sip.communicator.plugin.sipaccregwizz.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.json.simple.*;
diff --git a/src/net/java/sip/communicator/plugin/ippiaccregwizz/ippiaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/ippiaccregwizz/ippiaccregwizz.manifest.mf
index 941c07e..76acb12 100644
--- a/src/net/java/sip/communicator/plugin/ippiaccregwizz/ippiaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/ippiaccregwizz/ippiaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.sipaccregwizz,
javax.naming,
javax.naming.directory,
diff --git a/src/net/java/sip/communicator/plugin/iptelaccregwizz/iptelaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/iptelaccregwizz/iptelaccregwizz.manifest.mf
index 03df9d7..e440dc1 100644
--- a/src/net/java/sip/communicator/plugin/iptelaccregwizz/iptelaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/iptelaccregwizz/iptelaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.sipaccregwizz,
javax.naming,
javax.naming.directory,
diff --git a/src/net/java/sip/communicator/plugin/ircaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/ircaccregwizz/FirstWizardPage.java
index 0d166ad..b26b3e2 100644
--- a/src/net/java/sip/communicator/plugin/ircaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/ircaccregwizz/FirstWizardPage.java
@@ -13,9 +13,9 @@ import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
diff --git a/src/net/java/sip/communicator/plugin/ircaccregwizz/ircaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/ircaccregwizz/ircaccregwizz.manifest.mf
index 5731d33..e773cc6 100644
--- a/src/net/java/sip/communicator/plugin/ircaccregwizz/ircaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/ircaccregwizz/ircaccregwizz.manifest.mf
@@ -13,7 +13,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/AccountPanel.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/AccountPanel.java
index 167b0d5..fb58b5f 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/AccountPanel.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/AccountPanel.java
@@ -12,8 +12,8 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
/**
* @author Yana Stamcheva
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/ConnectionPanel.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/ConnectionPanel.java
index 768a69d..099d34c 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/ConnectionPanel.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/ConnectionPanel.java
@@ -12,7 +12,8 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+
import org.jitsi.util.*;
/**
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/FirstWizardPage.java
index 60e2585..ce1b0c2 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/FirstWizardPage.java
@@ -8,9 +8,9 @@ package net.java.sip.communicator.plugin.jabberaccregwizz;
import java.awt.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/IceConfigPanel.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/IceConfigPanel.java
index 3fd772c..5c523fc 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/IceConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/IceConfigPanel.java
@@ -14,9 +14,9 @@ import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountCreationForm.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountCreationForm.java
index 6eaf942..db934ac 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountCreationForm.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountCreationForm.java
@@ -12,8 +12,8 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jivesoftware.smack.*;
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistration.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistration.java
index f7f3501..9a23c34 100755
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistration.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistration.java
@@ -8,7 +8,7 @@ package net.java.sip.communicator.plugin.jabberaccregwizz;
import java.util.*;
-import net.java.sip.communicator.util.plugin.wizard.*;
+import net.java.sip.communicator.plugin.desktoputil.wizard.*;
import net.java.sip.communicator.service.protocol.*;
/**
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java
index 83fd431..48e4dbc 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java
@@ -11,10 +11,10 @@ import java.util.List;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.wizard.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
-import net.java.sip.communicator.util.plugin.wizard.*;
/**
* The <tt>JabberAccountRegistrationForm</tt>.
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberServerChooserDialog.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberServerChooserDialog.java
index 079fc76..bd5c42d 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberServerChooserDialog.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberServerChooserDialog.java
@@ -19,8 +19,8 @@ import javax.swing.event.*;
import javax.swing.table.*;
import javax.xml.parsers.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
import org.jitsi.service.fileaccess.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/TelephonyConfigPanel.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/TelephonyConfigPanel.java
index a6a61ac..c7b5ad6 100644
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/TelephonyConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/TelephonyConfigPanel.java
@@ -10,7 +10,7 @@ import java.awt.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Telephony related configuration panel.
diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/jabberaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/jabberaccregwizz/jabberaccregwizz.manifest.mf
index 0ff79a1..ccee2f4 100755
--- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/jabberaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/jabberaccregwizz.manifest.mf
@@ -6,7 +6,6 @@ Bundle-Version: 0.0.1
System-Bundle: yes
Export-package: net.java.sip.communicator.plugin.jabberaccregwizz
Import-Package: org.osgi.framework,
- net.java.sip.communicator.util.plugin.wizard,
net.java.sip.communicator.service.browserlauncher,
org.jitsi.service.configuration,
net.java.sip.communicator.service.credentialsstorage,
@@ -22,7 +21,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.wizard,
javax.naming,
javax.naming.directory,
javax.xml.parsers,
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/KeybindingsConfigPanel.java b/src/net/java/sip/communicator/plugin/keybindingchooser/KeybindingsConfigPanel.java
index bca0d61..1e6daab 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/KeybindingsConfigPanel.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/KeybindingsConfigPanel.java
@@ -14,8 +14,8 @@ import javax.swing.*;
import net.java.sip.communicator.plugin.keybindingchooser.chooser.*;
import net.java.sip.communicator.plugin.keybindingchooser.globalchooser.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.keybindings.*;
-import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingChooser.java b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingChooser.java
index 96f5243..39b2fe4 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingChooser.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingChooser.java
@@ -12,8 +12,8 @@ import java.util.*;
import javax.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.keybindings.*;
-import net.java.sip.communicator.util.swing.*;
/**
* Implementation of the BindingPanel that provides configuring functionality
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingEntry.java b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingEntry.java
index 00abfab..c474223 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingEntry.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingEntry.java
@@ -11,7 +11,7 @@ import java.awt.event.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Display element for a single key binding.
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingPanel.java b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingPanel.java
index a90da52..4f4ee0c 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingPanel.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/chooser/BindingPanel.java
@@ -13,7 +13,7 @@ import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Panel containing a listing of current keybinding mappings. This contains
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutConfigForm.java b/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutConfigForm.java
index d916f5a..e5b7e9a 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutConfigForm.java
@@ -15,10 +15,10 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.plugin.keybindingchooser.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.globalshortcut.*;
import net.java.sip.communicator.service.keybindings.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
/**
* This ConfigurationForm shows the list of global shortcut
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutDialog.java b/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutDialog.java
index 68f9ef5..c3a46f9 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutDialog.java
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/globalchooser/GlobalShortcutDialog.java
@@ -14,10 +14,10 @@ import java.util.List;
import javax.swing.*;
import net.java.sip.communicator.plugin.keybindingchooser.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.service.globalshortcut.*;
import net.java.sip.communicator.util.skin.*;
-import net.java.sip.communicator.util.swing.*;
-import net.java.sip.communicator.util.swing.plaf.*;
import org.jitsi.util.*;
// disambiguation
diff --git a/src/net/java/sip/communicator/plugin/keybindingchooser/keybindingChooser.manifest.mf b/src/net/java/sip/communicator/plugin/keybindingchooser/keybindingChooser.manifest.mf
index 780e860..1ff1759 100644
--- a/src/net/java/sip/communicator/plugin/keybindingchooser/keybindingChooser.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/keybindingchooser/keybindingChooser.manifest.mf
@@ -12,8 +12,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.globalshortcut,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
- net.java.sip.communicator.util.swing.plaf,
+ net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.plaf,
net.java.sip.communicator.util.skin,
javax.swing,
javax.swing.plaf,
diff --git a/src/net/java/sip/communicator/plugin/ldap/configform/DirectorySettingsForm.java b/src/net/java/sip/communicator/plugin/ldap/configform/DirectorySettingsForm.java
index 78aa393..6e9414b 100644
--- a/src/net/java/sip/communicator/plugin/ldap/configform/DirectorySettingsForm.java
+++ b/src/net/java/sip/communicator/plugin/ldap/configform/DirectorySettingsForm.java
@@ -18,7 +18,7 @@ import net.java.sip.communicator.service.ldap.*;
import net.java.sip.communicator.service.ldap.LdapConstants.Auth;
import net.java.sip.communicator.service.ldap.LdapConstants.Encryption;
import net.java.sip.communicator.service.ldap.LdapConstants.Scope;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
//disambiguation
/**
diff --git a/src/net/java/sip/communicator/plugin/ldap/configform/LdapConfigForm.java b/src/net/java/sip/communicator/plugin/ldap/configform/LdapConfigForm.java
index adece93..84c46de 100644
--- a/src/net/java/sip/communicator/plugin/ldap/configform/LdapConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/ldap/configform/LdapConfigForm.java
@@ -16,7 +16,7 @@ import net.java.sip.communicator.plugin.ldap.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.ldap.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* This ConfigurationForm shows the list of LDAP directories
diff --git a/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf b/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf
index a418501..d45fa03 100644
--- a/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf
@@ -10,7 +10,7 @@ Import-Package: net.java.sip.communicator.service.contactsource,
net.java.sip.communicator.service.ldap,
net.java.sip.communicator.service.ldap.event,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.border,
javax.swing.event,
diff --git a/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java b/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
index 1c1d162..39c9496 100644
--- a/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
+++ b/src/net/java/sip/communicator/plugin/loggingutils/LoggingConfigForm.java
@@ -16,7 +16,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.httputil.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.packetlogging.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/loggingutils/loggingutils.manifest.mf b/src/net/java/sip/communicator/plugin/loggingutils/loggingutils.manifest.mf
index b4d2ecc..8d57c13 100644
--- a/src/net/java/sip/communicator/plugin/loggingutils/loggingutils.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/loggingutils/loggingutils.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
org.jitsi.service.resources,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.net.ssl,
javax.swing,
javax.swing.border,
diff --git a/src/net/java/sip/communicator/plugin/msnaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/msnaccregwizz/FirstWizardPage.java
index 071d40b..8d35c4b 100644
--- a/src/net/java/sip/communicator/plugin/msnaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/msnaccregwizz/FirstWizardPage.java
@@ -12,7 +12,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
diff --git a/src/net/java/sip/communicator/plugin/msnaccregwizz/msnaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/msnaccregwizz/msnaccregwizz.manifest.mf
index c18c354..7f6f8b8 100755
--- a/src/net/java/sip/communicator/plugin/msnaccregwizz/msnaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/msnaccregwizz/msnaccregwizz.manifest.mf
@@ -16,7 +16,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/notificationconfiguration/NotificationConfigurationPanel.java b/src/net/java/sip/communicator/plugin/notificationconfiguration/NotificationConfigurationPanel.java
index 3de1e8e..4c962c5 100644
--- a/src/net/java/sip/communicator/plugin/notificationconfiguration/NotificationConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/notificationconfiguration/NotificationConfigurationPanel.java
@@ -16,7 +16,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.audionotifier.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/notificationconfiguration/SoundFilter.java b/src/net/java/sip/communicator/plugin/notificationconfiguration/SoundFilter.java
index 9604b1b..694269c 100644
--- a/src/net/java/sip/communicator/plugin/notificationconfiguration/SoundFilter.java
+++ b/src/net/java/sip/communicator/plugin/notificationconfiguration/SoundFilter.java
@@ -9,7 +9,7 @@ package net.java.sip.communicator.plugin.notificationconfiguration;
import java.io.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/notificationconfiguration/notificationconfiguration.manifest.mf b/src/net/java/sip/communicator/plugin/notificationconfiguration/notificationconfiguration.manifest.mf
index 07ff221..62bc3e6 100644
--- a/src/net/java/sip/communicator/plugin/notificationconfiguration/notificationconfiguration.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/notificationconfiguration/notificationconfiguration.manifest.mf
@@ -25,7 +25,7 @@ Import-Package:
net.java.sip.communicator.service.notification.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
org.jitsi.service.audionotifier,
org.jitsi.service.configuration,
org.jitsi.service.resources,
diff --git a/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java b/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
index 42deed6..3a69df5 100644
--- a/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
+++ b/src/net/java/sip/communicator/plugin/notificationwiring/NotificationManager.java
@@ -14,6 +14,7 @@ import java.util.concurrent.*;
import javax.imageio.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.notification.*;
diff --git a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java b/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java
index 3a964c0..8218838 100644
--- a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java
+++ b/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java
@@ -14,7 +14,7 @@ import javax.swing.border.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* @author @George Politis
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java b/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java
index c7e2076..6083970 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java
@@ -13,7 +13,7 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* @author George Politis
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java b/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java
index ecf02e7..a67e940 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java
@@ -15,7 +15,7 @@ import javax.swing.border.*;
import net.java.otr4j.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* A special {@link Panel} that manages the OTR configuration.
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java b/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
index df3062a..6f1a4cd 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
@@ -14,7 +14,7 @@ import javax.swing.*;
import net.java.otr4j.*;
import net.java.otr4j.session.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* A special {@link JMenu} that holds the menu items for controlling the
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
index c7952ba..5cf4a17 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
@@ -18,7 +18,7 @@ import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* A {@link AbstractPluginComponent} that registers the Off-the-Record button in
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactMenu.java b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactMenu.java
index c130e7c..a08ffaa 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactMenu.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactMenu.java
@@ -17,7 +17,7 @@ import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* @author George Politis
diff --git a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf
index c8296e5..e9c0d0c 100644
--- a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf
@@ -13,7 +13,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.imageio,
javax.swing,
javax.swing.border,
diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java b/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java
index fb1a2ec..20a57bf 100644
--- a/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java
+++ b/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java
@@ -13,7 +13,7 @@ import javax.swing.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java b/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java
index e96c601..5c64110 100644
--- a/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java
+++ b/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java
@@ -15,7 +15,7 @@ import javax.swing.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java b/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java
index 3bb5de3..86d625a 100644
--- a/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java
+++ b/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java
@@ -12,7 +12,7 @@ import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/PluginManagerPanel.java b/src/net/java/sip/communicator/plugin/pluginmanager/PluginManagerPanel.java
index 817c3d7..bc59d42 100644
--- a/src/net/java/sip/communicator/plugin/pluginmanager/PluginManagerPanel.java
+++ b/src/net/java/sip/communicator/plugin/pluginmanager/PluginManagerPanel.java
@@ -12,7 +12,7 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/pluginmanager.manifest.mf b/src/net/java/sip/communicator/plugin/pluginmanager/pluginmanager.manifest.mf
index 2b2d31b..0aa72b4 100644
--- a/src/net/java/sip/communicator/plugin/pluginmanager/pluginmanager.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/pluginmanager/pluginmanager.manifest.mf
@@ -10,7 +10,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/provisioning/ProvisioningForm.java b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningForm.java
index f42b6c2..b10184a 100644
--- a/src/net/java/sip/communicator/plugin/provisioning/ProvisioningForm.java
+++ b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningForm.java
@@ -14,7 +14,7 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java
index a3c26ab..d5c3f53 100644
--- a/src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java
+++ b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java
@@ -13,7 +13,7 @@ import net.java.sip.communicator.service.httputil.*;
import net.java.sip.communicator.service.provisioning.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf b/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf
index bb0cfce..afa6e85 100644
--- a/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf
@@ -18,7 +18,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.provisioning,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf b/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf
index 9163cb2..d68432a 100644
--- a/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/reconnectplugin/reconnectplugin.manifest.mf
@@ -14,4 +14,4 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing
+ net.java.sip.communicator.plugin.desktoputil
diff --git a/src/net/java/sip/communicator/plugin/rssaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/rssaccregwizz/FirstWizardPage.java
index 7737cf2..bb30aa8 100644
--- a/src/net/java/sip/communicator/plugin/rssaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/rssaccregwizz/FirstWizardPage.java
@@ -14,7 +14,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
diff --git a/src/net/java/sip/communicator/plugin/rssaccregwizz/rssaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/rssaccregwizz/rssaccregwizz.manifest.mf
index 81e2df7..9acedd6 100644
--- a/src/net/java/sip/communicator/plugin/rssaccregwizz/rssaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/rssaccregwizz/rssaccregwizz.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/SecurityConfigurationPanel.java b/src/net/java/sip/communicator/plugin/securityconfig/SecurityConfigurationPanel.java
index c60d871..e5ecd67 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/SecurityConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/SecurityConfigurationPanel.java
@@ -8,7 +8,7 @@ package net.java.sip.communicator.plugin.securityconfig;
import java.awt.*;
import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/ConfigurationPanel.java b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/ConfigurationPanel.java
index 698eab5..2de4ba0 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/ConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/ConfigurationPanel.java
@@ -8,7 +8,7 @@ package net.java.sip.communicator.plugin.securityconfig.masterpassword;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Implements a Swing <tt>Component</tt> to represent the user interface of the
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordChangeDialog.java b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordChangeDialog.java
index 2ec5be7..b6fe8b1 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordChangeDialog.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordChangeDialog.java
@@ -10,7 +10,7 @@ import java.awt.event.*;
import net.java.sip.communicator.plugin.securityconfig.*;
import net.java.sip.communicator.service.credentialsstorage.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* UI dialog to change the master password.
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordPanel.java b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordPanel.java
index 7e85595..d5de308 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordPanel.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/MasterPasswordPanel.java
@@ -15,7 +15,7 @@ import net.java.sip.communicator.plugin.securityconfig.*;
import net.java.sip.communicator.plugin.securityconfig.masterpassword.MasterPasswordChangeDialog.MasterPasswordExecutable;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsDialog.java b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsDialog.java
index 79ecdc5..10c567d 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsDialog.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsDialog.java
@@ -20,7 +20,7 @@ import net.java.sip.communicator.plugin.securityconfig.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsPanel.java b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsPanel.java
index 712f771..ef0eee9 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsPanel.java
+++ b/src/net/java/sip/communicator/plugin/securityconfig/masterpassword/SavedPasswordsPanel.java
@@ -13,7 +13,7 @@ import javax.swing.*;
import net.java.sip.communicator.plugin.securityconfig.*;
import net.java.sip.communicator.service.credentialsstorage.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Panel containing the saved passwords button.
diff --git a/src/net/java/sip/communicator/plugin/securityconfig/securityconfig.manifest.mf b/src/net/java/sip/communicator/plugin/securityconfig/securityconfig.manifest.mf
index 261175b..784e47a 100644
--- a/src/net/java/sip/communicator/plugin/securityconfig/securityconfig.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/securityconfig/securityconfig.manifest.mf
@@ -13,7 +13,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
gnu.java.zrtp,
javax.crypto,
javax.crypto.interfaces,
diff --git a/src/net/java/sip/communicator/plugin/simpleaccreg/InitialAccountRegistrationFrame.java b/src/net/java/sip/communicator/plugin/simpleaccreg/InitialAccountRegistrationFrame.java
index e83614f..ab68a11 100644
--- a/src/net/java/sip/communicator/plugin/simpleaccreg/InitialAccountRegistrationFrame.java
+++ b/src/net/java/sip/communicator/plugin/simpleaccreg/InitialAccountRegistrationFrame.java
@@ -19,7 +19,7 @@ import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.configuration.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/simpleaccreg/simpleaccreg.manifest.mf b/src/net/java/sip/communicator/plugin/simpleaccreg/simpleaccreg.manifest.mf
index 791a586..669759e 100644
--- a/src/net/java/sip/communicator/plugin/simpleaccreg/simpleaccreg.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/simpleaccreg/simpleaccreg.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/CreateSip2SipAccountForm.java b/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/CreateSip2SipAccountForm.java
index 5533fb2..ccf5c9d 100644
--- a/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/CreateSip2SipAccountForm.java
+++ b/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/CreateSip2SipAccountForm.java
@@ -17,7 +17,7 @@ import javax.swing.text.*;
import net.java.sip.communicator.plugin.ippiaccregwizz.*;
import net.java.sip.communicator.plugin.sipaccregwizz.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.json.simple.*;
diff --git a/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/sip2sipaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/sip2sipaccregwizz.manifest.mf
index a4a0c6c..5df1e81 100644
--- a/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/sip2sipaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/sip2sipaccregwizz/sip2sipaccregwizz.manifest.mf
@@ -17,7 +17,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.sipaccregwizz,
javax.naming,
javax.naming.directory,
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/AccountPanel.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/AccountPanel.java
index 6e10ace..1c5b2aa 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/AccountPanel.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/AccountPanel.java
@@ -12,7 +12,7 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The panel containing all account related information like user name and
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java
index c3fbc71..3210db7 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java
@@ -12,7 +12,7 @@ import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.certificate.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/FirstWizardPage.java
index f3342dc..51e8888 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/FirstWizardPage.java
@@ -9,7 +9,7 @@ import java.awt.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
index 7a9e216..73365d0 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
@@ -10,7 +10,7 @@ import java.awt.event.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>PresencePanel</tt> is the one containing presence information.
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
index 25b7894..45b5a1d 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
@@ -7,8 +7,7 @@ package net.java.sip.communicator.plugin.sipaccregwizz;
import java.util.*;
-import java.util.*;
-import net.java.sip.communicator.util.plugin.wizard.*;
+import net.java.sip.communicator.plugin.desktoputil.wizard.*;
/**
* The <tt>SIPAccountRegistration</tt> is used to store all user input data
* through the <tt>SIPAccountRegistrationWizard</tt>.
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
index 212cbbf..21b9dba 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
@@ -7,8 +7,8 @@ import java.util.List;
import javax.swing.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
-import net.java.sip.communicator.util.plugin.wizard.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.wizard.*;
import org.jitsi.util.*;
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/sipaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/sipaccregwizz/sipaccregwizz.manifest.mf
index 49a3fec..5f40115 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/sipaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/sipaccregwizz.manifest.mf
@@ -21,8 +21,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources,
org.jitsi.util,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.plugin.wizard,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.wizard,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java
index 09faefc..1de892a 100644
--- a/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java
+++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java
@@ -11,7 +11,7 @@ import java.awt.event.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectionListener.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectionListener.java
index 41cc4fb..2add580 100644
--- a/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectionListener.java
+++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectionListener.java
@@ -13,7 +13,7 @@ import java.util.zip.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectorRenderer.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectorRenderer.java
index a51cc8f..8031446 100644
--- a/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectorRenderer.java
+++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinSelectorRenderer.java
@@ -13,7 +13,7 @@ import java.util.*;
import javax.swing.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.osgi.framework.*;
diff --git a/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf b/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf
index 1464ff5..423dfd4 100644
--- a/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf
@@ -10,7 +10,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java b/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
index ba9ac69..4366994 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
@@ -21,8 +21,8 @@ import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
-import net.java.sip.communicator.util.swing.SwingWorker;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.SwingWorker;
/**
* Combo box providing a listing of all available locales with corresponding
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java
index ac51b27..f005a15 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/SpellCheckerConfigDialog.java
@@ -15,7 +15,7 @@ import javax.swing.text.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.dts.spell.dictionary.*;
import org.jitsi.service.resources.*;
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf b/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
index 3297747..5ef7fdc 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/spellcheck/spellCheck.manifest.mf
@@ -10,7 +10,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.service.contactlist,
net.java.sip.communicator.service.protocol,
javax.swing,
diff --git a/src/net/java/sip/communicator/plugin/sshaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/sshaccregwizz/FirstWizardPage.java
index 0f3e2a3..c04e313 100644
--- a/src/net/java/sip/communicator/plugin/sshaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/sshaccregwizz/FirstWizardPage.java
@@ -22,7 +22,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.impl.protocol.ssh.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
diff --git a/src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf
index d4fa337..6f8b5f9 100644
--- a/src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/update/Update.java b/src/net/java/sip/communicator/plugin/update/Update.java
index e3b836d..0e00d69 100644
--- a/src/net/java/sip/communicator/plugin/update/Update.java
+++ b/src/net/java/sip/communicator/plugin/update/Update.java
@@ -21,7 +21,7 @@ import net.java.sip.communicator.service.httputil.*;
import net.java.sip.communicator.service.update.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import org.jitsi.service.resources.*;
import org.jitsi.service.version.*;
diff --git a/src/net/java/sip/communicator/plugin/update/update.manifest.mf b/src/net/java/sip/communicator/plugin/update/update.manifest.mf
index 98b6948..3de434b 100644
--- a/src/net/java/sip/communicator/plugin/update/update.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/update/update.manifest.mf
@@ -16,7 +16,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.shutdown,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.service.update,
javax.imageio,
javax.net.ssl,
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/gui/InvitationReceivedDialog.java b/src/net/java/sip/communicator/plugin/whiteboard/gui/InvitationReceivedDialog.java
index 335accf..729c795 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/gui/InvitationReceivedDialog.java
+++ b/src/net/java/sip/communicator/plugin/whiteboard/gui/InvitationReceivedDialog.java
@@ -13,7 +13,7 @@ import javax.swing.*;
import net.java.sip.communicator.plugin.whiteboard.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The dialog that pops up when a chat room invitation is received.
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFileFilter.java b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFileFilter.java
index 42431d3..1048984 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFileFilter.java
+++ b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFileFilter.java
@@ -9,7 +9,7 @@ package net.java.sip.communicator.plugin.whiteboard.gui;
import java.io.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* A simple file filter manager
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFrame.java b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFrame.java
index fb875e3..00e36eb 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFrame.java
+++ b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardFrame.java
@@ -23,7 +23,7 @@ import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.protocol.whiteboardobjects.*;
import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The frame for the Whiteboard
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardPanel.java b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardPanel.java
index 5282b66..1d0a9ed 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardPanel.java
+++ b/src/net/java/sip/communicator/plugin/whiteboard/gui/WhiteboardPanel.java
@@ -15,7 +15,7 @@ import javax.swing.*;
import javax.swing.plaf.*;
import net.java.sip.communicator.plugin.whiteboard.gui.whiteboardshapes.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Panel for drawing shapes
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/gui/whiteboardshapes/WhiteboardShape.java b/src/net/java/sip/communicator/plugin/whiteboard/gui/whiteboardshapes/WhiteboardShape.java
index c303fba..9fd5e47 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/gui/whiteboardshapes/WhiteboardShape.java
+++ b/src/net/java/sip/communicator/plugin/whiteboard/gui/whiteboardshapes/WhiteboardShape.java
@@ -12,7 +12,7 @@ import java.util.List;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.whiteboardobjects.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* Abstract WhiteboardShape (Shape for the WhitheboardFrame)
diff --git a/src/net/java/sip/communicator/plugin/whiteboard/whiteboard.manifest.mf b/src/net/java/sip/communicator/plugin/whiteboard/whiteboard.manifest.mf
index 14cd534..9f22dd5 100644
--- a/src/net/java/sip/communicator/plugin/whiteboard/whiteboard.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/whiteboard/whiteboard.manifest.mf
@@ -14,7 +14,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.whiteboardobjects,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/yahooaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/yahooaccregwizz/FirstWizardPage.java
index c1e5c0d..810fc4a 100644
--- a/src/net/java/sip/communicator/plugin/yahooaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/yahooaccregwizz/FirstWizardPage.java
@@ -12,7 +12,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
diff --git a/src/net/java/sip/communicator/plugin/yahooaccregwizz/yahooaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/yahooaccregwizz/yahooaccregwizz.manifest.mf
index 1f27b2b..9a283ab 100644
--- a/src/net/java/sip/communicator/plugin/yahooaccregwizz/yahooaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/yahooaccregwizz/yahooaccregwizz.manifest.mf
@@ -16,7 +16,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.icqconstants,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,
diff --git a/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/FirstWizardPage.java
index d46a2e4..ef8b1e1 100644
--- a/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/FirstWizardPage.java
+++ b/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/FirstWizardPage.java
@@ -13,7 +13,7 @@ import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.swing.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
/**
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
diff --git a/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/zeroconfaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/zeroconfaccregwizz.manifest.mf
index 611a2d8..3ff6dd5 100644
--- a/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/zeroconfaccregwizz.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/zeroconfaccregwizz/zeroconfaccregwizz.manifest.mf
@@ -15,7 +15,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
- net.java.sip.communicator.util.swing,
+ net.java.sip.communicator.plugin.desktoputil,
javax.swing,
javax.swing.event,
javax.swing.table,