diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..582d972 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +compile diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..ecf6440 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Tue Sep 22 11:30:47 CEST 2009 +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..f67ef41 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Wed Oct 29 13:23:00 CET 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/additional/artwork/file_needs_download.pdn b/additional/artwork/file_needs_download.pdn new file mode 100644 index 0000000..b85f9e7 Binary files /dev/null and b/additional/artwork/file_needs_download.pdn differ diff --git a/additional/artwork/file_needs_download.png b/additional/artwork/file_needs_download.png new file mode 100644 index 0000000..c8bc08a Binary files /dev/null and b/additional/artwork/file_needs_download.png differ diff --git a/additional/artwork/folder_needs_download.pdn b/additional/artwork/folder_needs_download.pdn new file mode 100644 index 0000000..e5e763b Binary files /dev/null and b/additional/artwork/folder_needs_download.pdn differ diff --git a/additional/artwork/folder_needs_download.png b/additional/artwork/folder_needs_download.png new file mode 100644 index 0000000..42a286f Binary files /dev/null and b/additional/artwork/folder_needs_download.png differ diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..cd71b06 --- /dev/null +++ b/build.properties @@ -0,0 +1,12 @@ +app.name=Simidude +app.version=1.7.0 +app.version.url=170 +app.years=2008 - 2014 +app.company.name=AGYNAMIX +app.company.email=contact@agynamix.de +app.company.www=http://www.simidude.com +app.company.order_url=http://www.simidude.com/order + +update.url.release=http://downloads.simidude.com/v1/updates.xml +update.url.test=http://192.168.0.206/simidude/updates.xml + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..c44939a --- /dev/null +++ b/build.xml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + Application-Name=${app.name} +Application-Version=${app.version} +Application-Years=${app.years} +Company-Name=${app.company.name} +Company-Email=${app.company.email} +Company-WWW=${app.company.www} +Company-Order-Url=${app.company.order_url} +Repository-Revision=${svn.revision.max} +Build-Number=${build.number} +Build-Time=${build.time} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simidude]]> + + AGYNAMIX]]> + + + + + + + + + + + +
diff --git a/build/etc/Icon.gif b/build/etc/Icon.gif new file mode 100644 index 0000000..4180499 Binary files /dev/null and b/build/etc/Icon.gif differ diff --git a/build/etc/Icon.ico b/build/etc/Icon.ico new file mode 100644 index 0000000..129dec3 Binary files /dev/null and b/build/etc/Icon.ico differ diff --git a/build/etc/Icon.png b/build/etc/Icon.png new file mode 100644 index 0000000..aeeb098 Binary files /dev/null and b/build/etc/Icon.png differ diff --git a/build/etc/Icon_16.png b/build/etc/Icon_16.png new file mode 100644 index 0000000..beba1b0 Binary files /dev/null and b/build/etc/Icon_16.png differ diff --git a/build/etc/Icon_32.ico b/build/etc/Icon_32.ico new file mode 100644 index 0000000..d4a22d3 Binary files /dev/null and b/build/etc/Icon_32.ico differ diff --git a/build/etc/Icon_32.png b/build/etc/Icon_32.png new file mode 100644 index 0000000..1ece062 Binary files /dev/null and b/build/etc/Icon_32.png differ diff --git a/build/etc/Icon_32_2.ico b/build/etc/Icon_32_2.ico new file mode 100644 index 0000000..279ab3d Binary files /dev/null and b/build/etc/Icon_32_2.ico differ diff --git a/build/etc/Icon_48.png b/build/etc/Icon_48.png new file mode 100644 index 0000000..be23b28 Binary files /dev/null and b/build/etc/Icon_48.png differ diff --git a/build/etc/Simidude.icns b/build/etc/Simidude.icns new file mode 100644 index 0000000..5f4d41b Binary files /dev/null and b/build/etc/Simidude.icns differ diff --git a/build/etc/build.number b/build/etc/build.number new file mode 100644 index 0000000..806b4dd --- /dev/null +++ b/build/etc/build.number @@ -0,0 +1,3 @@ +#Build Number for ANT. Do not edit! +#Sun Oct 05 15:24:16 CEST 2014 +build.number=325 diff --git a/build/etc/favicon.ico b/build/etc/favicon.ico new file mode 100644 index 0000000..e6c0d09 Binary files /dev/null and b/build/etc/favicon.ico differ diff --git a/build/etc/installer.install4j b/build/etc/installer.install4j new file mode 100644 index 0000000..bd0415d --- /dev/null +++ b/build/etc/installer.install4j @@ -0,0 +1,2349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ./Icon_16.png + + + + + ./Icon_32.png + + + + + false + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context.getBooleanVariable("sys.confirmedUpdateInstallation") + + + + + + + + + + + + en + + ../../etc/license.html + + + + + + + + + + + + + + + + + + + + + !context.getBooleanVariable("sys.confirmedUpdateInstallation") + + + + + + + + + + + + Please make sure that a previous installation of ${compiler:sys.shortName} is not currently running! + +This installer deletes old application data from a previous installation which would fail or lead to unpredictable results if ${compiler:sys.shortName} was currently running. + + + Close any older Simidude instance + + + + + + Make sure Simidude is not currently running + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${compiler:sys.fullName} + + + + + !context.getBooleanVariable("sys.confirmedUpdateInstallation") + + + + + + + + + + + + + + + + + + + + + + + + ${i18n:CreateDesktopIcon} + + + true + + + createDesktopLinkAction + + + + + + + + + + + + + ${i18n:AddToDock} + + + true + + + addToDockAction + + + + + + Util.isMacOS() + + + + + + + ${i18n:CreateQuickLaunchIcon} + + + true + + + createQuicklaunchIconAction + + + + + component.setVisible(Util.isWindows()); + + + + + + + + Start automatically when Computer starts + + + true + + + createAutostartEntryAction + + + + + + Util.isWindows() || Util.isMacOS() + + + + + + + + + + + + + + + + + + + + + + + lib + + + + + + true + + + + + + + + + + + + + + + etc + + + + + + true + + + + + + + + + + + + + + + + + + + + ${i18n:UninstallerMenuEntry(${compiler:sys.fullName})} + + + + + !context.getBooleanVariable("sys.programGroupDisabled") + + + + + + + ${compiler:sys.fullName} ${compiler:sys.version} + + + + + + + + + + + + + Simidude + + + + ${compiler:sys.fullName} + + + + + context.getBooleanVariable("createAutostartEntryAction") + + + + + + + ${compiler:sys.fullName} + + + + Simidude + + + + + + context.getBooleanVariable("createQuicklaunchIconAction") + + + + + + + + Simidude + + + + ${compiler:sys.fullName} + + + + + context.getBooleanVariable("createDesktopLinkAction") + + + + + + + + Simidude + + + + + + context.getBooleanVariable("addToDockAction") + + + + + + + + + + + + + + + + + + + + + 19 + + + + + context.getBooleanVariable("executeLauncherAction") && (!context.isUnattended()) + + + + + + + + + ${i18n:RunEntryExec("${compiler:sys.fullName}")} + + + true + + + executeLauncherAction + + + + + + + + + + + + + + + + + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + com.agynamix.platform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <p>Thank you for trying Simidude!</p> +<p>We would appreciate your feedback at <a href="http://helpdesk.agynamix.de/index.php?pg=request">http://helpdesk.agynamix.de.</a></p> +<p>Thank you!</a> + + + + + + + + + + + + + + + + + + + ${compiler:sys.install4jHome}/resource/updater_16.png + + + + + ${compiler:sys.install4jHome}/resource/updater_32.png + + + + + update + + + false + + + true + + + false + + + ${i18n:updater.WindowTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + ${compiler:Update.Url} + + + updateDescriptor + + + + + + + + + + + + true + + + + + ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry() + + + + + updateDescriptorEntry + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion() + + + + + updaterNewVersion + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileSizeVerbose() + + + + + updaterDownloadSize + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getComment() + + + + + updaterComment + + + + + + + + + + + + + + Util.getUserHome() + + + + + updaterDownloadDir + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm() + + + + + updaterDownloadUrl + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive() ? Boolean.TRUE : Boolean.FALSE + + + + + isArchive + + + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + ${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")} + + + ${i18n:updater.NewVersionAvailableTitle} + + + + + + + + + + + + + + + + ${i18n:updater.CurrentVersionLabel} + + + + 128 + 0 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:sys.version} + + + + + + + + + + + + + ${i18n:updater.NewVersionLabel} + + + + 0 + 128 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:updaterNewVersion} + + + + + + + + + + + + + + + context.goForward(1, false, false); + + + + + ${i18n:updater.ShowComments} + + + + + boolean hasComment = ((String)context.getVariable("updaterComment")).length() > 0; +component.setVisible(hasComment); + + + + + + + + + + + + + + + + + ${i18n:updater.DownloadLocationLabel} + + + + + + + + + + + + + ${installer:updaterDownloadDir} + + + ${i18n:updater.DownloadToLabel} + + + false + + + updaterDownloadLocation + + + + + + + + + + + + + ${i18n:updater.DownloadSizeLabel} + + + ${installer:updaterDownloadSize} + + + + + + + + + + + + + + + ${installer:updaterComment} + + + ${i18n:updater.CommentsLabel} + + + ${i18n:updater.CommentsSubTitle} + + + + + + ${i18n:updater.CommentsTitle} + + + + + false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen. + + if (context.isConsole()) { + context.goBackInHistory(1); +} +return true; + WizardContext wizardContext = context.getWizardContext(); +if (wizardContext != null) { + wizardContext.setNextButtonVisible(false); + wizardContext.setCancelButtonVisible(false); +} + + + + + + + + + + ${i18n:updater.DownloadSubTitle} + + + ${i18n:updater.DownloadTitle} + + + + + + + + + + + + + + + + + context.getVariable("updaterDownloadLocation") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName() + + + + + updaterDownloadFile + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + ${installer:updaterDownloadUrl} + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + + 755 + + + + + + + + + + + + + + + ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.FinishTitle} + + + + + + + + + + + + + + + + + ((Integer)context.getVariable("updaterLaunchSelection")).intValue() == 0 && !context.getBooleanVariable("isArchive") + + + + + + + + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + ${installer:updaterDownloadLocation} + + + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterQuestion} + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterLabel} + + + ${i18n:updater.DoNotLaunchUpdaterLabel} + + + + + updaterLaunchSelection + + + + + if (context.getBooleanVariable("isArchive")) { + component.setVisible(false); +} + + + + + + + + + + Util.showPath((String)context.getVariable("updaterDownloadFile")); + + + + + ${i18n:updater.OpenContainingFolderLabel} + + + + + + + + + + + + + false + + + true + + + + + + + + + + + + + + + + + + + + + ${compiler:sys.install4jHome}/resource/updater_16.png + + + + + ${compiler:sys.install4jHome}/resource/updater_32.png + + + + + updman + + + false + + + true + + + false + + + ${i18n:updater.WindowTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${i18n:updater.WelcomeInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.WelcomeTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + ${i18n:updater.CheckForUpdateLabel} + + + ${i18n:updater.CheckForUpdateSubtitle} + + + ${i18n:updater.CheckForUpdateTitle} + + + + + + + + + + + + + + + + + + + + + + + + + + + ${compiler:Update.Url} + + + updateDescriptor + + + + + + + + + + + + + + + + + + + + + + ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry() + + + + + updateDescriptorEntry + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion() + + + + + updaterNewVersion + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileSizeVerbose() + + + + + updaterDownloadSize + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getComment() + + + + + updaterComment + + + + + + + + + + + + + + Util.getUserHome() + + + + + updaterDownloadDir + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm() + + + + + updaterDownloadUrl + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive() ? Boolean.TRUE : Boolean.FALSE + + + + + isArchive + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") == null + + + + + + + + + + + + + ${i18n:updater.UpToDateInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.UpToDateTitle} + + + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + ${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")} + + + ${i18n:updater.NewVersionAvailableTitle} + + + + + + + + + + + + + + + + ${i18n:updater.CurrentVersionLabel} + + + + 128 + 0 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:sys.version} + + + + + + + + + + + + + ${i18n:updater.NewVersionLabel} + + + + 0 + 128 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:updaterNewVersion} + + + + + + + + + + + + + + + context.goForward(1, false, false); + + + + + ${i18n:updater.ShowComments} + + + + + boolean hasComment = ((String)context.getVariable("updaterComment")).length() > 0; +component.setVisible(hasComment); + + + + + + + + + + + + + + + + + ${i18n:updater.DownloadLocationLabel} + + + + + + + + + + + + + ${installer:updaterDownloadDir} + + + ${i18n:updater.DownloadToLabel} + + + false + + + updaterDownloadLocation + + + + + + + + + + + + + ${i18n:updater.DownloadSizeLabel} + + + ${installer:updaterDownloadSize} + + + + + + + + + + + + + + + ${installer:updaterComment} + + + ${i18n:updater.CommentsLabel} + + + ${i18n:updater.CommentsSubTitle} + + + + + + ${i18n:updater.CommentsTitle} + + + + + false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen. + + if (context.isConsole()) { + context.goBackInHistory(1); +} +return true; + WizardContext wizardContext = context.getWizardContext(); +if (wizardContext != null) { + wizardContext.setNextButtonVisible(false); + wizardContext.setCancelButtonVisible(false); +} + + + + + + + + + + ${i18n:updater.DownloadSubTitle} + + + ${i18n:updater.DownloadTitle} + + + + + + + + + + + + + + + + + context.getVariable("updaterDownloadLocation") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName() + + + + + updaterDownloadFile + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + ${installer:updaterDownloadUrl} + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + + 755 + + + + + + + + + + + + + + + ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.FinishTitle} + + + + + + + + + + + + + + + + + ((Integer)context.getVariable("updaterLaunchSelection")).intValue() == 0 && !context.getBooleanVariable("isArchive") + + + + + + + + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + ${installer:updaterDownloadLocation} + + + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterQuestion} + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterLabel} + + + ${i18n:updater.DoNotLaunchUpdaterLabel} + + + + + updaterLaunchSelection + + + + + if (context.getBooleanVariable("isArchive")) { + component.setVisible(false); +} + + + + + + + + + + Util.showPath((String)context.getVariable("updaterDownloadFile")); + + + + + ${i18n:updater.OpenContainingFolderLabel} + + + + + + + + + + + + + false + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/etc/installer.install4j.ej-tech b/build/etc/installer.install4j.ej-tech new file mode 100644 index 0000000..9349e42 --- /dev/null +++ b/build/etc/installer.install4j.ej-tech @@ -0,0 +1,2135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../AppData/Local/Temp/Icon_16.png + + + + + ../AppData/Local/Temp/Icon_32.png + + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../AppData/etc/license.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please make sure that a previous installation of ${compiler:sys.shortName} is not currently running! + +This installer deletes old application data from a previous installation which would fail or lead to unpredictable results if ${compiler:sys.shortName} was currently running. + + + Make sure Simidude is not currently running + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${i18n:CreateDesktopIcon} + + + true + + + createDesktopLinkAction + + + + + + + + + + + + + ${i18n:CreateQuickLaunchIcon} + + + true + + + createQuicklaunchIconAction + + + + + + Util.isWindows() + + + + + + + Start automatically when Windows starts + + + true + + + createAutostartEntryAction + + + + + + Util.isWindows() + + + + + + + + + + + + + + + + + + + + + lib + + + + true + + + + + + + + + + + + + etc + + + + true + + + + + + + + + + + + + + + + + + + + ${compiler:sys.fullName} + + + + + + + + + + + + ${compiler:sys.fullName} ${compiler:sys.version} + + + + + + + + + + + + + Simidude + + + + ${compiler:sys.fullName} + + + + + context.getBooleanVariable("createAutostartEntryAction") + + + + + + + ${compiler:sys.fullName} + + + + Simidude + + + + + + context.getBooleanVariable("createQuicklaunchIconAction") + + + + + + + + Simidude + + + + ${compiler:sys.fullName} + + + + + context.getBooleanVariable("createDesktopLinkAction") + + + + + + + + + + + + + + + + + + + + + 19 + + + + + context.getBooleanVariable("executeLauncherAction") && (!context.isUnattended()) + + + + + + + + + ${i18n:RunEntryExec("${compiler:sys.fullName}")} + + + true + + + executeLauncherAction + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + com.agynamix.platform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <p>Thank you for trying Simidude!</p> +<p>We would appreciate your feedback at <a href="http://helpdesk.agynamix.de/index.php?pg=request">http://helpdesk.agynamix.de.</a></p> +<p>Thank you!</a> + + + + + + + + + + + + + + + + + + C:/Users/hannes/AppData/Local/Temp/${compiler:sys.install4jHome}/resource/updater_16.png + + + + + C:/Users/hannes/AppData/Local/Temp/${compiler:sys.install4jHome}/resource/updater_32.png + + + + update + + + true + + + false + + + ${i18n:updater.WindowTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + + + + + + false + + + ${compiler:Update.Url} + + + updateDescriptor + + + + + + + + + + + + true + + + + + ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry() + + + + + updateDescriptorEntry + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion() + + + + + updaterNewVersion + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileSizeVerbose() + + + + + updaterDownloadSize + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getComment() + + + + + updaterComment + + + + + + + + + + + + + + Util.getUserHome() + + + + + updaterDownloadDir + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm() + + + + + updaterDownloadUrl + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive() ? Boolean.TRUE : Boolean.FALSE + + + + + isArchive + + + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + ${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")} + + + ${i18n:updater.NewVersionAvailableTitle} + + + + + + + + + + + + + + + + ${i18n:updater.CurrentVersionLabel} + + + + 128 + 0 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:sys.version} + + + + + + + + + + + + + ${i18n:updater.NewVersionLabel} + + + + 0 + 128 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:updaterNewVersion} + + + + + + + + + + + + + + + context.goForward(1, false, false); + + + + + ${i18n:updater.ShowComments} + + + + + boolean hasComment = ((String)context.getVariable("updaterComment")).length() > 0; +component.setVisible(hasComment); + + + + + + + + + + + + + + + + + ${i18n:updater.DownloadLocationLabel} + + + + + + + + + + + + + ${installer:updaterDownloadDir} + + + ${i18n:updater.DownloadToLabel} + + + false + + + updaterDownloadLocation + + + + + + + + + + + + + ${i18n:updater.DownloadSizeLabel} + + + ${installer:updaterDownloadSize} + + + + + + + + + + + + + + + ${installer:updaterComment} + + + ${i18n:updater.CommentsLabel} + + + ${i18n:updater.CommentsSubTitle} + + + ${i18n:updater.CommentsTitle} + + + + + false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen. + + if (context.isConsole()) { + context.goBackInHistory(1); +} +return true; + WizardContext wizardContext = context.getWizardContext(); +if (wizardContext != null) { + wizardContext.setNextButtonVisible(false); + wizardContext.setCancelButtonVisible(false); +} + + + + + + + + + + ${i18n:updater.DownloadSubTitle} + + + ${i18n:updater.DownloadTitle} + + + + + + + + + + + + + + + + + context.getVariable("updaterDownloadLocation") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName() + + + + + updaterDownloadFile + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + ${installer:updaterDownloadUrl} + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + 755 + + + + + + + + + + + + + + + ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.FinishTitle} + + + + + + + + + + + + + + + + + ((Integer)context.getVariable("updaterLaunchSelection")).intValue() == 0 && !context.getBooleanVariable("isArchive") + + + + + + + + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + ${installer:updaterDownloadLocation} + + + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterQuestion} + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterLabel} + + + ${i18n:updater.DoNotLaunchUpdaterLabel} + + + + + updaterLaunchSelection + + + + + if (context.getBooleanVariable("isArchive")) { + component.setVisible(false); +} + + + + + + + + + + Util.showPath((String)context.getVariable("updaterDownloadFile")); + + + + + ${i18n:updater.OpenContainingFolderLabel} + + + + + + + + + + + + + false + + + true + + + + + + + + + + + + + + + + + + + + C:/Users/hannes/AppData/Local/Temp/${compiler:sys.install4jHome}/resource/updater_16.png + + + + + C:/Users/hannes/AppData/Local/Temp/${compiler:sys.install4jHome}/resource/updater_32.png + + + + updman + + + true + + + false + + + ${i18n:updater.WindowTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + + + + + + + + + + ${i18n:updater.WelcomeInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.WelcomeTitle("${compiler:sys.fullName}")} + + + + + + + + + + + + + + + + + ${i18n:updater.CheckForUpdateLabel} + + + ${i18n:updater.CheckForUpdateSubtitle} + + + ${i18n:updater.CheckForUpdateTitle} + + + + + + + + + + + + + + + + + + + + + + + + + + + ${compiler:Update.Url} + + + updateDescriptor + + + + + + + + + + + + + + + + + + + + + + ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry() + + + + + updateDescriptorEntry + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion() + + + + + updaterNewVersion + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileSizeVerbose() + + + + + updaterDownloadSize + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getComment() + + + + + updaterComment + + + + + + + + + + + + + + Util.getUserHome() + + + + + updaterDownloadDir + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm() + + + + + updaterDownloadUrl + + + + + + + + + + + + + + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive() ? Boolean.TRUE : Boolean.FALSE + + + + + isArchive + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") == null + + + + + + + + + + + + + ${i18n:updater.UpToDateInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.UpToDateTitle} + + + + + + + + + + + + + + + + + + + + + context.getVariable("updateDescriptorEntry") != null + + + + + + + + + + + + + ${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")} + + + ${i18n:updater.NewVersionAvailableTitle} + + + + + + + + + + + + + + + + ${i18n:updater.CurrentVersionLabel} + + + + 128 + 0 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:sys.version} + + + + + + + + + + + + + ${i18n:updater.NewVersionLabel} + + + + 0 + 128 + 0 + 255 + + + + + dialog + 1 + 0 + + + + ${installer:updaterNewVersion} + + + + + + + + + + + + + + + context.goForward(1, false, false); + + + + + ${i18n:updater.ShowComments} + + + + + boolean hasComment = ((String)context.getVariable("updaterComment")).length() > 0; +component.setVisible(hasComment); + + + + + + + + + + + + + + + + + ${i18n:updater.DownloadLocationLabel} + + + + + + + + + + + + + ${installer:updaterDownloadDir} + + + ${i18n:updater.DownloadToLabel} + + + false + + + updaterDownloadLocation + + + + + + + + + + + + + ${i18n:updater.DownloadSizeLabel} + + + ${installer:updaterDownloadSize} + + + + + + + + + + + + + + + ${installer:updaterComment} + + + ${i18n:updater.CommentsLabel} + + + ${i18n:updater.CommentsSubTitle} + + + ${i18n:updater.CommentsTitle} + + + + + false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen. + + if (context.isConsole()) { + context.goBackInHistory(1); +} +return true; + WizardContext wizardContext = context.getWizardContext(); +if (wizardContext != null) { + wizardContext.setNextButtonVisible(false); + wizardContext.setCancelButtonVisible(false); +} + + + + + + + + + + ${i18n:updater.DownloadSubTitle} + + + ${i18n:updater.DownloadTitle} + + + + + + + + + + + + + + + + + context.getVariable("updaterDownloadLocation") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName() + + + + + updaterDownloadFile + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + ${installer:updaterDownloadUrl} + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + 755 + + + + + + + + + + + + + + + ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")} + + + ${i18n:updater.FinishTitle} + + + + + + + + + + + + + + + + + ((Integer)context.getVariable("updaterLaunchSelection")).intValue() == 0 && !context.getBooleanVariable("isArchive") + + + + + + + + + + + + + + + + + + + + + + ${installer:updaterDownloadFile} + + + + + ${installer:updaterDownloadLocation} + + + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterQuestion} + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + ${i18n:updater.LaunchUpdaterLabel} + + + ${i18n:updater.DoNotLaunchUpdaterLabel} + + + + + updaterLaunchSelection + + + + + if (context.getBooleanVariable("isArchive")) { + component.setVisible(false); +} + + + + + + + + + + Util.showPath((String)context.getVariable("updaterDownloadFile")); + + + + + ${i18n:updater.OpenContainingFolderLabel} + + + + + + + + + + + + + false + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/etc/obfuscator.pro b/build/etc/obfuscator.pro new file mode 100644 index 0000000..ba99881 --- /dev/null +++ b/build/etc/obfuscator.pro @@ -0,0 +1,50 @@ +-injars /Users/tuhlmann/entw/aktuell/Simidude/target/distribution/Simidude/lib/simidude-naked.jar +-outjars /Users/tuhlmann/entw/aktuell/Simidude/target/distribution/Simidude/lib/simidude.jar + +-libraryjars /Users/tuhlmann/entw/aktuell/Simidude/lib +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/charsets.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/classes.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/dt.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/jce.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/jconsole.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/jsse.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/laf.jar +-libraryjars /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/ui.jar + +-target 1.5 +-printmapping out.map +# -keepattributes 'SourceFile,LineNumberTable' + + +-keep class *MBean + +-keep class * extends com.agynamix.platform.infra.IPluginMarker + +-keep class com.agynamix.platform.icons.PlatformIcons + +# Keep - Applications. Keep all application classes, along with their 'main' +# methods. +-keepclasseswithmembers public class * { + public static void main(java.lang.String[]); +} + +# Also keep - Enumerations. Keep the special static methods that are required in +# enumeration classes. +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +# Also keep - Database drivers. Keep all implementations of java.sql.Driver. +-keep class * extends java.sql.Driver + +# Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI, +# along with the special 'createUI' method. +-keep class * extends javax.swing.plaf.ComponentUI { + public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); +} + +# Keep names - Native method names. Keep all native class/method names. +-keepclasseswithmembers,allowshrinking class * { + native ; +} diff --git a/build/etc/obfuscator.pro.user b/build/etc/obfuscator.pro.user new file mode 100644 index 0000000..1eba357 --- /dev/null +++ b/build/etc/obfuscator.pro.user @@ -0,0 +1,143 @@ + + + + RunConfiguration0-CommandLineArguments + + + + RunConfiguration0-ProFile + obfuscator.pro + + + RunConfiguration0-RunConfiguration.name + obfuscator + + + RunConfiguration0-UseDyldImageSuffix + false + + + RunConfiguration0-UseTerminal + false + + + RunConfiguration0-UserEnvironmentChanges + + + + RunConfiguration0-UserSetName + false + + + RunConfiguration0-type + Qt4ProjectManager.Qt4RunConfiguration + + + activeRunConfiguration + 0 + + + activebuildconfiguration + Debug + + + buildConfiguration-Debug + + Debug + 0 + + + + buildConfiguration-Release + + Release + 0 + + + + buildconfiguration-Debug-buildstep0 + + Debug + 2 + + + + buildconfiguration-Debug-buildstep1 + + Debug + + + + buildconfiguration-Debug-cleanstep0 + + Debug + + + + buildconfiguration-Release-buildstep0 + + Release + 0 + + + + buildconfiguration-Release-buildstep1 + + Release + + + + buildconfiguration-Release-cleanstep0 + + Release + + + + buildconfigurations + + Debug + Release + + + + buildstep0 + + + + + + + buildstep1 + + + + + + buildsteps + + trolltech.qt4projectmanager.qmake + trolltech.qt4projectmanager.make + + + + cleanstep0 + + + true + + + + cleansteps + + trolltech.qt4projectmanager.make + + + + defaultFileEncoding + System + + + project + + + diff --git a/build/etc/out.map b/build/etc/out.map new file mode 100644 index 0000000..d43aa1b --- /dev/null +++ b/build/etc/out.map @@ -0,0 +1,1920 @@ +com.agynamix.license.DefaultLicenseManager -> com.agynamix.license.j: + com.agynamix.license.ILicenseParam licenseParam -> a + com.agynamix.license.License installedLicense -> b + java.security.PrivateKey privateKey -> c + java.security.PublicKey publicKey -> d + java.security.PublicKey publicTrialKey -> e + java.util.logging.Logger log -> f + com.agynamix.license.License reviewLicense() -> b + com.agynamix.license.License getInstalledLicense() -> c + com.agynamix.license.License installLicense(com.agynamix.license.License) -> b + java.lang.String exportLicense(com.agynamix.license.License) -> a + com.agynamix.license.License signLicense(com.agynamix.license.License) -> c + com.agynamix.license.License signTrialLicense(com.agynamix.license.License) -> d + com.agynamix.license.License signLicense(java.security.PrivateKey,com.agynamix.license.License) -> a + boolean verifyLicenseIntegrity(com.agynamix.license.License) -> e + com.agynamix.license.License validateLicenseText(java.lang.String) -> a + java.security.PrivateKey getPrivateKey(byte[],byte[]) -> a + java.security.PublicKey getPublicKey(byte[],byte[]) -> b + void createLicenseKeyPair() -> a +com.agynamix.license.GeneralLicenseException -> com.agynamix.license.a: +com.agynamix.license.ILicenseManager -> com.agynamix.license.g: + void createLicenseKeyPair() -> a + com.agynamix.license.License reviewLicense() -> b + com.agynamix.license.License getInstalledLicense() -> c + com.agynamix.license.License validateLicenseText(java.lang.String) -> a + java.lang.String exportLicense(com.agynamix.license.License) -> a + com.agynamix.license.License installLicense(com.agynamix.license.License) -> b + com.agynamix.license.License signLicense(com.agynamix.license.License) -> c +com.agynamix.license.ILicenseParam -> com.agynamix.license.h: + java.util.prefs.Preferences getPreferences() -> a + byte[] getPrivateKey() -> b + byte[] getPublicKey() -> c + byte[] getPublicTrialKey() -> d + byte[] getPrivateKeyPassword() -> f + byte[] getPublicKeyPassword() -> g + byte[] getPublicTrialKeyPassword() -> h + byte[] getLicenseKeyPassword() -> e + boolean isTrialEligible() -> k + void removeTrialEligibility() -> l + com.agynamix.license.License createTrialLicense() -> i + com.agynamix.license.ILicenseValidator getLicenseValidator() -> j + void storePublicTrialKey(byte[]) -> a +com.agynamix.license.ILicenseStatus -> com.agynamix.license.m: + boolean licenseValid -> a + java.lang.String userMessage -> b + boolean isLicenseValid() -> a + java.lang.String getUserMessage() -> b +com.agynamix.license.ILicenseValidator -> com.agynamix.license.d: + java.util.prefs.Preferences preferences -> a + com.agynamix.license.ILicenseStatus validate(com.agynamix.license.License) -> a + java.util.prefs.Preferences getPreferences() -> a + byte[] getPrivateKey() -> b + byte[] getPublicKey() -> c + byte[] getPublicTrialKey() -> d + byte[] getLicenseKeyPassword() -> e + byte[] getPrivateKeyPassword() -> f + byte[] getPublicKeyPassword() -> g + byte[] getPublicTrialKeyPassword() -> h + com.agynamix.license.License createTrialLicense() -> i + com.agynamix.license.ILicenseValidator getLicenseValidator() -> j + boolean isTrialEligible() -> k + void removeTrialEligibility() -> l + void storePublicTrialKey(byte[]) -> a + java.lang.String getVersionFirstDigit() -> m +com.agynamix.license.KeyGenerator -> com.agynamix.license.KeyGenerator: + void main(java.lang.String[]) -> main +com.agynamix.license.License -> com.agynamix.license.e: + java.util.Date NEVER_EXPIRE_DATE -> a + com.agynamix.license.License$LicenseType licenseType -> b + java.lang.String serialNumber -> c + java.lang.String holderCompany -> d + java.lang.String holderName -> e + java.lang.String holderEmail -> f + java.lang.String subject -> g + java.lang.String version -> h + java.lang.String signature -> i + java.util.Date expireDate -> j + java.lang.String licenseText -> k + void setSerialNumber(java.lang.String) -> a + void setSubject(java.lang.String) -> b + void setVersion(java.lang.String) -> c + void setNeverExpires() -> a + void setExpireDate(java.util.Date) -> a + java.lang.String getHolderCompany() -> b + void setHolderCompany(java.lang.String) -> d + java.lang.String getHolderName() -> c + void setHolderName(java.lang.String) -> e + java.lang.String getHolderEmail() -> d + void setHolderEmail(java.lang.String) -> f + void setSignature(java.lang.String) -> g + java.lang.String getSignature() -> e + java.lang.String getSubject() -> f + java.lang.String getVersion() -> g + java.util.Date getExpireDate() -> h + java.lang.String getExpireDateStr() -> i + void setLicenseType(com.agynamix.license.License$LicenseType) -> a + com.agynamix.license.License$LicenseType getLicenseType() -> j + java.util.Properties getProperties(boolean) -> a + void setLicenseText(java.lang.String) -> h + java.lang.String getLicenseText() -> k + java.lang.String getLicenseVersion() -> l +com.agynamix.license.License$LicenseType -> com.agynamix.license.l: + com.agynamix.license.License$LicenseType TRIAL -> a + com.agynamix.license.License$LicenseType FULL -> b + java.lang.String descriptiveName -> c + com.agynamix.license.License$LicenseType[] $VALUES -> d + com.agynamix.license.License$LicenseType[] values() -> values + com.agynamix.license.License$LicenseType valueOf(java.lang.String) -> valueOf + java.lang.String getDescriptiveName() -> a +com.agynamix.license.LicenseGenerationException -> com.agynamix.license.f: +com.agynamix.license.LicenseGenerator -> com.agynamix.license.LicenseGenerator: + void main(java.lang.String[]) -> main +com.agynamix.license.LicenseIntegrityViolationException -> com.agynamix.license.c: +com.agynamix.license.LicenseManagerFactory -> com.agynamix.license.k: + com.agynamix.license.ILicenseManager licenseManager -> a + com.agynamix.license.ILicenseManager getLicenseManager() -> a + void registerLicenseManager(com.agynamix.license.ILicenseManager) -> a +com.agynamix.license.LicenseUtils -> com.agynamix.license.i: + java.util.Date HIGH_DATE -> a + byte[] ivBytes -> b + java.lang.String license2encryptedString(com.agynamix.license.License,byte[]) -> a + java.lang.String padString(java.lang.String,int,java.lang.String) -> a + com.agynamix.license.License encryptedString2License(java.lang.String,byte[]) -> a + com.agynamix.license.License transportFormat2License(java.lang.String) -> a + java.lang.String license2TransportFormat(com.agynamix.license.License,boolean) -> a + byte[] base64ToBytes(java.lang.String) -> b + java.lang.String bytesToBase64(byte[]) -> a + byte[] decrypt(byte[],byte[]) -> a + byte[] encrypt(byte[],byte[]) -> b + byte[] signLicense(java.security.PrivateKey,com.agynamix.license.License) -> a + boolean verifyLicenseIntegrity(java.security.PublicKey,com.agynamix.license.License) -> a + byte[] getBytesFromClasspathResource(java.lang.Class,java.lang.String) -> a + java.security.KeyPair generateKeyPair(int) -> a +com.agynamix.license.LicenseVerificationException -> com.agynamix.license.b: +com.agynamix.license.SignatureExample -> com.agynamix.license.SignatureExample: + void main(java.lang.String[]) -> main + java.lang.String printBytes(byte[]) -> a + boolean verifySig(byte[],java.security.PublicKey,byte[]) -> a + java.security.KeyPair generateKeyPair(long) -> a +com.agynamix.license.SymmetricEncryptionExample -> com.agynamix.license.SymmetricEncryptionExample: + void main(java.lang.String[]) -> main +com.agynamix.license.ui.CmdLicenseGenerator -> com.agynamix.license.ui.CmdLicenseGenerator: + java.util.logging.Logger log -> a + void main(java.lang.String[]) -> main + java.lang.String decodeField(java.lang.String) -> a +com.agynamix.platform.bugzscout.BugzScoutCtl -> com.agynamix.platform.bugzscout.BugzScoutCtl: + java.lang.String url -> a + java.lang.String userName -> b + java.lang.String project -> c + java.lang.String area -> d + java.lang.String defaultMessage -> e + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer submitBug(java.lang.String,java.lang.String,java.lang.String,boolean) -> a + void setArea(java.lang.String) -> a + void setDefaultMessage(java.lang.String) -> b + void setProject(java.lang.String) -> c + void setUrl(java.lang.String) -> d + void setUserName(java.lang.String) -> e + void main(java.lang.String[]) -> main +com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer -> com.agynamix.platform.bugzscout.e: + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode returnCode -> a + java.lang.String message -> b + java.lang.String getMessage() -> a + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode getReturnCode() -> b +com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode -> com.agynamix.platform.bugzscout.b: + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode UNKNOWN -> a + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode SUCCESS -> b + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode ERROR -> c + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode SYSERROR -> d + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode[] $VALUES -> e + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode[] values() -> values + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer$ReturnCode valueOf(java.lang.String) -> valueOf +com.agynamix.platform.bugzscout.SimpleHttpClient -> com.agynamix.platform.bugzscout.a: + java.net.Proxy findProxy(java.net.URI) -> a + com.agynamix.platform.bugzscout.SimpleHttpClient$Response sendRequest(java.lang.String,java.util.Map) -> a + java.lang.String readFromStream(java.io.InputStream) -> a +com.agynamix.platform.bugzscout.SimpleHttpClient$Response -> com.agynamix.platform.bugzscout.c: + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status responseStatus -> a + java.lang.String errorMsg -> b + byte[] body -> c +com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status -> com.agynamix.platform.bugzscout.d: + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status SC_UNKNOWN -> c + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status SC_OK -> a + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status SC_ERROR -> b + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status[] $VALUES -> d + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status[] values() -> values + com.agynamix.platform.bugzscout.SimpleHttpClient$Response$Status valueOf(java.lang.String) -> valueOf +com.agynamix.platform.concurrent.AbstractService -> com.agynamix.platform.f.a: + java.lang.String serviceId -> a + boolean stopped -> b + boolean isInitialized -> c + java.util.logging.Logger log -> d + java.lang.String getId() -> a + void initialize() -> b + void internalInitialize() -> c + void shutdown() -> d + void internalRun() -> e + void run() -> run +com.agynamix.platform.concurrent.ThreadManager -> com.agynamix.platform.f.b: + java.util.List processList -> a + java.util.concurrent.ExecutorService service -> b + java.util.logging.Logger log -> c + void startRegisteredServices() -> a + void shutdownNow() -> b +com.agynamix.platform.concurrent.ThreadManagerAware -> com.agynamix.platform.f.c: + void shutdown() -> d + java.lang.String getId() -> a +com.agynamix.platform.frontend.action.CheckUpdatesAction -> com.agynamix.platform.a.c.n: + void run() -> run +com.agynamix.platform.frontend.action.CheckUpdatesAction$1 -> com.agynamix.platform.a.c.a: + void exited(int) -> exited + void prepareShutdown() -> prepareShutdown +com.agynamix.platform.frontend.action.ClearClipboardTableAction -> com.agynamix.platform.a.c.f: + boolean isNetworkRemove -> a + void run() -> run +com.agynamix.platform.frontend.action.CopyAction -> com.agynamix.platform.a.c.h: + void run() -> run +com.agynamix.platform.frontend.action.CutAction -> com.agynamix.platform.a.c.e: + void run() -> run +com.agynamix.platform.frontend.action.ExitAction -> com.agynamix.platform.a.c.j: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.HideAction -> com.agynamix.platform.a.c.l: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.InputTextAction -> com.agynamix.platform.a.c.i: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.LicenseDialogAction -> com.agynamix.platform.a.c.g: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.PreferencesAction -> com.agynamix.platform.a.c.k: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.RemoveSelectedClipboardEntry -> com.agynamix.platform.a.c.c: + boolean isNetworkRemove -> a + void selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) -> selectionChanged + void run() -> run +com.agynamix.platform.frontend.action.SaveAsAction -> com.agynamix.platform.a.c.b: + void run() -> run +com.agynamix.platform.frontend.action.SaveAsCompressedAction -> com.agynamix.platform.a.c.m: + void run() -> run +com.agynamix.platform.frontend.action.SubmitBugzScoutAction -> com.agynamix.platform.a.c.d: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.platform.frontend.action.ToggleShowToolbarAction -> com.agynamix.platform.a.c.o: + org.eclipse.jface.window.ApplicationWindow window -> a + org.eclipse.swt.widgets.Control toolbar -> b + void setToolbar(org.eclipse.swt.widgets.Control) -> a + void run() -> run + void showToolbar(boolean) -> a +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog -> com.agynamix.platform.a.b.d: + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea + void seperator(org.eclipse.swt.widgets.Composite) -> a + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + void access$000(com.agynamix.platform.frontend.dialogs.AboutApplicationDialog) -> a +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog$1 -> com.agynamix.platform.a.b.g: + org.eclipse.swt.widgets.Label val$email -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog$2 -> com.agynamix.platform.a.b.c: + org.eclipse.swt.graphics.Cursor val$hoverCursor -> a + org.eclipse.swt.graphics.Color val$hoverForeground -> b + void widgetDisposed(org.eclipse.swt.events.DisposeEvent) -> widgetDisposed +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog$3 -> com.agynamix.platform.a.b.l: + org.eclipse.swt.widgets.Label val$www -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog$4 -> com.agynamix.platform.a.b.a: + com.agynamix.platform.frontend.dialogs.AboutApplicationDialog this$0 -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.AboutApplicationDialog$5 -> com.agynamix.platform.a.b.b: + java.lang.String val$companyOrderUrl -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.AbstractDetailsDialog -> com.agynamix.platform.a.b.k: + java.lang.String shortTitle -> a + java.lang.String title -> b + java.lang.String message -> c + org.eclipse.swt.graphics.Image image -> d + org.eclipse.swt.widgets.Button detailsButton -> e + org.eclipse.swt.widgets.Control detailsArea -> f + org.eclipse.swt.graphics.Point cachedWindowSize -> g + void buttonPressed(int) -> buttonPressed + void configureShell(org.eclipse.swt.widgets.Shell) -> configureShell + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea + org.eclipse.swt.widgets.Control createDetailsArea(org.eclipse.swt.widgets.Composite) -> a + java.lang.String getDetailsAsString() -> a +com.agynamix.platform.frontend.dialogs.BugReportDetailsDialog -> com.agynamix.platform.a.b.h: + org.eclipse.swt.graphics.Image image -> a + org.eclipse.swt.graphics.Color backgroundColor -> b + java.lang.String title -> c + java.lang.String description -> d + java.lang.String userEmail -> e + boolean close() -> close + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea +com.agynamix.platform.frontend.dialogs.BugzScoutAnswerDialog -> com.agynamix.platform.a.b.j: + org.eclipse.swt.graphics.Image image -> a + org.eclipse.swt.graphics.Color backgroundColor -> b + com.agynamix.platform.bugzscout.BugzScoutCtl$ScoutAnswer answer -> c + boolean close() -> close + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea +com.agynamix.platform.frontend.dialogs.BugzScoutDialog -> com.agynamix.platform.a.b.n: + org.eclipse.swt.graphics.Image image -> a + org.eclipse.swt.widgets.Text bugTitle -> b + org.eclipse.swt.widgets.Text bugDescription -> c + org.eclipse.swt.widgets.Text userEmail -> d + java.lang.String extraInformation -> e + java.lang.String systemInformation -> f + java.lang.String bugTitleStr -> g + boolean isUserOpened -> h + boolean close() -> close + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + void buttonPressed(int) -> buttonPressed + java.lang.String composeTitle(java.lang.String,java.lang.String,boolean) -> a + java.lang.String composeBugDescription(java.lang.String,java.lang.String,java.lang.String) -> a + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea +com.agynamix.platform.frontend.dialogs.ExceptionDetailsDialog -> com.agynamix.platform.a.b.o: + java.lang.Throwable details -> a + org.eclipse.swt.widgets.Control createDetailsArea(org.eclipse.swt.widgets.Composite) -> a + java.lang.String getDetailsAsString() -> a + java.lang.String getTitle(java.lang.String,java.lang.Object) -> a + java.lang.String getMessage(java.lang.String,java.lang.Object) -> b + void appendException(java.io.PrintWriter,java.lang.Throwable) -> a + void appendStatus(java.io.PrintWriter,org.eclipse.core.runtime.IStatus,int) -> a +com.agynamix.platform.frontend.dialogs.InputNetworkAddressDialog -> com.agynamix.platform.a.b.m: + org.eclipse.swt.widgets.Text text -> a + java.lang.String finalContents -> b + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + void buttonPressed(int) -> buttonPressed + java.lang.String getText() -> a +com.agynamix.platform.frontend.dialogs.InputNetworkAddressDialog$1 -> com.agynamix.platform.a.b.i: + com.agynamix.platform.frontend.dialogs.InputNetworkAddressDialog this$0 -> a + void keyPressed(org.eclipse.swt.events.KeyEvent) -> keyPressed +com.agynamix.platform.frontend.dialogs.InputTextDialog -> com.agynamix.platform.a.b.f: + org.eclipse.swt.widgets.Text text -> a + java.lang.String finalContents -> b + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea + void createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) -> createButtonsForButtonBar + void buttonPressed(int) -> buttonPressed + java.lang.String getText() -> a +com.agynamix.platform.frontend.dialogs.InputTextDialog$1 -> com.agynamix.platform.a.b.e: + com.agynamix.platform.frontend.dialogs.InputTextDialog this$0 -> a + void keyPressed(org.eclipse.swt.events.KeyEvent) -> keyPressed +com.agynamix.platform.frontend.dialogs.license.ILicenseDialogView -> com.agynamix.platform.a.b.a.e: + int open() -> open + void setPresenter(com.agynamix.platform.frontend.dialogs.license.LicenseDialog) -> a + java.lang.String getLicenseString() -> a + void onLicenseNotValid(java.lang.String) -> a + void onLicenseValid() -> b + void setProduct(java.lang.String) -> b + void setExpDate(java.lang.String) -> d + void setLicenseType(java.lang.String) -> e + void setUserName(java.lang.String) -> f + void setCompany(java.lang.String) -> g + void setEmail(java.lang.String) -> h + void setProductVersion(java.lang.String) -> c + void setLicenseText(java.lang.String) -> i + void enableOkButton(boolean) -> a + org.eclipse.swt.widgets.Shell getShell() -> getShell +com.agynamix.platform.frontend.dialogs.license.LicenseDialog -> com.agynamix.platform.a.b.a.a: + com.agynamix.platform.frontend.dialogs.license.ILicenseDialogView view -> a + com.agynamix.license.License currentLicense -> b + int open() -> a + void onInit() -> b + void onValidate() -> c + void setLicenseFields(com.agynamix.license.License) -> a + com.agynamix.simidude.source.impl.TextSourceData$TextType recognizeTextType(java.lang.String) -> a +com.agynamix.platform.frontend.dialogs.license.LicenseDialogView -> com.agynamix.platform.a.b.a.d: + com.agynamix.platform.frontend.dialogs.license.LicenseDialog presenter -> a + org.eclipse.swt.widgets.Text licStr -> b + org.eclipse.swt.widgets.Button btnValidate -> c + org.eclipse.swt.dnd.Clipboard clipboard -> d + com.agynamix.platform.frontend.dialogs.license.LicenseInformationView licenseView -> e + void setPresenter(com.agynamix.platform.frontend.dialogs.license.LicenseDialog) -> a + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + void buttonPressed(int) -> buttonPressed + org.eclipse.swt.widgets.Control createDialogArea(org.eclipse.swt.widgets.Composite) -> createDialogArea + java.lang.String getLicenseString() -> a + void onLicenseNotValid(java.lang.String) -> a + void onLicenseValid() -> b + void enableOkButton(boolean) -> a + void setProduct(java.lang.String) -> b + void setProductVersion(java.lang.String) -> c + void setExpDate(java.lang.String) -> d + void setLicenseType(java.lang.String) -> e + void setUserName(java.lang.String) -> f + void setCompany(java.lang.String) -> g + void setEmail(java.lang.String) -> h + void setLicenseText(java.lang.String) -> i +com.agynamix.platform.frontend.dialogs.license.LicenseDialogView$1 -> com.agynamix.platform.a.b.a.c: + com.agynamix.platform.frontend.dialogs.license.LicenseDialogView this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.dialogs.license.LicenseDialogView$2 -> com.agynamix.platform.a.b.a.g: + com.agynamix.platform.frontend.dialogs.license.LicenseDialogView this$0 -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.license.LicenseDialogView$3 -> com.agynamix.platform.a.b.a.f: + com.agynamix.platform.frontend.dialogs.license.LicenseDialogView this$0 -> a + void mouseDown(org.eclipse.swt.events.MouseEvent) -> mouseDown +com.agynamix.platform.frontend.dialogs.license.LicenseInformationView -> com.agynamix.platform.a.b.a.b: + org.eclipse.swt.widgets.Composite parent -> a + org.eclipse.swt.widgets.Text txtProduct -> b + org.eclipse.swt.widgets.Text txtVersion -> c + org.eclipse.swt.widgets.Text expDate -> d + org.eclipse.swt.widgets.Text licType -> e + org.eclipse.swt.widgets.Text txtName -> f + org.eclipse.swt.widgets.Text txtCompany -> g + org.eclipse.swt.widgets.Text txtEmail -> h + org.eclipse.swt.widgets.Composite create() -> a + void setProduct(java.lang.String) -> a + void setProductVersion(java.lang.String) -> b + void setExpDate(java.lang.String) -> c + void setLicenseType(java.lang.String) -> d + void setUserName(java.lang.String) -> e + void setCompany(java.lang.String) -> f + void setEmail(java.lang.String) -> g + com.agynamix.platform.net.protocol.NodeCommand toProtocol(byte[]) -> a + java.lang.String getCommand(byte[]) -> b +com.agynamix.platform.frontend.gui.ApplicationGUI -> com.agynamix.platform.a.d.o: + org.eclipse.swt.graphics.Image shellImage -> e + com.agynamix.platform.frontend.gui.ApplicationTray myTray -> f + com.agynamix.platform.infra.IConfiguration config -> g + org.eclipse.jface.action.IAction exitAction -> h + org.eclipse.jface.action.IAction licenseDialogAction -> i + org.eclipse.jface.action.IAction hideAction -> j + org.eclipse.jface.action.IAction toggleMonitorClipboardAction -> k + com.agynamix.platform.frontend.action.ToggleShowToolbarAction toggleShowToolbarAction -> l + org.eclipse.jface.action.IAction clearClipboardTableAction -> m + com.agynamix.platform.frontend.action.RemoveSelectedClipboardEntry removeSelectedClipboardEntryAction -> n + org.eclipse.jface.action.IAction networkClearClipboardTableAction -> o + com.agynamix.platform.frontend.action.RemoveSelectedClipboardEntry networkRemoveSelectedClipboardEntryAction -> p + org.eclipse.jface.action.IAction helpAction -> q + org.eclipse.jface.action.IAction aboutAction -> r + org.eclipse.jface.action.IAction preferencesAction -> s + org.eclipse.jface.action.IAction copyAction -> a + org.eclipse.jface.action.IAction cutAction -> b + org.eclipse.jface.action.IAction saveAsAction -> c + org.eclipse.jface.action.IAction saveAsCompressedAction -> d + org.eclipse.jface.action.IAction inputTextAction -> t + org.eclipse.jface.action.IAction submitABugAction -> u + void initializeApplicationGUI() -> e + org.eclipse.jface.action.StatusLineManager createStatusLineManager() -> createStatusLineManager + com.agynamix.platform.frontend.gui.ApplicationStatusLineManager getStatusLineManager() -> f + org.eclipse.jface.action.CoolBarManager createCoolBarManager(int) -> createCoolBarManager + org.eclipse.jface.action.ToolBarManager createToolBarManager(int) -> createToolBarManager + org.eclipse.jface.action.MenuManager createMenuManager() -> createMenuManager + org.eclipse.swt.graphics.Image getShellImage() -> b + org.eclipse.swt.graphics.Point getInitialShellSize() -> a + java.lang.String getInitialStatusLine() -> c + org.eclipse.swt.widgets.Control fillMainWindow(org.eclipse.swt.widgets.Composite) -> a + org.eclipse.swt.widgets.Control getCustomToolbar() -> d + org.eclipse.swt.widgets.Control createContents(org.eclipse.swt.widgets.Composite) -> createContents + java.lang.String getShellText() -> g + com.agynamix.platform.frontend.gui.ApplicationTray createApplicationTray(org.eclipse.jface.window.Window,org.eclipse.swt.widgets.Shell,org.eclipse.swt.graphics.Image) -> a + boolean canHandleShellCloseEvent() -> canHandleShellCloseEvent + boolean close() -> close + void run() -> h + void shutdownApplicationGui() -> i + int open() -> open + org.eclipse.swt.widgets.Composite createCustomToolbar(org.eclipse.swt.widgets.Composite) -> b + org.eclipse.jface.action.StatusLineManager getStatusLineManager() -> getStatusLineManager +com.agynamix.platform.frontend.gui.ApplicationGUI$1 -> com.agynamix.platform.a.d.a: + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationGUI$2 -> com.agynamix.platform.a.d.r: + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationGUI$3 -> com.agynamix.platform.a.d.u: + com.agynamix.platform.frontend.gui.ApplicationGUI this$0 -> a + void menuAboutToShow(org.eclipse.jface.action.IMenuManager) -> menuAboutToShow +com.agynamix.platform.frontend.gui.ApplicationGUI$4 -> com.agynamix.platform.a.d.h: + com.agynamix.platform.frontend.gui.ApplicationGUI this$0 -> a + void menuAboutToShow(org.eclipse.jface.action.IMenuManager) -> menuAboutToShow +com.agynamix.platform.frontend.gui.ApplicationGUI$5 -> com.agynamix.platform.a.d.j: + com.agynamix.platform.frontend.gui.ApplicationGUI this$0 -> a + void shellClosed(org.eclipse.swt.events.ShellEvent) -> shellClosed +com.agynamix.platform.frontend.gui.ApplicationGUI$6 -> com.agynamix.platform.a.d.m: + com.agynamix.platform.frontend.gui.ApplicationGUI this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationStatusLineManager -> com.agynamix.platform.a.d.f: + void setErrorMessage(org.eclipse.swt.graphics.Image,java.lang.String) -> setErrorMessage + void setErrorMessage(java.lang.String) -> setErrorMessage + void setMessage(org.eclipse.swt.graphics.Image,java.lang.String) -> setMessage + void setMessage(java.lang.String) -> setMessage +com.agynamix.platform.frontend.gui.ApplicationTray -> com.agynamix.platform.a.d.p: + org.eclipse.jface.window.Window window -> g + org.eclipse.swt.widgets.Shell shell -> a + org.eclipse.swt.graphics.Image trayImage -> b + org.eclipse.swt.graphics.Image exitImage -> c + org.eclipse.swt.graphics.Image openImage -> d + org.eclipse.swt.widgets.Tray tray -> e + org.eclipse.swt.widgets.TrayItem trayItem -> f + void openMainWindow() -> a + void closeMainWindow() -> b + void toggleMainWindowActive() -> c + void closeApplication() -> d +com.agynamix.platform.frontend.gui.ApplicationTray$1 -> com.agynamix.platform.a.d.n: + com.agynamix.platform.frontend.gui.ApplicationTray this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationTray$2 -> com.agynamix.platform.a.d.i: + void run() -> a +com.agynamix.platform.frontend.gui.ApplicationTray$3 -> com.agynamix.platform.a.d.s: + void run() -> a +com.agynamix.platform.frontend.gui.ApplicationTray$4 -> com.agynamix.platform.a.d.t: + void run() -> a +com.agynamix.platform.frontend.gui.ApplicationTray$5 -> com.agynamix.platform.a.d.q: + com.agynamix.platform.infra.PluginMenuEntry val$entry -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationTray$6 -> com.agynamix.platform.a.d.v: + com.agynamix.platform.frontend.gui.ApplicationTray this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationTray$7 -> com.agynamix.platform.a.d.d: + com.agynamix.platform.frontend.gui.ApplicationTray this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationTray$8 -> com.agynamix.platform.a.d.b: + com.agynamix.platform.frontend.gui.ApplicationTray this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.ApplicationTray$9 -> com.agynamix.platform.a.d.e: + org.eclipse.swt.widgets.Menu val$menu -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.platform.frontend.gui.CarbonUIEnhancer -> com.agynamix.platform.a.d.l: + java.lang.String fgAboutActionName -> a + java.lang.Class osCls -> b + void hookApplicationMenu(org.eclipse.swt.widgets.Display,org.eclipse.swt.widgets.Listener,org.eclipse.jface.action.IAction,org.eclipse.jface.action.IAction) -> a + java.lang.Class classForName(java.lang.String) -> a + java.lang.Object newInstance(java.lang.String,java.lang.Class[],java.lang.Object[]) -> a + java.lang.Object invoke(java.lang.Class,java.lang.String,java.lang.Class[],java.lang.Object[]) -> a + java.lang.Object invoke(java.lang.Object,java.lang.String,java.lang.Class[],java.lang.Object[]) -> a + java.lang.Object fieldValue(java.lang.Class,java.lang.String) -> a + java.lang.Object access$600(com.agynamix.platform.frontend.gui.CarbonUIEnhancer,java.lang.Object,java.lang.String) -> a +com.agynamix.platform.frontend.gui.CarbonUIEnhancer$1 -> com.agynamix.platform.a.d.k: +com.agynamix.platform.frontend.gui.CarbonUIEnhancer$2 -> com.agynamix.platform.a.d.g: + java.lang.Object val$commandCallback -> a + com.agynamix.platform.frontend.gui.CarbonUIEnhancer this$0 -> b + void run() -> run +com.agynamix.platform.frontend.gui.CustomToolbar -> com.agynamix.platform.a.d.c: + java.util.List toolbarItems -> a + org.eclipse.swt.widgets.Composite toolbar -> b + org.eclipse.swt.widgets.Composite parent -> c + void add(org.eclipse.jface.action.IAction) -> a + void add(org.eclipse.jface.action.IContributionItem) -> a + org.eclipse.swt.widgets.Composite getToolbar() -> a +com.agynamix.platform.frontend.preferences.ApplicationChooserFieldEditor -> com.agynamix.platform.a.a.e: + boolean enforceAbsolute -> a + boolean checkState() -> checkState +com.agynamix.platform.frontend.preferences.ApplicationPreferenceDialog -> com.agynamix.platform.a.a.o: + org.eclipse.swt.widgets.Shell shell -> a + java.util.List preferenceDialogListeners -> b + int open() -> a + void addPreferenceDialogListener(com.agynamix.platform.frontend.preferences.IPreferenceDialogListener) -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> a +com.agynamix.platform.frontend.preferences.ApplicationPreferenceStore -> com.agynamix.platform.a.a.j: + org.eclipse.core.runtime.ListenerList listeners -> a + java.util.Properties properties -> b + java.util.Properties defaultProperties -> c + boolean dirty -> d + com.agynamix.platform.infra.IPreferenceConfigAdapter configAdapter -> e + void addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener) -> addPropertyChangeListener + boolean contains(java.lang.String) -> contains + void firePropertyChangeEvent(java.lang.String,java.lang.Object,java.lang.Object) -> firePropertyChangeEvent + boolean getBoolean(java.lang.String) -> getBoolean + boolean getBoolean(java.util.Properties,java.lang.String) -> a + boolean getDefaultBoolean(java.lang.String) -> getDefaultBoolean + double getDefaultDouble(java.lang.String) -> getDefaultDouble + float getDefaultFloat(java.lang.String) -> getDefaultFloat + int getDefaultInt(java.lang.String) -> getDefaultInt + long getDefaultLong(java.lang.String) -> getDefaultLong + java.lang.String getDefaultString(java.lang.String) -> getDefaultString + double getDouble(java.lang.String) -> getDouble + double getDouble(java.util.Properties,java.lang.String) -> b + float getFloat(java.lang.String) -> getFloat + float getFloat(java.util.Properties,java.lang.String) -> c + int getInt(java.lang.String) -> getInt + int getInt(java.util.Properties,java.lang.String) -> d + long getLong(java.lang.String) -> getLong + long getLong(java.util.Properties,java.lang.String) -> e + java.lang.String getString(java.lang.String) -> getString + java.lang.String getString(java.util.Properties,java.lang.String) -> f + boolean isDefault(java.lang.String) -> isDefault + void load(java.util.Properties) -> a + void loadDefaults(java.util.Properties) -> b + boolean needsSaving() -> needsSaving + void putValue(java.lang.String,java.lang.String) -> putValue + void removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener) -> removePropertyChangeListener + void save() -> save + void setDefault(java.lang.String,double) -> setDefault + void setDefault(java.lang.String,float) -> setDefault + void setDefault(java.lang.String,int) -> setDefault + void setDefault(java.lang.String,long) -> setDefault + void setDefault(java.lang.String,java.lang.String) -> setDefault + void setDefault(java.lang.String,boolean) -> setDefault + void setToDefault(java.lang.String) -> setToDefault + void setValue(java.lang.String,double) -> setValue + void setValue(java.lang.String,float) -> setValue + void setValue(java.lang.String,int) -> setValue + void setValue(java.lang.String,long) -> setValue + void setValue(java.lang.String,java.lang.String) -> setValue + void setValue(java.lang.String,boolean) -> setValue + void setValue(java.util.Properties,java.lang.String,double) -> a + void setValue(java.util.Properties,java.lang.String,float) -> a + void setValue(java.util.Properties,java.lang.String,int) -> a + void setValue(java.util.Properties,java.lang.String,long) -> a + void setValue(java.util.Properties,java.lang.String,java.lang.String) -> a + void setValue(java.util.Properties,java.lang.String,boolean) -> a +com.agynamix.platform.frontend.preferences.GlobalPreferencePageDefaults -> com.agynamix.platform.a.a.k: + org.eclipse.jface.preference.FieldEditor startMinimized -> a + org.eclipse.jface.preference.BooleanFieldEditor restoreLatestEntry -> b + org.eclipse.jface.preference.ComboFieldEditor updateSchedule -> c + org.eclipse.jface.preference.ComboFieldEditor modifierKey -> d + com.agynamix.platform.frontend.preferences.ApplicationChooserFieldEditor defaultTextEditor -> e + com.agynamix.platform.frontend.preferences.ApplicationChooserFieldEditor defaultImageViewer -> f + com.agynamix.platform.frontend.preferences.ApplicationChooserFieldEditor defaultFileBrowser -> g + java.lang.String[][] modifierKeyNames -> h + void createFieldEditors() -> createFieldEditors + void initialize() -> initialize +com.agynamix.platform.frontend.preferences.GlobalPreferencePageDefaults$1 -> com.agynamix.platform.a.a.d: + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.GlobalPreferencePageDefaults$2 -> com.agynamix.platform.a.a.a: + int[] $SwitchMap$com$agynamix$platform$infra$PlatformUtils$OS -> a +com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork -> com.agynamix.platform.a.a.i: + org.eclipse.jface.preference.StringFieldEditor groupName -> c + com.agynamix.platform.frontend.preferences.PasswordFieldEditor groupPassword -> d + org.eclipse.jface.preference.IntegerFieldEditor helloPort -> e + org.eclipse.jface.preference.IntegerFieldEditor serverPort -> f + org.eclipse.jface.preference.BooleanFieldEditor startHttpServer -> a + org.eclipse.jface.preference.IntegerFieldEditor httpServerPort -> b + com.agynamix.platform.frontend.preferences.NetworkAddressListFieldEditor networkAddrList -> g + void createFieldEditors() -> createFieldEditors + boolean checkPortsUnique() -> a + void initialize() -> initialize + org.eclipse.swt.widgets.Composite access$000(com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork) -> a + boolean access$100(com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork) -> b +com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork$1 -> com.agynamix.platform.a.a.s: + com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork this$0 -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork$2 -> com.agynamix.platform.a.a.n: + com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork this$0 -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork$3 -> com.agynamix.platform.a.a.r: + com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork this$0 -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork$4 -> com.agynamix.platform.a.a.p: + com.agynamix.platform.frontend.preferences.GlobalPreferencePageNetwork this$0 -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.IPreferenceDialogListener -> com.agynamix.platform.a.a.q: + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> a +com.agynamix.platform.frontend.preferences.LabelFieldEditor -> com.agynamix.platform.a.a.f: + org.eclipse.swt.widgets.Label label -> a + void adjustForNumColumns(int) -> adjustForNumColumns + void doFillIntoGrid(org.eclipse.swt.widgets.Composite,int) -> doFillIntoGrid + int getNumberOfControls() -> getNumberOfControls + void doLoad() -> doLoad + void doLoadDefault() -> doLoadDefault + void doStore() -> doStore +com.agynamix.platform.frontend.preferences.NetworkAddressListFieldEditor -> com.agynamix.platform.a.a.t: + java.lang.String createList(java.lang.String[]) -> createList + java.lang.String getNewInputObject() -> getNewInputObject + java.lang.String[] parseString(java.lang.String) -> parseString +com.agynamix.platform.frontend.preferences.PasswordFieldEditor -> com.agynamix.platform.a.a.u: + int UNLIMITED -> b + boolean isValid -> c + java.lang.String oldValue -> d + org.eclipse.swt.widgets.Text textField -> a + int widthInChars -> e + int textLimit -> f + java.lang.String errorMessage -> g + boolean emptyStringAllowed -> h + int validateStrategy -> i + void adjustForNumColumns(int) -> adjustForNumColumns + void doFillIntoGrid(org.eclipse.swt.widgets.Composite,int) -> doFillIntoGrid + void doLoad() -> doLoad + void doLoadDefault() -> doLoadDefault + void doStore() -> doStore + int getNumberOfControls() -> getNumberOfControls + org.eclipse.swt.widgets.Text getTextControl(org.eclipse.swt.widgets.Composite) -> a + boolean isValid() -> isValid + void refreshValidState() -> refreshValidState + void setFocus() -> setFocus + void valueChanged() -> a + void setEnabled(boolean,org.eclipse.swt.widgets.Composite) -> setEnabled + void access$000(com.agynamix.platform.frontend.preferences.PasswordFieldEditor) -> a + void access$100(com.agynamix.platform.frontend.preferences.PasswordFieldEditor) -> b +com.agynamix.platform.frontend.preferences.PasswordFieldEditor$1 -> com.agynamix.platform.a.a.c: + com.agynamix.platform.frontend.preferences.PasswordFieldEditor this$0 -> a + void keyReleased(org.eclipse.swt.events.KeyEvent) -> keyReleased +com.agynamix.platform.frontend.preferences.PasswordFieldEditor$2 -> com.agynamix.platform.a.a.g: + com.agynamix.platform.frontend.preferences.PasswordFieldEditor this$0 -> a + void keyPressed(org.eclipse.swt.events.KeyEvent) -> keyPressed +com.agynamix.platform.frontend.preferences.PasswordFieldEditor$3 -> com.agynamix.platform.a.a.h: + com.agynamix.platform.frontend.preferences.PasswordFieldEditor this$0 -> a + void focusGained(org.eclipse.swt.events.FocusEvent) -> focusGained + void focusLost(org.eclipse.swt.events.FocusEvent) -> focusLost +com.agynamix.platform.frontend.preferences.PasswordFieldEditor$4 -> com.agynamix.platform.a.a.b: + com.agynamix.platform.frontend.preferences.PasswordFieldEditor this$0 -> a + void widgetDisposed(org.eclipse.swt.events.DisposeEvent) -> widgetDisposed +com.agynamix.platform.frontend.preferences.PlatformFieldEditorPreferencePage -> com.agynamix.platform.a.a.m: + java.util.List preferenceDialogListeners -> a + java.util.Map listeners -> b + void addPropertyChangeListener(org.eclipse.jface.preference.FieldEditor,org.eclipse.jface.util.IPropertyChangeListener) -> a + void addPreferenceDialogListener(com.agynamix.platform.frontend.preferences.IPreferenceDialogListener) -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange +com.agynamix.platform.frontend.preferences.SpacerFieldEditor -> com.agynamix.platform.a.a.l: +com.agynamix.platform.httpd.HTTPResponse -> com.agynamix.platform.c.e: + java.lang.String status -> a + java.lang.String mimeType -> b + java.io.InputStream data -> c + java.util.Properties header -> d + void addHeader(java.lang.String,java.lang.String) -> a +com.agynamix.platform.httpd.HTTPSession -> com.agynamix.platform.c.g: + java.util.logging.Logger log -> b + java.lang.String cssContents -> c + java.lang.Object cssLoadMutex -> d + boolean postProcessRequestHeader(java.util.Properties,java.util.Properties) -> a + com.agynamix.platform.httpd.HTTPResponse serve$305a4fe9(java.lang.String,java.util.Properties,java.util.Properties) -> a + com.agynamix.platform.httpd.HTTPResponse serveAllEntries(java.util.Properties) -> a + java.lang.String htmlHeader(java.lang.String) -> a + java.lang.String loadCssFile(java.lang.String) -> b + com.agynamix.platform.httpd.HTTPResponse serveEntry(java.lang.String,java.util.Properties) -> a + com.agynamix.platform.httpd.HTTPResponse serveDownloadEntry(java.lang.String,java.util.Properties,boolean) -> a + java.lang.String getUUID(java.lang.String) -> c + java.lang.String serveListingText$56c101bd(com.agynamix.simidude.clipboard.IClipboardItem,java.lang.String,boolean) -> a + java.lang.String serveListingFile$56c101bd(com.agynamix.simidude.clipboard.IClipboardItem,java.lang.String,boolean) -> b + java.lang.String serveListingImage$56c101bd(com.agynamix.simidude.clipboard.IClipboardItem,java.lang.String,boolean) -> c + com.agynamix.platform.httpd.HTTPResponse serveDownloadFile(java.util.Properties,com.agynamix.simidude.clipboard.IClipboardItem,boolean) -> a + com.agynamix.platform.httpd.HTTPResponse serveDownloadBuffer$5153524a(byte[],java.lang.String) -> a + java.lang.String embeddImage(org.eclipse.swt.graphics.ImageData,java.lang.String,java.lang.String) -> a +com.agynamix.platform.httpd.HTTPSession$1 -> com.agynamix.platform.c.c: + int[] $SwitchMap$com$agynamix$simidude$source$ISourceData$SourceType -> a +com.agynamix.platform.httpd.HTTPSessionBase -> com.agynamix.platform.c.a: + com.agynamix.platform.httpd.HTTPUtils httpUtils -> a + java.net.Socket mySocket -> b + java.util.Properties environment -> c + boolean postProcessRequestHeader(java.util.Properties,java.util.Properties) -> a + com.agynamix.platform.httpd.HTTPResponse serve$305a4fe9(java.lang.String,java.util.Properties,java.util.Properties) -> a + void run() -> run + java.lang.String decodePercent(java.lang.String) -> a + void decodeParms(java.lang.String,java.util.Properties) -> a +com.agynamix.platform.httpd.HTTPUtils -> com.agynamix.platform.c.d: + java.text.SimpleDateFormat gmtFrmt -> b + java.net.Socket mySocket -> c + java.util.Hashtable theMimeTypes -> a + void sendError(java.lang.String,java.lang.String) -> a + void sendNotAuthorized(java.lang.String) -> a + void sendResponse(java.lang.String,java.lang.String,java.util.Properties,java.io.InputStream) -> a +com.agynamix.platform.httpd.HttpServer -> com.agynamix.platform.c.f: + java.util.Properties environment -> a + java.util.Properties access$000(com.agynamix.platform.httpd.HttpServer) -> a +com.agynamix.platform.httpd.HttpServer$1 -> com.agynamix.platform.c.b: + java.net.ServerSocket val$ss -> a + com.agynamix.platform.httpd.HttpServer this$0 -> b + void run() -> run +com.agynamix.platform.icons.PlatformIcons -> com.agynamix.platform.icons.PlatformIcons: + org.eclipse.jface.resource.ImageRegistry imageRegistry -> a + org.eclipse.swt.graphics.Image get(java.lang.String) -> a + org.eclipse.jface.resource.ImageDescriptor getDescriptor(java.lang.String) -> b + org.eclipse.jface.resource.ImageRegistry getImageRegistry() -> a +com.agynamix.platform.impl.ConfigurationImpl -> com.agynamix.platform.impl.c: + java.util.prefs.Preferences userPrefs -> a + java.util.Properties defaultValues -> b + java.util.logging.Logger log -> c + java.util.Properties exportProperties() -> a + java.util.Properties exportDefaultProperties() -> b + java.lang.String getProperty(java.lang.String) -> a + java.util.List getProperyList(java.lang.String) -> d + int getInteger(java.lang.String) -> b + org.eclipse.swt.graphics.Rectangle getRectangle(java.lang.String) -> e + boolean getBoolean(java.lang.String) -> c + void setBoolean(java.lang.String,boolean) -> a + void setProperty(java.lang.String,java.lang.String) -> a + void setRectangle(java.lang.String,org.eclipse.swt.graphics.Rectangle) -> a + void setProperty(java.lang.String,java.lang.Object) -> a + java.lang.String getStringDefault(java.lang.String) -> f + long getLongDefault(java.lang.String) -> g +com.agynamix.platform.impl.ConfigurationUtil -> com.agynamix.platform.impl.ConfigurationUtil: + void main(java.lang.String[]) -> main +com.agynamix.platform.impl.PreferenceConfigAdapterImpl -> com.agynamix.platform.impl.a: + com.agynamix.platform.infra.IConfiguration config -> a + org.eclipse.core.runtime.ListenerList listeners -> b + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> propertyChange + java.util.Properties loadDefaultProperties() -> a + java.util.Properties loadProperties() -> b +com.agynamix.platform.impl.QueueManagerImpl -> com.agynamix.platform.impl.b: + java.util.Map queueMap -> a + void put(java.lang.String,java.lang.Object) -> a + void putAllReverse(java.lang.String,java.util.List) -> a + void putAll(java.lang.String,java.lang.Object[]) -> a + java.lang.Object take(java.lang.String) -> a + java.util.concurrent.BlockingQueue getQueueByName(java.lang.String) -> b +com.agynamix.platform.infra.ApplicationBase -> com.agynamix.platform.d.s: + com.agynamix.platform.infra.ApplicationBase itsApplicationInstance -> a + com.agynamix.platform.infra.ApplicationContext applicationContext -> b + java.util.List exitListeners -> c + com.agynamix.platform.infra.ApplicationContext getContext() -> a + com.agynamix.platform.infra.ApplicationBase getInstance() -> b + void launch(java.lang.Class,com.agynamix.platform.infra.ApplicationContext,java.lang.String[]) -> a + void applicationSetup() -> c + void applicationInitialize() -> d + void prepareRun() -> e + com.agynamix.platform.frontend.gui.ApplicationGUI createApplicationGUI() -> f + void exit() -> g + void shutdown() -> h + void fireWillExit() -> i +com.agynamix.platform.infra.ApplicationBase$ShutdownHandler -> com.agynamix.platform.d.z: + void run() -> run +com.agynamix.platform.infra.ApplicationBase$UncaughtExceptionHandler -> com.agynamix.platform.d.q: + void uncaughtException(java.lang.Thread,java.lang.Throwable) -> uncaughtException +com.agynamix.platform.infra.ApplicationContext -> com.agynamix.platform.d.p: + org.eclipse.jface.resource.ImageRegistry imageRegistry -> c + org.eclipse.jface.resource.ColorRegistry colorRegistry -> a + org.eclipse.swt.dnd.Clipboard clipboard -> b + com.agynamix.platform.infra.IConfiguration configuration -> d + java.util.Map locatorMap -> e + void registerService(java.lang.String,java.lang.Object) -> a + java.lang.Object getService(java.lang.String) -> a + org.eclipse.jface.resource.ImageRegistry getImageRegistry() -> a + org.eclipse.swt.dnd.Clipboard getClipboard() -> b + com.agynamix.platform.infra.IConfiguration getConfiguration() -> c + com.agynamix.platform.concurrent.ThreadManager getThreadManager() -> d + com.agynamix.platform.frontend.gui.ApplicationGUI getApplicationGUI() -> e +com.agynamix.platform.infra.ApplicationContext$1 -> com.agynamix.platform.d.f: + com.agynamix.platform.infra.ApplicationContext this$0 -> a + void run() -> run +com.agynamix.platform.infra.ApplicationContext$2 -> com.agynamix.platform.d.a: + com.agynamix.platform.infra.ApplicationContext this$0 -> a + void run() -> run +com.agynamix.platform.infra.ApplicationInfo -> com.agynamix.platform.d.k: + java.lang.String[] systemProps -> a + java.util.Properties properties -> b + java.lang.String getApplicationName() -> a + java.lang.String getApplicationVersion() -> b + java.lang.String getApplicationYears() -> c + java.lang.String getCompanyName() -> d + java.lang.String getCompanyEmail() -> e + java.lang.String getCompanyWww() -> f + java.lang.String getCompanyOrderUrl() -> g + java.lang.String getRepoRevision() -> h + java.lang.String getBuildNumber() -> i + java.lang.String getBuildTime() -> j + java.lang.String saveGet(java.lang.String) -> a + java.lang.String getApplicationInfo() -> k +com.agynamix.platform.infra.DateUtils -> com.agynamix.platform.d.i: + java.util.Map formatMaps -> a + java.lang.String date2string(java.lang.String,java.util.Date) -> a + java.util.Date string2date(java.lang.String,java.lang.String) -> a + java.text.SimpleDateFormat getDateFormatter(java.util.Map,java.lang.String) -> a +com.agynamix.platform.infra.ExecutorUtils -> com.agynamix.platform.d.r: + java.util.concurrent.ScheduledExecutorService scheduledThreadPool -> a + java.util.concurrent.ExecutorService fixedThreadPool -> b + java.util.concurrent.ExecutorService cachedThreadPool -> c + void addScheduledService(java.lang.Runnable,long,long,java.util.concurrent.TimeUnit) -> a + void addFixedService(java.lang.Runnable) -> a + void addParallelTask(java.lang.Runnable) -> b + void shutdownScheduledService() -> a + void shutdownFixedService() -> b +com.agynamix.platform.infra.FileUtils -> com.agynamix.platform.d.t: + java.util.logging.Logger log -> a + java.lang.String[] imageFileExtensions -> b + java.lang.String[] textFileExtensions -> c + java.lang.String[] zipExtension -> d + void copyRecursive(java.io.File,java.io.File) -> a + void writeTextToFile(java.io.File,java.lang.String,java.lang.String,boolean) -> a + void writeImageToFile(java.io.File,java.lang.String,org.eclipse.swt.graphics.ImageData,boolean) -> a + byte[] readImage(org.eclipse.swt.graphics.ImageData,int) -> a + byte[] loadFile(java.io.InputStream,java.lang.String) -> a + java.lang.String[] getTextFileExtensions(boolean) -> a + java.lang.String[] getImageFileExtensions() -> a + java.io.File writeTextToTempFile(com.agynamix.simidude.source.impl.TextSourceData) -> a + java.io.File writeImageToTempFile(com.agynamix.simidude.source.impl.ImageSourceData) -> a + boolean deleteRecursive(java.io.File) -> a + java.lang.String replaceLastExtension(java.lang.String,java.lang.String) -> a + java.lang.String getCommonSourcePath(java.lang.String) -> a + java.lang.String getRelativePath(java.lang.String,java.lang.String) -> b + void serialize(java.lang.Object,java.lang.String) -> a + java.lang.Object deserialize(java.lang.String) -> b +com.agynamix.platform.infra.IConfiguration -> com.agynamix.platform.d.w: + java.lang.String getProperty(java.lang.String) -> a + int getInteger(java.lang.String) -> b + boolean getBoolean(java.lang.String) -> c + java.util.List getProperyList(java.lang.String) -> d + void setProperty(java.lang.String,java.lang.String) -> a + void setBoolean(java.lang.String,boolean) -> a + void setRectangle(java.lang.String,org.eclipse.swt.graphics.Rectangle) -> a + org.eclipse.swt.graphics.Rectangle getRectangle(java.lang.String) -> e + void setProperty(java.lang.String,java.lang.Object) -> a + java.util.Properties exportProperties() -> a + java.util.Properties exportDefaultProperties() -> b +com.agynamix.platform.infra.IExitListener -> com.agynamix.platform.d.m: + boolean canExit$40066ec9() -> a +com.agynamix.platform.infra.IPluginMenuAction -> com.agynamix.platform.d.x: + void run() -> a +com.agynamix.platform.infra.IPreferenceConfigAdapter -> com.agynamix.platform.d.v: + java.util.Properties loadDefaultProperties() -> a + java.util.Properties loadProperties() -> b +com.agynamix.platform.infra.IQueueManager -> com.agynamix.platform.d.j: + void put(java.lang.String,java.lang.Object) -> a + void putAll(java.lang.String,java.lang.Object[]) -> a + void putAllReverse(java.lang.String,java.util.List) -> a + java.lang.Object take(java.lang.String) -> a +com.agynamix.platform.infra.PlatformColors -> com.agynamix.platform.d.A: + org.eclipse.jface.resource.ColorRegistry colorRegistry -> a + java.util.Map colorMap -> b + org.eclipse.swt.graphics.Color get(java.lang.String) -> a + org.eclipse.jface.resource.ColorRegistry getColorRegistry() -> a +com.agynamix.platform.infra.PlatformException -> com.agynamix.platform.d.n: +com.agynamix.platform.infra.PlatformUtils -> com.agynamix.platform.d.u: + java.lang.Object syncThreadResult -> a + com.agynamix.platform.infra.PlatformUtils$OS getOsName() -> a + boolean isMacOs() -> b + java.lang.String getApplicationDataDir() -> c + java.lang.String getApplicationCacheDir() -> d + void setStatusLineContribution(java.lang.String) -> b + void setStatusLineErrorMsg(java.lang.String) -> c + org.eclipse.jface.action.IStatusLineManager getStatusLine() -> e + void setConnected(java.lang.String) -> a + void setConnected(int) -> a + void setNotConnected() -> f + void showErrorMessageWithException(java.lang.String,java.lang.String,java.lang.Throwable) -> a + void showErrorMessage(java.lang.String,java.lang.String) -> a + boolean showOverwriteFilesDialog(java.io.File) -> a + void safeAsyncRunnable(java.lang.Runnable) -> a + void safeSyncRunnable(java.lang.Runnable) -> b +com.agynamix.platform.infra.PlatformUtils$1 -> com.agynamix.platform.d.b: + java.lang.String val$msg -> a + void run() -> run +com.agynamix.platform.infra.PlatformUtils$2 -> com.agynamix.platform.d.d: + java.lang.String val$msg -> a + void run() -> run +com.agynamix.platform.infra.PlatformUtils$3 -> com.agynamix.platform.d.h: + java.lang.String val$title -> a + java.lang.String val$msg -> b + java.lang.Throwable val$t -> c + void run() -> run +com.agynamix.platform.infra.PlatformUtils$7 -> com.agynamix.platform.d.c: + java.lang.String val$title -> a + java.lang.String val$msg -> b + void run() -> run +com.agynamix.platform.infra.PlatformUtils$8 -> com.agynamix.platform.d.g: + java.io.File val$dest -> a + void run() -> run +com.agynamix.platform.infra.PlatformUtils$OS -> com.agynamix.platform.d.e: + com.agynamix.platform.infra.PlatformUtils$OS unknown -> g + com.agynamix.platform.infra.PlatformUtils$OS win32 -> a + com.agynamix.platform.infra.PlatformUtils$OS win64 -> b + com.agynamix.platform.infra.PlatformUtils$OS macosx -> c + com.agynamix.platform.infra.PlatformUtils$OS macosx64 -> d + com.agynamix.platform.infra.PlatformUtils$OS linux_x86 -> e + com.agynamix.platform.infra.PlatformUtils$OS linux_x86_64 -> f + java.util.List osname -> h + java.util.List osarch -> i + com.agynamix.platform.infra.PlatformUtils$OS[] $VALUES -> j + com.agynamix.platform.infra.PlatformUtils$OS[] values() -> values + com.agynamix.platform.infra.PlatformUtils$OS valueOf(java.lang.String) -> valueOf + com.agynamix.platform.infra.PlatformUtils$OS parseOs(java.lang.String,java.lang.String) -> a + java.lang.String toString() -> toString +com.agynamix.platform.infra.PluginMenuEntry -> com.agynamix.platform.d.y: + org.eclipse.swt.graphics.Image image -> a + java.lang.String mEntry -> b + com.agynamix.platform.infra.IPluginMenuAction menuAction -> c + java.lang.String getText() -> a + org.eclipse.swt.graphics.Image getImage() -> b + void setPluginMenuAction(com.agynamix.platform.infra.IPluginMenuAction) -> a + void action() -> c +com.agynamix.platform.infra.Tupel -> com.agynamix.platform.d.o: + java.lang.Object value1 -> a + java.lang.Object value2 -> b + java.lang.Object getValue1() -> a + java.lang.Object getValue2() -> b +com.agynamix.platform.infra.ZipUtils -> com.agynamix.platform.d.l: + java.util.logging.Logger log -> a + byte[] zipBuffer(java.lang.String,byte[]) -> a + java.io.File zipFile(java.io.File,java.io.File) -> a + void zipDirectory(java.io.File,java.lang.String,java.util.zip.ZipOutputStream) -> a + void zipFileEntry(java.io.File,java.lang.String,java.util.zip.ZipOutputStream) -> b +com.agynamix.platform.log.ApplicationLog -> com.agynamix.platform.e.a: + java.lang.String logDirectory -> a + java.util.logging.Logger getLogger(java.lang.Class) -> a + java.util.logging.Logger getLogger(java.lang.String) -> a +com.agynamix.platform.net.ClientListSynchronizer -> com.agynamix.platform.b.s: + java.util.logging.Logger log -> a + com.agynamix.platform.net.IConnector connector -> b + boolean shouldStop -> c + void run() -> run + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.platform.net.ClientNode -> com.agynamix.platform.b.o: + int hashCode -> g + java.util.UUID nodeId -> a + java.lang.String groupname -> b + java.net.InetAddress address -> c + int port -> d + java.util.Date creationDate -> e + java.util.Date inactiveSince -> f + java.util.Date shutdownDate -> h + java.net.InetAddress getAddress() -> a + java.lang.String toString() -> toString + java.util.UUID getNodeId() -> b + boolean equals(java.lang.Object) -> equals + int hashCode() -> hashCode + void setNodeInactive() -> c +com.agynamix.platform.net.ConnectionCtx -> com.agynamix.platform.b.a: + java.net.Socket socket -> b + java.io.BufferedInputStream istream -> c + java.io.BufferedOutputStream ostream -> d + com.agynamix.platform.net.protocol.NodeCommandUtils nodeCommandUtils -> a + void disconnect() -> a + void close() -> b + java.io.BufferedOutputStream getOutputStream() -> c + java.io.BufferedInputStream getInputStream() -> d + java.lang.String getHostAddress() -> e + com.agynamix.platform.net.protocol.NodeCommandUtils getNodeCommandUtils() -> f + java.lang.Object invoke(com.agynamix.platform.net.IRemoteCommand) -> a + java.lang.String escapeHtmlFull(java.lang.String) -> a +com.agynamix.platform.net.ConnectionUtils -> com.agynamix.platform.b.n: + java.util.logging.Logger log -> a + java.lang.Object miscSemaphore -> b + void safeAddToClientList(com.agynamix.platform.net.ClientNode,java.util.List) -> a + byte[] toByteArray(java.lang.String[]) -> a + void clearInactiveFromClientList(com.agynamix.platform.net.IConnector,java.util.List) -> a + com.agynamix.platform.net.ConnectionCtx connectTo(com.agynamix.platform.net.IConnector,com.agynamix.platform.net.ClientNode) -> a + com.agynamix.platform.net.ClientNode requestClientId(com.agynamix.platform.net.IConnector,java.lang.String,int) -> a + java.net.Socket connectSocket(java.net.InetSocketAddress) -> a + void setConnectionStatus(java.util.List) -> a +com.agynamix.platform.net.Connector -> com.agynamix.platform.b.l: + java.lang.String groupName -> a + java.lang.String groupPassword -> b + int helloPort -> c + int serverPort -> d + java.util.UUID nodeId -> e + java.util.concurrent.BlockingQueue requestorQueue -> f + com.agynamix.platform.net.PingService pingService -> g + com.agynamix.platform.net.PingServiceListener pingListener -> h + com.agynamix.platform.net.ClientListSynchronizer clientListSynchronizer -> i + com.agynamix.platform.net.ConnectorServer connectorServer -> j + com.agynamix.platform.net.ContactRequestorService contactRequestorService -> k + com.agynamix.platform.net.ClientNode myOwnNode -> l + java.util.List connectedClients -> m + java.util.List packetReceivedListeners -> n + java.util.logging.Logger log -> o + void initialize() -> h + void run() -> i + void shutdown() -> j + com.agynamix.platform.net.ClientNode getMyOwnNode() -> e + int getHelloPort() -> a + java.util.concurrent.BlockingQueue getRequestorQueue() -> c + java.util.List getConnectedClientList() -> d + com.agynamix.platform.net.ClientNode getClientNode(java.util.UUID) -> a + int getServerPort() -> b + java.lang.String getGroupName() -> g + java.lang.String getGroupPassword() -> f + void firePacketReceived(com.agynamix.platform.net.protocol.NodeCommand) -> a + void signalGoodBye(com.agynamix.platform.net.ClientNode) -> a +com.agynamix.platform.net.ConnectorServer -> com.agynamix.platform.b.j: + java.util.concurrent.ExecutorService serverHandlerService -> a + com.agynamix.platform.net.IConnector connector -> b + java.net.ServerSocket serverSocket -> c + boolean shouldStop -> d + void run() -> run + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.platform.net.ConnectorServerHandler -> com.agynamix.platform.b.d: + com.agynamix.platform.net.ConnectionCtx connectionCtx -> a + com.agynamix.platform.net.IConnector connector -> b + java.util.logging.Logger log -> c + void run() -> run +com.agynamix.platform.net.ContactRequestorService -> com.agynamix.platform.b.g: + java.util.logging.Logger log -> a + boolean shouldStop -> b + com.agynamix.platform.net.IConnector connector -> c + void run() -> run + void sendConnectedClientList(com.agynamix.platform.net.ClientNode,java.util.List) -> a + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.platform.net.FatalNetworkException -> com.agynamix.platform.b.r: +com.agynamix.platform.net.IConnector -> com.agynamix.platform.b.i: + int getHelloPort() -> a + int getServerPort() -> b + java.util.concurrent.BlockingQueue getRequestorQueue() -> c + java.util.List getConnectedClientList() -> d + com.agynamix.platform.net.ClientNode getMyOwnNode() -> e + java.lang.String getGroupPassword() -> f + java.lang.String getGroupName() -> g + void firePacketReceived(com.agynamix.platform.net.protocol.NodeCommand) -> a + com.agynamix.platform.net.ClientNode getClientNode(java.util.UUID) -> a +com.agynamix.platform.net.IRemoteCommand -> com.agynamix.platform.b.c: +com.agynamix.platform.net.NetUtils -> com.agynamix.platform.b.p: + java.util.logging.Logger log -> a + java.util.List getHostAddresses() -> a + java.net.InetAddress getPrimaryHostAddress() -> b + java.lang.String getLocalHostAddress() -> c + com.agynamix.platform.net.ClientNode bcBufferToNode(byte[]) -> a + byte[] nodeToBcBuffer(com.agynamix.platform.net.ClientNode) -> a + java.lang.String encodeField(java.lang.String) -> a + java.lang.String decodeField(java.lang.String) -> b + java.lang.String decodeField(byte[],int,int) -> a + byte[] intToByteArray(int) -> a + int byteArrayToInt(byte[],int) -> a +com.agynamix.platform.net.NetworkAuthException -> com.agynamix.platform.b.b: +com.agynamix.platform.net.NetworkProtocolException -> com.agynamix.platform.b.q: +com.agynamix.platform.net.PingService -> com.agynamix.platform.b.m: + com.agynamix.platform.net.IConnector connector -> a + boolean shouldStop -> b + java.util.logging.Logger log -> c + void run() -> run + java.net.InetAddress getBroadcastAddress(java.net.InetAddress) -> a + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.platform.net.PingServiceListener -> com.agynamix.platform.b.k: + boolean shouldStop -> a + com.agynamix.platform.net.IConnector connector -> b + java.net.DatagramSocket listenSocket -> c + java.util.List myAddresses -> d + java.util.logging.Logger log -> e + void run() -> run + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.platform.net.RequestClientIdCommand -> com.agynamix.platform.b.h: +com.agynamix.platform.net.SignalGoodByeCommand -> com.agynamix.platform.b.e: +com.agynamix.platform.net.TransportClientListCommand -> com.agynamix.platform.b.f: +com.agynamix.platform.net.protocol.Ackn -> com.agynamix.platform.b.a.h: +com.agynamix.platform.net.protocol.Acpt -> com.agynamix.platform.b.a.f: + java.util.UUID nodeId -> a + byte[] toByteArray() -> a +com.agynamix.platform.net.protocol.Auth -> com.agynamix.platform.b.a.d: + java.lang.String groupname -> a + java.lang.String password -> c + byte[] toByteArray() -> a + java.lang.String getGroupname() -> b + java.lang.String getPassword() -> c +com.agynamix.platform.net.protocol.Data -> com.agynamix.platform.b.a.b: + java.lang.String filename -> a + long length -> c + byte[] toByteArray() -> a +com.agynamix.platform.net.protocol.Expt -> com.agynamix.platform.b.a.c: +com.agynamix.platform.net.protocol.NodeCommand -> com.agynamix.platform.b.a.k: + java.lang.String command -> b + byte[] toByteArray() -> a + byte[] toPacket() -> d +com.agynamix.platform.net.protocol.NodeCommandUtils -> com.agynamix.platform.b.a.e: + com.agynamix.platform.net.ConnectionCtx connectionCtx -> a + com.agynamix.platform.net.IConnector connector -> b + void sendRejt() -> a + java.lang.Object invoke(com.agynamix.platform.net.IRemoteCommand) -> a + com.agynamix.platform.net.protocol.NodeCommand receiveCommand() -> b + com.agynamix.platform.net.protocol.NodeCommand receiveCommand(java.lang.String[]) -> a + byte[] receivePacket(java.lang.String[]) -> b + byte[] readPacket(byte[],int) -> a + void sendPacket(com.agynamix.platform.net.protocol.NodeCommand) -> a + void authenticate() -> c +com.agynamix.platform.net.protocol.Objt -> com.agynamix.platform.b.a.i: + java.lang.Object getObject() -> b +com.agynamix.platform.net.protocol.Quit -> com.agynamix.platform.b.a.a: +com.agynamix.platform.net.protocol.Rcmd -> com.agynamix.platform.b.a.g: +com.agynamix.platform.net.protocol.Rejt -> com.agynamix.platform.b.a.l: +com.agynamix.platform.net.protocol.SerializedDataCommand -> com.agynamix.platform.b.a.j: + java.lang.Object object -> a + byte[] toByteArray() -> a + java.lang.Object getObject() -> b +com.agynamix.simidude.Simidude -> com.agynamix.simidude.Simidude: + com.agynamix.simidude.clipboard.SourceDataManager sourceDataManager -> a + com.agynamix.simidude.source.ISource clipboardMonitor$bebbf8d -> b + java.util.logging.Logger log -> c + void applicationSetup() -> c + void applicationInitialize() -> d + void shutdown() -> h + void prepareRun() -> e + com.agynamix.platform.frontend.gui.ApplicationGUI createApplicationGUI() -> f + void main(java.lang.String[]) -> main + void access$000(com.agynamix.simidude.Simidude,com.agynamix.simidude.source.ISourceData,boolean) -> a +com.agynamix.simidude.Simidude$1 -> com.agynamix.simidude.c: + void exited(int) -> exited + void prepareShutdown() -> prepareShutdown +com.agynamix.simidude.Simidude$2 -> com.agynamix.simidude.b: + com.agynamix.simidude.Simidude this$0 -> a + void sourceDataChanged(com.agynamix.simidude.source.ISourceData) -> a +com.agynamix.simidude.Simidude$3 -> com.agynamix.simidude.a: + com.agynamix.simidude.Simidude this$0 -> a + void itemActivated(com.agynamix.simidude.clipboard.IClipboardItem) -> a +com.agynamix.simidude.clipboard.ClipboardItemFactory -> com.agynamix.simidude.a.c: + com.agynamix.simidude.clipboard.SourceDataManager sourceDataManager -> a + com.agynamix.simidude.clipboard.IClipboardItem createItemFromSourceData(com.agynamix.simidude.clipboard.SourceDataManager,com.agynamix.simidude.source.ISourceData) -> a + org.eclipse.swt.widgets.Control createControl(org.eclipse.swt.widgets.Composite) -> a +com.agynamix.simidude.clipboard.ClipboardItemFactory$1 -> com.agynamix.simidude.a.g: + int[] $SwitchMap$com$agynamix$simidude$source$ISourceData$SourceType -> a +com.agynamix.simidude.clipboard.ClipboardMonitorBase -> com.agynamix.simidude.a.q: + boolean itemActivated -> a + com.agynamix.simidude.source.ISourceData[] sourceDataInTransit -> b + com.agynamix.simidude.source.ISourceData activatedSourceData -> c + void itemActivated(com.agynamix.simidude.source.ISourceData) -> a + int getSleepTime() -> c + com.agynamix.simidude.source.ISourceData[] saveProcessClipboard(org.eclipse.swt.dnd.Clipboard) -> a +com.agynamix.simidude.clipboard.ClipboardMonitorBase$1 -> com.agynamix.simidude.a.K: + org.eclipse.swt.dnd.Clipboard val$clipboard -> a + com.agynamix.simidude.clipboard.ClipboardMonitorBase this$0 -> b + void run() -> run +com.agynamix.simidude.clipboard.ClipboardMonitorFactory$1 -> com.agynamix.simidude.a.w: + int[] $SwitchMap$com$agynamix$platform$infra$PlatformUtils$OS -> a +com.agynamix.simidude.clipboard.ClipboardTable -> com.agynamix.simidude.a.M: + com.agynamix.simidude.clipboard.SourceDataManager sourceDataManager -> a + org.eclipse.jface.viewers.TableViewer tableViewer -> b + org.eclipse.jface.viewers.TableViewerColumn itemColumn -> c + org.eclipse.swt.widgets.Composite tableParent -> d + boolean dragInProgress -> e + void addSelectionChangeListener(org.eclipse.jface.viewers.ISelectionChangedListener) -> a + org.eclipse.swt.widgets.Table getTable() -> a + org.eclipse.jface.viewers.TableViewer getTableViewer() -> b + boolean isDragInProgress() -> c + void setDragInProgress(boolean) -> a + void openSelectedEntry(com.agynamix.simidude.clipboard.IClipboardItem) -> a +com.agynamix.simidude.clipboard.ClipboardTable$1 -> com.agynamix.simidude.a.i: + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> a + void modelChanged$2838e5ad() -> a + com.agynamix.simidude.source.ISource newClipboardMonitor$5cf0b5d2() -> b +com.agynamix.simidude.clipboard.ClipboardTable$1$1 -> com.agynamix.simidude.a.H: + com.agynamix.simidude.clipboard.ClipboardTable$1 this$1 -> a + void run() -> run +com.agynamix.simidude.clipboard.ClipboardTable$10 -> com.agynamix.simidude.a.v: + org.eclipse.swt.widgets.MenuItem val$downloadContentsItem -> a + org.eclipse.swt.widgets.MenuItem val$activateItem -> b + org.eclipse.jface.viewers.TableViewer val$tableViewer -> c + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> d + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +com.agynamix.simidude.clipboard.ClipboardTable$11 -> com.agynamix.simidude.a.y: + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> a + void doubleClick(org.eclipse.jface.viewers.DoubleClickEvent) -> doubleClick +com.agynamix.simidude.clipboard.ClipboardTable$12 -> com.agynamix.simidude.a.z: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void keyPressed(org.eclipse.swt.events.KeyEvent) -> keyPressed +com.agynamix.simidude.clipboard.ClipboardTable$13 -> com.agynamix.simidude.a.u: + com.agynamix.simidude.source.impl.FileSourceData val$fsd -> a + void run() -> run +com.agynamix.simidude.clipboard.ClipboardTable$13$1 -> com.agynamix.simidude.a.l: + com.agynamix.simidude.clipboard.ClipboardTable$13 this$1 -> a + void run() -> run +com.agynamix.simidude.clipboard.ClipboardTable$2 -> com.agynamix.simidude.a.d: + boolean even -> a + org.eclipse.swt.graphics.Color oddColor -> b + com.agynamix.simidude.clipboard.OptimizedIndexSearcher val$searcher -> c + java.lang.String getText(java.lang.Object) -> getText + org.eclipse.swt.graphics.Image getImage(java.lang.Object) -> getImage + org.eclipse.swt.graphics.Color getBackground(java.lang.Object) -> getBackground + java.lang.String getToolTipText(java.lang.Object) -> getToolTipText + org.eclipse.swt.graphics.Point getToolTipShift(java.lang.Object) -> getToolTipShift + int getToolTipDisplayDelayTime(java.lang.Object) -> getToolTipDisplayDelayTime + int getToolTipTimeDisplayed(java.lang.Object) -> getToolTipTimeDisplayed + void update(org.eclipse.jface.viewers.ViewerCell) -> update +com.agynamix.simidude.clipboard.ClipboardTable$3 -> com.agynamix.simidude.a.p: + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> a + void controlResized(org.eclipse.swt.events.ControlEvent) -> controlResized +com.agynamix.simidude.clipboard.ClipboardTable$4 -> com.agynamix.simidude.a.b: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTable$5 -> com.agynamix.simidude.a.t: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTable$6 -> com.agynamix.simidude.a.f: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTable$7 -> com.agynamix.simidude.a.h: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTable$8 -> com.agynamix.simidude.a.k: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTable$9 -> com.agynamix.simidude.a.m: + org.eclipse.jface.viewers.TableViewer val$tableViewer -> a + com.agynamix.simidude.clipboard.ClipboardTable this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTableContentProvider -> com.agynamix.simidude.a.x: + void dispose() -> dispose + void inputChanged(org.eclipse.jface.viewers.Viewer,java.lang.Object,java.lang.Object) -> inputChanged + java.lang.Object[] getElements(java.lang.Object) -> getElements +com.agynamix.simidude.clipboard.ClipboardTableSearchBox$1 -> com.agynamix.simidude.a.N: + org.eclipse.swt.widgets.Text val$searchBox -> a + com.agynamix.simidude.clipboard.ClipboardItemFactory this$0$181e9bd5 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTableSearchBox$2 -> com.agynamix.simidude.a.e: + org.eclipse.swt.widgets.Text val$searchBox -> a + com.agynamix.simidude.clipboard.ClipboardItemFactory this$0$181e9bd5 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +com.agynamix.simidude.clipboard.ClipboardTableSearchBox$3 -> com.agynamix.simidude.a.I: + org.eclipse.swt.widgets.Text val$searchBox -> a + com.agynamix.simidude.clipboard.ClipboardItemFactory this$0$181e9bd5 -> b + void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) -> widgetDefaultSelected +com.agynamix.simidude.clipboard.ClipboardTableSearchBox$4 -> com.agynamix.simidude.a.A: + org.eclipse.swt.widgets.Text val$searchBox -> a + com.agynamix.simidude.clipboard.ClipboardItemFactory this$0$181e9bd5 -> b + void keyPressed(org.eclipse.swt.events.KeyEvent) -> keyPressed + void keyReleased(org.eclipse.swt.events.KeyEvent) -> keyReleased +com.agynamix.simidude.clipboard.ClipboardViewerFilter -> com.agynamix.simidude.a.o: + java.lang.String searchStr -> a + boolean select(org.eclipse.jface.viewers.Viewer,java.lang.Object,java.lang.Object) -> select + java.lang.String toString() -> toString +com.agynamix.simidude.clipboard.FileClipboardItem -> com.agynamix.simidude.a.n: + com.agynamix.simidude.source.impl.FileSourceData sourceData -> a + com.agynamix.simidude.clipboard.SourceDataManager sourceDataManager -> b + org.eclipse.swt.graphics.Image thumbnail -> c + org.eclipse.swt.graphics.Image downloadNeededThumbnail -> d + java.lang.String getDescription() -> a + java.lang.String getShortDescription() -> b + org.eclipse.swt.graphics.Image getImage() -> c + java.lang.String getTooltip() -> d + com.agynamix.simidude.source.ISourceData$SourceType getType() -> e + com.agynamix.simidude.source.ISourceData getSourceData() -> f + com.agynamix.simidude.clipboard.IClipboardItem deleteContents() -> g +com.agynamix.simidude.clipboard.IClipboardItem -> com.agynamix.simidude.a.L: + com.agynamix.simidude.source.ISourceData$SourceType getType() -> e + java.lang.String getDescription() -> a + java.lang.String getShortDescription() -> b + java.lang.String getTooltip() -> d + org.eclipse.swt.graphics.Image getImage() -> c + com.agynamix.simidude.source.ISourceData getSourceData() -> f + com.agynamix.simidude.clipboard.IClipboardItem deleteContents() -> g +com.agynamix.simidude.clipboard.ImageClipboardItem -> com.agynamix.simidude.a.r: + com.agynamix.simidude.source.impl.ImageSourceData sourceData -> a + org.eclipse.swt.graphics.Image cachedThumbnail -> b + java.lang.String tooltip -> c + java.lang.String getDescription() -> a + org.eclipse.swt.graphics.Image getImage() -> c + java.lang.String getShortDescription() -> b + com.agynamix.simidude.source.ISourceData getSourceData() -> f + java.lang.String getTooltip() -> d + com.agynamix.simidude.source.ISourceData$SourceType getType() -> e + com.agynamix.simidude.clipboard.IClipboardItem deleteContents() -> g +com.agynamix.simidude.clipboard.OptimizedIndexSearcher -> com.agynamix.simidude.a.F: + int lastIndex -> a + boolean isEven(org.eclipse.swt.widgets.TableItem) -> a +com.agynamix.simidude.clipboard.PollingClipboardMonitor -> com.agynamix.simidude.a.B: + org.eclipse.swt.dnd.Clipboard clipboard -> d + com.agynamix.simidude.source.ISourceData[] currentSourceData -> e + com.agynamix.simidude.source.ISourceData[] currentCompareSourceData -> f + boolean newDataAvailable -> g + boolean clipboardMonitorEnabled -> h + boolean isClipboardMonitorEnabled() -> d + void setClipboardMonitorEnabled(boolean) -> a + boolean isClipboardEmpty() -> e + com.agynamix.simidude.source.ISourceData[] getData() -> b + boolean isDataAvailable() -> a + int getSleepTime() -> c + org.eclipse.swt.dnd.Clipboard getClipboard() -> f + com.agynamix.simidude.source.ISourceData[] createEqualsCopy(com.agynamix.simidude.source.ISourceData[]) -> a +com.agynamix.simidude.clipboard.SourceDataManager -> com.agynamix.simidude.a.s: + com.agynamix.simidude.source.ISource clipboardMonitor$bebbf8d -> c + java.util.List clipboardItems -> a + java.util.List removedClipboardItems -> d + java.util.List downloadsInProgress -> e + java.util.List modelChangeListeners -> b + java.util.List itemActivationListeners -> f + org.eclipse.swt.dnd.Clipboard clipboard -> g + com.agynamix.simidude.clipboard.ClipboardViewerFilter currentViewerFilter -> h + com.agynamix.simidude.frontend.ctrl.SourceDataDialogController sourceDataDialogController -> i + void addItemActivationListener(com.agynamix.simidude.infra.IItemActivationListener) -> a + void addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) -> a + java.util.List getClipboardItems() -> a + void sourceDataChanged(com.agynamix.simidude.source.ISourceData) -> a + void addItemTimeDesc(java.util.List,com.agynamix.simidude.source.ISourceData) -> a + void activateItem(int) -> a + com.agynamix.simidude.clipboard.IClipboardItem getSelectedItem() -> b + int getSelectionIndex() -> c + void activateItem() -> d + void activateItem(com.agynamix.simidude.clipboard.IClipboardItem) -> a + com.agynamix.simidude.clipboard.IClipboardItem removeSelectedEntry() -> e + com.agynamix.simidude.clipboard.IClipboardItem removeItem(com.agynamix.simidude.clipboard.IClipboardItem) -> b + void removeAll() -> f + void contentsReceived() -> g + void fireDataChanged(java.lang.Object,java.lang.Object) -> a + void setClipboardMonitorEnabled(boolean) -> a + boolean isClipboardMonitorEnabled() -> h + boolean isClipboardEmpty() -> i + java.util.List getSourceDataStubEntries() -> j + java.util.List getRemovedSourceDataStubEntries() -> k + com.agynamix.simidude.clipboard.IClipboardItem getClipboardItem(com.agynamix.simidude.source.SourceDataStub) -> a + com.agynamix.simidude.clipboard.IClipboardItem getClipboardItem(int) -> b + boolean isRetrieveContentsNeeded(com.agynamix.simidude.clipboard.IClipboardItem) -> c + void setDownloadInProgress(com.agynamix.simidude.source.ISourceData,boolean) -> a + boolean isDownloadInProgress(com.agynamix.simidude.source.ISourceData) -> b + void setSourceDataDialogController(com.agynamix.simidude.frontend.ctrl.SourceDataDialogController) -> a + void filterClipboardItems(java.lang.String) -> a + void saveClipboardItemAs(com.agynamix.simidude.clipboard.IClipboardItem,boolean) -> a + void saveAs(java.lang.String,java.lang.String,com.agynamix.simidude.source.ISourceData,boolean) -> a + void saveSelectEntry(int) -> c +com.agynamix.simidude.clipboard.SourceDataManager$1 -> com.agynamix.simidude.a.j: + java.lang.String val$path2 -> a + java.lang.String val$entryName2 -> b + com.agynamix.simidude.clipboard.IClipboardItem val$item -> c + boolean val$compress -> d + com.agynamix.simidude.clipboard.SourceDataManager this$0 -> e + void run() -> run +com.agynamix.simidude.clipboard.SourceDataManager$2 -> com.agynamix.simidude.a.J: + org.eclipse.core.runtime.IProgressMonitor val$pm -> a + java.lang.String val$path -> b + void run() -> run +com.agynamix.simidude.clipboard.SourceDataManager$3 -> com.agynamix.simidude.a.G: + boolean val$compress -> a + java.io.File val$src -> b + java.io.File val$dest -> c + com.agynamix.simidude.source.impl.FileSourceData val$fsd -> d + org.eclipse.core.runtime.IStatus run(org.eclipse.core.runtime.IProgressMonitor) -> run +com.agynamix.simidude.clipboard.SourceDataManager$4 -> com.agynamix.simidude.a.E: + org.eclipse.core.runtime.IProgressMonitor val$pm -> a + void done(org.eclipse.core.runtime.jobs.IJobChangeEvent) -> done +com.agynamix.simidude.clipboard.SourceDataManager$4$1 -> com.agynamix.simidude.a.a: + com.agynamix.simidude.clipboard.SourceDataManager$4 this$1 -> a + void run() -> run +com.agynamix.simidude.clipboard.SourceDataManager$5 -> com.agynamix.simidude.a.D: + int[] $SwitchMap$com$agynamix$simidude$source$ISourceData$SourceType -> a +com.agynamix.simidude.clipboard.TextClipboardItem -> com.agynamix.simidude.a.C: + com.agynamix.simidude.source.impl.TextSourceData sourceData -> a + java.lang.String getDescription() -> a + java.lang.String getShortDescription() -> b + org.eclipse.swt.graphics.Image getImage() -> c + java.lang.String getTooltip() -> d + com.agynamix.simidude.source.ISourceData$SourceType getType() -> e + com.agynamix.simidude.source.ISourceData getSourceData() -> f + java.lang.String getSubstring(java.lang.String,int,java.lang.String) -> a + com.agynamix.simidude.clipboard.IClipboardItem deleteContents() -> g +com.agynamix.simidude.frontend.action.AboutAction -> com.agynamix.simidude.f.a.b: + org.eclipse.jface.window.ApplicationWindow window -> a + void run() -> run +com.agynamix.simidude.frontend.action.ShowOnlineHelpAction -> com.agynamix.simidude.f.a.a: + void run() -> run +com.agynamix.simidude.frontend.action.ToggleMonitorClipboardAction -> com.agynamix.simidude.f.a.c: + void run() -> run +com.agynamix.simidude.frontend.ctrl.SourceDataDialogController -> com.agynamix.simidude.f.c.a: + com.agynamix.simidude.frontend.gui.ISourceDataDialogView sourceDataDataView -> a + void addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) -> a + org.eclipse.swt.widgets.Composite createContent(org.eclipse.swt.widgets.Composite) -> a + com.agynamix.simidude.clipboard.ClipboardTable getClipboardTable() -> a + org.eclipse.swt.widgets.Control getCustomToolbar() -> b +com.agynamix.simidude.frontend.gui.ClipboardTableDragSource -> com.agynamix.simidude.f.b.e: + com.agynamix.simidude.clipboard.ClipboardTable clipboardTable -> a + org.eclipse.jface.viewers.TableViewer tableViewer -> b + com.agynamix.simidude.clipboard.SourceDataManager sourceDataManager -> c + org.eclipse.swt.dnd.DragSource dragSource -> d + org.eclipse.swt.dnd.Transfer[] currentTransfer -> e + java.util.logging.Logger log -> f + void dragStart(org.eclipse.swt.dnd.DragSourceEvent) -> dragStart + void dragSetData(org.eclipse.swt.dnd.DragSourceEvent) -> dragSetData + com.agynamix.simidude.clipboard.IClipboardItem getSelectedItem() -> a + void dragFinished(org.eclipse.swt.dnd.DragSourceEvent) -> dragFinished +com.agynamix.simidude.frontend.gui.ClipboardTableDragSource$1 -> com.agynamix.simidude.f.b.b: + int[] $SwitchMap$com$agynamix$simidude$source$ISourceData$SourceType -> a +com.agynamix.simidude.frontend.gui.ClipboardTableDropTarget -> com.agynamix.simidude.f.b.f: + com.agynamix.simidude.clipboard.ClipboardTable clipboardTable -> a + org.eclipse.jface.viewers.TableViewer tableViewer -> b + void dragEnter(org.eclipse.swt.dnd.DropTargetEvent) -> dragEnter + void drop(org.eclipse.swt.dnd.DropTargetEvent) -> drop +com.agynamix.simidude.frontend.gui.ISourceDataDialogView -> com.agynamix.simidude.f.b.d: + com.agynamix.simidude.clipboard.ClipboardTable clipboardTable -> a + org.eclipse.swt.widgets.Composite toolbar -> b + org.eclipse.swt.widgets.Composite createContent(org.eclipse.swt.widgets.Composite) -> a + com.agynamix.simidude.clipboard.ClipboardTable getClipboardTable() -> a + org.eclipse.swt.widgets.Control getCustomToolbar() -> b + void addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) -> a +com.agynamix.simidude.frontend.gui.SimidudeApplicationTray -> com.agynamix.simidude.f.b.a: +com.agynamix.simidude.frontend.gui.SimidudeGUI -> com.agynamix.simidude.f.b.c: + com.agynamix.simidude.frontend.gui.ISourceDataDialogView sourceDataView$6f677a7c -> e + com.agynamix.simidude.frontend.ctrl.SourceDataDialogController sourceDataController -> f + org.eclipse.swt.graphics.Point getInitialShellSize() -> a + org.eclipse.swt.graphics.Image getShellImage() -> b + java.lang.String getInitialStatusLine() -> c + org.eclipse.swt.widgets.Control fillMainWindow(org.eclipse.swt.widgets.Composite) -> a + org.eclipse.swt.widgets.Control getCustomToolbar() -> d + com.agynamix.platform.frontend.gui.ApplicationTray createApplicationTray(org.eclipse.jface.window.Window,org.eclipse.swt.widgets.Shell,org.eclipse.swt.graphics.Image) -> a +com.agynamix.simidude.impl.CacheCleaner -> com.agynamix.simidude.d.a: + java.lang.String cacheRoot -> a + java.util.logging.Logger log -> b + void run() -> run + boolean isReferenced(com.agynamix.simidude.clipboard.SourceDataManager,java.lang.String) -> a +com.agynamix.simidude.impl.ContentsCacheManagerImpl -> com.agynamix.simidude.d.b: + java.util.logging.Logger log -> a + java.lang.String cacheDirectoryStr -> b + java.io.File cacheDirectory -> c + java.io.File itsFileRoot -> d + java.io.File firstContentsElementInCache -> e + java.lang.String itsCommonSourcePath -> f + boolean isFirstItem -> g + java.io.OutputStream currentOutputStream -> h + boolean insideTransaction -> i + java.io.File createTempFile(java.lang.String) -> a + void begin() -> a + com.agynamix.simidude.infra.IContentsCacheInfo finish() -> b + void abort() -> c + void write(com.agynamix.simidude.source.SourceDataContents) -> a + void writeDirectoryToCache(java.io.File,com.agynamix.simidude.source.SourceDataContents) -> a + void removeContentsFromCache(com.agynamix.simidude.infra.IContentsCacheInfo) -> a +com.agynamix.simidude.impl.SimidudeApplicationContext -> com.agynamix.simidude.d.c: + com.agynamix.platform.infra.IQueueManager getQueueManager() -> f + com.agynamix.simidude.clipboard.SourceDataManager getSourceDataManager() -> g + com.agynamix.simidude.infra.ModelProvider getModelProvider() -> h + com.agynamix.simidude.remote.RemoteConnector getRemoteConnector() -> i +com.agynamix.simidude.infra.CacheManagerFactory -> com.agynamix.simidude.e.a: + com.agynamix.simidude.infra.IContentsCacheManager commonCacheManager -> a + java.util.List inTransitDirectories -> b + com.agynamix.simidude.infra.IContentsCacheManager newContentsCacheManager() -> a + com.agynamix.simidude.infra.IContentsCacheManager commonContentsCacheManager() -> c + java.io.File createTempFile(java.lang.String) -> a + void removeContentsFromCache(com.agynamix.simidude.infra.IContentsCacheInfo) -> a + java.lang.Runnable newCacheCleaner() -> b + void addInTransitCacheDirectory(java.io.File) -> a + void removeInTransitCacheDirectory(java.io.File) -> b + boolean isInTransitCacheDirectory(java.io.File) -> c +com.agynamix.simidude.infra.IContentsCacheInfo -> com.agynamix.simidude.e.c: + java.io.File itsFile -> a + java.lang.String getFilenameInCache() -> a +com.agynamix.simidude.infra.IContentsCacheManager -> com.agynamix.simidude.e.d: + void begin() -> a + void write(com.agynamix.simidude.source.SourceDataContents) -> a + com.agynamix.simidude.infra.IContentsCacheInfo finish() -> b + void abort() -> c + java.io.File createTempFile(java.lang.String) -> a + void removeContentsFromCache(com.agynamix.simidude.infra.IContentsCacheInfo) -> a +com.agynamix.simidude.infra.IItemActivationListener -> com.agynamix.simidude.e.g: + void itemActivated(com.agynamix.simidude.clipboard.IClipboardItem) -> a +com.agynamix.simidude.infra.IModelChangeListener -> com.agynamix.simidude.e.i: + void modelChanged$2838e5ad() -> a +com.agynamix.simidude.infra.ModelProvider -> com.agynamix.simidude.e.e: + java.util.UUID senderId -> b + boolean preferenceDialogChanges -> a + java.util.UUID getSenderId() -> a + void retrieveContentsForProxyObject(com.agynamix.simidude.source.ISourceData) -> a + void retrieveContentsForProxyObject(com.agynamix.simidude.source.ISourceData,java.lang.Runnable) -> a + void openPreferencesDialog(org.eclipse.swt.widgets.Shell) -> a + void networkRemoveItem(com.agynamix.simidude.source.SourceDataStub) -> a +com.agynamix.simidude.infra.ModelProvider$1 -> com.agynamix.simidude.e.b: + com.agynamix.simidude.infra.ModelProvider this$0 -> a + void propertyChange(org.eclipse.jface.util.PropertyChangeEvent) -> a +com.agynamix.simidude.infra.ModelProvider$2 -> com.agynamix.simidude.e.h: + java.util.List val$connectedClients -> a + com.agynamix.simidude.remote.RemoteConnector val$remoteConnector -> b + com.agynamix.simidude.source.SourceDataStub val$sourceDataStub -> c + void run() -> run +com.agynamix.simidude.infra.SimidudeUtils -> com.agynamix.simidude.e.f: + int currentModifierKey -> a + void launchDefaultImageEditor(java.io.File) -> a + void launchDefaultTextEditor(java.io.File) -> b + void launchDefaultFileBowser(com.agynamix.simidude.source.impl.FileSourceData) -> a + void findAndlaunchApplication(java.lang.String,java.lang.String) -> a + org.eclipse.swt.program.Program findProgram(java.lang.String) -> a + void launchURI(com.agynamix.simidude.source.impl.TextSourceData) -> a + void keyPressed(int) -> a + void keyReleased(int) -> b + boolean isModifierKeyPressed() -> a + boolean isSupportedModifierKey(int) -> d + java.lang.String getKeyCodeName(int) -> c +com.agynamix.simidude.remote.CompareSourceDataStubListsCommand -> com.agynamix.simidude.b.l: +com.agynamix.simidude.remote.CompareSourceDataStubListsResult -> com.agynamix.simidude.b.j: +com.agynamix.simidude.remote.ContentsLoaderException -> com.agynamix.simidude.b.n: +com.agynamix.simidude.remote.RemoteConnector -> com.agynamix.simidude.b.k: + com.agynamix.platform.net.Connector connector -> a + com.agynamix.simidude.remote.SourceDataSynchronizer sourceDataSynchronizer -> b + java.util.logging.Logger log -> c + void shutdown() -> a + void initializeConnector(com.agynamix.simidude.infra.ModelProvider) -> a + void establishConnection() -> b + void contactPermanentNetworkAddresses() -> c + com.agynamix.platform.net.ClientNode requestClientNode(com.agynamix.platform.net.IConnector,java.lang.String,java.lang.Integer) -> a + com.agynamix.platform.infra.Tupel getIPAddressAndPort(com.agynamix.platform.net.IConnector,java.lang.String) -> a + com.agynamix.platform.net.IConnector getConnector() -> d + void sourceDataChanged(com.agynamix.simidude.source.ISourceData) -> a + void send(java.util.List,com.agynamix.simidude.source.ISourceData) -> a + com.agynamix.platform.infra.Tupel access$000(com.agynamix.simidude.remote.RemoteConnector,com.agynamix.platform.net.IConnector,java.lang.String) -> a + com.agynamix.platform.net.ClientNode access$100(com.agynamix.simidude.remote.RemoteConnector,com.agynamix.platform.net.IConnector,java.lang.String,java.lang.Integer) -> a +com.agynamix.simidude.remote.RemoteConnector$1 -> com.agynamix.simidude.b.b: + com.agynamix.simidude.remote.RemoteConnector this$0 -> a + void run() -> run +com.agynamix.simidude.remote.RemoteException -> com.agynamix.simidude.b.c: +com.agynamix.simidude.remote.RemoteRemoveItemCommand -> com.agynamix.simidude.b.d: +com.agynamix.simidude.remote.RequestSourceDataContentCommand -> com.agynamix.simidude.b.h: +com.agynamix.simidude.remote.SourceDataContentsCollector -> com.agynamix.simidude.b.m: + com.agynamix.platform.net.ConnectionCtx connectionCtx -> a + com.agynamix.simidude.source.impl.FileSourceData fileSourceData -> b + java.lang.Runnable attachedCommand -> c + void run() -> run +com.agynamix.simidude.remote.SourceDataContentsCollector$1 -> com.agynamix.simidude.b.i: + org.eclipse.core.runtime.IProgressMonitor val$pm -> a + com.agynamix.platform.net.ConnectionCtx val$connectionCtx -> b + void run() -> run +com.agynamix.simidude.remote.SourceDataContentsCollector$2 -> com.agynamix.simidude.b.f: + org.eclipse.core.runtime.IProgressMonitor val$pm -> a + void run() -> run +com.agynamix.simidude.remote.SourceDataSynchronizer -> com.agynamix.simidude.b.e: + java.util.logging.Logger log -> a + com.agynamix.simidude.remote.RemoteConnector remoteConnector -> b + java.util.List lastRunClientList -> c + int callCount -> d + boolean shouldStop -> e + void run() -> run + void synchronizeSourceData(com.agynamix.platform.net.IConnector,com.agynamix.platform.net.ClientNode,java.util.List) -> a + java.util.List assembleRemotelyNeededEntries(com.agynamix.simidude.clipboard.SourceDataManager,java.util.List) -> a + java.lang.String getId() -> a + void shutdown() -> d +com.agynamix.simidude.remote.TransmitSourceDataStubListsCommand -> com.agynamix.simidude.b.g: +com.agynamix.simidude.remote.TransportSourceDataCommand -> com.agynamix.simidude.b.a: +com.agynamix.simidude.source.ISource -> com.agynamix.simidude.c.b: + boolean isDataAvailable() -> a + com.agynamix.simidude.source.ISourceData[] getData() -> b + int getSleepTime() -> c + void itemActivated(com.agynamix.simidude.source.ISourceData) -> a + void setClipboardMonitorEnabled(boolean) -> a + boolean isClipboardMonitorEnabled() -> d + boolean isClipboardEmpty() -> e +com.agynamix.simidude.source.ISourceData -> com.agynamix.simidude.c.i: + com.agynamix.simidude.source.ISourceData$SourceType getType() -> m + java.lang.String getText() -> c + java.util.UUID getSenderId() -> k + java.util.UUID getSourceId() -> l + void setTransportType(com.agynamix.simidude.source.ISourceData$TransportType) -> a + com.agynamix.simidude.source.ISourceData$TransportType getTransportType() -> n + boolean isCached() -> o + com.agynamix.simidude.infra.IContentsCacheInfo getContentsCacheInfo() -> p + com.agynamix.simidude.source.ISourceData copy() -> a + com.agynamix.simidude.source.ISourceData equalsCopy() -> b + com.agynamix.simidude.source.SourceDataStub getStub() -> r + java.util.Date getCreationDate() -> q +com.agynamix.simidude.source.ISourceData$SourceType -> com.agynamix.simidude.c.a: + com.agynamix.simidude.source.ISourceData$SourceType TEXT -> a + com.agynamix.simidude.source.ISourceData$SourceType FILE -> b + com.agynamix.simidude.source.ISourceData$SourceType IMAGE -> c + com.agynamix.simidude.source.ISourceData$SourceType[] $VALUES -> d + com.agynamix.simidude.source.ISourceData$SourceType[] values() -> values + com.agynamix.simidude.source.ISourceData$SourceType valueOf(java.lang.String) -> valueOf +com.agynamix.simidude.source.ISourceData$TransportType -> com.agynamix.simidude.c.g: + com.agynamix.simidude.source.ISourceData$TransportType local -> a + com.agynamix.simidude.source.ISourceData$TransportType remote -> b + com.agynamix.simidude.source.ISourceData$TransportType[] $VALUES -> c + com.agynamix.simidude.source.ISourceData$TransportType[] values() -> values + com.agynamix.simidude.source.ISourceData$TransportType valueOf(java.lang.String) -> valueOf +com.agynamix.simidude.source.ISourceDataListener -> com.agynamix.simidude.c.e: + void sourceDataChanged(com.agynamix.simidude.source.ISourceData) -> a +com.agynamix.simidude.source.SourceDataContents -> com.agynamix.simidude.c.h: +com.agynamix.simidude.source.SourceDataFactory -> com.agynamix.simidude.c.c: + com.agynamix.simidude.infra.ModelProvider modelProvider -> a + java.util.logging.Logger log -> b + com.agynamix.simidude.source.ISourceData[] createFromDropTarget(org.eclipse.swt.dnd.DropTargetEvent) -> a + com.agynamix.simidude.source.ISourceData createFromText(java.lang.String) -> a + com.agynamix.simidude.source.ISourceData createFromFile(java.lang.String) -> b + com.agynamix.simidude.source.ISourceData createFromImage(org.eclipse.swt.graphics.ImageData) -> a + java.util.UUID getSenderId() -> a +com.agynamix.simidude.source.SourceDataStub -> com.agynamix.simidude.c.d: + int hashCode -> a + java.util.UUID sourceId -> b + boolean equals(java.lang.Object) -> equals + int hashCode() -> hashCode + java.lang.String toString() -> toString +com.agynamix.simidude.source.SourceQueueService -> com.agynamix.simidude.c.f: + com.agynamix.platform.infra.IQueueManager queueManager -> a + java.util.List listeners -> b + void addSourceDataListener(com.agynamix.simidude.source.ISourceDataListener) -> a + void internalInitialize() -> c + void internalRun() -> e +com.agynamix.simidude.source.impl.AbstractSourceData -> com.agynamix.simidude.c.a.f: + java.util.UUID senderId -> a + java.util.UUID uuid -> b + com.agynamix.simidude.source.ISourceData$SourceType sourceType -> c + com.agynamix.simidude.source.ISourceData$TransportType transportType -> d + java.util.Date creationDate -> e + com.agynamix.simidude.source.SourceDataStub sourceDataStub -> f + boolean isProxy -> g + com.agynamix.simidude.infra.IContentsCacheInfo contentsCacheInfo -> h + java.util.UUID getSenderId() -> k + java.util.UUID getSourceId() -> l + com.agynamix.simidude.source.ISourceData$SourceType getType() -> m + void setTransportType(com.agynamix.simidude.source.ISourceData$TransportType) -> a + com.agynamix.simidude.source.ISourceData$TransportType getTransportType() -> n + void setProxy(boolean) -> a + boolean isCached() -> o + void setContentsCacheInfo(com.agynamix.simidude.infra.IContentsCacheInfo) -> a + com.agynamix.simidude.infra.IContentsCacheInfo getContentsCacheInfo() -> p + java.util.Date getCreationDate() -> q + com.agynamix.simidude.source.SourceDataStub getStub() -> r +com.agynamix.simidude.source.impl.FileSourceData -> com.agynamix.simidude.c.a.a: + java.lang.String[] imgExt -> a + java.io.File file -> b + boolean isDirectory -> c + java.lang.String filename -> d + boolean isImage -> e + com.agynamix.simidude.source.impl.ImageDataWrapper thumbnail -> f + int hashCode -> g + com.agynamix.simidude.source.ISourceData copy() -> a + com.agynamix.simidude.source.ISourceData equalsCopy() -> b + java.lang.String toString() -> toString + java.lang.String getText() -> c + boolean isDirectory() -> d + java.lang.String getFilename() -> e + java.io.File getFile() -> f + java.lang.String getLocalFilename() -> g + boolean equals(java.lang.Object) -> equals + int hashCode() -> hashCode + boolean checkFileIsImage(java.io.File) -> a + boolean isImage() -> h + org.eclipse.swt.graphics.ImageData getThumbnail() -> i + void deleteContents() -> j +com.agynamix.simidude.source.impl.ImageDataWrapper -> com.agynamix.simidude.c.a.e: + int width -> a + int height -> b + int depth -> d + int red -> e + int green -> f + int blue -> g + int scanlinePad -> h + byte[] data -> c + org.eclipse.swt.graphics.ImageData thumbnail -> i + org.eclipse.swt.graphics.ImageData getImageData() -> a + org.eclipse.swt.graphics.ImageData getThumbnailImageData() -> b +com.agynamix.simidude.source.impl.ImageSourceData -> com.agynamix.simidude.c.a.b: + com.agynamix.simidude.source.impl.ImageDataWrapper imageDataWrapper -> a + java.lang.String imageText -> b + int hashCode -> c + com.agynamix.simidude.source.ISourceData copy() -> a + com.agynamix.simidude.source.ISourceData equalsCopy() -> b + org.eclipse.swt.graphics.ImageData getImageData() -> d + org.eclipse.swt.graphics.ImageData getThumbnail() -> e + java.lang.String getText() -> c + boolean equals(java.lang.Object) -> equals + int hashCode() -> hashCode + void deleteContents() -> f +com.agynamix.simidude.source.impl.SourceListener -> com.agynamix.simidude.c.a.g: + com.agynamix.simidude.source.ISource source -> a + com.agynamix.platform.infra.IQueueManager queueManager -> b + int sleepTime -> c + void internalInitialize() -> c + void internalRun() -> e +com.agynamix.simidude.source.impl.TextSourceData -> com.agynamix.simidude.c.a.d: + java.lang.String data -> a + com.agynamix.simidude.source.impl.TextSourceData$TextType textType -> b + int hashCode -> c + com.agynamix.simidude.source.ISourceData copy() -> a + com.agynamix.simidude.source.ISourceData equalsCopy() -> b + java.lang.String toString() -> toString + java.lang.String getText() -> c + com.agynamix.simidude.source.impl.TextSourceData$TextType getTextType() -> d + boolean equals(java.lang.Object) -> equals + int hashCode() -> hashCode + void deleteContents() -> e +com.agynamix.simidude.source.impl.TextSourceData$TextType -> com.agynamix.simidude.c.a.c: + com.agynamix.simidude.source.impl.TextSourceData$TextType Text -> a + com.agynamix.simidude.source.impl.TextSourceData$TextType URI -> b + com.agynamix.simidude.source.impl.TextSourceData$TextType[] $VALUES -> c + com.agynamix.simidude.source.impl.TextSourceData$TextType[] values() -> values + com.agynamix.simidude.source.impl.TextSourceData$TextType valueOf(java.lang.String) -> valueOf +swt.snippets.AlternateColumnColorExample -> swt.snippets.AlternateColumnColorExample: + swt.snippets.AlternateColumnColorExample$MyModel[] createModel() -> a + void main(java.lang.String[]) -> main +swt.snippets.AlternateColumnColorExample$1 -> swt.snippets.C: + boolean even -> a + org.eclipse.jface.viewers.TableViewer val$v -> b + swt.snippets.AlternateColumnColorExample$OptimizedIndexSearcher val$searcher -> c + org.eclipse.swt.graphics.Color getBackground(java.lang.Object) -> getBackground + void update(org.eclipse.jface.viewers.ViewerCell) -> update +swt.snippets.AlternateColumnColorExample$2 -> swt.snippets.u: + boolean even -> a + org.eclipse.jface.viewers.TableViewer val$v -> b + swt.snippets.AlternateColumnColorExample$OptimizedIndexSearcher val$searcher -> c + org.eclipse.swt.graphics.Color getBackground(java.lang.Object) -> getBackground + void update(org.eclipse.jface.viewers.ViewerCell) -> update +swt.snippets.AlternateColumnColorExample$3 -> swt.snippets.A: + boolean select(org.eclipse.jface.viewers.Viewer,java.lang.Object,java.lang.Object) -> select +swt.snippets.AlternateColumnColorExample$4 -> swt.snippets.v: + boolean b -> a + org.eclipse.jface.viewers.TableViewer val$v -> b + org.eclipse.jface.viewers.ViewerFilter val$filter -> c + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.AlternateColumnColorExample$MyContentProvider -> swt.snippets.p: + java.lang.Object[] getElements(java.lang.Object) -> getElements + void dispose() -> dispose + void inputChanged(org.eclipse.jface.viewers.Viewer,java.lang.Object,java.lang.Object) -> inputChanged +swt.snippets.AlternateColumnColorExample$MyModel -> swt.snippets.s: + int counter -> a + java.lang.String toString() -> toString +swt.snippets.AlternateColumnColorExample$OptimizedIndexSearcher -> swt.snippets.y: + int lastIndex -> a + boolean isEven(org.eclipse.swt.widgets.TableItem) -> a +swt.snippets.BroadcastExample -> swt.snippets.BroadcastExample: + void main(java.lang.String[]) -> main +swt.snippets.ClipboardExample -> swt.snippets.ClipboardExample: + org.eclipse.swt.dnd.Clipboard clipboard -> a + org.eclipse.swt.widgets.Shell shell -> b + org.eclipse.swt.widgets.Text copyText -> c + org.eclipse.swt.widgets.Text pasteText -> d + org.eclipse.swt.widgets.Text copyRtfText -> e + org.eclipse.swt.widgets.Text pasteRtfText -> f + org.eclipse.swt.widgets.Text copyHtmlText -> g + org.eclipse.swt.widgets.Text pasteHtmlText -> h + org.eclipse.swt.widgets.Table copyFileTable -> i + org.eclipse.swt.widgets.Table pasteFileTable -> j + org.eclipse.swt.widgets.Text text -> k + org.eclipse.swt.widgets.Combo combo -> l + org.eclipse.swt.custom.StyledText styledText -> m + org.eclipse.swt.widgets.Label status -> n + void main(java.lang.String[]) -> main + void open(org.eclipse.swt.widgets.Display) -> a +swt.snippets.ClipboardExample$1 -> swt.snippets.i: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$10 -> swt.snippets.c: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$11 -> swt.snippets.b: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$12 -> swt.snippets.n: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$13 -> swt.snippets.o: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$14 -> swt.snippets.q: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$15 -> swt.snippets.r: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$16 -> swt.snippets.e: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$17 -> swt.snippets.g: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$18 -> swt.snippets.j: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$19 -> swt.snippets.h: + org.eclipse.swt.widgets.List val$list -> a + swt.snippets.ClipboardExample this$0 -> b + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$2 -> swt.snippets.f: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$3 -> swt.snippets.t: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$4 -> swt.snippets.F: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$5 -> swt.snippets.z: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$6 -> swt.snippets.x: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$7 -> swt.snippets.l: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$8 -> swt.snippets.m: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ClipboardExample$9 -> swt.snippets.a: + swt.snippets.ClipboardExample this$0 -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.ComplexToolbarExample -> swt.snippets.ComplexToolbarExample: + org.eclipse.swt.widgets.Display display -> c + org.eclipse.swt.widgets.Shell shell -> a + org.eclipse.swt.widgets.ToolBar toolBar -> b + void main(java.lang.String[]) -> main +swt.snippets.ComplexToolbarExample$1 -> swt.snippets.w: + org.eclipse.swt.widgets.ToolItem val$itemDropDown -> a + org.eclipse.swt.widgets.Menu val$menu -> b + swt.snippets.ComplexToolbarExample this$0 -> c + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.ComplexToolbarExample$2 -> swt.snippets.D: + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.ComplexToolbarExample$3 -> swt.snippets.E: + swt.snippets.ComplexToolbarExample this$0 -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.CustomGradientSelection -> swt.snippets.CustomGradientSelection: + void main(java.lang.String[]) -> main +swt.snippets.CustomGradientSelection$1 -> swt.snippets.H: + org.eclipse.swt.widgets.Table val$table -> a + org.eclipse.swt.widgets.Display val$display -> b + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.EnableMenuItemsDynamicallyExample -> swt.snippets.EnableMenuItemsDynamicallyExample: + void main(java.lang.String[]) -> main +swt.snippets.EnableMenuItemsDynamicallyExample$1 -> swt.snippets.B: + org.eclipse.swt.widgets.Menu val$menu -> a + org.eclipse.swt.widgets.Tree val$tree -> b + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.ImageInTableCell -> swt.snippets.ImageInTableCell: + void main(java.lang.String[]) -> main +swt.snippets.ImageInTableCell$1 -> swt.snippets.G: + org.eclipse.swt.graphics.Image val$image -> a + void handleEvent(org.eclipse.swt.widgets.Event) -> handleEvent +swt.snippets.InetAddrFinder -> swt.snippets.InetAddrFinder: + void main(java.lang.String[]) -> main +swt.snippets.ListSystemInfo -> swt.snippets.ListSystemInfo: + void main(java.lang.String[]) -> main +swt.snippets.PreferenceTest -> swt.snippets.PreferenceTest: + void main(java.lang.String[]) -> main +swt.snippets.SearchFieldExample -> swt.snippets.SearchFieldExample: + void main(java.lang.String[]) -> main +swt.snippets.SearchFieldExample$1 -> swt.snippets.k: + org.eclipse.swt.widgets.Text val$text -> a + void widgetSelected(org.eclipse.swt.events.SelectionEvent) -> widgetSelected +swt.snippets.SearchFieldExample$2 -> swt.snippets.d: + org.eclipse.swt.widgets.Text val$text -> a + void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) -> widgetDefaultSelected +swt.snippets.SimpleHttp2 -> swt.snippets.SimpleHttp2: + java.net.Socket s -> a + java.io.File docRoot -> b + java.lang.String canonicalDocRoot -> c + int port -> d + java.util.Properties typeMap -> e + java.lang.String statusCode -> f + java.util.Hashtable myHeaders -> g + void main(java.lang.String[]) -> main + void run() -> run + void sendDocument(java.io.DataOutputStream,java.io.File) -> a + void sendStatusLine(java.io.DataOutputStream) -> a + void setHeader(java.lang.String,java.lang.String) -> a + void sendHeader(java.io.DataOutputStream) -> b + void sendError(java.lang.String,java.io.DataOutputStream) -> a diff --git a/build/lib/jna.jar b/build/lib/jna.jar new file mode 100644 index 0000000..33461ec Binary files /dev/null and b/build/lib/jna.jar differ diff --git a/build/lib/proguard.jar b/build/lib/proguard.jar new file mode 100644 index 0000000..3a9aebc Binary files /dev/null and b/build/lib/proguard.jar differ diff --git a/build/lib/proguardgui.jar b/build/lib/proguardgui.jar new file mode 100644 index 0000000..5866856 Binary files /dev/null and b/build/lib/proguardgui.jar differ diff --git a/build/lib/retrace.jar b/build/lib/retrace.jar new file mode 100644 index 0000000..8e42e5a Binary files /dev/null and b/build/lib/retrace.jar differ diff --git a/build/lib/svnClientAdapter.jar b/build/lib/svnClientAdapter.jar new file mode 100644 index 0000000..225fb19 Binary files /dev/null and b/build/lib/svnClientAdapter.jar differ diff --git a/build/lib/svnant.jar b/build/lib/svnant.jar new file mode 100644 index 0000000..62e0e07 Binary files /dev/null and b/build/lib/svnant.jar differ diff --git a/build/lib/svnkit-javahl.jar b/build/lib/svnkit-javahl.jar new file mode 100644 index 0000000..6b9f0fa Binary files /dev/null and b/build/lib/svnkit-javahl.jar differ diff --git a/build/lib/svnkit.jar b/build/lib/svnkit.jar new file mode 100644 index 0000000..8fe3f41 Binary files /dev/null and b/build/lib/svnkit.jar differ diff --git a/build/lib/trilead.jar b/build/lib/trilead.jar new file mode 100644 index 0000000..6de76b9 Binary files /dev/null and b/build/lib/trilead.jar differ diff --git a/build/lib/xmltask-1.16.jar b/build/lib/xmltask-1.16.jar new file mode 100644 index 0000000..b815813 Binary files /dev/null and b/build/lib/xmltask-1.16.jar differ diff --git a/doc/Simidude User Manual.pdf b/doc/Simidude User Manual.pdf new file mode 100755 index 0000000..5665faa Binary files /dev/null and b/doc/Simidude User Manual.pdf differ diff --git a/doc/licenses/jintellitype-license.txt b/doc/licenses/jintellitype-license.txt new file mode 100644 index 0000000..f91da00 --- /dev/null +++ b/doc/licenses/jintellitype-license.txt @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/doc/licenses/jxgrabkey-license.txt b/doc/licenses/jxgrabkey-license.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/doc/licenses/jxgrabkey-license.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/etc/appinfo.txt b/etc/appinfo.txt new file mode 100644 index 0000000..8e13d1c --- /dev/null +++ b/etc/appinfo.txt @@ -0,0 +1,11 @@ +Application-Name=Simidude +Application-Version=1.0.0 beta +Application-Years=2008, 2009 +Company-Name=AGYNAMIX +Company-Email=contact@agynamix.de +Company-WWW=http://www.simidude.com +Company-Order-Url=http://www.simidude.com/order +Repository-Revision=26 +Build-Number=12 +Build-Time=2008-11-21 19:33:12 + \ No newline at end of file diff --git a/etc/config.properties b/etc/config.properties new file mode 100644 index 0000000..3dd4ff4 --- /dev/null +++ b/etc/config.properties @@ -0,0 +1,18 @@ +app.show_splash=true +app.start_minimized=false +app.restore_latest_clp_entry=true +app.is_monitor_clipboard=true +app.is_first_run=true +app.server_port=10034 +app.broadcast_port=10035 +app.node_group_name=Simidude +app.node_group_pwd=Simidude +app.start_http_server=true +app.http_server_port=10036 +app.is_monitor_clipboard=true +app.is_monitor_clipboard_text=true +app.is_monitor_clipboard_images=true +app.is_monitor_clipboard_files=true +app.is_toolbar_shown=true +app.show_balloon_tooltip=true +app.modifier_key=131072 diff --git a/etc/favicon.ico b/etc/favicon.ico new file mode 100755 index 0000000..e6c0d09 Binary files /dev/null and b/etc/favicon.ico differ diff --git a/etc/license.html b/etc/license.html new file mode 100644 index 0000000..1b61269 --- /dev/null +++ b/etc/license.html @@ -0,0 +1,259 @@ + + + + +Eclipse Public License - Version 1.0 + + + + + + +

Eclipse Public License - v 1.0

+ +

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.

+ +

1. DEFINITIONS

+ +

"Contribution" means:

+ +

a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and

+

b) in the case of each subsequent Contributor:

+

i) changes to the Program, and

+

ii) additions to the Program;

+

where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.

+ +

"Contributor" means any person or entity that distributes +the Program.

+ +

"Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.

+ +

"Program" means the Contributions distributed in accordance +with this Agreement.

+ +

"Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.

+ +

2. GRANT OF RIGHTS

+ +

a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.

+ +

b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.

+ +

c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.

+ +

d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.

+ +

3. REQUIREMENTS

+ +

A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:

+ +

a) it complies with the terms and conditions of this +Agreement; and

+ +

b) its license agreement:

+ +

i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;

+ +

ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;

+ +

iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and

+ +

iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.

+ +

When the Program is made available in source code form:

+ +

a) it must be made available under this Agreement; and

+ +

b) a copy of this Agreement must be included with each +copy of the Program.

+ +

Contributors may not remove or alter any copyright notices contained +within the Program.

+ +

Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.

+ +

4. COMMERCIAL DISTRIBUTION

+ +

Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.

+ +

For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.

+ +

5. NO WARRANTY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.

+ +

6. DISCLAIMER OF LIABILITY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), 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 OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

+ +

7. GENERAL

+ +

If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.

+ +

If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.

+ +

All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.

+ +

Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.

+ +

This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.

+ + + + \ No newline at end of file diff --git a/etc/license.txt b/etc/license.txt new file mode 100644 index 0000000..0fa5bd2 --- /dev/null +++ b/etc/license.txt @@ -0,0 +1,87 @@ +Eclipse Public License -v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file diff --git a/etc/logging.properties b/etc/logging.properties new file mode 100755 index 0000000..47b894a --- /dev/null +++ b/etc/logging.properties @@ -0,0 +1,30 @@ +handlers=com.agynamix.platform.log.FileHandler +#handlers=java.util.logging.ConsoleHandler,com.agynamix.platform.log.FileHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. +.level= INFO + +############################################################ +# Handler specific properties +############################################################ + +java.util.logging.ConsoleHandler.level=FINEST +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + +# default file output is in user's home directory. +com.agynamix.platform.log.FileHandler.level = FINEST +com.agynamix.platform.log.FileHandler.append = true +com.agynamix.platform.log.FileHandler.pattern = ${log.dir}/simidude.log +com.agynamix.platform.log.FileHandler.limit = 5000000 +com.agynamix.platform.log.FileHandler.count = 3 +com.agynamix.platform.log.FileHandler.formatter = java.util.logging.SimpleFormatter + +#com.agynamix.guardian.transformer.impl.level = FINER + +#com.agynamix.platform.net.PingService.level = FINE +#com.agynamix.platform.net.NetUtils.level = FINE +#com.agynamix.platform.net.PingServiceListener.level = FINE +#com.agynamix.platform.net.ContactRequestorService.level = FINE + diff --git a/etc/style.css b/etc/style.css new file mode 100644 index 0000000..9a31d23 --- /dev/null +++ b/etc/style.css @@ -0,0 +1,128 @@ +/* +------------------------------------------------------------------------ +Name: Simidude CSS +Author: Torsten Uhlmann +Version: 1.0 +------------------------------------------------------------------------ + +Copyright: (c) 2009 AGYNAMIX Torsten Uhlmann + +All rights reserved. +*/ + +body { + text-align:center; + font: 12px Arial, Helvetica, sans-serif; +} + +h1 { + text-align: center; + font: 20px Georgia, serif; + color: #960620; +} + +h2 { + text-align: center; + font: 18px Georgia, serif; +} + +ul { + margin-left: auto; + margin-right: auto; +} + +li { + list-style-type: none; + padding: .3em 0; +} + +table { + width: 90%; + border-width: 1px; + border-style: dashed; + border-collapse: collapse; +} + +th { + padding: 1em 1em 0.5em 0.5em; + border-width: 1px; + border-style: dotted; +} + +td { + padding: 1em 1em 0.5em 0.5em; + border-width: 1px; + border-style: dotted; +} + +.table_even { + background-color: #FFFFFF; +} + +.table_odd { + background-color: #FBFFDF; +} + +.table_single { + background-color: #F4F5FB; +} + +.li_even { + +} + +.li_odd { + +} + +.list_all { + +} + +.list_single { + text-align: center; + +} + +.text_box_single { + +} + +.text_box_list { + +} + +.file_box_single { + +} + +.file_box_list { + +} + +.image_box_single { + +} + +.image_box_list { + +} + +.image_thumb { + +} + +.image { +} + +a:link, a:visited { + text-decoration: none; +} + +img { + border-width: 1px; + border-style: solid; + border-color: #960620; + padding: 0.5em; + +} \ No newline at end of file diff --git a/lib/linux_x86/jna.jar b/lib/linux_x86/jna.jar new file mode 100644 index 0000000..55ca1eb Binary files /dev/null and b/lib/linux_x86/jna.jar differ diff --git a/lib/linux_x86/jxgrabkey-0.3.1-32.jar b/lib/linux_x86/jxgrabkey-0.3.1-32.jar new file mode 100644 index 0000000..5f5da41 Binary files /dev/null and b/lib/linux_x86/jxgrabkey-0.3.1-32.jar differ diff --git a/lib/linux_x86/org.eclipse.swt.gtk.linux.x86_3.7.0.v3735b.jar b/lib/linux_x86/org.eclipse.swt.gtk.linux.x86_3.7.0.v3735b.jar new file mode 100644 index 0000000..34e80e2 Binary files /dev/null and b/lib/linux_x86/org.eclipse.swt.gtk.linux.x86_3.7.0.v3735b.jar differ diff --git a/lib/linux_x86_64/jna.jar b/lib/linux_x86_64/jna.jar new file mode 100644 index 0000000..55ca1eb Binary files /dev/null and b/lib/linux_x86_64/jna.jar differ diff --git a/lib/linux_x86_64/jxgrabkey-0.3.1-64.jar b/lib/linux_x86_64/jxgrabkey-0.3.1-64.jar new file mode 100644 index 0000000..72b54fb Binary files /dev/null and b/lib/linux_x86_64/jxgrabkey-0.3.1-64.jar differ diff --git a/lib/linux_x86_64/org.eclipse.swt.gtk.linux.x86_64_3.7.0.v3735b.jar b/lib/linux_x86_64/org.eclipse.swt.gtk.linux.x86_64_3.7.0.v3735b.jar new file mode 100644 index 0000000..e08f85a Binary files /dev/null and b/lib/linux_x86_64/org.eclipse.swt.gtk.linux.x86_64_3.7.0.v3735b.jar differ diff --git a/lib/not_for_installer/i4jruntime.jar b/lib/not_for_installer/i4jruntime.jar new file mode 100644 index 0000000..4dcea2b Binary files /dev/null and b/lib/not_for_installer/i4jruntime.jar differ diff --git a/lib/org.eclipse.core.commands_3.6.0.I20110111-0800.jar b/lib/org.eclipse.core.commands_3.6.0.I20110111-0800.jar new file mode 100644 index 0000000..a45a6d3 Binary files /dev/null and b/lib/org.eclipse.core.commands_3.6.0.I20110111-0800.jar differ diff --git a/lib/org.eclipse.core.jobs_3.5.100.v20110404.jar b/lib/org.eclipse.core.jobs_3.5.100.v20110404.jar new file mode 100644 index 0000000..35ff327 Binary files /dev/null and b/lib/org.eclipse.core.jobs_3.5.100.v20110404.jar differ diff --git a/lib/org.eclipse.core.runtime_3.7.0.v20110110.jar b/lib/org.eclipse.core.runtime_3.7.0.v20110110.jar new file mode 100644 index 0000000..cafc45a Binary files /dev/null and b/lib/org.eclipse.core.runtime_3.7.0.v20110110.jar differ diff --git a/lib/org.eclipse.equinox.common_3.6.0.v20110523.jar b/lib/org.eclipse.equinox.common_3.6.0.v20110523.jar new file mode 100644 index 0000000..759302f Binary files /dev/null and b/lib/org.eclipse.equinox.common_3.6.0.v20110523.jar differ diff --git a/lib/org.eclipse.jface_3.7.0.I20110522-1430.jar b/lib/org.eclipse.jface_3.7.0.I20110522-1430.jar new file mode 100644 index 0000000..5c1e6b4 Binary files /dev/null and b/lib/org.eclipse.jface_3.7.0.I20110522-1430.jar differ diff --git a/lib/org.eclipse.osgi_3.7.0.v20110613.jar b/lib/org.eclipse.osgi_3.7.0.v20110613.jar new file mode 100644 index 0000000..ebf23d5 Binary files /dev/null and b/lib/org.eclipse.osgi_3.7.0.v20110613.jar differ diff --git a/lib/org.eclipse.swt_3.7.0.v3735b.jar b/lib/org.eclipse.swt_3.7.0.v3735b.jar new file mode 100644 index 0000000..0b0e37c Binary files /dev/null and b/lib/org.eclipse.swt_3.7.0.v3735b.jar differ diff --git a/lib/ossupport-connector-common-1.0-SNAPSHOT.jar b/lib/ossupport-connector-common-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..a4f80fe Binary files /dev/null and b/lib/ossupport-connector-common-1.0-SNAPSHOT.jar differ diff --git a/lib/osx_x86/org.eclipse.swt.carbon.macosx_3.7.0.v3735b.jar b/lib/osx_x86/org.eclipse.swt.carbon.macosx_3.7.0.v3735b.jar new file mode 100644 index 0000000..d3152bb Binary files /dev/null and b/lib/osx_x86/org.eclipse.swt.carbon.macosx_3.7.0.v3735b.jar differ diff --git a/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT-osx32.jar b/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT-osx32.jar new file mode 100644 index 0000000..81fc44a Binary files /dev/null and b/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT-osx32.jar differ diff --git a/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT.jar b/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..3aa1ed5 Binary files /dev/null and b/lib/osx_x86/ossupport-connector-mac-1.0-SNAPSHOT.jar differ diff --git a/lib/solaris_x86/org.eclipse.swt.gtk.solaris.x86_3.6.0.v3650b.jar b/lib/solaris_x86/org.eclipse.swt.gtk.solaris.x86_3.6.0.v3650b.jar new file mode 100644 index 0000000..e9d55d5 Binary files /dev/null and b/lib/solaris_x86/org.eclipse.swt.gtk.solaris.x86_3.6.0.v3650b.jar differ diff --git a/lib/win32/JIntellitype.dll b/lib/win32/JIntellitype.dll new file mode 100644 index 0000000..839236b Binary files /dev/null and b/lib/win32/JIntellitype.dll differ diff --git a/lib/win32/jintellitype-1.3.4.jar b/lib/win32/jintellitype-1.3.4.jar new file mode 100644 index 0000000..88cccdd Binary files /dev/null and b/lib/win32/jintellitype-1.3.4.jar differ diff --git a/lib/win32/jna.jar b/lib/win32/jna.jar new file mode 100644 index 0000000..55ca1eb Binary files /dev/null and b/lib/win32/jna.jar differ diff --git a/lib/win32/org.eclipse.swt.win32.win32.x86_3.7.0.v3735b.jar b/lib/win32/org.eclipse.swt.win32.win32.x86_3.7.0.v3735b.jar new file mode 100644 index 0000000..fdf01db Binary files /dev/null and b/lib/win32/org.eclipse.swt.win32.win32.x86_3.7.0.v3735b.jar differ diff --git a/lib/win32_64/JIntellitype.dll b/lib/win32_64/JIntellitype.dll new file mode 100644 index 0000000..6dc2680 Binary files /dev/null and b/lib/win32_64/JIntellitype.dll differ diff --git a/lib/win32_64/jintellitype-1.3.4.jar b/lib/win32_64/jintellitype-1.3.4.jar new file mode 100644 index 0000000..88cccdd Binary files /dev/null and b/lib/win32_64/jintellitype-1.3.4.jar differ diff --git a/lib/win32_64/jna.jar b/lib/win32_64/jna.jar new file mode 100644 index 0000000..55ca1eb Binary files /dev/null and b/lib/win32_64/jna.jar differ diff --git a/lib/win32_64/org.eclipse.swt.win32.win32.x86_64_3.7.0.v3735b.jar b/lib/win32_64/org.eclipse.swt.win32.win32.x86_64_3.7.0.v3735b.jar new file mode 100644 index 0000000..5d9917c Binary files /dev/null and b/lib/win32_64/org.eclipse.swt.win32.win32.x86_64_3.7.0.v3735b.jar differ diff --git a/localbuild.properties b/localbuild.properties new file mode 100644 index 0000000..dad51e5 --- /dev/null +++ b/localbuild.properties @@ -0,0 +1 @@ +install4j.ant.task.path=/Applications/install4j 5/bin/ant.jar diff --git a/src/java/com/agynamix/platform/bugzscout/BugzScoutCtl.java b/src/java/com/agynamix/platform/bugzscout/BugzScoutCtl.java new file mode 100644 index 0000000..143399a --- /dev/null +++ b/src/java/com/agynamix/platform/bugzscout/BugzScoutCtl.java @@ -0,0 +1,204 @@ +package com.agynamix.platform.bugzscout; + +import java.util.HashMap; +import java.util.Map; + +public class BugzScoutCtl { + +// static { +// String logging = "org.apache.commons.logging"; +// +// System.setProperty(logging + ".Log", logging + ".impl.SimpleLog"); +// System.setProperty(logging + ".logging.simplelog.showdatetime", "true"); +// System.setProperty(logging + ".simplelog.log.httpclient.wire", "debug"); +// System.setProperty(logging + ".simplelog.log.org.apache.commons.httpclient", "debug"); +// } + + /** URL to send Request to */ + String url; + + /** the FogBugz user */ + String userName; + + /** the FogBugz project */ + String project; + + /** the FogBugz Area within the project */ + String area; + + /** the default message to show to the user */ + String defaultMessage; + + /** + * Submit a bug to BugzScout + * + * @param description + * the description of the bug (should be generated by the software. Same bugs should have same description + * line so FogBugz will identify them as duplicates + * @param extraInfo + * Info the user entered + * @param email + * the email address of the user + * @param isForceNewBug + * do we want FogBugz to create a new bug report even if it is a duplicate? + * @return true if submission was successful, false otherwise + */ + public ScoutAnswer submitBug(String description, String extraInfo, String email, boolean isForceNewBug) + { + Map params = new HashMap(); + + params.put("Description", description); //$NON-NLS-1$ + params.put("Extra", extraInfo); //$NON-NLS-1$ + params.put("Email", email); //$NON-NLS-1$ + params.put("ScoutUserName", getUserName()); //$NON-NLS-1$ + params.put("ScoutProject", getProject()); //$NON-NLS-1$ + params.put("ScoutArea", getArea()); //$NON-NLS-1$ + params.put("ScoutDefaultMessage", getDefaultMessage()); //$NON-NLS-1$ + + if (isForceNewBug) + { + params.put("ForceNewBug", "1"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + params.put("ForceNewBug", "0"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + SimpleHttpClient client = new SimpleHttpClient(); + + String result = ""; //$NON-NLS-1$ + try { + SimpleHttpClient.Response response = client.sendRequest( url, params ); + + if (response.getStatusCode() == SimpleHttpClient.Response.Status.SC_OK) + { + byte[] r = response.getResponseBody(); + result = new String(r, "utf-8"); //$NON-NLS-1$ +// System.out.println("RES="+result); //$NON-NLS-1$ + } else { + return new ScoutAnswer(ScoutAnswer.ReturnCode.SYSERROR, + response.getStatusCode() + ": "+response.getErrorMessage()); //+ response.getStatusText()+", "+response.getStatusLine()); //$NON-NLS-1$ + } + } catch (Exception e) + { + e.printStackTrace(); + return new ScoutAnswer(ScoutAnswer.ReturnCode.SYSERROR, e.getMessage()); + } + + return new ScoutAnswer(result); + } + + public String getArea() + { + return area; + } + + public void setArea(String area) + { + this.area = area; + } + + public String getDefaultMessage() + { + return defaultMessage; + } + + public void setDefaultMessage(String defaultMessage) + { + this.defaultMessage = defaultMessage; + } + + public String getProject() + { + return project; + } + + public void setProject(String project) + { + this.project = project; + } + + public String getUrl() + { + return url; + } + + public void setUrl(String url) + { + this.url = url; + } + + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public static class ScoutAnswer { + + public enum ReturnCode { UNKNOWN, SUCCESS, ERROR, SYSERROR } + + ReturnCode returnCode; + String message; + + public ScoutAnswer(ReturnCode rc, String message) + { + this.returnCode = rc; + this.message = message; + } + + /** + * Strip the answer from the xml response. This is a bit buggy but I want not to use an xml parser + * for this bit as it would increase dependencies. + * @param xmlAnswer the string received with the http response. + */ + public ScoutAnswer(String xmlAnswer) + { + int sStart = xmlAnswer.indexOf(""); //$NON-NLS-1$ + int sEnd = xmlAnswer.indexOf(""); //$NON-NLS-1$ + int fStart = xmlAnswer.indexOf(""); //$NON-NLS-1$ + int fEnd = xmlAnswer.indexOf(""); //$NON-NLS-1$ + if ((sStart > -1) && (sEnd > -1)) + { + returnCode = ScoutAnswer.ReturnCode.SUCCESS; + message = xmlAnswer.substring(sStart+9, sEnd); + } else { + if ((fStart > -1) && (fEnd > -1)) + { + returnCode = ScoutAnswer.ReturnCode.ERROR; + message = xmlAnswer.substring(fStart+7, fEnd); + } else { + returnCode = ScoutAnswer.ReturnCode.UNKNOWN; + message = xmlAnswer; + } + } + } + + public String getMessage() + { + return message; + } + + public ReturnCode getReturnCode() + { + return returnCode; + } + + } + + public static void main(String[] args) + { +// System.out.println("FogBugz Test"); + BugzScoutCtl ctl = new BugzScoutCtl(); + ctl.setArea("BugzScout"); //$NON-NLS-1$ + ctl.setDefaultMessage("Vielen Dank!"); //$NON-NLS-1$ + ctl.setProject("Simidude"); //$NON-NLS-1$ + ctl.setUrl("https://agynamix.fogbugz.com/scoutSubmit.asp"); //$NON-NLS-1$ + ctl.setUserName("Torsten Uhlmann"); //$NON-NLS-1$ + ScoutAnswer answer = ctl.submitBug("Fehler 443", "extra Info", "tuhlmann@gmx.de", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ +// System.out.println("RC="+answer.getReturnCode()+", Message="+answer.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/src/java/com/agynamix/platform/bugzscout/SimpleHttpClient.java b/src/java/com/agynamix/platform/bugzscout/SimpleHttpClient.java new file mode 100644 index 0000000..a70c5cb --- /dev/null +++ b/src/java/com/agynamix/platform/bugzscout/SimpleHttpClient.java @@ -0,0 +1,166 @@ +package com.agynamix.platform.bugzscout; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.List; +import java.util.Map; + +public class SimpleHttpClient { + + protected Proxy findProxy(URI uri) + { + try + { + ProxySelector selector = ProxySelector.getDefault(); + List proxyList = selector.select(uri); + if (proxyList.size() > 1) + { + return proxyList.get(0); + } + } catch (IllegalArgumentException e) + { + System.out.println("Proxy not found: "+e.getMessage()); + } + return Proxy.NO_PROXY; + } + + public Response sendRequest(String sUrl, Map params) + { + Response response = null; + + StringBuffer sb = new StringBuffer(); + try + { + boolean isFirst = true; + + for (String key : params.keySet()) + { + String pName = "&"; //$NON-NLS-1$ + if (isFirst) + { + isFirst = false; + pName = ""; //$NON-NLS-1$ + } + pName += URLEncoder.encode(key, "UTF-8") + "="; //$NON-NLS-1$ //$NON-NLS-2$ + sb.append(pName); + sb.append(URLEncoder.encode(params.get(key), "UTF-8")); //$NON-NLS-1$ + } + } catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e); + } + + String formData = sb.toString(); +// System.out.println("REQ="+formData); + + HttpURLConnection urlcon = null; + + try + { + URL url = new URL(sUrl); + Proxy itsProxy = findProxy(new URI(sUrl)); +// System.out.println("Proxy: "+itsProxy); + urlcon = (HttpURLConnection) url.openConnection(itsProxy); + urlcon.setRequestMethod("POST"); //$NON-NLS-1$ + urlcon.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); //$NON-NLS-1$ //$NON-NLS-2$ + urlcon.setDoOutput(true); + urlcon.setDoInput(true); + PrintWriter pout = new PrintWriter(new OutputStreamWriter(urlcon.getOutputStream(), "UTF-8"), true); //$NON-NLS-1$ + pout.print(formData); + pout.flush(); + pout.close(); + + // read results... + if (urlcon.getResponseCode() != HttpURLConnection.HTTP_OK) + { + response = new Response(Response.Status.SC_ERROR, urlcon.getResponseCode(), readFromStream(urlcon.getErrorStream()).getBytes()); + return response; + } + + response = new Response(Response.Status.SC_OK, urlcon.getResponseCode(), readFromStream(urlcon.getInputStream()).getBytes()); + } catch (IOException e) + { + response = new Response(Response.Status.SC_ERROR, e); + } catch (URISyntaxException e) + { + System.out.println("Could not convert URL to URI: "+sUrl+", Msg: "+e.getMessage()); + response = new Response(Response.Status.SC_ERROR, e); + } finally { + if (urlcon != null) + { + urlcon.disconnect(); + } + } + return response; + + } + + private String readFromStream(InputStream stream) throws IOException + { + if (stream == null) return ""; //$NON-NLS-1$ + StringBuilder sb = new StringBuilder(); + String line = ""; //$NON-NLS-1$ + BufferedReader rd = new BufferedReader(new InputStreamReader(stream)); + while ((line = rd.readLine()) != null) + { + sb.append(line); + } + rd.close(); + return sb.toString(); + } + + public static class Response { + + public enum Status { SC_UNKNOWN, SC_OK, SC_ERROR }; + + final Status responseStatus; + final String errorMsg; + final int responseCode; + final byte[] body; + + public Response(Status responseStatus, int respCode, byte[] body) + { + this.responseStatus = responseStatus; + this.responseCode = respCode; + this.body = body; + this.errorMsg = ""; //$NON-NLS-1$ + } + + public Response(Status responseStatus, Throwable error) + { + this.responseStatus = responseStatus; + this.responseCode = -1; + this.body = new byte[0]; + this.errorMsg = error.getMessage(); + } + + public Status getStatusCode() + { + return responseStatus; + } + + public String getErrorMessage() + { + return this.errorMsg; + } + + public byte[] getResponseBody() + { + return body; + } + + } + +} diff --git a/src/java/com/agynamix/platform/concurrent/AbstractService.java b/src/java/com/agynamix/platform/concurrent/AbstractService.java new file mode 100644 index 0000000..bdb3566 --- /dev/null +++ b/src/java/com/agynamix/platform/concurrent/AbstractService.java @@ -0,0 +1,94 @@ +/* + * Class AbstractDispatcher + * Created on 15.02.2005 + * + * This file is copyrighted by AGYNAMIX. + * Please refer to the license of our products for details. + */ +package com.agynamix.platform.concurrent; + +import java.util.logging.Logger; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.log.ApplicationLog; + + + +/** + * Base class for all Dispatchers. This class provides a Runnable implementation + * to run in a thread of it's own. + * + * @author tuhlmann + */ +public abstract class AbstractService implements ThreadManagerAware { + + protected final String serviceId; + protected boolean stopped; + + private boolean isInitialized = false; + + Logger log = ApplicationLog.getLogger(AbstractService.class); + + public AbstractService(String serviceId) + { + this.serviceId = serviceId; + } + + public String getId() { + return this.serviceId; + } + + public synchronized void initialize() { + if (!isInitialized) { + internalInitialize(); + ApplicationBase.getContext().getThreadManager().registerNew(this); + isInitialized = true; + } + } + + /** + * internalInitialize() is called by this Objects initialize() method + * + */ + protected abstract void internalInitialize(); + + public void shutdown() { + this.stopped = true; + } + + /** + * internalRun is called by this objects run() method. + * It is embedded in a loop so the subclass does not have to care + * about implementing a sane Thread loop. + * + * @throws InterruptedException + */ + protected abstract void internalRun() throws InterruptedException; + + /** + * Everything that should be executed during run, but only once. + * + */ + protected abstract void preRunLoop(); + + /** + * @see java.lang.Runnable#run() + */ + public void run() { + preRunLoop(); + stopped = false; + while (!stopped) { + try { + internalRun(); + } catch (InterruptedException e) { + } + } + log.config("Exiting run() loop: "+this.getClass().getName()); + } + + public void setStopped(boolean stopped) + { + this.stopped = stopped; + } + +} diff --git a/src/java/com/agynamix/platform/concurrent/ThreadManager.java b/src/java/com/agynamix/platform/concurrent/ThreadManager.java new file mode 100644 index 0000000..bc6ceb4 --- /dev/null +++ b/src/java/com/agynamix/platform/concurrent/ThreadManager.java @@ -0,0 +1,85 @@ +/* + * Class ThreadManager + * Created on 31.01.2005 + * + * This file is copyrighted by AGYNAMIX. + * Please refer to the license of our products for details. + */ +package com.agynamix.platform.concurrent; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Logger; + +import com.agynamix.platform.log.ApplicationLog; + +/** + * Class is a pin point for the created threads. + * They are gonna be registered here. + * + * @author tuhlmann + * @created 31.01.2005 + */ +public class ThreadManager { + + public static final int MaxThreads = 50; + + public static final String SERVICE_NAME = "ThreadManager"; + + List processList = new CopyOnWriteArrayList(); + + ExecutorService service; + + Logger log = ApplicationLog.getLogger(ThreadManager.class); + + public ThreadManager() { + initialize(); + } + + public void initialize() { + service = Executors.newFixedThreadPool(MaxThreads); + } + + /** + * @param process + */ + public void registerNew(ThreadManagerAware process) { +// System.out.println("Register process: "+process.getClass().getName()); + if (!processList.contains(process)) + { +// System.out.println("Start new thread for "+process.getClass().getName()); + processList.add(process); + } + } + + /** + * Call this method to really start the registered processed. + */ + public void startRegisteredServices() { +// System.out.println("Start registered services"); + for (ThreadManagerAware proc : processList) + { + service.execute(proc); + } + } + + public void shutdownNow() { + log.info("Shutdown ThreadManager"); + for (ThreadManagerAware proc : processList) + { + log.config("Shutdown Object: "+proc.getId()); + proc.shutdown(); + } + service.shutdownNow(); + } + + /** + * @see org.springframework.beans.factory.DisposableBean#destroy() + */ + public void destroy() throws Exception { + shutdownNow(); + } + +} diff --git a/src/java/com/agynamix/platform/concurrent/ThreadManagerAware.java b/src/java/com/agynamix/platform/concurrent/ThreadManagerAware.java new file mode 100644 index 0000000..a4bb9b7 --- /dev/null +++ b/src/java/com/agynamix/platform/concurrent/ThreadManagerAware.java @@ -0,0 +1,27 @@ +/* + * Class ThreadManagerAware + * Created on 06.02.2005 + * + * This file is copyrighted by AGYNAMIX. + * Please refer to the license of our products for details. + */ +package com.agynamix.platform.concurrent; + + + +/** + * @author tuhlmann + * @created 06.02.2005 + */ +public interface ThreadManagerAware extends Runnable { + + /** + * This method is called by the ThreadManager prior to shutting down the started threads. + * + */ + public void shutdown(); + + public String getId(); + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/BuildInfoAction.java b/src/java/com/agynamix/platform/frontend/action/BuildInfoAction.java new file mode 100644 index 0000000..950965a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/BuildInfoAction.java @@ -0,0 +1,43 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.dialogs.BuildInfoDialog; +import com.agynamix.platform.frontend.dialogs.BuildInfoDialogView; + + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since 1.0 + */ +public class BuildInfoAction extends Action { + + final ApplicationWindow window; + + public BuildInfoAction(ApplicationWindow w) { + this.window = w; + setText("Build &Info"); + setToolTipText("Shows the build information dialog"); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + BuildInfoDialog dialog = new BuildInfoDialog(new BuildInfoDialogView(window.getShell())); + dialog.open(); + } + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/action/CheckUpdatesAction.java b/src/java/com/agynamix/platform/frontend/action/CheckUpdatesAction.java new file mode 100644 index 0000000..264db77 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/CheckUpdatesAction.java @@ -0,0 +1,57 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.Simidude; +import com.install4j.api.launcher.ApplicationLauncher; + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class CheckUpdatesAction extends Action { + + final ApplicationWindow window; + + public CheckUpdatesAction(ApplicationWindow w) { + this.window = w; + setText("&Check for Updates"); + setToolTipText("Check if new updates are available"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.UPDATE)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + try + { + ApplicationLauncher.launchApplication(Simidude.MANUAL_UPDATER_ID, null, false, new ApplicationLauncher.Callback(){ + + public void exited(int exitValue){} + + public void prepareShutdown() + { + try { + ApplicationGUI gui = ApplicationBase.getContext().getApplicationGUI(); + gui.close(); + } catch (Exception ignore){} + } + + }); + } catch (Exception ignore){} + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/ClearClipboardTableAction.java b/src/java/com/agynamix/platform/frontend/action/ClearClipboardTableAction.java new file mode 100644 index 0000000..ba35c0d --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/ClearClipboardTableAction.java @@ -0,0 +1,57 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.SimidudeUtils; + +public class ClearClipboardTableAction extends Action { + + final ApplicationWindow window; + final boolean isNetworkRemove; + + public ClearClipboardTableAction(ApplicationWindow w, boolean isNetworkRemove) { + super(isNetworkRemove ? "Clear Table Everywhere" : "Clear Table Locally", IAction.AS_PUSH_BUTTON); + this.window = w; + this.isNetworkRemove = isNetworkRemove; + if (isNetworkRemove) + { + setToolTipText("Clears all entries from the clipboard table AND all connected clients"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.NETWORK_CLEAR_CLIPBOARD)); + } else { + setToolTipText("Clears all entries from the clipboard table"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.CLEAR_CLIPBOARD)); + } + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + boolean isNetworkRemove = SimidudeUtils.isModifierKeyPressed() || this.isNetworkRemove; + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sdm.removeAll(); + if (isNetworkRemove) + { + ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider().networkRemoveItem(null); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/action/CopyAction.java b/src/java/com/agynamix/platform/frontend/action/CopyAction.java new file mode 100644 index 0000000..6009ba2 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/CopyAction.java @@ -0,0 +1,46 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class CopyAction extends Action { + + final ApplicationWindow window; + + public CopyAction(ApplicationWindow w) { + super("Copy Selected Entry", IAction.AS_PUSH_BUTTON); + this.window = w; + setToolTipText("Copy the selected entry to the clipboard"); + setAccelerator(SWT.MOD1 + 'C'); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.COPY)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + tm.activateItem(); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/action/CutAction.java b/src/java/com/agynamix/platform/frontend/action/CutAction.java new file mode 100644 index 0000000..a59c9b6 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/CutAction.java @@ -0,0 +1,49 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class CutAction extends Action { + + final ApplicationWindow window; + + public CutAction(ApplicationWindow w) { + super("Cut Selected Entry", IAction.AS_PUSH_BUTTON); + this.window = w; + setToolTipText("Copy the selected entry to clipboard and remove it from the list"); + setAccelerator(SWT.MOD1 + 'X'); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.CUT)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + int currentSelectionIndex = sdm.getSelectionIndex(); + sdm.activateItem(); + sdm.removeSelectedEntry(); + sdm.saveSelectEntry(currentSelectionIndex); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/action/ExitAction.java b/src/java/com/agynamix/platform/frontend/action/ExitAction.java new file mode 100644 index 0000000..f998f4a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/ExitAction.java @@ -0,0 +1,41 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.icons.PlatformIcons; + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class ExitAction extends Action { + + final ApplicationWindow window; + + public ExitAction(ApplicationWindow w) { + this.window = w; + setText("E&xit"); + setToolTipText("Exit the application"); + setAccelerator(SWT.MOD1 + 'Q'); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.EXIT)); + setDescription("Exit the application"); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + window.close(); + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/HideAction.java b/src/java/com/agynamix/platform/frontend/action/HideAction.java new file mode 100644 index 0000000..6cf866f --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/HideAction.java @@ -0,0 +1,41 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +public class HideAction extends Action implements IAction { + + final ApplicationWindow window; + + public HideAction(ApplicationWindow w) { + this.window = w; + setText("&Hide Window"); + setToolTipText("Hide this window"); + setAccelerator(SWT.MOD1 + 'H'); +// setImageDescriptor(ImageDescriptor.createFromImage(new Image(Display.getDefault(), getClass().getClassLoader().getResourceAsStream("icons/cancle.gif")))); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + window.getShell().setVisible(false); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/action/IActionWithValue.java b/src/java/com/agynamix/platform/frontend/action/IActionWithValue.java new file mode 100644 index 0000000..602c4a7 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/IActionWithValue.java @@ -0,0 +1,14 @@ +package com.agynamix.platform.frontend.action; + + +public interface IActionWithValue { + + /** + * Runs an action with the given selection value. + * @param value the given selection value. + */ + public void runWithValue(boolean value); + + public boolean getSelectionValue(); + +} diff --git a/src/java/com/agynamix/platform/frontend/action/InputTextAction.java b/src/java/com/agynamix/platform/frontend/action/InputTextAction.java new file mode 100644 index 0000000..15d232b --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/InputTextAction.java @@ -0,0 +1,58 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.frontend.dialogs.InputTextDialog; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.SourceDataFactory; + +public class InputTextAction extends Action { + + final ApplicationWindow window; + + public InputTextAction(ApplicationWindow w) { + super("Simple Text Editor", IAction.AS_PUSH_BUTTON); + this.window = w; + setToolTipText("Open the Simple Text Editor to directly input text"); + setAccelerator(SWT.MOD1 + 'N'); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.INPUT_TEXT)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + InputTextDialog dialog = new InputTextDialog(window.getShell()); + if (dialog.open() == IDialogConstants.OK_ID) + { + String contents = dialog.getText(); + if ((contents != null) && (contents.length() > 0)) + { + IQueueManager queueManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + queueManager.put(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, SourceDataFactory.createFromText(contents)); + } + } + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/action/NetworkAnalysisAction.java b/src/java/com/agynamix/platform/frontend/action/NetworkAnalysisAction.java new file mode 100644 index 0000000..a8422c1 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/NetworkAnalysisAction.java @@ -0,0 +1,45 @@ +/* + * Class NetworkAnalysisAction + * created on 07.01.2010 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.dialogs.SimpleInformationViewerDialog; +import com.agynamix.platform.net.NetworkAnalyzer; + + + +/** + * @author tuhlmann + * @since 1.0 + */ +public class NetworkAnalysisAction extends Action { + + final ApplicationWindow window; + + public NetworkAnalysisAction(ApplicationWindow w) { + this.window = w; + setText("&Network Analysis"); + setToolTipText("Shows diagnosis information about how Simidude uses the network."); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + NetworkAnalyzer networkAnalyzer = new NetworkAnalyzer(); + networkAnalyzer.run(); + String info = networkAnalyzer.asString(); + SimpleInformationViewerDialog dialog = new SimpleInformationViewerDialog(window.getShell(), + "Network Analysis", "This dialog shows diagnosis information about your network and how Simidude utilizes it.\nPlease include this in any network related bug reports.", info); + networkAnalyzer.close(); + dialog.open(); + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/PreferencesAction.java b/src/java/com/agynamix/platform/frontend/action/PreferencesAction.java new file mode 100644 index 0000000..f93b45c --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/PreferencesAction.java @@ -0,0 +1,41 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.ModelProvider; + + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + */ +public class PreferencesAction extends Action { + + final ApplicationWindow window; + + public PreferencesAction(ApplicationWindow w) { + this.window = w; + setText("&Preferences"); + setToolTipText("Use this to set Simidude's preferences according to your needs."); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.openPreferencesDialog(window.getShell()); + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/RemoveSelectedClipboardEntry.java b/src/java/com/agynamix/platform/frontend/action/RemoveSelectedClipboardEntry.java new file mode 100644 index 0000000..2b26374 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/RemoveSelectedClipboardEntry.java @@ -0,0 +1,91 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.SimidudeUtils; + +public class RemoveSelectedClipboardEntry extends Action implements ISelectionChangedListener { + + final ApplicationWindow window; + + final boolean isNetworkRemove; + + public RemoveSelectedClipboardEntry(ApplicationWindow w, boolean isNetworkRemove) + { + super(isNetworkRemove ? "Remove Selected Entry Everywhere" : "Remove Selected Entry Locally", IAction.AS_PUSH_BUTTON); + this.window = w; + this.isNetworkRemove = isNetworkRemove; + if (isNetworkRemove) + { + setToolTipText("Removes the selected entry from the clipboard table AND all connected clients"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.NETWORK_REMOVE_SELECTED_CLIPBOARD_ENTRY)); + } else { + setToolTipText("Removes the selected entry from the clipboard table"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.REMOVE_SELECTED_CLIPBOARD_ENTRY)); + } + setEnabled(false); + } + + public void selectionChanged(SelectionChangedEvent event) + { +// System.out.println("Source: "+event.getSource()); +// System.out.println("Selection Class "+event.getSelection().getClass()); +// System.out.println(event.getSelectionProvider().getClass().getName()); + if (event.getSelection() instanceof IStructuredSelection) + { + IStructuredSelection ss = (IStructuredSelection) event.getSelection(); + Object first = ss.getFirstElement(); + if (first != null) + { +// System.out.println("First Element Class: "+first.getClass().getName()); + if (first instanceof IClipboardItem) + { + setEnabled(true); + } + } else { +// System.out.println("First Element EMPTY"); + setEnabled(false); + } + } + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() + { + boolean isNetworkRemove = SimidudeUtils.isModifierKeyPressed() || this.isNetworkRemove; + SourceDataManager sdm = ((SimidudeApplicationContext) ApplicationBase.getContext()).getSourceDataManager(); + int currentSelectionIndex = sdm.getSelectionIndex(); + + IClipboardItem removedItem = sdm.removeSelectedEntry(); + sdm.saveSelectEntry(currentSelectionIndex); + if ((isNetworkRemove) && (removedItem != null)) + { + ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider().networkRemoveItem(removedItem.getSourceData().getStub()); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/action/SaveAsAction.java b/src/java/com/agynamix/platform/frontend/action/SaveAsAction.java new file mode 100644 index 0000000..f101f34 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/SaveAsAction.java @@ -0,0 +1,50 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class SaveAsAction extends Action { + + final ApplicationWindow window; + + public SaveAsAction(ApplicationWindow w) { + super("Save As...", IAction.AS_PUSH_BUTTON); + this.window = w; + setToolTipText("Save the selected entry to the filesystem"); + setAccelerator(SWT.MOD1 + 'S'); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.SAVE_CONTENTS_AS_TABLE_ENTRY)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = tm.getSelectedItem(); + if (item != null) + { + tm.saveClipboardItemAs(item, false); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/action/SaveAsCompressedAction.java b/src/java/com/agynamix/platform/frontend/action/SaveAsCompressedAction.java new file mode 100644 index 0000000..3e438b4 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/SaveAsCompressedAction.java @@ -0,0 +1,48 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class SaveAsCompressedAction extends Action { + + final ApplicationWindow window; + + public SaveAsCompressedAction(ApplicationWindow w) { + super("Save Compressed...", IAction.AS_PUSH_BUTTON); + this.window = w; + setToolTipText("Save the selected entry as a zip compressed file to the filesystem"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.SAVE_CONTENTS_COMPRESSED_TABLE_ENTRY)); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = tm.getSelectedItem(); + if (item != null) + { + tm.saveClipboardItemAs(item, true); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/action/SubmitBugzScoutAction.java b/src/java/com/agynamix/platform/frontend/action/SubmitBugzScoutAction.java new file mode 100644 index 0000000..3ae78b3 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/SubmitBugzScoutAction.java @@ -0,0 +1,40 @@ +/* + * Class LicenseDialogAction + * created on 01.06.2004 + * + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.dialogs.BugzScoutDialog; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationInfo; + + +/** + * @author tuhlmann + */ +public class SubmitBugzScoutAction extends Action { + + final ApplicationWindow window; + + public SubmitBugzScoutAction(ApplicationWindow w) { + this.window = w; + setText("Submit A Bug"); + setToolTipText("Use this dialog to submit a bug to the Simidude developers."); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.SUBMIT_BUG_REPORT)); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + BugzScoutDialog dialog = new BugzScoutDialog(window.getShell(), ApplicationInfo.getApplicationInfo(), true ); + dialog.open(); + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/action/ToggleShowStatuslineAction.java b/src/java/com/agynamix/platform/frontend/action/ToggleShowStatuslineAction.java new file mode 100644 index 0000000..04b2cb1 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/ToggleShowStatuslineAction.java @@ -0,0 +1,78 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; + +public class ToggleShowStatuslineAction extends Action implements IAction { + + final ApplicationWindow window; + Control statusline; + + Rectangle position; + + public ToggleShowStatuslineAction(ApplicationWindow w) { + super("Show Statusline", IAction.AS_CHECK_BOX); + this.window = w; + setToolTipText("Click to toggle the visibility of the status line at the bottom of the window."); + //setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.TOGGLE_MONITOR_CLIPBOARD)); + boolean checkStatus = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_SHOW_STATUSLINE); + setChecked(checkStatus); + } + + public void setStatusline(Control statusline) + { + this.statusline = statusline; + position = statusline.getBounds(); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + showStatusline(isChecked()); + ApplicationBase.getContext().getConfiguration().setBoolean(IPreferenceConstants.TOGGLE_SHOW_STATUSLINE, isChecked()); + } + + public void showStatusline() + { + boolean isShowStatusline = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_SHOW_STATUSLINE); + showStatusline(isShowStatusline); + } + + public void showStatusline(boolean show) + { + if (show) + { + statusline.setBounds(position.x, position.y, position.width, position.height); +// ((GridData)statusline.getLayoutData()).heightHint = -1; + //statusline.setVisible(true); + } else { + statusline.setBounds(position.x, position.y, position.width, 0); +// ((GridData)statusline.getLayoutData()).heightHint = 0; + statusline.setVisible(false); + } + statusline.getParent().layout(true); + window.getShell().layout(true); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/action/ToggleShowToolbarAction.java b/src/java/com/agynamix/platform/frontend/action/ToggleShowToolbarAction.java new file mode 100644 index 0000000..b9e62d0 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/action/ToggleShowToolbarAction.java @@ -0,0 +1,77 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; + +public class ToggleShowToolbarAction extends Action implements IAction { + + final ApplicationWindow window; + Control toolbar; + + public ToggleShowToolbarAction(ApplicationWindow w) { + super("Show Toolbar", IAction.AS_CHECK_BOX); + this.window = w; + setToolTipText("Click to toggle the visibility of the toolbar."); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.TOGGLE_SHOW_TOOLBAR)); + setAccelerator(SWT.MOD1 + 'T'); + boolean checkStatus = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_SHOW_TOOLBAR); + setChecked(checkStatus); +// if (!checkStatus) +// { +// showToolbar(false); +// } + } + + public void setToolbar(Control toolbar) + { + this.toolbar = toolbar; + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + showToolbar(isChecked()); + ApplicationBase.getContext().getConfiguration().setBoolean(IPreferenceConstants.TOGGLE_SHOW_TOOLBAR, isChecked()); + } + + public void showToolbar() + { + boolean isShowToolbar = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_SHOW_TOOLBAR); + showToolbar(isShowToolbar); + } + + public void showToolbar(boolean show) + { + if (show) + { + ((GridData)toolbar.getLayoutData()).heightHint = -1; + } else { + ((GridData)toolbar.getLayoutData()).heightHint = 0; + } + toolbar.getParent().pack(true); + window.getShell().layout(true); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/AboutApplicationDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/AboutApplicationDialog.java new file mode 100644 index 0000000..b7cb67d --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/AboutApplicationDialog.java @@ -0,0 +1,189 @@ +/* + * Class LicenseDialogView + * created on 31.08.2004 + * + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.program.Program; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationInfo; + +/** + * This dialog is used to show some build information to the user + * + * @author tuhlmann + */ +public class AboutApplicationDialog extends TitleAreaDialog { + + public AboutApplicationDialog(Shell shell) + { + super(shell); + } + + /** + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite) + */ + protected Control createContents(Composite parent) + { + Control content = super.createContents(parent); + String applicationName = ApplicationInfo.getApplicationName(); + String applicationVersion = ApplicationInfo.getApplicationVersion(); + getShell().setText("About Simidude, Version " + applicationVersion); + setTitle("About AGYNAMIX Simidude"); + setTitleImage(PlatformIcons.get(PlatformIcons.SIMIDUDE_LOGO)); + setMessage("Simidude - Painless cross platform Drag & Drop."); + return content; + } + + /** + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + protected Control createDialogArea(final Composite arg0) + { + final Composite parentComp = (Composite) super.createDialogArea(arg0); + final Composite composite = new Composite(parentComp, SWT.NONE); + + String applicationName = ApplicationInfo.getApplicationName(); + String company = ApplicationInfo.getCompanyName(); + String companyEmail = ApplicationInfo.getCompanyEmail(); + String companyWww = ApplicationInfo.getCompanyWww(); + final String companyOrderUrl = ApplicationInfo.getCompanyOrderUrl(); + String applicationYear = ApplicationInfo.getApplicationYears(); + String applicationVersion = ApplicationInfo.getApplicationVersion(); + + composite.setSize(parentComp.getSize()); + + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + final Label l1 = new Label(composite, SWT.WRAP); + l1.setText(" "+applicationName + " is developed by " + company + ".\n For requests or problems please email us at"); + + Composite linkC = new Composite(composite, SWT.NONE); + GridLayout linkLay = new GridLayout(); + linkLay.numColumns = 3; + linkC.setLayout(linkLay); + + final Label email = new Label(linkC, SWT.LEAD); + email.setText(companyEmail); + final Color hoverForeground = new Color(linkC.getDisplay(), 255, 0, 0); + final Cursor hoverCursor = new Cursor(linkC.getDisplay(), SWT.CURSOR_HAND); + email.setForeground(hoverForeground); + email.setCursor(hoverCursor); + email.addMouseListener(new MouseAdapter() { + public void mouseDown(MouseEvent e) + { + Program.launch("mailto:" + email.getText() + "?subject=Simidude"); + } + }); + linkC.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) + { + hoverCursor.dispose(); + hoverForeground.dispose(); + } + }); + + new Label(linkC, SWT.NONE).setText("or visit us at"); + final Label www = new Label(linkC, SWT.LEAD); + www.setText(companyWww); + www.setForeground(hoverForeground); + www.setCursor(hoverCursor); + www.addMouseListener(new MouseAdapter() { + public void mouseDown(MouseEvent e) + { + Program.launch(www.getText()); + } + + }); + + seperator(composite); + + Composite buildInfo = new Composite(composite, SWT.BORDER); + layout = new GridLayout(); + layout.numColumns = 2; + buildInfo.setLayout(layout); + GridData d = new GridData(); + d.horizontalAlignment = SWT.FILL; + buildInfo.setLayoutData(d); + +// String biStr = "Version: "+ApplicationInfo.getApplicationVersion()+", Build-No: " + ApplicationInfo.getBuildNumber()+ +// ", Rev-Id: "+ApplicationInfo.getRepoRevision()+", Build-Time: "+ApplicationInfo.getBuildTime(); + String biStr = "Version: "+ApplicationInfo.getApplicationVersion()+", Build-No: " + ApplicationInfo.getBuildNumber()+ + ", Build-Time: "+ApplicationInfo.getBuildTime(); + Label biLbl = new Label(buildInfo, SWT.NONE); + biLbl.setText(biStr); + d = new GridData(); + d.grabExcessHorizontalSpace = true; + biLbl.setLayoutData(d); + Button btnBuild = new Button(buildInfo, SWT.PUSH); + d = new GridData(); + d.horizontalAlignment = SWT.RIGHT; + btnBuild.setLayoutData(d); + btnBuild.setText("Copy"); + btnBuild.addMouseListener(new MouseAdapter(){ + @Override + public void mouseDown(MouseEvent e) + { + copyBuildInfoToClipboard(); + } + }); + + composite.pack(); + + return composite; + } + + protected void seperator(Composite parent) + { + final Label sep = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData spec = new GridData(); + spec.widthHint = 420; + spec.grabExcessHorizontalSpace = true; + spec.horizontalAlignment = GridData.HORIZONTAL_ALIGN_CENTER; + sep.setLayoutData(spec); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + + private void copyBuildInfoToClipboard() + { + String appInfo = ApplicationInfo.getApplicationInfo(); + Clipboard clipboard = new Clipboard(getShell().getDisplay()); + clipboard.setContents(new Object[]{appInfo}, new Transfer[]{TextTransfer.getInstance()}); + clipboard.dispose(); + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/dialogs/AbstractDetailsDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/AbstractDetailsDialog.java new file mode 100644 index 0000000..a1d025b --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/AbstractDetailsDialog.java @@ -0,0 +1,166 @@ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.infra.ApplicationInfo; + +/** + * A dialog with a details button. Subclasses provide + * details area content. + */ +public abstract class AbstractDetailsDialog extends Dialog +{ + private final String shortTitle; + private final String title; + private final String message; + private final Image image; + + private Button detailsButton; + private Button reportBugButton; + private Control detailsArea; + private Point cachedWindowSize; + + public AbstractDetailsDialog(Shell parentShell, String shortTitle, String title, Image image, String message) { + + super(parentShell); + + this.shortTitle = shortTitle; + this.title = title; + this.image = image; + this.message = message; + + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); + } + + protected void buttonPressed(int id) { + if (id == IDialogConstants.DETAILS_ID) + toggleDetailsArea(); + else if (id == IDialogConstants.OPEN_ID) + reportBug(); + else + super.buttonPressed(id); + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + if (title != null) + shell.setText(title); + } + + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false); + reportBugButton = createButton(parent, IDialogConstants.OPEN_ID, "Report Bug", false); + } + + protected Control createDialogArea(Composite parent) { + Composite composite = + (Composite) super.createDialogArea(parent); + composite.setLayoutData( + new GridData(GridData.FILL_HORIZONTAL)); + + if (image != null) + { + ((GridLayout) composite.getLayout()).numColumns = 2; + Label label = new Label(composite, 0); + image.setBackground(label.getBackground()); + label.setImage(image); + label.setLayoutData(new GridData( GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_BEGINNING)); + } + + Label label = new Label(composite, SWT.WRAP); + if (message != null) + label.setText(message); + GridData data = + new GridData( + GridData.FILL_HORIZONTAL + | GridData.VERTICAL_ALIGN_CENTER); + data.widthHint = + convertHorizontalDLUsToPixels( + IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + label.setLayoutData(data); + label.setFont(parent.getFont()); + + return composite; + } + + /** + * Toggles the unfolding of the details area. This is + * triggered by the user pressing the details button. + */ + protected void toggleDetailsArea() { + Point oldWindowSize = getShell().getSize(); + Point newWindowSize = cachedWindowSize; + cachedWindowSize = oldWindowSize; + + // show the details area + if (detailsArea == null) { + detailsArea = createDetailsArea((Composite) getContents()); + detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); + } + + // hide the details area + else { + detailsArea.dispose(); + detailsArea = null; + detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL); + } + + /* + * Must be sure to call + * getContents().computeSize(SWT.DEFAULT, + * SWT.DEFAULT) before calling + * getShell().setSize(newWindowSize); + * since controls have been added or removed + */ + + // compute the new window size + Point oldSize = getContents().getSize(); + Point newSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT); + if (newWindowSize == null) + newWindowSize = new Point(oldWindowSize.x, oldWindowSize.y + (newSize.y - oldSize.y)); + + // crop new window size to screen + Point windowLoc = getShell().getLocation(); + Rectangle screenArea = getContents().getDisplay().getClientArea(); + if (newWindowSize.y > screenArea.height - (windowLoc.y - screenArea.y)) + newWindowSize.y = screenArea.height - (windowLoc.y - screenArea.y); + + getShell().setSize(newWindowSize); + ((Composite) getContents()).layout(); + } + + protected void reportBug() + { + // Bugtitle is exception message + BugzScoutDialog dialog = new BugzScoutDialog(getShell(), shortTitle, getDetailsAsString(), ApplicationInfo.getApplicationInfo() ); + dialog.open(); + } + + /** + * Create the details area with content. + * + * @param parent the parent of the details area + * @return the details area + */ + protected abstract Control createDetailsArea(Composite parent); + + /** + * Provide the exception details and Plugin details as a string. This will be appended + * to the bugreport the user might send. + * @return a string containing the exception and plugin details + */ + protected abstract String getDetailsAsString(); +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/BugReportDetailsDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/BugReportDetailsDialog.java new file mode 100644 index 0000000..cbef8fe --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/BugReportDetailsDialog.java @@ -0,0 +1,116 @@ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.icons.PlatformIcons; + +/** + * This dialog shows the user the data that is submitted to our bug tracking system. + * @author tuhlmann + * + */ +public class BugReportDetailsDialog extends TitleAreaDialog { + + private Image image; + private Color backgroundColor; + + private String title; + private String description; + private String userEmail; + + public BugReportDetailsDialog(Shell parentShell, String title, String description, String userEmail) + { + super(parentShell); + setShellStyle(getShellStyle() | SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); + + image = PlatformIcons.get(PlatformIcons.BUGZSCOUT_DIALOG); + backgroundColor = new Color(parentShell.getDisplay(), 255, 255, 255); + this.title = title; + this.description = description; + this.userEmail = userEmail; + } + + @Override + public boolean close() + { + if (backgroundColor != null) + { + backgroundColor.dispose(); + } + return super.close(); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle("Your Bug Report"); + int style = IMessageProvider.INFORMATION; + setMessage("This dialog shows you the bug report information that is submitted to our database.", style); //$NON-NLS-1$ + + if (image != null) + { + setTitleImage(image); + } + + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite composite = (Composite) super.createDialogArea(parent); + + composite.setLayout(new GridLayout(1, false)); + + Label l = new Label(composite, SWT.WRAP); + l.setText("Bug Report Details:"); //$NON-NLS-1$ + + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); + l.setLayoutData(data); + + Text msg = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.READ_ONLY); + msg.setBackground(backgroundColor); + msg.setText(composeBugReport(title, description, userEmail)); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 200; + msg.setLayoutData(data); + + return composite; + } + + private String composeBugReport(String title, String description, String userEmail) + { + StringBuilder sb = new StringBuilder(); + + sb.append("== Title: ==\n"+title+"\n\n"); + if ((userEmail != null) && (userEmail.length() > 0)) + { + sb.append("== Submitted by: ==\n"+userEmail+"\n\n"); + } + sb.append("== Description: ==\n"); + sb.append(description); + + + return sb.toString(); + } + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutAnswerDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutAnswerDialog.java new file mode 100644 index 0000000..fdebb22 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutAnswerDialog.java @@ -0,0 +1,108 @@ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.bugzscout.BugzScoutCtl; +import com.agynamix.platform.icons.PlatformIcons; + +/** + * This dialog is shown whenever a hard error was found that will crash the client. + * The data gathered here is send to our bug tracking system + * @author tuhlmann + * + */ +public class BugzScoutAnswerDialog extends TitleAreaDialog { + + private Image image; + private Color backgroundColor; + + private BugzScoutCtl.ScoutAnswer answer; + + public BugzScoutAnswerDialog(Shell parentShell, BugzScoutCtl.ScoutAnswer answer) + { + super(parentShell); + setShellStyle(getShellStyle() | SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); + + image = PlatformIcons.get(PlatformIcons.BUGZSCOUT_DIALOG); + backgroundColor = new Color(parentShell.getDisplay(), 255, 255, 255); + this.answer = answer; + } + + @Override + public boolean close() + { + if (backgroundColor != null) + { + backgroundColor.dispose(); + } + return super.close(); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle("Bug Database Answer"); + int style = IMessageProvider.INFORMATION; + if (BugzScoutCtl.ScoutAnswer.ReturnCode.SUCCESS != answer.getReturnCode()) + { + style = IMessageProvider.ERROR; + } + setMessage("This is the answer provided by our bug tracking system.", style); //$NON-NLS-1$ + + if (image != null) + { + setTitleImage(image); + } + + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite composite = (Composite) super.createDialogArea(parent); + + composite.setLayout(new GridLayout(1, false)); + + Label l = new Label(composite, SWT.WRAP); + l.setText("Status of the submission: " + answer.getReturnCode()); //$NON-NLS-1$ + + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + l.setLayoutData(data); + + Label msgLabel = new Label(composite, SWT.WRAP); + msgLabel.setText("\nThe message provided by our bug tracking system: "); + + data = new GridData(SWT.FILL, SWT.FILL, true, false); + msgLabel.setLayoutData(data); + + Text msg = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.READ_ONLY); + msg.setBackground(backgroundColor); + msg.setText(answer.getMessage()); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 80; + msg.setLayoutData(data); + + return composite; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutDialog.java new file mode 100644 index 0000000..262a972 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/BugzScoutDialog.java @@ -0,0 +1,230 @@ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.bugzscout.BugzScoutCtl; +import com.agynamix.platform.bugzscout.BugzScoutCtl.ScoutAnswer; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.net.NetworkAnalyzer; + +/** + * This dialog is shown whenever a hard error was found that will crash the client. + * The data gathered here is send to our bug tracking system + * @author tuhlmann + * + */ +public class BugzScoutDialog extends TitleAreaDialog { + + private Image image; + private Text bugTitle; + private Text bugDescription; + private Text userEmail; + + private String extraInformation; + private String systemInformation; + + private String bugTitleStr; + + private boolean isUserOpened = false; + + public BugzScoutDialog(Shell parentShell) + { + this(parentShell, "", true); + } + + public BugzScoutDialog(Shell parentShell, String bugTitle, String extraInformation, String systemInformation) + { + this(parentShell, systemInformation, false); + this.bugTitleStr = bugTitle; + this.extraInformation = extraInformation; + } + + public BugzScoutDialog(Shell parentShell, String systemInformation, boolean isUserOpened) + { + super(parentShell); + setShellStyle(getShellStyle() | SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); + + image = PlatformIcons.get(PlatformIcons.BUGZSCOUT_DIALOG); + + this.isUserOpened = isUserOpened; + this.extraInformation = ""; //$NON-NLS-1$ + this.systemInformation = systemInformation; + + } + + @Override + public boolean close() + { + return super.close(); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.YES_ID, "Send!", true); //$NON-NLS-1$ + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CLOSE_LABEL, false); + createButton(parent, IDialogConstants.DETAILS_ID, "View Report", false); +// super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == IDialogConstants.YES_ID) + { + BugzScoutCtl ctl = new BugzScoutCtl(); + ctl.setArea("BugzScout"); //$NON-NLS-1$ + ctl.setDefaultMessage("Thank you for submitting this report!"); + ctl.setProject("Simidude"); //$NON-NLS-1$ + ctl.setUrl("https://agynamix.fogbugz.com/scoutSubmit.asp"); //$NON-NLS-1$ + ctl.setUserName("Torsten Uhlmann"); //$NON-NLS-1$ + String title = composeTitle(bugTitle.getText(), bugTitleStr, isUserOpened); + String bugDesc = composeBugDescription(bugDescription.getText(), extraInformation, systemInformation); + ScoutAnswer answer = ctl.submitBug(title, bugDesc, userEmail.getText(), false); + BugzScoutAnswerDialog dialog = new BugzScoutAnswerDialog(getShell(), answer); + dialog.open(); + if (answer.getReturnCode() == BugzScoutCtl.ScoutAnswer.ReturnCode.SUCCESS) + { + setReturnCode(buttonId); + this.close(); + } + } else if (buttonId == IDialogConstants.DETAILS_ID) + { + String title = composeTitle(bugTitle.getText(), bugTitleStr, isUserOpened); + String bugDesc = composeBugDescription(bugDescription.getText(), extraInformation, systemInformation); + BugReportDetailsDialog detailsDialog = new BugReportDetailsDialog(this.getParentShell(), title, bugDesc, userEmail.getText()); + detailsDialog.open(); + } else { + super.buttonPressed(buttonId); + } + } + + String composeTitle(String userTitle, String autoTitle, boolean isUserOpened) + { + return (isUserOpened) ? userTitle : autoTitle; + } + + String composeBugDescription(String bugDescription, String extraInformation, String systemInfo) + { + StringBuilder sb = new StringBuilder(); + sb.append("\n").append(bugDescription); //$NON-NLS-1$ + if (extraInformation.length() > 0) + { + sb.append("\n\n#####################\nAdded by the software:\n\n").append(extraInformation); //$NON-NLS-1$ + } + + sb.append("\n\n#####################\nNetwork Information:\n\n"); + NetworkAnalyzer networkAnalyzer = new NetworkAnalyzer(); + networkAnalyzer.run(); + String info = networkAnalyzer.asString(); + networkAnalyzer.close(); + sb.append(info); + + if (systemInfo.length() > 0) + { + sb.append("\n\n#####################\nSystem Information:\n\n").append(systemInfo); + } + return sb.toString(); + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle("Bug Report"); + setMessage("Submit a Bug Report", IMessageProvider.INFORMATION); + + if (image != null) + { + setTitleImage(image); + } + + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite parentComposite = (Composite) super.createDialogArea(parent); + parentComposite.setLayout(new GridLayout()); + + Composite composite = new Composite(parentComposite, parentComposite.getStyle()); + GridData compData = new GridData(SWT.FILL, SWT.FILL, true, true); + composite.setLayoutData(compData); + + composite.setLayout(new GridLayout(2, false)); + + Label l = new Label(composite, SWT.WRAP); + l.setText("Thank you very much for helping us to improve our software!"); + + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); + data.horizontalSpan = 2; + l.setLayoutData(data); + + Label tell = new Label(composite, SWT.WRAP); + tell.setText("\nPlease tell us about this problem.\n\nWhile telling us about the action you where about to execute when the error occured you help us \nto correct this bug and make our product more stable in future versions. \nThis bug report will be sent to our internal bug database.\nYour submitted data will be disclosed to third parties!\nThank you very much!\n\n"); + + data = new GridData(SWT.FILL, SWT.FILL, true, false); + data.horizontalSpan = 2; + tell.setLayoutData(data); + + if (isUserOpened) + { + Label titleLabel = new Label(composite, SWT.NONE); + titleLabel.setText("A Headline for the problem:"); + + data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.horizontalSpan = 2; + titleLabel.setLayoutData(data); + + bugTitle = new Text(composite, SWT.BORDER ); + data = new GridData(SWT.FILL, SWT.FILL, true, false); + data.horizontalSpan = 2; + data.minimumHeight = 12; + bugTitle.setLayoutData(data); + bugTitle.setTextLimit(100); + } + + Label whatHappened = new Label(composite, SWT.NONE); + whatHappened.setText("What did you do when the problem occured?"); + + data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.horizontalSpan = 2; + whatHappened.setLayoutData(data); + + bugDescription = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.WRAP); + data = new GridData(SWT.FILL, SWT.FILL, false, true); + data.horizontalSpan = 2; + data.minimumHeight = 150; + bugDescription.setLayoutData(data); + bugDescription.setTextLimit(2000); + + Label lUserEmail = new Label(composite, SWT.NONE); + lUserEmail.setText("Email address (optional)"); //$NON-NLS-1$ + data = new GridData(SWT.LEAD, SWT.FILL, false, false); + data.horizontalSpan = 1; + lUserEmail.setLayoutData(data); + + userEmail = new Text(composite, SWT.BORDER ); + data = new GridData(SWT.FILL, SWT.FILL, true, false); + data.horizontalSpan = 1; + data.minimumHeight = 12; + data.minimumWidth = 100; + userEmail.setLayoutData(data); + userEmail.setTextLimit(100); + + return parentComposite; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialog.java new file mode 100644 index 0000000..a3c5b11 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialog.java @@ -0,0 +1,68 @@ +/* + * Class LicenseDialog + * created on 01.09.2004 + * + */ +package com.agynamix.platform.frontend.dialogs; + +import com.agynamix.simidude.Simidude; + + + +/** + * @version $Revision$ $Date$ + * @author tuhlmann + */ +public class BuildInfoDialog { + + final IBuildInfoDialogView view; + + public BuildInfoDialog(IBuildInfoDialogView view) { + this.view = view; + this.view.setPresenter(this); + } + + /** + * + */ + public void open() { + view.open(); + } + + /** + * hook into initialization of the view. + * + */ + public void onInit() { + } + + /** + * Hook that is called from view at the end of the createDialogArea function. + * + */ + public void onCreateDialogArea() { + setBuildInfo(); + } + + /** + * Passes the license information into the proper fields of the view + * @param l a License object + */ + private void setBuildInfo() { + StringBuffer sb = new StringBuffer(); + Package pkg = Simidude.class.getPackage(); + + sb.append("Specification Title: \t\t\t").append(pkg.getSpecificationTitle()).append('\n'); + sb.append("Specification Vendor: \t\t").append(pkg.getSpecificationVendor()).append('\n'); + sb.append("Specification Version: \t\t").append(pkg.getSpecificationVersion()).append('\n'); + sb.append("Implementation Title: \t\t").append(pkg.getImplementationTitle()).append('\n'); + sb.append("Implementation Vendor: \t\t").append(pkg.getImplementationVendor()).append('\n'); + sb.append("Implementation Version: \t\t").append(pkg.getImplementationVersion()).append('\n'); + + view.setInfo(sb.toString()); + } + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialogView.java b/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialogView.java new file mode 100644 index 0000000..1d81a6c --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/BuildInfoDialogView.java @@ -0,0 +1,111 @@ +/* + * Class LicenseDialogView + * created on 31.08.2004 + * + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + + +/** + * This dialog is used to show some build information to the user + * @version $Revision$ $Date$ + * @author tuhlmann + */ +public class BuildInfoDialogView extends TitleAreaDialog implements IBuildInfoDialogView { + + BuildInfoDialog presenter; + Text info; + Button copyToClipboard; + + public BuildInfoDialogView(Shell arg0) { + super(arg0); + } + + + /** + * @see com.agynamix.simidude.dialogs.ILicenseDialogView#setPresenter(com.agynamix.simidude.dialogs.LicenseDialog) + */ + public void setPresenter(BuildInfoDialog dialog) { + presenter = dialog; + } + + /** + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite) + */ + protected Control createContents(Composite parent) { + Control content = super.createContents(parent); + getShell().setText("Build Information Dialog"); + setTitle("Build Information Dialog"); + setMessage("This dialog shows some build information. "+ + "If you have problems\n running this application please send the "+ + "information shown here\n together with your problem report to "+ + "contact@agynamix.com"); + + presenter.onInit(); + + return content; + } + + /** + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + protected Control createDialogArea(Composite arg0) { + final Composite parentComp = (Composite) super.createDialogArea(arg0); + final Composite composite = new Composite(parentComp, SWT.NONE); + composite.setSize(parentComp.getSize()); + + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + info = new Text(composite, SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL ); + GridData catSpec = new GridData(); + catSpec = new GridData(); + catSpec.heightHint = 100; + catSpec.horizontalAlignment = SWT.FILL; + catSpec.verticalAlignment = GridData.FILL; + catSpec.grabExcessVerticalSpace = true; + catSpec.grabExcessHorizontalSpace = true; + info.setLayoutData(catSpec); + + info.setFocus(); + + composite.pack(); +// composite.layout(); + + presenter.onCreateDialogArea(); + + return composite; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + + /** + * @see com.agynamix.simidude.dialogs.ILicenseDialogView#setProduct(java.lang.String) + */ + public void setInfo(String buildinfo) { + info.setText(buildinfo); + } + + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/dialogs/ExceptionDetailsDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/ExceptionDetailsDialog.java new file mode 100644 index 0000000..7381cb5 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/ExceptionDetailsDialog.java @@ -0,0 +1,243 @@ +package com.agynamix.platform.frontend.dialogs; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * A dialog to display an error message, product and + * provider information, plus the details of the exception + * itself. A details button shows or hides an error details + * viewer. + * TODO: Rename into MessageDetailsDialog + */ +public class ExceptionDetailsDialog extends AbstractDetailsDialog { + + public enum MessageClass { OK, INFO, WARNING, ERROR }; + + IStatus a; + + /** + * The details to be shown ({@link Exception}, + * {@link IStatus}, or null if no details) + */ + private final Throwable details; + private final String strDetails; + + public ExceptionDetailsDialog(Shell parentShell, String title, Image image, String message, IStatus details) + { + super(parentShell, title, getTitle(title, details), getImage(image, details), getMessage(message, details)); + this.details = details.getException(); + strDetails = null; + } + + public ExceptionDetailsDialog(Shell parentShell, String title, Image image, String message, Throwable details) + { + super(parentShell, details.getLocalizedMessage(), getTitle(title, details), getImage(image, details), + getMessage(message, details)); + + this.details = details; + strDetails = null; + } + + public ExceptionDetailsDialog(Shell parentShell, String title, Image image, String message, IStatus details, String strDetails) + { + super(parentShell, title, getTitle(title, details), getImage(image, details), getMessage(message, details)); + this.details = details.getException(); + this.strDetails = strDetails; + } + + protected Control createDetailsArea(Composite parent) + { + // create the details area + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayoutData(new GridData(GridData.FILL_BOTH)); + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 0; + panel.setLayout(layout); + + // create the details content + createProductInfoArea(panel); + createDetailsViewer(panel); + + return panel; + } + + protected Composite createProductInfoArea(Composite parent) + { + Composite composite = new Composite(parent, SWT.NULL); + composite.setLayoutData(new GridData()); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + composite.setLayout(layout); + + new Label(composite, SWT.NONE).setText("Provider:"); + new Label(composite, SWT.NONE).setText("AGYNAMIX"); + return composite; + } + + protected Control createDetailsViewer(Composite parent) + { + if ((details == null) && (strDetails == null)) + return null; + + Text text = new Text(parent, SWT.COLOR_WHITE | SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + + text.setLayoutData(new GridData(GridData.FILL_BOTH)); + + text.setText(getDetailsAsString()); + text.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + + return text; + } + + @Override + protected String getDetailsAsString() + { + if ((details == null) && (strDetails == null)) + { + return ""; //$NON-NLS-1$ + } + + // Create the content + StringWriter writer = new StringWriter(1000); + + if (details != null) + { + if (details instanceof Throwable) + { + appendException(new PrintWriter(writer), (Throwable) details); + } else if (details instanceof IStatus) + { + appendStatus(new PrintWriter(writer), (IStatus) details, 0); + } + } + + if (strDetails != null) { + writer.append("\n"); + writer.append(strDetails); + } + + return writer.toString(); + + } + + /** + * Answer the title based upon the provided title and + * the details object. + */ + public static String getTitle(String title, Object details) + { + if (title != null) + return title; + if (details instanceof Throwable) + { + Throwable e = (Throwable) details; + while (e instanceof InvocationTargetException) + e = ((InvocationTargetException) e).getTargetException(); + String name = e.getClass().getName(); + return name.substring(name.lastIndexOf('.') + 1); + } + return "Exception"; + } + + /** + * Answer the image based upon the provided image and + * the details object. + */ + public static Image getImage(Image image, Object details) + { + if (image != null) + return image; + ImageRegistry imageRegistry = JFaceResources.getImageRegistry(); + if (details instanceof IStatus) + { + switch (((IStatus) details).getSeverity()) + { + case IStatus.ERROR: + return imageRegistry.get(Dialog.DLG_IMG_ERROR); + case IStatus.WARNING: + return imageRegistry.get(Dialog.DLG_IMG_WARNING); + case IStatus.INFO: + return imageRegistry.get(Dialog.DLG_IMG_INFO); + case IStatus.OK: + return null; + } + } + return imageRegistry.get(Dialog.DLG_IMG_ERROR); + } + + /** + * Answer the message based upon the provided message + * and the details object. + */ + public static String getMessage(String message, Object details) + { + if (details instanceof Throwable) + { + Throwable e = (Throwable) details; + while (e instanceof InvocationTargetException) + e = ((InvocationTargetException) e).getTargetException(); + if (message == null) + return e.toString(); + return MessageFormat.format(message, new Object[] { e.toString() }); + } + if (details instanceof IStatus) + { + String statusMessage = ((IStatus) details).getMessage(); + if (message == null) + return statusMessage; + return MessageFormat.format(message, new Object[] { statusMessage }); + } + if (message != null) + return message; + return "An exception has occured."; + } + + public static void appendException(PrintWriter writer, Throwable ex) + { + if (ex instanceof CoreException) + { + appendStatus(writer, ((CoreException) ex).getStatus(), 0); + writer.println(); + } + appendStackTrace(writer, ex); + if (ex instanceof InvocationTargetException) + appendException(writer, ((InvocationTargetException) ex).getTargetException()); + } + + public static void appendStatus(PrintWriter writer, IStatus status, int nesting) + { + for (int i = 0; i < nesting; i++) + writer.print(" "); //$NON-NLS-1$ + writer.println(status.getMessage()); + IStatus[] children = status.getChildren(); + for (int i = 0; i < children.length; i++) + appendStatus(writer, children[i], nesting + 1); + } + + public static void appendStackTrace(PrintWriter writer, Throwable ex) + { + ex.printStackTrace(writer); + } +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/dialogs/IBuildInfoDialogView.java b/src/java/com/agynamix/platform/frontend/dialogs/IBuildInfoDialogView.java new file mode 100644 index 0000000..40e1232 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/IBuildInfoDialogView.java @@ -0,0 +1,36 @@ +/* + * Class ILicenseDialogView + * created on 01.09.2004 + * + */ +package com.agynamix.platform.frontend.dialogs; + + + +/** + * @version $Revision$ $Date$ + * @author tuhlmann + */ +public interface IBuildInfoDialogView { + + /** + * Opens the dialog + */ + int open(); + + /** + * Pass the presenter class to the view + * @param dialog the smart object that implements the dialog's logic + */ + void setPresenter(BuildInfoDialog dialog); + + /** + * Sends a formatted build info string to the dialog to display. + * @param buildinfo the build info to display. + */ + void setInfo(String buildinfo); + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/dialogs/InputNetworkAddressDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/InputNetworkAddressDialog.java new file mode 100644 index 0000000..23a1e19 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/InputNetworkAddressDialog.java @@ -0,0 +1,116 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.infra.PlatformUtils; + +public class InputNetworkAddressDialog extends TitleAreaDialog { + + Text text; + String finalContents; + + public InputNetworkAddressDialog(Shell shell) + { + super(shell); + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle("Input Network Address"); + String meta = PlatformUtils.isMacOs() ? "APPLE" : "CTRL"; + String text = "Please enter one IP address or network name.You can add a port by appending ':'.\nPress 'Close' or "+meta+"+'Enter' to close the dialog."; + setMessage(text, IMessageProvider.INFORMATION); + + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite parentComposite = (Composite) super.createDialogArea(parent); + parentComposite.setLayout(new GridLayout()); + + Composite composite = new Composite(parentComposite, parentComposite.getStyle()); + GridData compData = new GridData(SWT.FILL, SWT.FILL, true, true); + composite.setLayoutData(compData); + + composite.setLayout(new GridLayout(1, false)); + + Label l = new Label(composite, SWT.WRAP); + l.setText("Enter Network Address:"); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); + l.setLayoutData(data); + + text = new Text(composite, SWT.BORDER ); + data = new GridData(SWT.FILL, SWT.CENTER, true, false); + text.setLayoutData(data); + + text.addKeyListener(new KeyAdapter(){ + @Override + public void keyPressed(KeyEvent e) + { + if (e.keyCode == 13) + { + if ((e.stateMask & SWT.MOD1) != 0) + { + buttonPressed(IDialogConstants.OK_ID); + } + } + } + }); + + return parentComposite; + } + + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); +// super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == IDialogConstants.OK_ID) + { + finalContents = text.getText(); + } + super.buttonPressed(buttonId); + } + + public String getText() + { + return finalContents; + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/InputTextDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/InputTextDialog.java new file mode 100644 index 0000000..0a134c1 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/InputTextDialog.java @@ -0,0 +1,122 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.infra.PlatformUtils; + +public class InputTextDialog extends TitleAreaDialog { + + Text text; + String finalContents; + + public InputTextDialog(Shell shell) + { + super(shell); + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle("Input Text"); + String meta = PlatformUtils.isMacOs() ? "APPLE" : "CTRL"; + String text = "Use this dialog to directly enter some text. Press 'Close' or "+meta+"+'Enter' to close the dialog."; + setMessage(text, IMessageProvider.INFORMATION); + +// if (image != null) +// { +// setTitleImage(image); +// } +// + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite parentComposite = (Composite) super.createDialogArea(parent); + parentComposite.setLayout(new GridLayout()); + + Composite composite = new Composite(parentComposite, parentComposite.getStyle()); + GridData compData = new GridData(SWT.FILL, SWT.FILL, true, true); + composite.setLayoutData(compData); + + composite.setLayout(new GridLayout(1, false)); + + Label l = new Label(composite, SWT.WRAP); + l.setText("Enter Text here:"); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); + l.setLayoutData(data); + + text = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 80; + text.setLayoutData(data); + + text.addKeyListener(new KeyAdapter(){ + @Override + public void keyPressed(KeyEvent e) + { + if (e.keyCode == 13) + { + if ((e.stateMask & SWT.MOD1) != 0) + { + buttonPressed(IDialogConstants.OK_ID); + } + } + } + }); + + return parentComposite; + } + + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); +// super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == IDialogConstants.OK_ID) + { + finalContents = text.getText(); + } + super.buttonPressed(buttonId); + } + + public String getText() + { + return finalContents; + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/ProgressBarDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/ProgressBarDialog.java new file mode 100644 index 0000000..56a0768 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/ProgressBarDialog.java @@ -0,0 +1,194 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.Shell; + +public abstract class ProgressBarDialog extends TitleAreaDialog { + + private Label processMessageLabel; // info of process finish + private Label lineLabel; // + private Composite progressBarComposite; // + private CLabel message; // + private ProgressBar progressBar = null; // + + protected volatile boolean isClosed = false; // closed state + + protected int executeTime = 50; // process times + protected Image processImage = null; // FIXME: SWTUtil.getImageOfMessage();//image + + public ProgressBarDialog(Shell parent) + { + super(parent); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.ABORT_ID, IDialogConstants.ABORT_LABEL, true); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == IDialogConstants.ABORT_ID) + { + isClosed = true; + } + super.buttonPressed(buttonId); + } + /** + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite) + */ + protected Control createContents(Composite parent) + { + Control content = super.createContents(parent); + getShell().setText("Please wait..."); + setTitle("Please wait..."); + setMessage("Please be patient while the requested operation is performed."); + return content; + } + + // public int open() + // { + // createContents(); // create window + // shell.open(); + // shell.layout(); + // + // // start work + // new ProcessThread(executeTime).start(); + // + // return result; + // } + + protected Control createDialogArea(Composite parent) + { + final Composite parentComp = (Composite) super.createDialogArea(parent); + final Composite composite = new Composite(parentComp, SWT.NONE); + composite.setSize(parentComp.getSize()); + + final GridLayout gridLayout = new GridLayout(); + gridLayout.verticalSpacing = 10; + + composite.setLayout(gridLayout); + composite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + composite.setLayout(new GridLayout()); + + message = new CLabel(composite, SWT.NONE); +// message.setImage(processImage); + message.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + message.setText("Transfering data..."); + + progressBarComposite = new Composite(parentComp, SWT.NONE); + progressBarComposite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false)); + progressBarComposite.setLayout(new FillLayout()); + + progressBar = new ProgressBar(progressBarComposite, SWT.SMOOTH); + progressBar.setMaximum(executeTime); + + processMessageLabel = new Label(parentComp, SWT.NONE); + processMessageLabel.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false)); + lineLabel = new Label(parentComp, SWT.HORIZONTAL | SWT.SEPARATOR); + lineLabel.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false)); + + return composite; + } + + protected abstract String process(int times); + + protected void cleanUp() + { + } + + protected void doBefore() + { + } + + protected void doAfter() + { + } + + class ProcessThread extends Thread { + private int max = 0; + private volatile boolean shouldStop = false; + + ProcessThread(int max) + { + this.max = max; + } + + public void run() + { + doBefore(); + for (final int[] i = new int[] { 1 }; i[0] <= max; i[0]++) + { + // + final String info = process(i[0]); + if (getShell().getDisplay().isDisposed()) + { + return; + } + getShell().getDisplay().syncExec(new Runnable() { + public void run() + { + if (progressBar.isDisposed()) + { + return; + } + // + processMessageLabel.setText(info); + // + progressBar.setSelection(i[0]); + // + if (i[0] == max || isClosed) + { + if (isClosed) + { + shouldStop = true;// + cleanUp();// + } + } + } + }); + + if (shouldStop) + { + break; + } + } + doAfter(); + } + } + + public void setExecuteTime(int executeTime) + { + this.executeTime = executeTime; + } + + public abstract void initGuage(); + +} diff --git a/src/java/com/agynamix/platform/frontend/dialogs/SimpleInformationViewerDialog.java b/src/java/com/agynamix/platform/frontend/dialogs/SimpleInformationViewerDialog.java new file mode 100644 index 0000000..9119e31 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/dialogs/SimpleInformationViewerDialog.java @@ -0,0 +1,122 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.dialogs; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.infra.PlatformUtils; + +public class SimpleInformationViewerDialog extends TitleAreaDialog { + + final String title; + final String headerText; + Text text; + final String finalContents; + + Font textFont = null; + + public SimpleInformationViewerDialog(Shell shell, String title, String headerText, String info) + { + super(shell); + setShellStyle(getShellStyle() | SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); + + this.finalContents = info; + this.title = title; + this.headerText = headerText; + } + + @Override + protected Control createContents(Composite parent) + { + Control contents = super.createContents(parent); + setTitle(title); + setMessage(headerText, IMessageProvider.INFORMATION); + text.setText(finalContents); + + return contents; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite parentComposite = (Composite) super.createDialogArea(parent); + parentComposite.setLayout(new GridLayout()); + + Composite composite = new Composite(parentComposite, parentComposite.getStyle()); + GridData compData = new GridData(SWT.FILL, SWT.FILL, true, true); + composite.setLayoutData(compData); + + composite.setLayout(new GridLayout(1, false)); + + text = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 80; + text.setLayoutData(data); + FontData defaultFont = new FontData("Courier", 12, SWT.NONE); + textFont = new Font(Display.getDefault(), defaultFont); + text.setFont(textFont); + + return parentComposite; + } + + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); +// super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == IDialogConstants.OK_ID) + { +// finalContents = text.getText(); + } + super.buttonPressed(buttonId); + } + + @Override + public boolean close() + { + if ((textFont != null) && (!textFont.isDisposed())) + { + textFont.dispose(); + textFont = null; + } + return super.close(); + } + + public String getText() + { + return finalContents; + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/AbstractHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/AbstractHotkeyRegistrar.java new file mode 100644 index 0000000..329869c --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/AbstractHotkeyRegistrar.java @@ -0,0 +1,78 @@ +package com.agynamix.platform.frontend.gui; + +import java.io.File; +import java.util.StringTokenizer; + +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.Tupel; + +public abstract class AbstractHotkeyRegistrar implements IHotkeyRegistrar { + + public void activateGlobalPaste(HotkeyListenerInfo listenerInfo) + { + // TODO Auto-generated method stub + + } + + public Tupel parseHotkeyDefinition(String hotKeyStr) + { + if ((hotKeyStr == null) || (hotKeyStr.length() == 0)) + { + return new Tupel(0, 0); + } + + StringTokenizer st = new StringTokenizer(hotKeyStr, "+"); + + int modifier = 0; + int keyCode = 0; + + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (!st.hasMoreTokens()) + { + keyCode = tokenToKeyCode(token); + } else { + modifier |= tokenToModifier(token); + } + } + + return new Tupel(modifier, keyCode); + } + + protected abstract int tokenToModifier(String token); + + protected int tokenToKeyCode(String token) + { + return (int)token.charAt(0); + } + + /** + * Loads native library located inside some jar in classpath + * + * @param jarLib library name + * @return success? + */ + protected boolean loadJarLibrary(final String jarLib) + { + final String tempLib = System.getProperty("java.io.tmpdir") + + File.separator + jarLib; + boolean copied = FileUtils.copyFile(jarLib, tempLib); + if (!copied) + { + return false; + } + try { + System.load(tempLib); + } catch (Throwable e) + { + return false; + } + return true; +} + + + + + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/ApplicationGUI.java b/src/java/com/agynamix/platform/frontend/gui/ApplicationGUI.java new file mode 100644 index 0000000..1821ad3 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/ApplicationGUI.java @@ -0,0 +1,562 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * * Contributors: + * IBM Corporation - initial API and implementation + * + * AGYNAMIX Torsten Uhlmann, http://www.agynamix.de + *******************************************************************************/ + +package com.agynamix.platform.frontend.gui; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.jface.action.CoolBarManager; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.action.StatusLineManager; +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.frontend.action.CheckUpdatesAction; +import com.agynamix.platform.frontend.action.ClearClipboardTableAction; +import com.agynamix.platform.frontend.action.CopyAction; +import com.agynamix.platform.frontend.action.CutAction; +import com.agynamix.platform.frontend.action.ExitAction; +import com.agynamix.platform.frontend.action.HideAction; +import com.agynamix.platform.frontend.action.InputTextAction; +import com.agynamix.platform.frontend.action.NetworkAnalysisAction; +import com.agynamix.platform.frontend.action.PreferencesAction; +import com.agynamix.platform.frontend.action.RemoveSelectedClipboardEntry; +import com.agynamix.platform.frontend.action.SaveAsAction; +import com.agynamix.platform.frontend.action.SaveAsCompressedAction; +import com.agynamix.platform.frontend.action.SubmitBugzScoutAction; +import com.agynamix.platform.frontend.action.ToggleShowToolbarAction; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ApplicationInfo; +import com.agynamix.platform.infra.IConfiguration; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.NetUtils; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.action.AboutAction; +import com.agynamix.simidude.frontend.action.SelectMonitoredClipboardItemsAction; +import com.agynamix.simidude.frontend.action.ShowOfflineHelpAction; +import com.agynamix.simidude.frontend.action.ToggleMonitorClipboardAction; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.SimidudeUtils; + +/** + * @author tuhlmann + * + */ +public abstract class ApplicationGUI extends ApplicationWindow { + + public static final String SERVICE_NAME = "ApplicationGUI"; + + Image shellImage; + ApplicationTray myTray; + + protected IConfiguration config; + + Logger log = ApplicationLog.getLogger(ApplicationGUI.class); + + protected IAction exitAction; + protected IAction hideAction; + protected ToggleMonitorClipboardAction toggleMonitorClipboardAction; + protected IAction selectMonitoredClipboardItemsAction; + protected ToggleShowToolbarAction toggleShowToolbarAction; +// protected ToggleShowStatuslineAction toggleShowStatuslineAction; + protected IAction clearClipboardTableAction; + protected RemoveSelectedClipboardEntry removeSelectedClipboardEntryAction; + protected IAction networkClearClipboardTableAction; + protected RemoveSelectedClipboardEntry networkRemoveSelectedClipboardEntryAction; +// protected IAction onlineHelpAction; + protected IAction offlineHelpAction; + protected IAction aboutAction; + protected IAction preferencesAction; + protected IAction copyAction; + protected IAction cutAction; + protected IAction saveAsAction; + protected IAction saveAsCompressedAction; + protected IAction inputTextAction; + protected IAction submitABugAction; + protected IAction networkAnalysisAction; + + public ApplicationGUI() + { + super(null); + ApplicationBase.getContext().registerService(ApplicationGUI.SERVICE_NAME, this); + config = ApplicationBase.getContext().getConfiguration(); + } + + public void initializeApplicationGUI() + { + makeActions(); + addMenuBar(); + // addToolBar(SWT.TOP | SWT.FLAT | SWT.HORIZONTAL | SWT.SHADOW_OUT ); + // addCoolBar(SWT.TOP); + addStatusLine(); + create(); + getMenuBarManager().updateAll(true); + registerForMacOSXEvents(); + +// toggleShowStatuslineAction.setStatusline(getStatusLineManager().getControl()); +// toggleShowStatuslineAction.showStatusline(); + + // XXX Comment to disable license check + if (config.getBoolean(IPreferenceConstants.IS_FIRST_RUN)) + { +// System.out.println("First Run"); +// preferencesAction.run(); + config.setBoolean(IPreferenceConstants.IS_FIRST_RUN, false); + } + + getShell().getDisplay().addFilter(SWT.KeyDown, new Listener(){ + public void handleEvent(Event event) + { + SimidudeUtils.keyPressed(event.keyCode); + } + }); + + getShell().getDisplay().addFilter(SWT.KeyUp, new Listener(){ + public void handleEvent(Event event) + { + SimidudeUtils.keyReleased(event.keyCode); + } + }); + + } + + protected void makeActions() + { + exitAction = new ExitAction(this); + hideAction = new HideAction(this); + toggleMonitorClipboardAction = new ToggleMonitorClipboardAction(this); + selectMonitoredClipboardItemsAction = new SelectMonitoredClipboardItemsAction(this); + clearClipboardTableAction = new ClearClipboardTableAction(this, false); + networkClearClipboardTableAction = new ClearClipboardTableAction(this, true); + removeSelectedClipboardEntryAction = new RemoveSelectedClipboardEntry(this, false); + networkRemoveSelectedClipboardEntryAction = new RemoveSelectedClipboardEntry(this, true); +// onlineHelpAction = new ShowOnlineHelpAction(this); + offlineHelpAction = new ShowOfflineHelpAction(this); + preferencesAction = new PreferencesAction(this); + aboutAction = new AboutAction(this); + copyAction = new CopyAction(this); + cutAction = new CutAction(this); + saveAsAction = new SaveAsAction(this); + saveAsCompressedAction = new SaveAsCompressedAction(this); + inputTextAction = new InputTextAction(this); + toggleShowToolbarAction = new ToggleShowToolbarAction(this); +// toggleShowStatuslineAction = new ToggleShowStatuslineAction(this); + submitABugAction = new SubmitBugzScoutAction(this); + networkAnalysisAction = new NetworkAnalysisAction(this); + } + + protected StatusLineManager createStatusLineManager() + { + return new ApplicationStatusLineManager(); + } + + public ApplicationStatusLineManager getStatusLineManager() + { + return (ApplicationStatusLineManager) super.getStatusLineManager(); + } + + @Override + protected CoolBarManager createCoolBarManager(int style) + { + CoolBarManager cbm = new CoolBarManager(style); + cbm.add(createToolBarManager(SWT.FLAT)); + // cbm.add(createSearchToolbar(SWT.FLAT)); + return cbm; + } + + @Override + protected ToolBarManager createToolBarManager(int style) + { + ToolBarManager tm = new ToolBarManager(style); + tm.add(exitAction); + tm.add(new Separator()); + tm.add(toggleMonitorClipboardAction); + tm.add(selectMonitoredClipboardItemsAction); + tm.add(new Separator()); + tm.add(clearClipboardTableAction); + tm.add(new Separator()); + tm.add(removeSelectedClipboardEntryAction); + tm.add(new Separator()); + tm.add(offlineHelpAction); + tm.add(new Separator()); + // tm.add(new SpacerToolbarItem()); + // SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + // ClipboardTableSearchBox searchBox = new ClipboardTableSearchBox(sdm); + // tm.add(new Separator()); + // tm.add(searchBox); + return tm; + } + + // protected ToolBarManager createSearchToolbar(int style) + // { + // ToolBarManager tm = new ToolBarManager(style); + // SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + // ClipboardTableSearchBox searchBox = new ClipboardTableSearchBox(sdm); + // tm.add(new Separator()); + // tm.add(searchBox); + // + // return tm; + // } + + /** + * @see org.eclipse.jface.window.ApplicationWindow#createMenuManager() + */ + protected MenuManager createMenuManager() + { + MenuManager menubar = new MenuManager(); + MenuManager filemenu = new MenuManager("&File"); + MenuManager editmenu = new MenuManager("&Edit"); + MenuManager windowmenu = new MenuManager("&Window"); + MenuManager helpmenu = new MenuManager("&Help"); + menubar.add(filemenu); + menubar.add(editmenu); + menubar.add(windowmenu); + menubar.add(helpmenu); + + filemenu.add(inputTextAction); + filemenu.add(new Separator()); + filemenu.add(saveAsAction); + filemenu.add(saveAsCompressedAction); + filemenu.add(new Separator()); + filemenu.add(hideAction); + if (!PlatformUtils.isMacOs()) + { + filemenu.add(new Separator()); + filemenu.add(exitAction); + } + + filemenu.addMenuListener(new IMenuListener(){ + public void menuAboutToShow(IMenuManager manager) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getSelectedItem(); + saveAsAction.setEnabled(item != null); + saveAsCompressedAction.setEnabled(item != null); + } + }); + + editmenu.add(copyAction); + editmenu.add(cutAction); + editmenu.add(new Separator()); + editmenu.add(toggleMonitorClipboardAction); + editmenu.add(new Separator()); + editmenu.add(removeSelectedClipboardEntryAction); + editmenu.add(networkRemoveSelectedClipboardEntryAction); + editmenu.add(clearClipboardTableAction); + editmenu.add(networkClearClipboardTableAction); + if (!PlatformUtils.isMacOs()) + { + editmenu.add(new Separator()); + editmenu.add(preferencesAction); + helpmenu.add(aboutAction); + } + + windowmenu.add(toggleShowToolbarAction); +// windowmenu.add(toggleShowStatuslineAction); + + helpmenu.add(offlineHelpAction); + helpmenu.add(new Separator()); +// helpmenu.add(onlineHelpAction); +// helpmenu.add(new Separator()); + helpmenu.add(new CheckUpdatesAction(this)); + helpmenu.add(new Separator()); + helpmenu.add(networkAnalysisAction); +// helpmenu.add(new Separator()); +// helpmenu.add(submitABugAction); + + editmenu.addMenuListener(new IMenuListener(){ + public void menuAboutToShow(IMenuManager manager) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getSelectedItem(); + copyAction.setEnabled(item != null); + cutAction.setEnabled(item != null); +// diese 2 Actions sind als Listener registriert und enablen sich selbst. +// removeSelectedClipboardEntryAction.setEnabled(item != null); +// networkRemoveSelectedClipboardEntryAction.setEnabled(item != null); + } + }); + + return menubar; + } + + /** + * Returns the image shown as the shell image + */ + protected abstract Image getShellImage(); + + /** + * @return the initial size of the shell + */ + protected abstract Point getInitialShellSize(); + + protected abstract String getInitialStatusLine(); + + protected abstract Control fillMainWindow(Composite parent); + + protected abstract Control getCustomToolbar(); + + protected Control createContents(Composite parent) + { + shellImage = getShellImage(); + + getShell().setText(getShellText()); + + if (!PlatformUtils.isMacOs()) + { + getShell().setImage(shellImage); + } + + getShell().setVisible(false); + + Rectangle bounds = config.getRectangle(IPreferenceConstants.GUI_POSITION); + if (bounds != null) + { + getShell().setBounds(bounds); + } else { + getShell().setSize(getInitialShellSize()); + } + + Control c1 = fillMainWindow(parent); + + // Now the toolbar was created and can be handed to the ToolbarAction + toggleShowToolbarAction.setToolbar(getCustomToolbar()); + toggleShowToolbarAction.showToolbar(); + + // Now we can register Actions with the SelectionProvider (the ClipboardTable) + ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager().addSelectionChangedListener(removeSelectedClipboardEntryAction); + ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager().addSelectionChangedListener(networkRemoveSelectedClipboardEntryAction); + + myTray = createTray(this, getShell(), shellImage); + + setStatus(getInitialStatusLine()); + + getShell().addShellListener(new ShellAdapter() { + + public void shellClosed(ShellEvent arg0) + { + super.shellIconified(arg0); + // System.out.println("Close"); + getShell().setVisible(false); + } + }); + + return c1; + } + + public String getShellText() + { + String shellText = ""; + String urlStr = NetUtils.getLocalHostAddress(); + if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.START_HTTP_SERVER)) + { + urlStr = " - http://" + urlStr + ":" + ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.HTTP_SERVER_PORT); + } else { + urlStr = " - " + urlStr; + } + shellText += urlStr; + return ApplicationInfo.getApplicationName() + shellText; + } + + protected abstract ApplicationTray createApplicationTray(Window window, Shell shell, Image image); + + /** + * Create the SimiDude Tray + * + * @param shell + * the shell we use + * @param img + * the image to show + * @return Returns an SimiDudeTray Object + */ + ApplicationTray createTray(Window w, Shell shell, Image img) + { + ApplicationTray t = createApplicationTray(w, shell, img); + if (t != null) + { + t.initializeTray(); + } + return t; + } + + protected boolean canHandleShellCloseEvent() + { + return false; + } + + /** + * @see org.eclipse.jface.window.ApplicationWindow#close() + */ + public boolean close() + { + saveShellPosition(getShell().getBounds()); + return super.close(); + } + + private void saveShellPosition(Rectangle bounds) + { + IConfiguration config = ApplicationBase.getContext().getConfiguration(); + config.setRectangle(IPreferenceConstants.GUI_POSITION, bounds); + } + + public void startup() + { + this.open(); + } + + /** + * Runs the GUI. A call to this method blocks until the user exits. + */ + public void run() + { + runEventLoop(getShell()); + + shutdownApplicationGui(); + + Display.getCurrent().dispose(); + } + + protected void shutdownApplicationGui() + { + myTray.closeTray(); + ApplicationBase.getInstance().exit(); + } + + /** + * @see org.eclipse.jface.window.Window#open() + */ + public int open() + { + super.open(); + if (getShell() == null) + { + // create the window + create(); + } + + // limit the shell size to the display size + constrainShellSize(); + + if (config.getBoolean("app.start_minimized")) + { + getShell().setVisible(false); + getShell().setMinimized(true); + } + + // open the window + getShell().open(); + + if (config.getBoolean("app.start_minimized")) + { + getShell().setVisible(false); + getShell().setMinimized(false); + } + return 0; + } + + private void runEventLoop(Shell loopShell) + { + + Display display; + if (loopShell != null) + { + display = loopShell.getDisplay(); + + while (loopShell != null && !loopShell.isDisposed()) + { + try + { + if (!display.readAndDispatch()) + display.sleep(); + } catch (Throwable e) + { + e.printStackTrace(); + log.log(Level.SEVERE, e.getMessage(), e); +// throw new RuntimeException(e.getMessage()); + } + } + display.update(); + } + } + + public Composite createCustomToolbar(Composite parent) + { + CustomToolbar ctb = new CustomToolbar(parent); + +// ctb.add(exitAction); +// ctb.add(new Separator()); + ctb.add(inputTextAction); + ctb.add(new Separator()); + ctb.add(toggleMonitorClipboardAction); + ctb.add(selectMonitoredClipboardItemsAction); + ctb.add(new Separator()); + ctb.add(clearClipboardTableAction); + ctb.add(removeSelectedClipboardEntryAction); + ctb.add(new Separator()); + ctb.add(offlineHelpAction); + + return ctb.getToolbar(); + } + + // Generic registration with the Mac OS X application menu + // Checks the platform, then attempts to register with the Apple EAWT + // See OSXAdapter.java to see how this is done without directly referencing any Apple APIs + public void registerForMacOSXEvents() + { + if (PlatformUtils.isMacOs()) + { + try + { + CarbonUIEnhancer carbonUI = new CarbonUIEnhancer("About "+ApplicationInfo.getApplicationName()); + carbonUI.hookApplicationMenu(getShell().getDisplay(), new Listener() { + public void handleEvent(Event event) + { + shutdownApplicationGui(); + // could veto +// event.doit = false; + } + }, aboutAction, preferencesAction); + } catch (Exception e) + { + System.err.println("Error while registering OSX specific events"); + e.printStackTrace(); + } + } + } + + public ApplicationTray getTray() + { + return myTray; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/ApplicationStatusLineManager.java b/src/java/com/agynamix/platform/frontend/gui/ApplicationStatusLineManager.java new file mode 100644 index 0000000..8e797e3 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/ApplicationStatusLineManager.java @@ -0,0 +1,116 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.gui; + +import org.eclipse.jface.action.StatusLineManager; +import org.eclipse.jface.preference.JFacePreferences; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceColors; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; + +public class ApplicationStatusLineManager extends StatusLineManager { + + public enum MessageType {error, message}; + + Image currentImage = null; + String currentMessage = null; + MessageType currentMessageType = null; + + + public ApplicationStatusLineManager() + { + ColorRegistry cr = JFaceResources.getColorRegistry(); + cr.put(JFacePreferences.ERROR_COLOR, new RGB (205, 2, 4)); // schoen rot + } + + private void setCurrentMessage(Image image, String message) + { +// System.out.println("set message"+message); +// Exception e = new Exception(); +// e.printStackTrace(); + currentImage = image; + currentMessage = message; + currentMessageType = MessageType.message; + } + + private void setCurrentError(Image image, String message) + { +// System.out.println("set error "+message); +// Exception e = new Exception(); +// e.printStackTrace(); + currentImage = image; + currentMessage = message; + currentMessageType = MessageType.error; + } + + @Override + public void setErrorMessage(Image image, String message) + { + setCurrentError(image, message); + super.setErrorMessage(image, message); + } + + @Override + public void setErrorMessage(String message) + { + setCurrentError(null, message); + super.setErrorMessage(message); + JFaceColors.getErrorText(null); + } + + @Override + public void setMessage(Image image, String message) + { + setCurrentMessage(image, message); + super.setMessage(image, message); + } + + + @Override + public void setMessage(String message) + { + setCurrentMessage(null, message); + super.setMessage(message); + } + + public void restoreStatusLine() + { +// System.out.println("Restore "+currentMessage); + if (currentMessageType != null) + { + switch (currentMessageType) + { + case message: + if (currentImage != null) + { + super.setMessage(currentImage, currentMessage); + } else { + super.setMessage(currentMessage); + } + break; + case error: + if (currentImage != null) + { + super.setErrorMessage(currentImage, currentMessage); + } else { + super.setErrorMessage(currentMessage); + } + break; + } + } + + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/ApplicationTray.java b/src/java/com/agynamix/platform/frontend/gui/ApplicationTray.java new file mode 100644 index 0000000..cb0abcc --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/ApplicationTray.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.gui; + +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolTip; +import org.eclipse.swt.widgets.Tray; +import org.eclipse.swt.widgets.TrayItem; + +import com.agynamix.platform.frontend.action.IActionWithValue; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ApplicationInfo; +import com.agynamix.platform.infra.IPluginMenuAction; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.infra.PluginMenuEntry; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +/** + * @version $Revision: 27 $ $Date: 2004-11-27 22:42:44 +0100 (Sa, 27 Nov 2004) $ + * @author tuhlmann + */ +public class ApplicationTray { + + final Window window; + final Shell shell; + final Image trayImage; + Image exitImage; + Image openImage; + + Tray tray; + TrayItem trayItem; + ToolTip trayItemTooltip; + + MenuItem toggleMonitorClipboard; + + public ApplicationTray(Window w, Shell shell, Image trayImage) + { + this.window = w; + this.shell = shell; + this.trayImage = trayImage; + } + + public void initializeTray() + { + tray = shell.getDisplay().getSystemTray(); + if (tray == null) + { + // System has no tray + return; + } + + trayItem = new TrayItem(tray, SWT.NONE); + + trayItemTooltip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_INFORMATION); + trayItemTooltip.setAutoHide(true); + + trayItem.setToolTip(trayItemTooltip); + + exitImage = PlatformIcons.get(PlatformIcons.EXIT); + openImage = PlatformIcons.get(PlatformIcons.HOME); + + trayItem.setToolTipText(ApplicationInfo.getApplicationName() + " System Tray"); + trayItem.addListener(SWT.Selection, new Listener() { + + public void handleEvent(Event event) + { + toggleMainWindowActive(true); + } + }); +// trayItem.addListener(SWT.DefaultSelection, new Listener() { +// +// public void handleEvent(Event event) +// { +// toggleMainWindowActive(); +// } +// }); + + final Menu menu = new Menu(shell, SWT.POP_UP); + + PluginMenuEntry[] mEntries = new PluginMenuEntry[3]; + mEntries[0] = new PluginMenuEntry(PlatformIcons.get(PlatformIcons.COPY), "Copy Last Entry to Clipboard"); + mEntries[0].setPluginMenuAction(new IPluginMenuAction() { + + public void run(MenuItem menuItem) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sdm.activateItem(0); + } + }); + + mEntries[1] = new PluginMenuEntry(PlatformIcons.get(PlatformIcons.SAVE_CONTENTS_AS_TABLE_ENTRY), "Save Last Entry As..."); + mEntries[1].setPluginMenuAction(new IPluginMenuAction() { + + public void run(MenuItem menuItem) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getClipboardItem(0); + if (item != null) + { + sdm.saveClipboardItemAs(item, false); + } + } + }); + + mEntries[2] = new PluginMenuEntry(PlatformIcons.get(PlatformIcons.SAVE_CONTENTS_AS_TABLE_ENTRY), "Save Last Entry Compressed..."); + mEntries[2].setPluginMenuAction(new IPluginMenuAction() { + + public void run(MenuItem menuItem) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getClipboardItem(0); + if (item != null) + { + sdm.saveClipboardItemAs(item, true); + } + } + }); + + for (int j = 0; j < mEntries.length; j++) + { + final PluginMenuEntry entry = mEntries[j]; + final MenuItem mi = new MenuItem(menu, entry.getButtonStyle()); + if (entry.isCheckButton()) + { + mi.setSelection(entry.getChecked()); + } + mi.setText(entry.getText()); + mi.setImage(entry.getImage()); + mi.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) + { + entry.action(mi); + } + }); + + new MenuItem(menu, SWT.SEPARATOR); + } + + + toggleMonitorClipboard = new MenuItem(menu, SWT.CHECK); + toggleMonitorClipboard.setText("Toggle Clipboard Monitoring"); + toggleMonitorClipboard.setImage(PlatformIcons.get(PlatformIcons.TOGGLE_MONITOR_CLIPBOARD)); + toggleMonitorClipboard.addListener(SWT.Selection, new Listener(){ + public void handleEvent(Event event) + { + IActionWithValue toggleAction = ((SimidudeApplicationContext)ApplicationBase.getContext()).getApplicationGUI().toggleMonitorClipboardAction; + boolean newValue = toggleMonitorClipboard.getSelection(); + toggleAction.runWithValue(newValue); + } + }); + toggleMonitorClipboard.setSelection(ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR)); + + MenuItem miOpen = new MenuItem(menu, SWT.PUSH); + miOpen.setText("Open Window"); + miOpen.setImage(openImage); + miOpen.addListener(SWT.Selection, new Listener() { + + public void handleEvent(Event arg0) + { + openMainWindow(); + } + }); + + MenuItem miHide = new MenuItem(menu, SWT.PUSH); + miHide.setText("Hide Window"); +// miHide.setImage(openImage); + miHide.addListener(SWT.Selection, new Listener() { + + public void handleEvent(Event arg0) + { + closeMainWindow(); + } + }); + + MenuItem miExit = new MenuItem(menu, SWT.PUSH); + miExit.setText("Exit Simidude"); + miExit.setImage(exitImage); + miExit.addListener(SWT.Selection, new Listener() { + + public void handleEvent(Event arg0) + { + closeApplication(); + } + }); + + // TODO: Should listen to left MB on Mac- so we might listen to a different event + // when on Mac + trayItem.addListener(SWT.MenuDetect, new Listener() { + + public void handleEvent(Event event) + { + toggleMonitorClipboard.setSelection(ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR)); + menu.setVisible(true); + } + }); + trayItem.setImage(trayImage); + // image.dispose(); + + // Bind DropTarget object + // ??? Where can I find a control to bind it to ??? +// TransferDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getTransferDataManager(); +// System.out.println("TM="+tm); +// new SimidudeTrayDropTarget(this, tm); + + } + + public void openMainWindow() + { + if (!shell.isVisible()) + { + shell.setVisible(true); + shell.forceActive(); + shell.forceFocus(); + shell.setMinimized(false); + } else { + if (!shell.isFocusControl()) + { + shell.forceActive(); + shell.forceFocus(); + shell.setMinimized(false); + } + } + } + + protected void closeMainWindow() + { + if (shell.isVisible()) + { + shell.setVisible(false); + } + } + + public void toggleMainWindowActive(boolean clickedFromTray) + { + if ((!shell.isVisible())) //|| ((!shell.isFocusControl()) && (!clickedFromTray))) + { + openMainWindow(); + } else { + closeMainWindow(); + } + } + + public void showTooltip(final IClipboardItem item) + { + if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.SHOW_BALLOON_TOOLTIP)) + { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + trayItemTooltip.setMessage("New Simidude Entry:\n"+item.getShortDescription()); + trayItemTooltip.setVisible(true); + } + }); + } + } + + protected void closeApplication() + { + this.dispose(); + window.close(); + } + + protected void dispose() + { + if (exitImage != null) + { + exitImage.dispose(); + } + if (openImage != null) + { + openImage.dispose(); + } + } + + public void closeTray() + { + if ((tray != null) && (trayItem != null)) + { + trayItem.setVisible(false); + trayItem.dispose(); + tray.dispose(); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/CarbonUIEnhancer.java b/src/java/com/agynamix/platform/frontend/gui/CarbonUIEnhancer.java new file mode 100644 index 0000000..29a8294 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/CarbonUIEnhancer.java @@ -0,0 +1,239 @@ +package com.agynamix.platform.frontend.gui; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Listener; + +@SuppressWarnings("unchecked") +public class CarbonUIEnhancer { + private static final int kHICommandPreferences = ('p' << 24) + ('r' << 16) + ('e' << 8) + 'f'; + private static final int kHICommandAbout = ('a' << 24) + ('b' << 16) + ('o' << 8) + 'u'; + private static final int kHICommandServices = ('s' << 24) + ('e' << 16) + ('r' << 8) + 'v'; + + private final String fgAboutActionName; + final Class osCls; + + public CarbonUIEnhancer(String aboutTitle) + { + osCls = classForName("org.eclipse.swt.internal.carbon.OS"); + fgAboutActionName = aboutTitle; + } + + /** + * See Apple Technical Q&A 1079 (http://developer.apple.com/qa/qa2001/qa1079.html) + */ + public void hookApplicationMenu(Display display, final Listener quitListener, final IAction aboutAction, final IAction preferencesAction) + { + // Callback target + Object target = new Object() { + @SuppressWarnings("unused") + int commandProc(int nextHandler, int theEvent, int userData) + { + int osActualEventKind = (Integer) invoke(osCls, "GetEventKind", new Class[]{int.class}, theEvent); + int osEventProcessCommand = (Integer) fieldValue(osCls, "kEventProcessCommand"); + if (osActualEventKind == osEventProcessCommand) + { +// HICommand command = new HICommand(); + Class hiCmdCls = classForName("org.eclipse.swt.internal.carbon.HICommand"); + Object command = newInstance("org.eclipse.swt.internal.carbon.HICommand"); + + Class[] pt = new Class[]{int.class, int.class, int.class, int[].class, int.class, int[].class, hiCmdCls}; + invoke(osCls, "GetEventParameter", pt, theEvent, fieldValue(osCls, "kEventParamDirectObject"), + fieldValue(osCls, "typeHICommand"), null, fieldValue(command, "sizeof"), null, command); + switch ((Integer)fieldValue(command, "commandID")) + { + case kHICommandPreferences: + return runAction(preferencesAction); + case kHICommandAbout: + return runAction(aboutAction); + default: + break; + } + } + return (Integer) fieldValue(osCls, "eventNotHandledErr"); + } + }; + + Class[] pt = new Class[] {Object.class, String.class, int.class}; + final Object commandCallback = newInstance("org.eclipse.swt.internal.Callback", pt, target, "commandProc", 3); + int commandProc = (Integer)invoke(commandCallback, "getAddress"); + if (commandProc == 0) + { + invoke(commandCallback, "dispose"); + return; // give up + } + + // Install event handler for commands + int[] mask = new int[] { (Integer)fieldValue(osCls, "kEventClassCommand"), (Integer)fieldValue(osCls, "kEventProcessCommand") }; + pt = new Class[] {int.class, int.class, int.class, int[].class, int.class, int[].class}; + + int appEventTarget = (Integer)invoke(osCls, "GetApplicationEventTarget"); + invoke(osCls, "InstallEventHandler", pt, appEventTarget, commandProc, mask.length / 2, mask, 0, null); + + // create About Eclipse menu command + int[] outMenu = new int[1]; + short[] outIndex = new short[1]; +// GetIndMenuItemWithCommandID(int mHandle, int commandId, int index, int[] outMenu, short[] outIndex); + int indMenuItem = (Integer)invoke(osCls, "GetIndMenuItemWithCommandID", new Class[]{int.class, int.class, int.class, int[].class, short[].class}, + 0, kHICommandPreferences, 1, outMenu, outIndex); + int osNoErr = (Integer)fieldValue(osCls, "noErr"); +// if (OS.GetIndMenuItemWithCommandID(0, kHICommandPreferences, 1, outMenu, outIndex) == OS.noErr && outMenu[0] != 0) + if (indMenuItem == osNoErr && outMenu[0] != 0) + { + int menu = outMenu[0]; + + int l = fgAboutActionName.length(); + char buffer[] = new char[l]; + fgAboutActionName.getChars(0, l, buffer, 0); + int str = (Integer)invoke(osCls, "CFStringCreateWithCharacters", new Class[]{int.class, char[].class, int.class}, + fieldValue(osCls, "kCFAllocatorDefault"), buffer, l); + +// OS.InsertMenuItemTextWithCFString(menu, str, (short) 0, 0, kHICommandAbout); + invoke(osCls, "InsertMenuItemTextWithCFString", new Class[]{int.class, int.class, short.class, int.class, int.class}, + menu, str, (short) 0, 0, kHICommandAbout); +// OS.CFRelease(str); + invoke(osCls, "CFRelease", new Class[]{int.class}, str); + // add separator between About & Preferences +// OS.InsertMenuItemTextWithCFString(menu, 0, (short) 1, OS.kMenuItemAttrSeparator, 0); + invoke(osCls, "InsertMenuItemTextWithCFString", new Class[]{int.class, int.class, short.class, int.class, int.class}, + menu, 0, (short) 1, fieldValue(osCls, "kMenuItemAttrSeparator"), 0); + + + // enable pref menu +// OS.EnableMenuCommand(menu, kHICommandPreferences); + invoke(osCls, "EnableMenuCommand", new Class[]{int.class, int.class}, menu, kHICommandPreferences); + // disable services menu +// OS.DisableMenuCommand(menu, kHICommandServices); + invoke(osCls, "DisableMenuCommand", new Class[]{int.class, int.class}, menu, kHICommandServices); + + } + + // hook up quit listener + if (!display.isDisposed()) + { + display.addListener(SWT.Close, quitListener); + } + + // schedule disposal of callback object + display.disposeExec(new Runnable() { + public void run() + { + invoke(commandCallback, "dispose"); + } + }); + } + + /** + * Locate and run an action in the current menubar by name. + */ + private int runAction(IAction action) + { + try { + action.run(); + return (Integer)fieldValue(osCls, "noErr"); + } catch (Exception e) { + System.out.println("Error while executing Apple menu action: "+e.getMessage()); + } + return (Integer) fieldValue(osCls, "eventNotHandledErr"); + } + + + private Class classForName(String classname) + { + try + { + Class cls = Class.forName(classname); + return cls; + } catch (ClassNotFoundException e) + { + throw new IllegalStateException(e); + } + } + + private Object newInstance(String classname) + { + try + { + Class cls = classForName(classname); + return cls.newInstance(); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + private Object newInstance(String classname, Class[] paramTypes, Object... arguments) + { + try + { + Class cls = classForName(classname); + Constructor ctor = cls.getConstructor(paramTypes); + return ctor.newInstance(arguments); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + private Object invoke(Class cls, String methodName) + { + return invoke(cls, methodName, null, (Object[])null); + } + + private Object invoke(Class cls, String methodName, Class[] paramTypes, Object... arguments) + { + try { + Method m = cls.getDeclaredMethod(methodName, paramTypes); + return m.invoke(null, arguments); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + private Object invoke(Object obj, String methodName) + { + return invoke(obj, methodName, (Class[]) null, (Object[]) null); + } + + private Object invoke(Object obj, String methodName, Class[] paramTypes, Object... arguments) + { + try { + Method m = obj.getClass().getDeclaredMethod(methodName, paramTypes); + return m.invoke(obj, arguments); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + private Object fieldValue(Class cls, String fieldName) + { + try + { + Field field = cls.getDeclaredField(fieldName); + return field.get(null); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + private Object fieldValue(Object obj, String fieldName) + { + try + { + Field field = obj.getClass().getDeclaredField(fieldName); + return field.get(obj); + } catch (Exception e) + { + throw new IllegalStateException(e); + } + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/CustomToolbar.java b/src/java/com/agynamix/platform/frontend/gui/CustomToolbar.java new file mode 100644 index 0000000..a832e8a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/CustomToolbar.java @@ -0,0 +1,108 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.gui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.ClipboardTableSearchBox; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class CustomToolbar { + + List toolbarItems = new ArrayList(); + Composite toolbar = null; + + final Composite parent; + + public CustomToolbar(Composite parent) + { + this.parent = parent; + } + + public void add(IAction action) + { + toolbarItems.add(new ActionContributionItem(action)); + } + + public void add(IContributionItem item) + { + toolbarItems.add(item); + } + + public Composite createContents(Composite parent) + { + final Composite toolbar = new Composite(parent, SWT.NONE); + GridData data = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); + toolbar.setLayoutData(data); +// toolbar.addListener(SWT.Resize, new Listener() { +// public void handleEvent(Event event) +// { +// GradientHelper.applyGradientBG(toolbar); +// } +// }); + + GridLayout tbLayout = new GridLayout(); + tbLayout.numColumns = 2; + tbLayout.marginTop = 0; + tbLayout.marginBottom = 0; + tbLayout.marginLeft = 0; + tbLayout.marginRight = 0; + toolbar.setLayout(tbLayout); + + ToolBarManager tbm = new ToolBarManager(SWT.FLAT); + for (IContributionItem item : toolbarItems) + { + tbm.add(item); + } + tbm.createControl(toolbar); + + addSearchBar(toolbar); + + return toolbar; + } + + private void addSearchBar(Composite parent) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + + final Control search = new ClipboardTableSearchBox(sdm).createControl(parent); + GridData data = new GridData(); + data.horizontalAlignment = SWT.RIGHT; + data.grabExcessHorizontalSpace = true; + data.widthHint = 190; + search.setLayoutData(data); + } + + public Composite getToolbar() + { + if (toolbar == null) + { + toolbar = createContents(parent); + } + return toolbar; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/CustomToolbarItem.java b/src/java/com/agynamix/platform/frontend/gui/CustomToolbarItem.java new file mode 100644 index 0000000..7dc4abf --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/CustomToolbarItem.java @@ -0,0 +1,26 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.gui; + +import org.eclipse.jface.action.IAction; + +public class CustomToolbarItem { + + IAction itsAction = null; + + public CustomToolbarItem(IAction action) + { + itsAction = action; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/GradientHelper.java b/src/java/com/agynamix/platform/frontend/gui/GradientHelper.java new file mode 100644 index 0000000..d82d7f1 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/GradientHelper.java @@ -0,0 +1,50 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.gui; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; + +public class GradientHelper { + + private static Image oldImage = null; + + public static void applyGradientBG(Composite composite) + { + Rectangle rect = composite.getClientArea(); + Image newImage = new Image(composite.getDisplay(), 1, Math.max(1, rect.height)); + GC gc = new GC(newImage); +// gc.setForeground(composite.getDisplay().getSystemColor(SWT.COLOR_WHITE)); + + // Windows + gc.setForeground(new Color(composite.getDisplay(), 239, 242, 249)); + +// gc.setBackground(new Color(composite.getDisplay(), 228, 234, 243)); + + // Windows + gc.setBackground(new Color(composite.getDisplay(), 240, 240, 240)); + + gc.fillGradientRectangle(0, 0, 1, rect.height, true); + gc.dispose(); + composite.setBackgroundImage(newImage); + + if (oldImage != null) + { + oldImage.dispose(); + } + oldImage = newImage; + } +} diff --git a/src/java/com/agynamix/platform/frontend/gui/HotkeyListenerInfo.java b/src/java/com/agynamix/platform/frontend/gui/HotkeyListenerInfo.java new file mode 100644 index 0000000..bf47d5b --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/HotkeyListenerInfo.java @@ -0,0 +1,45 @@ +package com.agynamix.platform.frontend.gui; + +import com.agynamix.ossupport.HotKeyDesc; + +public class HotkeyListenerInfo { + + private final IHotkeyRegistrar hotkeyRegistrar; + private final int hotkeyId; + private final HotKeyDesc hotkeyDesc; + private final IHotkeyListener listener; + + public HotkeyListenerInfo(IHotkeyRegistrar hotkeyRegistrar, int hotkeyId, HotKeyDesc hotkeyDesc, IHotkeyListener listener) + { + this.hotkeyRegistrar = hotkeyRegistrar; + this.hotkeyId = hotkeyId; + this.hotkeyDesc = hotkeyDesc; + this.listener = listener; + } + + public IHotkeyListener getListener() + { + return listener; + } + + public IHotkeyRegistrar getHotkeyRegistrar() + { + return hotkeyRegistrar; + } + + public int getHotkeyId() + { + return hotkeyId; + } + + public HotKeyDesc getHotKeyDesc() + { + return hotkeyDesc; + } + + public void onHotkey(int hotkeyId) + { + listener.onHotkey(this); + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/HotkeyRegistrarFactory.java b/src/java/com/agynamix/platform/frontend/gui/HotkeyRegistrarFactory.java new file mode 100644 index 0000000..01f98ce --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/HotkeyRegistrarFactory.java @@ -0,0 +1,66 @@ +package com.agynamix.platform.frontend.gui; + +import com.agynamix.platform.infra.PlatformUtils; + +public class HotkeyRegistrarFactory { + + static IHotkeyRegistrar windowsHotkeyRegistrar; + static IHotkeyRegistrar unixHotkeyRegistrar; + static IHotkeyRegistrar osSupportHotkeyRegistrar; + static IHotkeyRegistrar placeboHotkeyRegistrar; + + public static IHotkeyRegistrar getHotkeyRegistrarInstance() { + IHotkeyRegistrar registrar; + switch (PlatformUtils.getOsName()) + { + case win32: + case win64: + registrar = getJIntellitypeHotkeyRegistrarInstance(); + break; + case linux_x86: + case linux_x86_64: + registrar = getJXGrabKeyHotkeyRegistrarInstance(); + break; + case macosx: + case macosx64: + registrar = getOsSupportHotkeyRegistrarInstance(); + break; + default: + registrar = getPlaceboHotkeyRegistrarInstance(); + } + return registrar; + } + + private static IHotkeyRegistrar getPlaceboHotkeyRegistrarInstance() { + if (placeboHotkeyRegistrar == null) + { + placeboHotkeyRegistrar = new PlaceboHotkeyRegistrar(); + } + return placeboHotkeyRegistrar; + } + + private static IHotkeyRegistrar getOsSupportHotkeyRegistrarInstance() { + if (osSupportHotkeyRegistrar == null) + { + osSupportHotkeyRegistrar = new OsSupportHotkeyRegistrar(); + } + return osSupportHotkeyRegistrar; + } + + private static IHotkeyRegistrar getJIntellitypeHotkeyRegistrarInstance() { + if (windowsHotkeyRegistrar == null) + { + windowsHotkeyRegistrar = new JIntellitypeHotkeyRegistrar(); + } + return windowsHotkeyRegistrar; + } + + private static IHotkeyRegistrar getJXGrabKeyHotkeyRegistrarInstance() { + if (unixHotkeyRegistrar == null) + { + unixHotkeyRegistrar = new JXGrabKeyHotkeyRegistrar(); + } + return unixHotkeyRegistrar; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/IHotkeyListener.java b/src/java/com/agynamix/platform/frontend/gui/IHotkeyListener.java new file mode 100644 index 0000000..87357d7 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/IHotkeyListener.java @@ -0,0 +1,7 @@ +package com.agynamix.platform.frontend.gui; + +public interface IHotkeyListener { + + void onHotkey(HotkeyListenerInfo listenerInfo); + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/IHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/IHotkeyRegistrar.java new file mode 100644 index 0000000..2d5bdab --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/IHotkeyRegistrar.java @@ -0,0 +1,28 @@ +package com.agynamix.platform.frontend.gui; + + +public interface IHotkeyRegistrar { + + /** + * True if the HotkeyRegistrar has been enabled, false otherwise + * @return + */ + boolean isEnabled(); + + void addHotkeyListener(String hotkeyCombination, IHotkeyListener listener); + + void unregisterHotkeys(); + + void activateGlobalPaste(HotkeyListenerInfo listenerInfo); + + /** + * Parse the Hotkey definition from the preferences into the platform + * dependent representation. + * @param hotkeyCombination Hotkey in the form 'Shift+Alt+L' + * @return a tuple of the parsed hotkey. The first value if the modifier key, the second is the hotkey value. + */ + //Tupel parseHotkeyDefinition(String hotkeyCombination); + + + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/JIntellitypeHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/JIntellitypeHotkeyRegistrar.java new file mode 100644 index 0000000..1d8376c --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/JIntellitypeHotkeyRegistrar.java @@ -0,0 +1,218 @@ +package com.agynamix.platform.frontend.gui; + +import java.util.HashMap; +import java.util.Map; + +import com.agynamix.ossupport.HotKeyDesc; +import com.agynamix.platform.infra.ApplicationInfo; +import com.agynamix.platform.infra.Tupel; +import com.melloware.jintellitype.HotkeyListener; +import com.melloware.jintellitype.JIntellitype; +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; + +/** + * @author tuhlmann + * + */ +public class JIntellitypeHotkeyRegistrar extends AbstractHotkeyRegistrar implements HotkeyListener { + + public interface User32 extends Library { + User32 lib = (User32) Native.loadLibrary("user32" , User32.class); + + void keybd_event(short bVk, short bScan, long dwFlags, com.sun.jna.Pointer dwExtraInfo); + } + + + /** + * ALT key for registering Hotkeys. + */ + public static final int MOD_ALT = 1; + + /** + * CONTROL key for registering Hotkeys. + */ + public static final int MOD_CONTROL = 2; + + /** + * SHIFT key for registering Hotkeys. + */ + public static final int MOD_SHIFT = 4; + + /** + * WINDOWS key for registering Hotkeys. + */ + public static final int MOD_WIN = 8; + + final static short VK_SHIFT = 0x10; + final static short VK_CONTROL = 0x11; + final static short VK_ALT = 0x12; + final static short KEYEVENTF_KEYUP = 0x2; + + Map listenerMap = new HashMap(); + + int currentHotkeyId = 100; + boolean hotkeysEnabled = true; + + public JIntellitypeHotkeyRegistrar() + { + try + { + if (JIntellitype.checkInstanceAlreadyRunning(ApplicationInfo.getApplicationName())) + { + System.out.println("JIntellitype started twice"); + } + // next check to make sure JIntellitype DLL can be found and we are on + // a Windows operating System + if (!JIntellitype.isJIntellitypeSupported()) + { + hotkeysEnabled = false; + } else { + initJIntellitype(); + } + } catch (Exception e) + { + System.out.println("Error initializing JIntellitype: "+e.getMessage()); + hotkeysEnabled = false; + } + + } + + public void initJIntellitype() + { + try + { + // initialize JIntellitype with the frame so all windows commands can + // be attached to this window + JIntellitype.getInstance().addHotKeyListener(this); +// System.out.println("JIntellitype initialized"); + } catch (RuntimeException ex) + { + System.out.println("Either you are not on Windows, or there is a problem with the JIntellitype library!"); + } + } + + public boolean isEnabled() + { + return hotkeysEnabled; + } + + /** + * Currently only works with a 1:1 relationship between Hotkey and listener + */ + public void addHotkeyListener(String hotkeyCombination, IHotkeyListener listener) + { + if (hotkeysEnabled) + { + Tupel hotkeys = parseHotkeyDefinition(hotkeyCombination); + + // System.out.println("modKey="+modKey); + // System.out.println("hotKey="+hotKey); + JIntellitype.getInstance().registerHotKey(currentHotkeyId, hotkeys.getValue1(), hotkeys.getValue2()); + listenerMap.put(currentHotkeyId, new HotkeyListenerInfo(this, currentHotkeyId, new HotKeyDesc(hotkeys.getValue1(), 0, hotkeys.getValue2()), listener)); + // System.out.println("JIntellitypeHotkeyRegistrar.addHotkeyListener called"); + currentHotkeyId++; + } + } + + public void onHotKey(int hotkeyId) + { + HotkeyListenerInfo listenerInfo = listenerMap.get(hotkeyId); + if (listenerInfo != null) + { + listenerInfo.onHotkey(hotkeyId); + } else { + System.out.println("No listener registered for id "+hotkeyId); + } + + } + + public void unregisterHotkeys() + { + if (hotkeysEnabled) + { + for (Object o : listenerMap.keySet()) + { + JIntellitype.getInstance().unregisterHotKey(((Integer)o).intValue()); + // System.out.println("Remove hotkeyId "+o); + } + listenerMap.clear(); + } + } + + public void activateGlobalPaste(HotkeyListenerInfo listenerInfo) + { +// IUnknown scriptHost = new IUnknownImpl(CLSID.createFromProgID("WScript.Shell"), ClsCtx.INPROC_SERVER); +// Automation scriptHostAutomation = new Automation(scriptHost, true); +// scriptHostAutomation.invoke("SendKeys", "^v"); // "Ctrl+V" + + resetKeyPress(listenerInfo.getHotKeyDesc().getModifier(), listenerInfo.getHotKeyDesc().getKeycode()); + +// Function keybd_event = User32.getInstance().getFunction("keybd_event"); +// keybd_event.invoke(null, new UInt8(VK_CONTROL), new UInt8((short)0x9d), new UInt32(0), new Pointer.Void()); +// keybd_event.invoke(null, new UInt8((short)'V'), new UInt8((short)0xaf), new UInt32(0), new Pointer.Void()); +// keybd_event.invoke(null, new UInt8((short)'V'), new UInt8((short)0xaf), new UInt32(KEYEVENTF_KEYUP), new Pointer.Void()); +// keybd_event.invoke(null, new UInt8(VK_CONTROL), new UInt8((short)0x9d), new UInt32(KEYEVENTF_KEYUP), new Pointer.Void()); + + User32.lib.keybd_event(VK_CONTROL, (short)0x9d, (short)0, Pointer.NULL); + User32.lib.keybd_event((short)'V', (short)0xaf, (short)0, Pointer.NULL); + User32.lib.keybd_event((short)'V', (short)0xaf, KEYEVENTF_KEYUP, Pointer.NULL); + User32.lib.keybd_event(VK_CONTROL, (short)0x9d, KEYEVENTF_KEYUP, Pointer.NULL); + + } + + private void resetKeyPress(int modKey, int hotKey) + { + //Function keybd_event = User32.getInstance().getFunction("keybd_event"); + resetKey((short)hotKey); + + if ((modKey & MOD_SHIFT) != 0) + { + resetKey(VK_SHIFT); + } + + if ((modKey & MOD_ALT) != 0) + { + resetKey(VK_ALT); + } + + if ((modKey & MOD_CONTROL) != 0) + { + resetKey(VK_CONTROL); + } + + } + + private void resetKey(short key) + { + short scanCode = mapVirtualKey(key); + User32.lib.keybd_event(key, scanCode, KEYEVENTF_KEYUP, Pointer.NULL); + } + + private short mapVirtualKey(short key) + { +// Function mapVirtualKey = User32.getInstance().getFunction("MapVirtualKey"); +// UInt8 result = new UInt8(); +// mapVirtualKey.invoke(result, new UInt8(key), new UInt8((short)0)); +// return (short) result.getValue(); + return (short)0; + } + + protected int tokenToModifier(String token) + { + if (token.equalsIgnoreCase("Ctrl")) + { + return MOD_CONTROL; + } else if (token.equalsIgnoreCase("Shift")) + { + return MOD_SHIFT; + } else if (token.equalsIgnoreCase("Alt")) + { + return MOD_ALT; + } + return 0; + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyHotkeyRegistrar.java new file mode 100644 index 0000000..8633cd8 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyHotkeyRegistrar.java @@ -0,0 +1,207 @@ +package com.agynamix.platform.frontend.gui; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jxgrabkey.HotkeyConflictException; +import jxgrabkey.HotkeyListener; +import jxgrabkey.JXGrabKey; +import jxgrabkey.X11KeysymDefinitions; + +import com.agynamix.ossupport.HotKeyDesc; +import com.agynamix.platform.frontend.gui.JIntellitypeHotkeyRegistrar.User32; +import com.agynamix.platform.frontend.gui.x11.X11; +import com.agynamix.platform.frontend.gui.x11.X11.Display; +import com.agynamix.platform.frontend.gui.x11.X11.KeySym; +import com.agynamix.platform.infra.Tupel; +import com.agynamix.platform.log.ApplicationLog; +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; + +/** + * @author tuhlmann + * + */ +public class JXGrabKeyHotkeyRegistrar extends AbstractHotkeyRegistrar implements HotkeyListener { + + /** + * ALT key for registering Hotkeys. + */ + public static final int MOD_ALT = 1; + + /** + * CONTROL key for registering Hotkeys. + */ + public static final int MOD_CONTROL = 2; + + /** + * SHIFT key for registering Hotkeys. + */ + public static final int MOD_SHIFT = 4; + + /** + * WINDOWS key for registering Hotkeys. + */ + public static final int MOD_WIN = 8; + + final static short VK_SHIFT = 0x10; + final static short VK_CONTROL = 0x11; + final static short VK_ALT = 0x12; + final static short KEYEVENTF_KEYUP = 0x2; + + Map listenerMap = new HashMap(); + + Logger log = ApplicationLog.getLogger(JXGrabKeyHotkeyRegistrar.class); + + int currentHotkeyId = 100; + + boolean hotkeysEnabled = true; + + public JXGrabKeyHotkeyRegistrar() + { + initJXGrabKey(); + } + + public void initJXGrabKey() + { + if (!loadJarLibrary("libJXGrabKey.so")) + { + System.out.println("Can not load native Hotkey library. Disabling hotkeys..."); + hotkeysEnabled = false; + } + + if (hotkeysEnabled) + { + try + { + // initialize JIntellitype with the frame so all windows commands can + // be attached to this window + JXGrabKey.getInstance().addHotkeyListener(this); + // System.out.println("JIntellitype initialized"); + } catch (RuntimeException ex) + { + System.out.println("Either you are not on Linux, or there is a problem with the JXGrabKey library!"); + } + } + } + + public boolean isEnabled() + { + return hotkeysEnabled; + } + + /** + * Currently only works with a 1:1 relationship between Hotkey and listener + */ + public void addHotkeyListener(String hotkeyCombination, IHotkeyListener listener) + { + + if (!hotkeysEnabled) return; + +// System.out.println("modKey="+modKey); +// System.out.println("hotKey="+hotKey); + try + { + Tupel hotkeys = parseHotkeyDefinition(hotkeyCombination); + + JXGrabKey.getInstance().registerAwtHotkey(currentHotkeyId, hotkeys.getValue1(), hotkeys.getValue2()); + listenerMap.put(currentHotkeyId, new HotkeyListenerInfo(this, currentHotkeyId, new HotKeyDesc(hotkeys.getValue1(), 0, hotkeys.getValue2()), listener)); + currentHotkeyId++; +// System.out.println("JXGrabKeyHotkeyRegistrar.addHotkeyListener called"); + } catch (HotkeyConflictException e) + { + log.log(Level.WARNING, "Hotkey could not be registered.", e); + } + } + + public void onHotkey(int hotkeyId) + { + HotkeyListenerInfo listenerInfo = listenerMap.get(hotkeyId); + if (listenerInfo != null) + { + listenerInfo.onHotkey(hotkeyId); + } else { + System.out.println("No listener registered for id "+hotkeyId); + } + + } + + public void unregisterHotkeys() + { + if (!hotkeysEnabled) return; + + for (Object o : listenerMap.keySet()) + { + JXGrabKey.getInstance().unregisterHotKey(((Integer)o).intValue()); +// System.out.println("Remove hotkeyId "+o); + } + listenerMap.clear(); + } + + public void activateGlobalPaste(HotkeyListenerInfo listenerInfo) + { + // get X11 display + X11.Display display = X11.INSTANCE.XOpenDisplay(null); + + if (display == null) { + log.warning("Can't open X11 display"); + } else { + + boolean allKeysUp = false; + while (!allKeysUp) + { + allKeysUp = true; + byte[] keysReturn = new byte[32]; + X11.INSTANCE.XQueryKeymap(display, keysReturn); + //System.out.print("KeyMap State:"); + for (int i = 0; i < 32; i++) { + //System.out.print(keysReturn[i]+" "); + if (keysReturn[i] != 0) { + allKeysUp = false; + } + } + //System.out.println(""); + try { + Thread.sleep(50); + } catch (InterruptedException IGNORE) {} + } + + //System.out.println("Opened X11 Display. Can send Keypresses now..."); + + byte ctrlKC = X11.INSTANCE.XKeysymToKeycode(display, new X11.KeySym(X11KeysymDefinitions.CONTROL_L)); + byte vKC = X11.INSTANCE.XKeysymToKeycode(display, new X11.KeySym(X11KeysymDefinitions.V)); + + X11.XTest.INSTANCE.XTestFakeKeyEvent(display, ctrlKC, true, new NativeLong(0)); // CTRL DOWN + X11.XTest.INSTANCE.XTestFakeKeyEvent(display, vKC, true, new NativeLong(0)); // V DOWN + X11.XTest.INSTANCE.XTestFakeKeyEvent(display, vKC, false, new NativeLong(0)); // V UP + X11.XTest.INSTANCE.XTestFakeKeyEvent(display, ctrlKC, false, new NativeLong(0)); // CTRL UP + + X11.INSTANCE.XCloseDisplay(display); + } + + } + + protected int tokenToModifier(String token) + { + if (token.equalsIgnoreCase("Ctrl")) + { + return java.awt.event.InputEvent.CTRL_MASK; + } else if (token.equalsIgnoreCase("Shift")) + { + return java.awt.event.InputEvent.SHIFT_MASK; + } else if (token.equalsIgnoreCase("Alt")) + { + return java.awt.event.InputEvent.ALT_MASK; + } + return 0; + } + + protected int tokenToKeyCode(String token) + { + int swtKey = (int)token.charAt(0); + return JXGrabKeyKeyCodeTranslator.translateSWTKey(swtKey); + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyKeyCodeTranslator.java b/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyKeyCodeTranslator.java new file mode 100644 index 0000000..8ff5f1a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/JXGrabKeyKeyCodeTranslator.java @@ -0,0 +1,469 @@ +package com.agynamix.platform.frontend.gui; + +import org.eclipse.swt.SWT; + +/** + * Code copied from class swingwt\awt\event\KeyEvent.java + * in project swingwt http://swingwt.sourceforge.net + * + * Usage: + * JXGrabKey.getInstance().registerAWTHotkey(1, + * KeyCodeTranslator.translateSWTModifiers(SWT.CTRL), + * KeyCodeTranslator.translateSWTKey(SWT.F8)); + */ +public class JXGrabKeyKeyCodeTranslator { + + /** Returns the AWT modifier code for an SWT modifier */ + public static int translateSWTModifiers(int swtModifiers) { + int awtModifiers = 0; + if ((swtModifiers & SWT.CTRL) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.CTRL_MASK; + if ((swtModifiers & SWT.SHIFT) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.SHIFT_MASK; + if ((swtModifiers & SWT.ALT) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.ALT_MASK; + if ((swtModifiers & SWT.BUTTON1) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.BUTTON1_DOWN_MASK; + if ((swtModifiers & SWT.BUTTON2) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.BUTTON2_DOWN_MASK; + if ((swtModifiers & SWT.BUTTON3) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.BUTTON3_DOWN_MASK; + if ((swtModifiers & SWT.COMMAND) > 0) + awtModifiers = awtModifiers | java.awt.event.InputEvent.META_MASK; + return awtModifiers; + } + + /** Returns the AWT key code for an SWT key */ + public static int translateSWTKey(int swtKey) { + int awt = 0; + for (int i = 1; i < translationMap.length; i += 2) { + if (translationMap[i] == swtKey) { + awt = translationMap[i - 1]; + break; + } + } + return awt; + } + + /** Returns the SWT key code for an AWT key */ + public static int translateAWTKey(int awtKey) { + int swt = 0; + for (int i = 0; i < translationMap.length; i += 2) { + if (translationMap[i] == awtKey) { + swt = translationMap[i + 1]; + break; + } + } + return swt; + } + + private static final int VK_ENTER = '\n'; + private static final int VK_BACK_SPACE = '\b'; + private static final int VK_TAB = '\t'; + private static final int VK_CANCEL = 0x03; + private static final int VK_CLEAR = 0x0C; + private static final int VK_SHIFT = 0x10; + private static final int VK_CONTROL = 0x11; + private static final int VK_ALT = 0x12; + private static final int VK_PAUSE = 0x13; + private static final int VK_CAPS_LOCK = 0x14; + private static final int VK_ESCAPE = 0x1B; + private static final int VK_SPACE = 0x20; + private static final int VK_PAGE_UP = 0x21; + private static final int VK_PAGE_DOWN = 0x22; + private static final int VK_END = 0x23; + private static final int VK_HOME = 0x24; + private static final int VK_LEFT = 0x25; + private static final int VK_UP = 0x26; + private static final int VK_RIGHT = 0x27; + private static final int VK_DOWN = 0x28; + private static final int VK_COMMA = 0x2C; + private static final int VK_MINUS = 0x2D; + private static final int VK_PERIOD = 0x2E; + private static final int VK_SLASH = 0x2F; + private static final int VK_0 = 0x30; + private static final int VK_1 = 0x31; + private static final int VK_2 = 0x32; + private static final int VK_3 = 0x33; + private static final int VK_4 = 0x34; + private static final int VK_5 = 0x35; + private static final int VK_6 = 0x36; + private static final int VK_7 = 0x37; + private static final int VK_8 = 0x38; + private static final int VK_9 = 0x39; + private static final int VK_SEMICOLON = 0x3B; + private static final int VK_EQUALS = 0x3D; + private static final int VK_A = 0x41; + private static final int VK_B = 0x42; + private static final int VK_C = 0x43; + private static final int VK_D = 0x44; + private static final int VK_E = 0x45; + private static final int VK_F = 0x46; + private static final int VK_G = 0x47; + private static final int VK_H = 0x48; + private static final int VK_I = 0x49; + private static final int VK_J = 0x4A; + private static final int VK_K = 0x4B; + private static final int VK_L = 0x4C; + private static final int VK_M = 0x4D; + private static final int VK_N = 0x4E; + private static final int VK_O = 0x4F; + private static final int VK_P = 0x50; + private static final int VK_Q = 0x51; + private static final int VK_R = 0x52; + private static final int VK_S = 0x53; + private static final int VK_T = 0x54; + private static final int VK_U = 0x55; + private static final int VK_V = 0x56; + private static final int VK_W = 0x57; + private static final int VK_X = 0x58; + private static final int VK_Y = 0x59; + private static final int VK_Z = 0x5A; + private static final int VK_OPEN_BRACKET = 0x5B; + private static final int VK_BACK_SLASH = 0x5C; + private static final int VK_CLOSE_BRACKET = 0x5D; + private static final int VK_NUMPAD0 = 0x60; + private static final int VK_NUMPAD1 = 0x61; + private static final int VK_NUMPAD2 = 0x62; + private static final int VK_NUMPAD3 = 0x63; + private static final int VK_NUMPAD4 = 0x64; + private static final int VK_NUMPAD5 = 0x65; + private static final int VK_NUMPAD6 = 0x66; + private static final int VK_NUMPAD7 = 0x67; + private static final int VK_NUMPAD8 = 0x68; + private static final int VK_NUMPAD9 = 0x69; + private static final int VK_MULTIPLY = 0x6A; + private static final int VK_ADD = 0x6B; + private static final int VK_SEPARATOR = 0x6C; + private static final int VK_SUBTRACT = 0x6D; + private static final int VK_DECIMAL = 0x6E; + private static final int VK_DIVIDE = 0x6F; + private static final int VK_DELETE = 0x7F; + private static final int VK_NUM_LOCK = 0x90; + private static final int VK_SCROLL_LOCK = 0x91; + private static final int VK_F1 = 0x70; + private static final int VK_F2 = 0x71; + private static final int VK_F3 = 0x72; + private static final int VK_F4 = 0x73; + private static final int VK_F5 = 0x74; + private static final int VK_F6 = 0x75; + private static final int VK_F7 = 0x76; + private static final int VK_F8 = 0x77; + private static final int VK_F9 = 0x78; + private static final int VK_F10 = 0x79; + private static final int VK_F11 = 0x7A; + private static final int VK_F12 = 0x7B; + private static final int VK_PRINTSCREEN = 0x9A; + private static final int VK_INSERT = 0x9B; + private static final int VK_HELP = 0x9C; + private static final int VK_META = 0x9D; + private static final int VK_BACK_QUOTE = 0xC0; + private static final int VK_QUOTE = 0xDE; + private static final int VK_KP_UP = 0xE0; + private static final int VK_KP_DOWN = 0xE1; + private static final int VK_KP_LEFT = 0xE2; + private static final int VK_KP_RIGHT = 0xE3; + private static final int VK_AMPERSAND = 0x96; + private static final int VK_ASTERISK = 0x97; + private static final int VK_QUOTEDBL = 0x98; + private static final int VK_LESS = 0x99; + private static final int VK_GREATER = 0xa0; + private static final int VK_BRACELEFT = 0xa1; + private static final int VK_BRACERIGHT = 0xa2; + private static final int VK_AT = 0x0200; + private static final int VK_COLON = 0x0201; + private static final int VK_CIRCUMFLEX = 0x0202; + private static final int VK_DOLLAR = 0x0203; + private static final int VK_EURO_SIGN = 0x0204; + private static final int VK_EXCLAMATION_MARK = 0x0205; + private static final int VK_INVERTED_EXCLAMATION_MARK = 0x0206; + private static final int VK_LEFT_PARENTHESIS = 0x0207; + private static final int VK_NUMBER_SIGN = 0x0208; + private static final int VK_PLUS = 0x0209; + private static final int VK_RIGHT_PARENTHESIS = 0x020A; + private static final int VK_UNDERSCORE = 0x020B; + + private static final int SWTVK_A = 'A'; + private static final int SWTVK_B = 'B'; + private static final int SWTVK_C = 'C'; + private static final int SWTVK_D = 'D'; + private static final int SWTVK_E = 'E'; + private static final int SWTVK_F = 'F'; + private static final int SWTVK_G = 'G'; + private static final int SWTVK_H = 'H'; + private static final int SWTVK_I = 'I'; + private static final int SWTVK_J = 'J'; + private static final int SWTVK_K = 'K'; + private static final int SWTVK_L = 'L'; + private static final int SWTVK_M = 'M'; + private static final int SWTVK_N = 'N'; + private static final int SWTVK_O = 'O'; + private static final int SWTVK_P = 'P'; + private static final int SWTVK_Q = 'Q'; + private static final int SWTVK_R = 'R'; + private static final int SWTVK_S = 'S'; + private static final int SWTVK_T = 'T'; + private static final int SWTVK_U = 'U'; + private static final int SWTVK_V = 'V'; + private static final int SWTVK_W = 'W'; + private static final int SWTVK_X = 'X'; + private static final int SWTVK_Y = 'Y'; + private static final int SWTVK_Z = 'Z'; + private static final int SWTVK_SPACE = ' '; + private static final int SWTVK_0 = '0'; + private static final int SWTVK_1 = '1'; + private static final int SWTVK_2 = '2'; + private static final int SWTVK_3 = '3'; + private static final int SWTVK_4 = '4'; + private static final int SWTVK_5 = '5'; + private static final int SWTVK_6 = '6'; + private static final int SWTVK_7 = '7'; + private static final int SWTVK_8 = '8'; + private static final int SWTVK_9 = '9'; + private static final int SWTVK_SEMICOLON = ';'; + private static final int SWTVK_EQUALS = '='; + private static final int SWTVK_COMMA = ','; + private static final int SWTVK_MINUS = '-'; + private static final int SWTVK_PERIOD = '.'; + private static final int SWTVK_SLASH = '/'; + private static final int SWTVK_OPEN_BRACKET = '('; + private static final int SWTVK_BACK_SLASH = '\\'; + private static final int SWTVK_CLOSE_BRACKET = ')'; + private static final int SWTVK_UNDERSCORE = '_'; + private static final int SWTVK_ADD = '+'; + private static final int SWTVK_PLUS = '+'; + private static final int SWTVK_NUMBER_SIGN = '+'; + private static final int SWTVK_MULTIPLY = '*'; + private static final int SWTVK_SUBTRACT = '-'; + private static final int SWTVK_DECIMAL = '.'; + private static final int SWTVK_DIVIDE = '.'; + private static final int SWTVK_BACK_QUOTE = '`'; + private static final int SWTVK_QUOTE = '\''; + private static final int SWTVK_AMPERSAND = '&'; + private static final int SWTVK_ASTERISK = '*'; + private static final int SWTVK_QUOTEDBL = '"'; + private static final int SWTVK_LESS = '<'; + private static final int SWTVK_GREATER = '>'; + private static final int SWTVK_BRACELEFT = '{'; + private static final int SWTVK_BRACERIGHT = '}'; + private static final int SWTVK_AT = '@'; + private static final int SWTVK_CIRCUMFLEX = '~'; + private static final int SWTVK_DOLLAR = '$'; + private static final int SWTVK_EURO_SIGN = '$'; + private static final int SWTVK_EXCLAMATION_MARK = '!'; + private static final int SWTVK_INVERTED_EXCLAMATION_MARK = '!'; + private static final int SWTVK_LEFT_PARENTHESIS = '('; + private static final int SWTVK_RIGHT_PARENTHESIS = ')'; + private static final int SWTVK_COLON = ':'; + private static final int SWTVK_TAB = '\t'; + private static final int SWTVK_F1 = SWT.F1; + private static final int SWTVK_F2 = SWT.F2; + private static final int SWTVK_F3 = SWT.F3; + private static final int SWTVK_F4 = SWT.F4; + private static final int SWTVK_F5 = SWT.F5; + private static final int SWTVK_F6 = SWT.F6; + private static final int SWTVK_F7 = SWT.F7; + private static final int SWTVK_F8 = SWT.F8; + private static final int SWTVK_F9 = SWT.F9; + private static final int SWTVK_F10 = SWT.F10; + private static final int SWTVK_F11 = SWT.F11; + private static final int SWTVK_F12 = SWT.F12; + private static final int SWTVK_ENTER = SWT.CR; + private static final int SWTVK_BACK_SPACE = 8; + private static final int SWTVK_DELETE = SWT.DEL; + private static final int SWTVK_ESCAPE = SWT.ESC; + + // NOTE: I think this is right... should use the arrow ids instead of left/right/etc (intended for alignment) + private static final int SWTVK_LEFT = SWT.ARROW_LEFT; + private static final int SWTVK_RIGHT = SWT.ARROW_RIGHT; + private static final int SWTVK_UP = SWT.ARROW_UP; + private static final int SWTVK_DOWN = SWT.ARROW_DOWN; + private static final int SWTVK_HOME = SWT.HOME; + private static final int SWTVK_END = SWT.END; + /* + private static final int SWTVK_LEFT = SWT.LEFT; + private static final int SWTVK_KP_LEFT = SWT.LEFT; + private static final int SWTVK_RIGHT = SWT.RIGHT; + private static final int SWTVK_KP_RIGHT = SWT.RIGHT; + private static final int SWTVK_UP = SWT.UP; + private static final int SWTVK_KP_UP = SWT.UP; + private static final int SWTVK_DOWN = SWT.DOWN; + private static final int SWTVK_KP_DOWN = SWT.DOWN; + private static final int SWTVK_HOME = SWT.HOME; + private static final int SWTVK_END = SWT.END; + */ + + private static final int SWTVK_PAGE_UP = SWT.PAGE_UP; + private static final int SWTVK_PAGE_DOWN = SWT.PAGE_DOWN; + private static final int SWTVK_INSERT = SWT.INSERT; + private static final int SWTVK_SHIFT = SWT.SHIFT; + private static final int SWTVK_CONTROL = SWT.CONTROL; + private static final int SWTVK_ALT = SWT.ALT; + private static final int SWTVK_META = SWT.ALT; + private static final int SWTVK_CANCEL = SWT.CANCEL; + private static final int SWTVK_CLEAR = SWT.NONE; + private static final int SWTVK_PAUSE = SWT.PAUSE; + private static final int SWTVK_CAPS_LOCK = SWT.CAPS_LOCK; + private static final int SWTVK_SEPARATOR = SWT.SEPARATOR; + private static final int SWTVK_NUM_LOCK = SWT.NUM_LOCK; + private static final int SWTVK_SCROLL_LOCK = SWT.SCROLL_LOCK; + private static final int SWTVK_PRINTSCREEN = SWT.PRINT_SCREEN; + private static final int SWTVK_HELP = SWT.HELP; + + /** Map of SWT key constants to AWT constants. This is to + * ensure binary compatibility for existing Swing/AWT apps. + */ + private static int[] translationMap = new int[] { + VK_ENTER, SWTVK_ENTER, + VK_BACK_SPACE, SWTVK_BACK_SPACE, + VK_TAB, SWTVK_TAB, + VK_CANCEL, SWTVK_CANCEL, + VK_CLEAR, SWTVK_CLEAR, + VK_SHIFT, SWTVK_SHIFT, + VK_CONTROL, SWTVK_CONTROL, + VK_ALT, SWTVK_ALT, + VK_PAUSE, SWTVK_PAUSE, + VK_CAPS_LOCK, SWTVK_CAPS_LOCK, + VK_ESCAPE, SWTVK_ESCAPE, + VK_SPACE, SWTVK_SPACE, + VK_PAGE_UP, SWTVK_PAGE_UP, + VK_PAGE_DOWN, SWTVK_PAGE_DOWN, + VK_END, SWTVK_END, + VK_HOME, SWTVK_HOME, + VK_LEFT, SWTVK_LEFT, + VK_UP, SWTVK_UP, + VK_RIGHT, SWTVK_RIGHT, + VK_DOWN, SWTVK_DOWN, + VK_COMMA, SWTVK_COMMA, + VK_MINUS, SWTVK_MINUS, + VK_PERIOD, SWTVK_PERIOD, + VK_SLASH, SWTVK_SLASH, + VK_0, SWTVK_0, + VK_1, SWTVK_1, + VK_2, SWTVK_2, + VK_3, SWTVK_3, + VK_4, SWTVK_4, + VK_5, SWTVK_5, + VK_6, SWTVK_6, + VK_7, SWTVK_7, + VK_8, SWTVK_8, + VK_9, SWTVK_9, + VK_SEMICOLON, SWTVK_SEMICOLON, + VK_EQUALS, SWTVK_EQUALS, + VK_A, SWTVK_A, + VK_B, SWTVK_B, + VK_C, SWTVK_C, + VK_D, SWTVK_D, + VK_E, SWTVK_E, + VK_F, SWTVK_F, + VK_G, SWTVK_G, + VK_H, SWTVK_H, + VK_I, SWTVK_I, + VK_J, SWTVK_J, + VK_K, SWTVK_K, + VK_L, SWTVK_L, + VK_M, SWTVK_M, + VK_N, SWTVK_N, + VK_O, SWTVK_O, + VK_P, SWTVK_P, + VK_Q, SWTVK_Q, + VK_R, SWTVK_R, + VK_S, SWTVK_S, + VK_T, SWTVK_T, + VK_U, SWTVK_U, + VK_V, SWTVK_V, + VK_W, SWTVK_W, + VK_X, SWTVK_X, + VK_Y, SWTVK_Y, + VK_Z, SWTVK_Z, + VK_OPEN_BRACKET, SWTVK_OPEN_BRACKET, + VK_BACK_SLASH, SWTVK_BACK_SLASH, + VK_CLOSE_BRACKET, SWTVK_CLOSE_BRACKET, + VK_NUMPAD0, SWTVK_0, + VK_NUMPAD1, SWTVK_1, + VK_NUMPAD2, SWTVK_2, + VK_NUMPAD3, SWTVK_3, + VK_NUMPAD4, SWTVK_4, + VK_NUMPAD5, SWTVK_5, + VK_NUMPAD6, SWTVK_6, + VK_NUMPAD7, SWTVK_7, + VK_NUMPAD8, SWTVK_8, + VK_NUMPAD9, SWTVK_9, + VK_MULTIPLY, SWTVK_MULTIPLY, + VK_ADD, SWTVK_ADD, + VK_SEPARATOR, SWTVK_SEPARATOR, + VK_SUBTRACT, SWTVK_SUBTRACT, + VK_DECIMAL, SWTVK_DECIMAL, + VK_DIVIDE, SWTVK_DIVIDE, + VK_DELETE, SWTVK_DELETE, + VK_NUM_LOCK, SWTVK_NUM_LOCK, + VK_SCROLL_LOCK, SWTVK_SCROLL_LOCK, + VK_F1, SWTVK_F1, + VK_F2, SWTVK_F2, + VK_F3, SWTVK_F3, + VK_F4, SWTVK_F4, + VK_F5, SWTVK_F5, + VK_F6, SWTVK_F6, + VK_F7, SWTVK_F7, + VK_F8, SWTVK_F8, + VK_F9, SWTVK_F9, + VK_F10, SWTVK_F10, + VK_F11, SWTVK_F11, + VK_F12, SWTVK_F12, + VK_PRINTSCREEN, SWTVK_PRINTSCREEN, + VK_INSERT, SWTVK_INSERT, + VK_HELP, SWTVK_HELP, + VK_META, SWTVK_META, + VK_BACK_QUOTE, SWTVK_BACK_QUOTE, + VK_QUOTE, SWTVK_QUOTE, + VK_KP_UP, SWTVK_UP, + VK_KP_DOWN, SWTVK_DOWN, + VK_KP_LEFT, SWTVK_LEFT, + VK_KP_RIGHT, SWTVK_RIGHT, + VK_AMPERSAND, SWTVK_AMPERSAND, + VK_ASTERISK, SWTVK_ASTERISK, + VK_QUOTEDBL, SWTVK_QUOTEDBL, + VK_LESS, SWTVK_LESS, + VK_GREATER, SWTVK_GREATER, + VK_BRACELEFT, SWTVK_BRACELEFT, + VK_BRACERIGHT, SWTVK_BRACERIGHT, + VK_AT, SWTVK_AT, + VK_COLON, SWTVK_COLON, + VK_CIRCUMFLEX, SWTVK_CIRCUMFLEX, + VK_DOLLAR, SWTVK_DOLLAR, + VK_EURO_SIGN, SWTVK_EURO_SIGN, + VK_EXCLAMATION_MARK, SWTVK_EXCLAMATION_MARK, + VK_INVERTED_EXCLAMATION_MARK, SWTVK_INVERTED_EXCLAMATION_MARK, + VK_LEFT_PARENTHESIS, SWTVK_LEFT_PARENTHESIS, + VK_NUMBER_SIGN, SWTVK_NUMBER_SIGN, + VK_PLUS, SWTVK_PLUS, + VK_RIGHT_PARENTHESIS, SWTVK_RIGHT_PARENTHESIS, + VK_UNDERSCORE, SWTVK_UNDERSCORE, + VK_A, SWTVK_A + 32, + VK_B, SWTVK_B + 32, + VK_C, SWTVK_C + 32, + VK_D, SWTVK_D + 32, + VK_E, SWTVK_E + 32, + VK_F, SWTVK_F + 32, + VK_G, SWTVK_G + 32, + VK_H, SWTVK_H + 32, + VK_I, SWTVK_I + 32, + VK_J, SWTVK_J + 32, + VK_K, SWTVK_K + 32, + VK_L, SWTVK_L + 32, + VK_M, SWTVK_M + 32, + VK_N, SWTVK_N + 32, + VK_O, SWTVK_O + 32, + VK_P, SWTVK_P + 32, + VK_Q, SWTVK_Q + 32, + VK_R, SWTVK_R + 32, + VK_S, SWTVK_S + 32, + VK_T, SWTVK_T + 32, + VK_U, SWTVK_U + 32, + VK_V, SWTVK_V + 32, + VK_W, SWTVK_W + 32, + VK_X, SWTVK_X + 32, + VK_Y, SWTVK_Y + 32, + VK_Z, SWTVK_Z + 32, + }; +} diff --git a/src/java/com/agynamix/platform/frontend/gui/OsSupportHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/OsSupportHotkeyRegistrar.java new file mode 100644 index 0000000..1ce3028 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/OsSupportHotkeyRegistrar.java @@ -0,0 +1,129 @@ +package com.agynamix.platform.frontend.gui; + +import java.util.HashMap; +import java.util.Map; + +import com.agynamix.ossupport.HotKeyDesc; +import com.agynamix.ossupport.HotkeyListener; +import com.agynamix.ossupport.OsSupport; + +/** + * @author tuhlmann + * + */ +public class OsSupportHotkeyRegistrar implements IHotkeyRegistrar, HotkeyListener { + + Map listenerMap = new HashMap(); + + int currentHotkeyId = 1; + boolean hotkeysEnabled = true; + + public OsSupportHotkeyRegistrar() + { + try + { + if (OsSupport.checkInstanceAlreadyRunning()) + { + System.out.println("AGYNAMIX OsSupport started twice"); + } + // next check to make sure JIntellitype DLL can be found and we are on + // a Windows operating System + if (!OsSupport.isSupported(OsSupport.TypeSupported.OS)) + { + hotkeysEnabled = false; + } else { + initOsSupport(); + } + } catch (Throwable e) + { + System.out.println("Error initializing native Mac support: "+e.getMessage()); + hotkeysEnabled = false; + } + + } + + public void initOsSupport() + { + try + { + // initialize JIntellitype with the frame so all windows commands can + // be attached to this window + OsSupport.getInstance().addHotKeyListener(this); +// System.out.println("JIntellitype initialized"); + } catch (RuntimeException ex) + { + ex.printStackTrace(); + System.out.println("Your operating system is not supported by the OsSupport library."); + } + } + + public boolean isEnabled() + { + return hotkeysEnabled; + } + + /** + * Currently only works with a 1:1 relationship between Hotkey and listener + */ + public void addHotkeyListener(String hotkeyCombination, IHotkeyListener listener) + { + if (hotkeysEnabled) + { + HotKeyDesc hotkey = parseHotkeyDefinition(hotkeyCombination); + + // System.out.println("modKey="+modKey); + // System.out.println("hotKey="+hotKey); + OsSupport.getInstance().registerHotKey(currentHotkeyId, hotkey); + listenerMap.put(currentHotkeyId, new HotkeyListenerInfo(this, currentHotkeyId, hotkey, listener)); + // System.out.println("JIntellitypeHotkeyRegistrar.addHotkeyListener called"); + currentHotkeyId++; + } + } + + public void onHotKey(int hotkeyId) + { + HotkeyListenerInfo listenerInfo = listenerMap.get(hotkeyId); + if (listenerInfo != null) + { + listenerInfo.onHotkey(hotkeyId); + } else { + //System.out.println("No listener registered for id "+hotkeyId); + } + + } + + public void unregisterHotkeys() + { + if (hotkeysEnabled) + { + for (Object o : listenerMap.keySet()) + { + OsSupport.getInstance().unregisterHotKey(((Integer)o).intValue()); + // System.out.println("Remove hotkeyId "+o); + } + listenerMap.clear(); + } + } + + public void activateGlobalPaste(HotkeyListenerInfo listenerInfo) + { + if (hotkeysEnabled) + { + if (OsSupport.isSupported(OsSupport.TypeSupported.PASTE)) + { + OsSupport.getInstance().activateGlobalePaste(listenerInfo.getHotKeyDesc()); + } + } + } + + public HotKeyDesc parseHotkeyDefinition(String hotKeyStr) + { + if (hotkeysEnabled) { + return OsSupport.getInstance().parseHotkeyDefinition(hotKeyStr); + } else { + return null; + } + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/PlaceboHotkeyRegistrar.java b/src/java/com/agynamix/platform/frontend/gui/PlaceboHotkeyRegistrar.java new file mode 100644 index 0000000..7d50177 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/PlaceboHotkeyRegistrar.java @@ -0,0 +1,31 @@ +package com.agynamix.platform.frontend.gui; + +public class PlaceboHotkeyRegistrar extends AbstractHotkeyRegistrar { + + public boolean isEnabled() + { + return false; + } + + public void addHotkeyListener(String hotkeyCombination, IHotkeyListener listener) + { +// System.out.println("PlaceboHotkeyRegistrar.addHotkeyListener called"); + } + + public void unregisterHotkeys() + { +// System.out.println("PlaceboHotkeyRegistrar.unregisterHotkeys called"); + } + + public void activateGlobalPaste(HotkeyListenerInfo listenerInfo) + { +// System.out.println("PlaceboHotkeyRegistrar.activateGlobalPaste called"); + } + + @Override + protected int tokenToModifier(String token) + { + return 0; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/gui/x11/X11.java b/src/java/com/agynamix/platform/frontend/gui/x11/X11.java new file mode 100644 index 0000000..426268a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/gui/x11/X11.java @@ -0,0 +1,1893 @@ +/* Copyright (c) 2007 Timothy Wall, All Rights Reserved +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +*

+* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +*/ +package com.agynamix.platform.frontend.gui.x11; + +import com.sun.jna.FromNativeContext; +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; +import com.sun.jna.PointerType; +import com.sun.jna.Structure; +import com.sun.jna.Union; +import com.sun.jna.ptr.ByReference; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.NativeLongByReference; +import com.sun.jna.ptr.PointerByReference; + +/** Definition (incomplete) of the X library. */ +public interface X11 extends Library { + + class VisualID extends NativeLong { + private static final long serialVersionUID = 6193026617691868548L; + public VisualID() { } + public VisualID(long value) { super(value); } + } + + class XID extends NativeLong { + private static final long serialVersionUID = -6266868873222788404L; + public static final XID None = null; + public XID() { this(0); } + public XID(long id) { super(id); } + protected boolean isNone(Object o) { + return o == null + || (o instanceof Number + && ((Number)o).longValue() == X11.None); + } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new XID(((Number)nativeValue).longValue()); + } + public String toString() { + return "0x" + Long.toHexString(longValue()); + } + } + class Atom extends XID { + private static final long serialVersionUID = -6025382529265492148L; + public static final Atom None = null; + public Atom() { } + public Atom(long id) { super(id); } + /** Return constants for predefined Atom values. */ + public Object fromNative(Object nativeValue, FromNativeContext context) { + long value = ((Number)nativeValue).longValue(); + if (value <= Integer.MAX_VALUE) { + switch((int)value) { + case 0: return None; + case 1: return XA_PRIMARY; + case 2: return XA_SECONDARY; + case 3: return XA_ARC; + case 4: return XA_ATOM; + case 5: return XA_BITMAP; + case 6: return XA_CARDINAL; + case 7: return XA_COLORMAP; + case 8: return XA_CURSOR; + case 9: return XA_CUT_BUFFER0; + case 10: return XA_CUT_BUFFER1; + case 11: return XA_CUT_BUFFER2; + case 12: return XA_CUT_BUFFER3; + case 13: return XA_CUT_BUFFER4; + case 14: return XA_CUT_BUFFER5; + case 15: return XA_CUT_BUFFER6; + case 16: return XA_CUT_BUFFER7; + case 17: return XA_DRAWABLE; + case 18: return XA_FONT; + case 19: return XA_INTEGER; + case 20: return XA_PIXMAP; + case 21: return XA_POINT; + case 22: return XA_RECTANGLE; + case 23: return XA_RESOURCE_MANAGER; + case 24: return XA_RGB_COLOR_MAP; + case 25: return XA_RGB_BEST_MAP; + case 26: return XA_RGB_BLUE_MAP; + case 27: return XA_RGB_DEFAULT_MAP; + case 28: return XA_RGB_GRAY_MAP; + case 29: return XA_RGB_GREEN_MAP; + case 30: return XA_RGB_RED_MAP; + case 31: return XA_STRING; + case 32: return XA_VISUALID; + case 33: return XA_WINDOW; + case 34: return XA_WM_COMMAND; + case 35: return XA_WM_HINTS; + case 36: return XA_WM_CLIENT_MACHINE; + case 37: return XA_WM_ICON_NAME; + case 38: return XA_WM_ICON_SIZE; + case 39: return XA_WM_NAME; + case 40: return XA_WM_NORMAL_HINTS; + case 41: return XA_WM_SIZE_HINTS; + case 42: return XA_WM_ZOOM_HINTS; + case 43: return XA_MIN_SPACE; + case 44: return XA_NORM_SPACE; + case 45: return XA_MAX_SPACE; + case 46: return XA_END_SPACE; + case 47: return XA_SUPERSCRIPT_X; + case 48: return XA_SUPERSCRIPT_Y; + case 49: return XA_SUBSCRIPT_X; + case 50: return XA_SUBSCRIPT_Y; + case 51: return XA_UNDERLINE_POSITION; + case 52: return XA_UNDERLINE_THICKNESS; + case 53: return XA_STRIKEOUT_ASCENT; + case 54: return XA_STRIKEOUT_DESCENT; + case 55: return XA_ITALIC_ANGLE; + case 56: return XA_X_HEIGHT; + case 57: return XA_QUAD_WIDTH; + case 58: return XA_WEIGHT; + case 59: return XA_POINT_SIZE; + case 60: return XA_RESOLUTION; + case 61: return XA_COPYRIGHT; + case 62: return XA_NOTICE; + case 63: return XA_FONT_NAME; + case 64: return XA_FAMILY_NAME; + case 65: return XA_FULL_NAME; + case 66: return XA_CAP_HEIGHT; + case 67: return XA_WM_CLASS; + case 68: return XA_WM_TRANSIENT_FOR; + default: + } + } + return new Atom(value); + } + } + class AtomByReference extends ByReference { + public AtomByReference() { super(XID.SIZE); } + public Atom getValue() { + NativeLong value = getPointer().getNativeLong(0); + return (Atom)new Atom().fromNative(value, null); + } + } + class Colormap extends XID { + private static final long serialVersionUID = -8865724028114796414L; + public static final Colormap None = null; + public Colormap() { } + public Colormap(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Colormap(((Number)nativeValue).longValue()); + } + } + class Font extends XID { + private static final long serialVersionUID = 7406717014178896866L; + public static final Font None = null; + public Font() { } + public Font(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Font(((Number)nativeValue).longValue()); + } + } + class Cursor extends XID { + private static final long serialVersionUID = 5620711837331314122L; + public static final Cursor None = null; + public Cursor() { } + public Cursor(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Cursor(((Number)nativeValue).longValue()); + } + } + class KeySym extends XID { + private static final long serialVersionUID = -9097834479465072104L; + public static final KeySym None = null; + public KeySym() { } + public KeySym(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new KeySym(((Number)nativeValue).longValue()); + } + } + class Drawable extends XID { + private static final long serialVersionUID = -1587544291026121638L; + public static final Drawable None = null; + public Drawable() { } + public Drawable(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Drawable(((Number)nativeValue).longValue()); + } + } + class Window extends Drawable { + private static final long serialVersionUID = 8914937811536206468L; + public static final Window None = null; + public Window() { } + public Window(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Window(((Number)nativeValue).longValue()); + } + } + class WindowByReference extends ByReference { + public WindowByReference() { super(XID.SIZE); } + public Window getValue() { + NativeLong value = getPointer().getNativeLong(0); + return value.longValue() == X11.None + ? Window.None : new Window(value.longValue()); + } + } + class Pixmap extends Drawable { + private static final long serialVersionUID = 1255707082854132125L; + public static final Pixmap None = null; + public Pixmap() { } + public Pixmap(long id) { super(id); } + public Object fromNative(Object nativeValue, FromNativeContext context) { + if (isNone(nativeValue)) { + return None; + } + return new Pixmap(((Number)nativeValue).longValue()); + } + } + // TODO: define structure + class Display extends PointerType { } + // TODO: define structure + class Visual extends PointerType { + public NativeLong getVisualID() { + if (getPointer() != null) { + return getPointer().getNativeLong(Native.POINTER_SIZE); + } + return new NativeLong(0); + } + public String toString() { + return "Visual: VisualID=0x" + Long.toHexString(getVisualID().longValue()); + } + } + // TODO: define structure + class Screen extends PointerType { } + // TODO: define structure + class GC extends PointerType { } + // TODO: define structure + class XImage extends PointerType { } + + /** Definition (incomplete) of the Xext library. */ + interface Xext extends Library { + Xext INSTANCE = (Xext)Native.loadLibrary("Xext", Xext.class); + // Shape Kinds + int ShapeBounding = 0; + int ShapeClip = 1; + int ShapeInput = 2; + // Operations + int ShapeSet = 0; + int ShapeUnion = 1; + int ShapeIntersect = 2; + int ShapeSubtract = 3; + int ShapeInvert = 4; + + void XShapeCombineMask(Display display, Window window, int dest_kind, + int x_off, int y_off, Pixmap src, int op); + } + + /** Definition (incomplete) of the Xrender library. */ + interface Xrender extends Library { + Xrender INSTANCE = (Xrender)Native.loadLibrary("Xrender", Xrender.class); + class XRenderDirectFormat extends Structure { + public short red, redMask; + public short green, greenMask; + public short blue, blueMask; + public short alpha, alphaMask; + } + class PictFormat extends NativeLong { + private static final long serialVersionUID = 1516972470097828137L; + public PictFormat(long value) { super(value); } + public PictFormat() { } + } + class XRenderPictFormat extends Structure { + public PictFormat id; + public int type; + public int depth; + public XRenderDirectFormat direct; + public Colormap colormap; + } + int PictTypeIndexed = 0x0; + int PictTypeDirect = 0x1; + XRenderPictFormat XRenderFindVisualFormat(Display display, Visual visual); + } + + /** Definition of the Xevie library. */ + interface Xevie extends Library { + /** Instance of Xevie. Note: This extension has been removed from xorg/xserver on Oct 22, 2008 because it is broken and maintainerless. */ + Xevie INSTANCE = (Xevie)Native.loadLibrary("Xevie", Xevie.class); + int XEVIE_UNMODIFIED = 0; + int XEVIE_MODIFIED = 1; + // Bool XevieQueryVersion (Display* display, int* major_version, int* minor_version); + boolean XevieQueryVersion (Display display, IntByReference major_version, IntByReference minor_version); + // Status XevieStart (Display* display); + int XevieStart (Display display); + // Status XevieEnd (Display* display); + int XevieEnd (Display display); + // Status XevieSendEvent (Display* display, XEvent* event, int data_type); + int XevieSendEvent (Display display, XEvent event, int data_type); + // Status XevieSelectInput (Display* display, NativeLong event_mask); + int XevieSelectInput (Display display, NativeLong event_mask); + } + + /** Definition of the XTest library. */ + interface XTest extends Library { + XTest INSTANCE = (XTest)Native.loadLibrary("Xtst", XTest.class);///usr/lib/libxcb-xtest.so.0 + boolean XTestQueryExtension(Display display, IntByReference event_basep, IntByReference error_basep, IntByReference majorp, IntByReference minorp); + boolean XTestCompareCursorWithWindow(Display display, Window window, Cursor cursor); + boolean XTestCompareCurrentCursorWithWindow(Display display, Window window); + // extern int XTestFakeKeyEvent(Display* display, unsigned int keycode, Bool is_press, unsigned long delay); + int XTestFakeKeyEvent(Display display, int keycode, boolean is_press, NativeLong delay); + int XTestFakeButtonEvent(Display display, int button, boolean is_press, NativeLong delay); + int XTestFakeMotionEvent(Display display, int screen, int x, int y, NativeLong delay); + int XTestFakeRelativeMotionEvent(Display display, int x, int y, NativeLong delay); + int XTestFakeDeviceKeyEvent(Display display, XDeviceByReference dev, int keycode, boolean is_press, IntByReference axes, int n_axes, NativeLong delay); + int XTestFakeDeviceButtonEvent(Display display, XDeviceByReference dev, int button, boolean is_press, IntByReference axes, int n_axes, NativeLong delay); + int XTestFakeProximityEvent(Display display, XDeviceByReference dev, boolean in_prox, IntByReference axes, int n_axes, NativeLong delay); + int XTestFakeDeviceMotionEvent(Display display, XDeviceByReference dev, boolean is_relative, int first_axis, IntByReference axes, int n_axes, NativeLong delay); + int XTestGrabControl(Display display, boolean impervious); + //void XTestSetGContextOfGC(GC gc, GContext gid); + void XTestSetVisualIDOfVisual(Visual visual, VisualID visualid); + int XTestDiscard(Display display); + } + + class XInputClassInfoByReference extends Structure implements Structure.ByReference { + public byte input_class; + public byte event_type_base; + } + + class XDeviceByReference extends Structure implements Structure.ByReference { + public XID device_id; + public int num_classes; + public XInputClassInfoByReference classes; + } + + X11 INSTANCE = (X11)Native.loadLibrary("X11", X11.class); + + /* + typedef struct { + long flags; // marks which fields in this structure are defined + Bool input; // does this application rely on the window manager to + // get keyboard input? + int initial_state; // see below + Pixmap icon_pixmap; // pixmap to be used as icon + Window icon_window; // window to be used as icon + int icon_x, icon_y; // initial position of icon + Pixmap icon_mask; // icon mask bitmap + XID window_group; // id of related window group + // this structure may be extended in the future + } XWMHints; + */ + class XWMHints extends Structure { + public NativeLong flags; + public boolean input; + public int initial_state; + public Pixmap icon_pixmap; + public Window icon_window; + public int icon_x, icon_y; + public Pixmap icon_mask; + public XID window_group; + } + + /* + typedef struct { + unsigned char *value; // same as Property routines + Atom encoding; // prop type + int format; // prop data format: 8, 16, or 32 + unsigned long nitems; // number of data items in value + } XTextProperty; + */ + class XTextProperty extends Structure { + public String value; + public Atom encoding; + public int format; + public NativeLong nitems; + } + + /* + typedef struct { + long flags; // marks which fields in this structure are defined + int x, y; // obsolete for new window mgrs, but clients + int width, height; /// should set so old wm's don't mess up + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; + struct { + int x; // numerator + int y; // denominator + } min_aspect, max_aspect; + int base_width, base_height; // added by ICCCM version 1 + int win_gravity; // added by ICCCM version 1 + } XSizeHints; + */ + class XSizeHints extends Structure { + public NativeLong flags; + public int x, y; + public int width, height; + public int min_width, min_height; + public int max_width, max_height; + public int width_inc, height_inc; + public static class Aspect extends Structure { + public int x; // numerator + public int y; // denominator + } + public Aspect min_aspect, max_aspect; + public int base_width, base_height; + public int win_gravity; + } + + /* + typedef struct { + int x, y; // location of window + int width, height; // width and height of window + int border_width; // border width of window + int depth; // depth of window + Visual *visual; // the associated visual structure + Window root; // root of screen containing window +#if defined(__cplusplus) || defined(c_plusplus) + int c_class; // C++ InputOutput, InputOnly +#else + int class; // InputOutput, InputOnly +#endif + int bit_gravity; // one of bit gravity values + int win_gravity; // one of the window gravity values + int backing_store; // NotUseful, WhenMapped, Always + unsigned long backing_planes;// planes to be preserved if possible + unsigned long backing_pixel;// value to be used when restoring planes + Bool save_under; // boolean, should bits under be saved? + Colormap colormap; // color map to be associated with window + Bool map_installed; // boolean, is color map currently installed + int map_state; // IsUnmapped, IsUnviewable, IsViewable + long all_event_masks; // set of events all people have interest in + long your_event_mask; // my event mask + long do_not_propagate_mask; // set of events that should not propagate + Bool override_redirect; // boolean value for override-redirect + Screen *screen; // back pointer to correct screen + } XWindowAttributes; + */ + class XWindowAttributes extends Structure { + public int x, y; + public int width, height; + public int border_width; + public int depth; + public Visual visual; + public Window root; + public int c_class; + public int bit_gravity; + public int win_gravity; + public int backing_store; + public NativeLong backing_planes; + public NativeLong backing_pixel; + public boolean save_under; + public Colormap colormap; + public boolean map_installed; + public int map_state; + public NativeLong all_event_masks; + public NativeLong your_event_mask; + public NativeLong do_not_propagate_mask; + public boolean override_redirect; + public Screen screen; + } + + /* + typedef struct { + Pixmap background_pixmap; // background or None or ParentRelative + unsigned long background_pixel; // background pixel + Pixmap border_pixmap; // border of the window + unsigned long border_pixel; // border pixel value + int bit_gravity; // one of bit gravity values + int win_gravity; // one of the window gravity values + int backing_store; // NotUseful, WhenMapped, Always + unsigned long backing_planes;// planes to be preseved if possible + unsigned long backing_pixel;// value to use in restoring planes + Bool save_under; // should bits under be saved? (popups) + long event_mask; // set of events that should be saved + long do_not_propagate_mask; // set of events that should not propagate + Bool override_redirect; // boolean value for override-redirect + Colormap colormap; // color map to be associated with window + Cursor cursor; // cursor to be displayed (or None) + } XSetWindowAttributes; + */ + class XSetWindowAttributes extends Structure { + public Pixmap background_pixmap; + public NativeLong background_pixel; + public Pixmap border_pixmap; + public NativeLong border_pixel; + public int bit_gravity; + public int win_gravity; + public int backing_store; + public NativeLong backing_planes; + public NativeLong backing_pixel; + public boolean save_under; + public NativeLong event_mask; + public NativeLong do_not_propagate_mask; + public boolean override_redirect; + public Colormap colormap; + public Cursor cursor; + } + + int XK_0 = 0x30; + int XK_9 = 0x39; + int XK_A = 0x41; + int XK_Z = 0x5a; + int XK_a = 0x61; + int XK_z = 0x7a; + int XK_Shift_L = 0xffe1; + int XK_Shift_R = 0xffe1; + int XK_Control_L = 0xffe3; + int XK_Control_R = 0xffe4; + int XK_CapsLock = 0xffe5; + int XK_ShiftLock = 0xffe6; + int XK_Meta_L = 0xffe7; + int XK_Meta_R = 0xffe8; + int XK_Alt_L = 0xffe9; + int XK_Alt_R = 0xffea; + + int VisualNoMask = 0x0; + int VisualIDMask = 0x1; + int VisualScreenMask = 0x2; + int VisualDepthMask = 0x4; + int VisualClassMask = 0x8; + int VisualRedMaskMask = 0x10; + int VisualGreenMaskMask = 0x20; + int VisualBlueMaskMask = 0x40; + int VisualColormapSizeMask = 0x80; + int VisualBitsPerRGBMask = 0x100; + int VisualAllMask = 0x1FF; + + class XVisualInfo extends Structure { + public Visual visual; + public VisualID visualid; + public int screen; + public int depth; + public int c_class; + public NativeLong red_mask; + public NativeLong green_mask; + public NativeLong blue_mask; + public int colormap_size; + public int bits_per_rgb; + } + class XPoint extends Structure { + public short x, y; + public XPoint() { } + public XPoint(short x, short y) { + this.x = x; + this.y = y; + } + } + class XRectangle extends Structure { + public short x, y; + public short width, height; + public XRectangle() { } + public XRectangle(short x, short y, short width, short height) { + this.x = x; this.y = y; + this.width = width; this.height = height; + } + } + + Atom XA_PRIMARY = new Atom(1); + Atom XA_SECONDARY = new Atom(2); + Atom XA_ARC = new Atom(3); + Atom XA_ATOM = new Atom(4); + Atom XA_BITMAP = new Atom(5); + Atom XA_CARDINAL = new Atom(6); + Atom XA_COLORMAP = new Atom(7); + Atom XA_CURSOR = new Atom(8); + Atom XA_CUT_BUFFER0 = new Atom(9); + Atom XA_CUT_BUFFER1 = new Atom(10); + Atom XA_CUT_BUFFER2 = new Atom(11); + Atom XA_CUT_BUFFER3 = new Atom(12); + Atom XA_CUT_BUFFER4 = new Atom(13); + Atom XA_CUT_BUFFER5 = new Atom(14); + Atom XA_CUT_BUFFER6 = new Atom(15); + Atom XA_CUT_BUFFER7 = new Atom(16); + Atom XA_DRAWABLE = new Atom(17); + Atom XA_FONT = new Atom(18); + Atom XA_INTEGER = new Atom(19); + Atom XA_PIXMAP = new Atom(20); + Atom XA_POINT = new Atom(21); + Atom XA_RECTANGLE = new Atom(22); + Atom XA_RESOURCE_MANAGER = new Atom(23); + Atom XA_RGB_COLOR_MAP = new Atom(24); + Atom XA_RGB_BEST_MAP = new Atom(25); + Atom XA_RGB_BLUE_MAP = new Atom(26); + Atom XA_RGB_DEFAULT_MAP = new Atom(27); + Atom XA_RGB_GRAY_MAP = new Atom(28); + Atom XA_RGB_GREEN_MAP = new Atom(29); + Atom XA_RGB_RED_MAP = new Atom(30); + Atom XA_STRING = new Atom(31); + Atom XA_VISUALID = new Atom(32); + Atom XA_WINDOW = new Atom(33); + Atom XA_WM_COMMAND = new Atom(34); + Atom XA_WM_HINTS = new Atom(35); + Atom XA_WM_CLIENT_MACHINE = new Atom(36); + Atom XA_WM_ICON_NAME = new Atom(37); + Atom XA_WM_ICON_SIZE = new Atom(38); + Atom XA_WM_NAME = new Atom(39); + Atom XA_WM_NORMAL_HINTS = new Atom(40); + Atom XA_WM_SIZE_HINTS = new Atom(41); + Atom XA_WM_ZOOM_HINTS = new Atom(42); + Atom XA_MIN_SPACE = new Atom(43); + Atom XA_NORM_SPACE = new Atom(44); + Atom XA_MAX_SPACE = new Atom(45); + Atom XA_END_SPACE = new Atom(46); + Atom XA_SUPERSCRIPT_X = new Atom(47); + Atom XA_SUPERSCRIPT_Y = new Atom(48); + Atom XA_SUBSCRIPT_X = new Atom(49); + Atom XA_SUBSCRIPT_Y = new Atom(50); + Atom XA_UNDERLINE_POSITION = new Atom(51); + Atom XA_UNDERLINE_THICKNESS = new Atom(52); + Atom XA_STRIKEOUT_ASCENT = new Atom(53); + Atom XA_STRIKEOUT_DESCENT = new Atom(54); + Atom XA_ITALIC_ANGLE = new Atom(55); + Atom XA_X_HEIGHT = new Atom(56); + Atom XA_QUAD_WIDTH = new Atom(57); + Atom XA_WEIGHT = new Atom(58); + Atom XA_POINT_SIZE = new Atom(59); + Atom XA_RESOLUTION = new Atom(60); + Atom XA_COPYRIGHT = new Atom(61); + Atom XA_NOTICE = new Atom(62); + Atom XA_FONT_NAME = new Atom(63); + Atom XA_FAMILY_NAME = new Atom(64); + Atom XA_FULL_NAME = new Atom(65); + Atom XA_CAP_HEIGHT = new Atom(66); + Atom XA_WM_CLASS = new Atom(67); + Atom XA_WM_TRANSIENT_FOR = new Atom(68); + Atom XA_LAST_PREDEFINED = XA_WM_TRANSIENT_FOR; + + Display XOpenDisplay(String name); + int XGetErrorText(Display display, int code, byte[] buffer, int len); + int XDefaultScreen(Display display); + Screen DefaultScreenOfDisplay(Display display); + Visual XDefaultVisual(Display display, int screen); + Colormap XDefaultColormap(Display display, int screen); + int XDisplayWidth(Display display, int screen); + int XDisplayHeight(Display display, int screen); + Window XDefaultRootWindow(Display display); + Window XRootWindow(Display display, int screen); + int XAllocNamedColor(Display display, int colormap, String color_name, + Pointer screen_def_return, Pointer exact_def_return); + XSizeHints XAllocSizeHints(); + void XSetWMProperties(Display display, Window window, String window_name, + String icon_name, String[] argv, int argc, + XSizeHints normal_hints, Pointer wm_hints, + Pointer class_hints); + int XFree(Pointer data); + Window XCreateSimpleWindow(Display display, Window parent, int x, int y, + int width, int height, int border_width, + int border, int background); + Pixmap XCreateBitmapFromData(Display display, Window window, Pointer data, + int width, int height); + int XMapWindow(Display display, Window window); + int XMapRaised(Display display, Window window); + int XMapSubwindows(Display display, Window window); + + /** Flushes the output buffer. Most client applications need not use this function because the output buffer is automatically flushed as needed by calls to XPending, XNextEvent, and XWindowEvent. Events generated by the server may be enqueued into the library's event queue. */ + int XFlush(Display display); + /** Flushes the output buffer and then waits until all requests have been received and processed by the X server. Any errors generated must be handled by the error handler. For each protocol error received by Xlib, XSync calls the client application's error handling routine (see section 11.8.2). Any events generated by the server are enqueued into the library's event queue.
Finally, if you passed False, XSync does not discard the events in the queue. If you passed True, XSync discards all events in the queue, including those events that were on the queue before XSync was called. Client applications seldom need to call XSync. */ + int XSync(Display display, boolean discard); + /** If mode is QueuedAlready, XEventsQueued returns the number of events already in the event queue (and never performs a system call). If mode is QueuedAfterFlush, XEventsQueued returns the number of events already in the queue if the number is nonzero. If there are no events in the queue, XEventsQueued flushes the output buffer, attempts to read more events out of the application's connection, and returns the number read. If mode is QueuedAfterReading, XEventsQueued returns the number of events already in the queue if the number is nonzero. If there are no events in the queue, XEventsQueued attempts to read more events out of the application's connection without flushing the output buffer and returns the number read.
XEventsQueued always returns immediately without I/O if there are events already in the queue. XEventsQueued with mode QueuedAfterFlush is identical in behavior to XPending. XEventsQueued with mode QueuedAlready is identical to the XQLength function. */ + int XEventsQueued(Display display, int mode); + /** Returns the number of events that have been received from the X server but have not been removed from the event queue. XPending is identical to XEventsQueued with the mode QueuedAfterFlush specified. */ + int XPending(Display display); + + int XUnmapWindow(Display display, Window window); + int XDestroyWindow(Display display, Window window); + int XCloseDisplay(Display display); + int XClearWindow(Display display, Window window); + int XClearArea(Display display, Window window, int x, int y, int w, int h, int exposures); + Pixmap XCreatePixmap(Display display, Drawable drawable, int width, int height, int depth); + int XFreePixmap(Display display, Pixmap pixmap); + class XGCValues extends Structure { + public int function; /* logical operation */ + public NativeLong plane_mask;/* plane mask */ + public NativeLong foreground;/* foreground pixel */ + public NativeLong background;/* background pixel */ + public int line_width; /* line width (in pixels) */ + public int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash*/ + public int cap_style; /* CapNotLast, CapButt, CapRound, CapProjecting */ + public int join_style; /* JoinMiter, JoinRound, JoinBevel */ + public int fill_style; /* FillSolid, FillTiled, FillStippled FillOpaqueStippled*/ + public int fill_rule; /* EvenOddRule, WindingRule */ + public int arc_mode; /* ArcChord, ArcPieSlice */ + public Pixmap tile; /* tile pixmap for tiling operations */ + public Pixmap stipple; /* stipple 1 plane pixmap for stippling */ + public int ts_x_origin; /* offset for tile or stipple operations */ + public int ts_y_origin; + public Font font; /* default text font for text operations */ + public int subwindow_mode; /* ClipByChildren, IncludeInferiors */ + public boolean graphics_exposures; /* boolean, should exposures be generated */ + public int clip_x_origin; /* origin for clipping */ + public int clip_y_origin; + public Pixmap clip_mask; /* bitmap clipping; other calls for rects */ + public int dash_offset; /* patterned/dashed line information */ + public byte dashes; + } + GC XCreateGC(Display display, Drawable drawable, NativeLong mask, XGCValues values); + int XSetFillRule(Display display, GC gc, int fill_rule); + int XFreeGC(Display display, GC gc); + int XDrawPoint(Display display, Drawable drawable, GC gc, int x, int y); + int XDrawPoints(Display display, Drawable drawable, GC gc, + XPoint[] points, int npoints, int mode); + int XFillRectangle(Display display, Drawable drawable, GC gc, + int x, int y, int width, int height); + int XFillRectangles(Display display, Drawable drawable, GC gc, + XRectangle[] rectangles, int nrectangles); + int XSetForeground(Display display, GC gc, NativeLong color); + int XSetBackground(Display display, GC gc, NativeLong color); + int XFillArc(Display display, Drawable drawable, GC gc, int x, int y, + int width, int height, int angle1, int angle2); + int XFillPolygon(Display dpy, Drawable drawable, GC gc, XPoint[] points, + int npoints, int shape, int mode); + int XQueryTree(Display display, Window window, WindowByReference root, + WindowByReference parent, PointerByReference children, + IntByReference childCount); + boolean XQueryPointer(Display display, Window window, + WindowByReference root_return, + WindowByReference child_return, + IntByReference root_x_return, + IntByReference root_y_return, + IntByReference win_x_return, + IntByReference win_y_return, + IntByReference mask_return); + int XGetWindowAttributes(Display display, Window window, XWindowAttributes attributes); + int XChangeWindowAttributes(Display display, Window window, NativeLong valuemask, XSetWindowAttributes attributes); + // Status XGetGeometry(Display *display, Drawable d, Window *root_return, int *x_return, int *y_return, unsigned int *width_return, + // unsigned int *height_return, unsigned int *border_width_return, unsigned int *depth_return); + int XGetGeometry(Display display, Drawable d, WindowByReference w, IntByReference x, IntByReference y, IntByReference width, + IntByReference heigth, IntByReference border_width, IntByReference depth); + // Bool XTranslateCoordinates(Display *display, Window src_w, dest_w, int src_x, int src_y, + // int *dest_x_return, int *dest_y_return, Window *child_return); + boolean XTranslateCoordinates(Display display, Window src_w, Window dest_w, int src_x, int src_y, + IntByReference dest_x_return, IntByReference dest_y_return, WindowByReference child_return); + + /***************************************************************** + * RESERVED RESOURCE AND CONSTANT DEFINITIONS + *****************************************************************/ + + int None = 0; /* universal null resource or null atom */ + int ParentRelative = 1; /* background pixmap in CreateWindow and ChangeWindowAttributes */ + int CopyFromParent = 0; /* border pixmap in CreateWindow + and ChangeWindowAttributes + special VisualID and special window + class passed to CreateWindow */ + int PointerWindow = 0; /* destination window in SendEvent */ + int InputFocus = 1; /* destination window in SendEvent */ + int PointerRoot = 1; /* focus window in SetInputFocus */ + int AnyPropertyType = 0; /* special Atom, passed to GetProperty */ + int AnyKey = 0; /* special Key Code, passed to GrabKey */ + int AnyButton = 0; /* special Button Code, passed to GrabButton */ + int AllTemporary = 0; /* special Resource ID passed to KillClient */ + int CurrentTime = 0; /* special Time */ + int NoSymbol = 0; /* special KeySym */ + + /***************************************************************** + * EVENT DEFINITIONS + *****************************************************************/ + + /* Input Event Masks. Used as event-mask window attribute and as arguments + to Grab requests. Not to be confused with event names. */ + int NoEventMask = 0; + int KeyPressMask = (1<<0); + int KeyReleaseMask = (1<<1); + int ButtonPressMask = (1<<2); + int ButtonReleaseMask = (1<<3); + int EnterWindowMask = (1<<4); + int LeaveWindowMask = (1<<5); + int PointerMotionMask = (1<<6); + int PointerMotionHintMask = (1<<7); + int Button1MotionMask = (1<<8); + int Button2MotionMask = (1<<9); + int Button3MotionMask = (1<<10); + int Button4MotionMask = (1<<11); + int Button5MotionMask = (1<<12); + int ButtonMotionMask = (1<<13); + int KeymapStateMask = (1<<14); + int ExposureMask = (1<<15); + int VisibilityChangeMask = (1<<16); + int StructureNotifyMask = (1<<17); + int ResizeRedirectMask = (1<<18); + int SubstructureNotifyMask = (1<<19); + int SubstructureRedirectMask = (1<<20); + int FocusChangeMask = (1<<21); + int PropertyChangeMask = (1<<22); + int ColormapChangeMask = (1<<23); + int OwnerGrabButtonMask = (1<<24); + + /* Event names. Used in "type" field in XEvent structures. Not to be + confused with event masks above. They start from 2 because 0 and 1 + are reserved in the protocol for errors and replies. */ + int KeyPress = 2; + int KeyRelease = 3; + int ButtonPress = 4; + int ButtonRelease = 5; + int MotionNotify = 6; + int EnterNotify = 7; + int LeaveNotify = 8; + int FocusIn = 9; + int FocusOut = 10; + int KeymapNotify = 11; + int Expose = 12; + int GraphicsExpose = 13; + int NoExpose = 14; + int VisibilityNotify = 15; + int CreateNotify = 16; + int DestroyNotify = 17; + int UnmapNotify = 18; + int MapNotify = 19; + int MapRequest = 20; + int ReparentNotify = 21; + int ConfigureNotify = 22; + int ConfigureRequest = 23; + int GravityNotify = 24; + int ResizeRequest = 25; + int CirculateNotify = 26; + int CirculateRequest = 27; + int PropertyNotify = 28; + int SelectionClear = 29; + int SelectionRequest = 30; + int SelectionNotify = 31; + int ColormapNotify = 32; + int ClientMessage = 33; + int MappingNotify = 34; + int LASTEvent = 35; // must be bigger than any event # + + /* Key masks. Used as modifiers to GrabButton and GrabKey, results of QueryPointer, + state in various key-, mouse-, and button-related events. */ + int ShiftMask = (1 << 0); + int LockMask = (1 << 1); + int ControlMask = (1 << 2); + int Mod1Mask = (1 << 3); + int Mod2Mask = (1 << 4); + int Mod3Mask = (1 << 5); + int Mod4Mask = (1 << 6); + int Mod5Mask = (1 << 7); + + /* modifier names. Used to build a SetModifierMapping request or + to read a GetModifierMapping request. These correspond to the + masks defined above. */ + int ShiftMapIndex = 0; + int LockMapIndex = 1; + int ControlMapIndex = 2; + int Mod1MapIndex = 3; + int Mod2MapIndex = 4; + int Mod3MapIndex = 5; + int Mod4MapIndex = 6; + int Mod5MapIndex = 7; + + /* button masks. Used in same manner as Key masks above. Not to be confused + with button names below. */ + int Button1Mask = (1 << 8); + int Button2Mask = (1 << 9); + int Button3Mask = (1 << 10); + int Button4Mask = (1 << 11); + int Button5Mask = (1 << 12); + + int AnyModifier = (1 << 15); /* used in GrabButton, GrabKey */ + + /* button names. Used as arguments to GrabButton and as detail in ButtonPress + and ButtonRelease events. Not to be confused with button masks above. + Note that 0 is already defined above as "AnyButton". */ + int Button1 = 1; + int Button2 = 2; + int Button3 = 3; + int Button4 = 4; + int Button5 = 5; + + /* Notify modes */ + int NotifyNormal = 0; + int NotifyGrab = 1; + int NotifyUngrab = 2; + int NotifyWhileGrabbed = 3; + + int NotifyHint = 1; /* for MotionNotify events */ + + /* Notify detail */ + int NotifyAncestor = 0; + int NotifyVirtual = 1; + int NotifyInferior = 2; + int NotifyNonlinear = 3; + int NotifyNonlinearVirtual = 4; + int NotifyPointer = 5; + int NotifyPointerRoot = 6; + int NotifyDetailNone = 7; + + /* Visibility notify */ + int VisibilityUnobscured = 0; + int VisibilityPartiallyObscured = 1; + int VisibilityFullyObscured = 2; + + /* Circulation request */ + int PlaceOnTop = 0; + int PlaceOnBottom = 1; + + /* protocol families */ + int FamilyInternet = 0; /* IPv4 */ + int FamilyDECnet = 1; + int FamilyChaos = 2; + int FamilyInternet6 = 6; /* IPv6 */ + + /* authentication families not tied to a specific protocol */ + int FamilyServerInterpreted = 5; + + /* Property notification */ + int PropertyNewValue = 0; + int PropertyDelete = 1; + + /* Color Map notification */ + int ColormapUninstalled = 0; + int ColormapInstalled = 1; + + /* GrabPointer, GrabButton, GrabKeyboard, GrabKey Modes */ + int GrabModeSync = 0; + int GrabModeAsync = 1; + + /* GrabPointer, GrabKeyboard reply status */ + int GrabSuccess = 0; + int AlreadyGrabbed = 1; + int GrabInvalidTime = 2; + int GrabNotViewable = 3; + int GrabFrozen = 4; + + /* AllowEvents modes */ + int AsyncPointer = 0; + int SyncPointer = 1; + int ReplayPointer = 2; + int AsyncKeyboard = 3; + int SyncKeyboard = 4; + int ReplayKeyboard = 5; + int AsyncBoth = 6; + int SyncBoth = 7; + + /* Used in SetInputFocus, GetInputFocus */ + int RevertToNone = None; + int RevertToPointerRoot = PointerRoot; + int RevertToParent = 2; + + /***************************************************************** + * ERROR CODES + *****************************************************************/ + + int Success = 0; /* everything's okay */ + int BadRequest = 1; /* bad request code */ + int BadValue = 2; /* int parameter out of range */ + int BadWindow = 3; /* parameter not a Window */ + int BadPixmap = 4; /* parameter not a Pixmap */ + int BadAtom = 5; /* parameter not an Atom */ + int BadCursor = 6; /* parameter not a Cursor */ + int BadFont = 7; /* parameter not a Font */ + int BadMatch = 8; /* parameter mismatch */ + int BadDrawable = 9; /* parameter not a Pixmap or Window */ + int BadAccess = 10; /* depending on context: + - key/button already grabbed + - attempt to free an illegal + cmap entry + - attempt to store into a read-only + color map entry. + - attempt to modify the access control + list from other than the local host. + */ + int BadAlloc = 11; /* insufficient resources */ + int BadColor = 12; /* no such colormap */ + int BadGC = 13; /* parameter not a GC */ + int BadIDChoice = 14; /* choice not in range or already used */ + int BadName = 15; /* font or color name doesn't exist */ + int BadLength = 16; /* Request length incorrect */ + int BadImplementation = 17; /* server is defective */ + + int FirstExtensionError = 128; + int LastExtensionError = 255; + + /***************************************************************** + * WINDOW DEFINITIONS + *****************************************************************/ + + /* Window classes used by CreateWindow */ + /* Note that CopyFromParent is already defined as 0 above */ + int InputOutput = 1; + int InputOnly = 2; + + /* Window attributes for CreateWindow and ChangeWindowAttributes */ + int CWBackPixmap = (1<<0); + int CWBackPixel = (1<<1); + int CWBorderPixmap = (1<<2); + int CWBorderPixel = (1<<3); + int CWBitGravity = (1<<4); + int CWWinGravity = (1<<5); + int CWBackingStore = (1<<6); + int CWBackingPlanes = (1<<7); + int CWBackingPixel = (1<<8); + int CWOverrideRedirect = (1<<9); + int CWSaveUnder = (1<<10); + int CWEventMask = (1<<11); + int CWDontPropagate = (1<<12); + int CWColormap = (1<<13); + int CWCursor = (1<<14); + + /* ConfigureWindow structure */ + int CWX = (1<<0); + int CWY = (1<<1); + int CWWidth = (1<<2); + int CWHeight = (1<<3); + int CWBorderWidth = (1<<4); + int CWSibling = (1<<5); + int CWStackMode = (1<<6); + + + /* Bit Gravity */ + int ForgetGravity = 0; + int NorthWestGravity = 1; + int NorthGravity = 2; + int NorthEastGravity = 3; + int WestGravity = 4; + int CenterGravity = 5; + int EastGravity = 6; + int SouthWestGravity = 7; + int SouthGravity = 8; + int SouthEastGravity = 9; + int StaticGravity = 10; + + /* Window gravity + bit gravity above */ + int UnmapGravity = 0; + + /* Used in CreateWindow for backing-store hint */ + int NotUseful = 0; + int WhenMapped = 1; + int Always = 2; + + /* Used in GetWindowAttributes reply */ + int IsUnmapped = 0; + int IsUnviewable = 1; + int IsViewable = 2; + + /* Used in ChangeSaveSet */ + int SetModeInsert = 0; + int SetModeDelete = 1; + + /* Used in ChangeCloseDownMode */ + int DestroyAll = 0; + int RetainPermanent = 1; + int RetainTemporary = 2; + + /* Window stacking method (in configureWindow) */ + int Above = 0; + int Below = 1; + int TopIf = 2; + int BottomIf = 3; + int Opposite = 4; + + /* Circulation direction */ + int RaiseLowest = 0; + int LowerHighest = 1; + + /* Property modes */ + int PropModeReplace = 0; + int PropModePrepend = 1; + int PropModeAppend = 2; + + /***************************************************************** + * GRAPHICS DEFINITIONS + *****************************************************************/ + + /* graphics functions, as in GC.alu */ + int GXclear = 0x0; /* 0 */ + int GXand = 0x1; /* src AND dst */ + int GXandReverse = 0x2; /* src AND NOT dst */ + int GXcopy = 0x3; /* src */ + int GXandInverted = 0x4; /* NOT src AND dst */ + int GXnoop = 0x5; /* dst */ + int GXxor = 0x6; /* src XOR dst */ + int GXor = 0x7; /* src OR dst */ + int GXnor = 0x8; /* NOT src AND NOT dst */ + int GXequiv = 0x9; /* NOT src XOR dst */ + int GXinvert = 0xa; /* NOT dst */ + int GXorReverse = 0xb; /* src OR NOT dst */ + int GXcopyInverted = 0xc; /* NOT src */ + int GXorInverted = 0xd; /* NOT src OR dst */ + int GXnand = 0xe; /* NOT src OR NOT dst */ + int GXset = 0xf; /* 1 */ + + /* LineStyle */ + int LineSolid = 0; + int LineOnOffDash = 1; + int LineDoubleDash = 2; + + /* capStyle */ + int CapNotLast = 0; + int CapButt = 1; + int CapRound = 2; + int CapProjecting = 3; + + /* joinStyle */ + int JoinMiter = 0; + int JoinRound = 1; + int JoinBevel = 2; + + /* fillStyle */ + int FillSolid = 0; + int FillTiled = 1; + int FillStippled = 2; + int FillOpaqueStippled = 3; + + /* fillRule */ + int EvenOddRule = 0; + int WindingRule = 1; + + /* subwindow mode */ + int ClipByChildren = 0; + int IncludeInferiors = 1; + + /* SetClipRectangles ordering */ + int Unsorted = 0; + int YSorted = 1; + int YXSorted = 2; + int YXBanded = 3; + + /* CoordinateMode for drawing routines */ + int CoordModeOrigin = 0; /* relative to the origin */ + int CoordModePrevious = 1; /* relative to previous point */ + + /* Polygon shapes */ + int Complex = 0; /* paths may intersect */ + int Nonconvex = 1; /* no paths intersect, but not convex */ + int Convex = 2; /* wholly convex */ + + /* Arc modes for PolyFillArc */ + int ArcChord = 0; /* join endpoints of arc */ + int ArcPieSlice = 1; /* join endpoints to center of arc */ + + /* GC components: masks used in CreateGC, CopyGC, ChangeGC, OR'ed into + GC.stateChanges */ + int GCFunction = (1<<0); + int GCPlaneMask = (1<<1); + int GCForeground = (1<<2); + int GCBackground = (1<<3); + int GCLineWidth = (1<<4); + int GCLineStyle = (1<<5); + int GCCapStyle = (1<<6); + int GCJoinStyle = (1<<7); + int GCFillStyle = (1<<8); + int GCFillRule = (1<<9); + int GCTile = (1<<10); + int GCStipple = (1<<11); + int GCTileStipXOrigin = (1<<12); + int GCTileStipYOrigin = (1<<13); + int GCFont = (1<<14); + int GCSubwindowMode = (1<<15); + int GCGraphicsExposures = (1<<16); + int GCClipXOrigin = (1<<17); + int GCClipYOrigin = (1<<18); + int GCClipMask = (1<<19); + int GCDashOffset = (1<<20); + int GCDashList = (1<<21); + int GCArcMode = (1<<22); + + int GCLastBit = 22; + /***************************************************************** + * FONTS + *****************************************************************/ + + /* used in QueryFont -- draw direction */ + int FontLeftToRight = 0; + int FontRightToLeft = 1; + + int FontChange = 255; + + /***************************************************************** + * IMAGING + *****************************************************************/ + + /* ImageFormat -- PutImage, GetImage */ + int XYBitmap = 0; /* depth 1, XYFormat */ + int XYPixmap = 1; /* depth == drawable depth */ + int ZPixmap = 2; /* depth == drawable depth */ + + /***************************************************************** + * COLOR MAP STUFF + *****************************************************************/ + + /* For CreateColormap */ + int AllocNone = 0; /* create map with no entries */ + int AllocAll = 1; /* allocate entire map writeable */ + + + /* Flags used in StoreNamedColor, StoreColors */ + int DoRed = (1<<0); + int DoGreen = (1<<1); + int DoBlue = (1<<2); + + /***************************************************************** + * CURSOR STUFF + *****************************************************************/ + + /* QueryBestSize Class */ + int CursorShape = 0; /* largest size that can be displayed */ + int TileShape = 1; /* size tiled fastest */ + int StippleShape = 2; /* size stippled fastest */ + + /***************************************************************** + * KEYBOARD/POINTER STUFF + *****************************************************************/ + + int AutoRepeatModeOff = 0; + int AutoRepeatModeOn = 1; + int AutoRepeatModeDefault = 2; + + int LedModeOff = 0; + int LedModeOn = 1; + + /* masks for ChangeKeyboardControl */ + int KBKeyClickPercent = (1<<0); + int KBBellPercent = (1<<1); + int KBBellPitch = (1<<2); + int KBBellDuration = (1<<3); + int KBLed = (1<<4); + int KBLedMode = (1<<5); + int KBKey = (1<<6); + int KBAutoRepeatMode = (1<<7); + + int MappingSuccess = 0; + int MappingBusy = 1; + int MappingFailed = 2; + + int MappingModifier = 0; + int MappingKeyboard = 1; + int MappingPointer = 2; + + /***************************************************************** + * SCREEN SAVER STUFF + *****************************************************************/ + + int DontPreferBlanking = 0; + int PreferBlanking = 1; + int DefaultBlanking = 2; + + int DisableScreenSaver = 0; + int DisableScreenInterval = 0; + + int DontAllowExposures = 0; + int AllowExposures = 1; + int DefaultExposures = 2; + + /* for ForceScreenSaver */ + int ScreenSaverReset = 0; + int ScreenSaverActive = 1; + + /***************************************************************** + * HOSTS AND CONNECTIONS + *****************************************************************/ + + /* for ChangeHosts */ + int HostInsert = 0; + int HostDelete = 1; + + /* for ChangeAccessControl */ + int EnableAccess = 1; + int DisableAccess = 0; + + /* Display classes used in opening the connection + * Note that the statically allocated ones are even numbered and the + * dynamically changeable ones are odd numbered */ + int StaticGray = 0; + int GrayScale = 1; + int StaticColor = 2; + int PseudoColor = 3; + int TrueColor = 4; + int DirectColor = 5; + + /* Byte order used in imageByteOrder and bitmapBitOrder */ + int LSBFirst = 0; + int MSBFirst = 1; + + + + /***************************************************************** + * DEFINITIONS OF SPECIFIC EVENTS + *****************************************************************/ + + public static class XEvent extends Union { + public int type; + public XAnyEvent xany; + public XKeyEvent xkey; + public XButtonEvent xbutton; + public XMotionEvent xmotion; + public XCrossingEvent xcrossing; + public XFocusChangeEvent xfocus; + public XExposeEvent xexpose; + public XGraphicsExposeEvent xgraphicsexpose; + public XNoExposeEvent xnoexpose; + public XVisibilityEvent xvisibility; + public XCreateWindowEvent xcreatewindow; + public XDestroyWindowEvent xdestroywindow; + public XUnmapEvent xunmap; + public XMapEvent xmap; + public XMapRequestEvent xmaprequest; + public XReparentEvent xreparent; + public XConfigureEvent xconfigure; + public XGravityEvent xgravity; + public XResizeRequestEvent xresizerequest; + public XConfigureRequestEvent xconfigurerequest; + public XCirculateEvent xcirculate; + public XCirculateRequestEvent xcirculaterequest; + public XPropertyEvent xproperty; + public XSelectionClearEvent xselectionclear; + public XSelectionRequestEvent xselectionrequest; + public XSelectionEvent xselection; + public XColormapEvent xcolormap; + public XClientMessageEvent xclient; + public XMappingEvent xmapping; + public XErrorEvent xerror; + public XKeymapEvent xkeymap; + public NativeLong[] pad = new NativeLong[24]; + } + + public static class XAnyEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // window on which event was requested in event mask + } + + class XKeyEvent extends Structure { + public int type; // of event + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // public Display the event was read from + public Window window; // "event" window it is reported relative to + public Window root; // root window that the event occurred on + public Window subwindow; // child window + public NativeLong time; // milliseconds + public int x, y; // pointer x, y coordinates in event window + public int x_root, y_root; // coordinates relative to root + public int state; // key or button mask + public int keycode; // detail + public int same_screen; // same screen flag + } + + class XButtonEvent extends Structure { + public int type; // of event + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // "event" window it is reported relative to + public Window root; // root window that the event occurred on + public Window subwindow; // child window + public NativeLong time; // milliseconds + public int x, y; // pointer x, y coordinates in event window + public int x_root, y_root; // coordinates relative to root + public int state; // key or button mask + public int button; // detail + public int same_screen; // same screen flag + } + + class XButtonPressedEvent extends XButtonEvent { + } + + class XButtonReleasedEvent extends XButtonEvent { + } + + public static class XClientMessageEvent extends Structure { + public int type; // ClientMessage + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public Atom message_type; + public int format; + public Data data; + + public static class Data extends Union { + public byte b[] = new byte[20]; + public short s[] = new short[10]; + public NativeLong[] l = new NativeLong[5]; + } + } + + class XMotionEvent extends Structure { + public int type; // of event + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // "event" window reported relative to + public Window root; // root window that the event occurred on + public Window subwindow; // child window + public NativeLong time; // milliseconds + public int x, y; // pointer x, y coordinates in event window + public int x_root, y_root; // coordinates relative to root + public int state; // key or button mask + public byte is_hint; // detail + public int same_screen; // same screen flag + } + + class XPointerMovedEvent extends XMotionEvent { + } + + class XCrossingEvent extends Structure { + public int type; // of event + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // "event" window reported relative to + public Window root; // root window that the event occurred on + public Window subwindow; // child window + public NativeLong time; // milliseconds + public int x, y; // pointer x, y coordinates in event window + public int x_root, y_root; // coordinates relative to root + public int mode; // NotifyNormal, NotifyGrab, NotifyUngrab + public int detail; + /* + * NotifyAncestor, NotifyVirtual, NotifyInferior, + * NotifyNonlinear,NotifyNonlinearVirtual + */ + public int same_screen; // same screen flag + public int focus; // intean focus + public int state; // key or button mask + } + + class XEnterWindowEvent extends XCrossingEvent { + } + + class XLeaveWindowEvent extends XCrossingEvent { + } + + class XFocusChangeEvent extends Structure { + public int type; // FocusIn or FocusOut + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // window of event + public int mode; // NotifyNormal, NotifyWhileGrabbed, NotifyGrab, NotifyUngrab + public int detail; + /* + * NotifyAncestor, NotifyVirtual, NotifyInferior, + * NotifyNonlinear,NotifyNonlinearVirtual, NotifyPointer, + * NotifyPointerRoot, NotifyDetailNone + */ + } + + class XFocusInEvent extends XFocusChangeEvent { + } + + class XFocusOutEvent extends XFocusChangeEvent { + } + + class XExposeEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public int x, y; + public int width, height; + public int count; // if non-zero, at least this many more + } + + class XGraphicsExposeEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Drawable drawable; + public int x, y; + public int width, height; + public int count; // if non-zero, at least this many more + public int major_code; // core is CopyArea or CopyPlane + public int minor_code; // not defined in the core + } + + class XNoExposeEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Drawable drawable; + public int major_code; // core is CopyArea or CopyPlane + public int minor_code; // not defined in the core + } + + class XVisibilityEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public int state; // Visibility state + } + + class XCreateWindowEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window parent; // parent of the window + public Window window; // window id of window created + public int x, y; // window location + public int width, height; // size of window + public int border_width; // border width + public int override_redirect; // creation should be overridden + } + + class XDestroyWindowEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + } + + class XUnmapEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public int from_configure; + } + + class XMapEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public int override_redirect; // intean, is override set... + } + + class XMapRequestEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window parent; + public Window window; + } + + class XReparentEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public Window parent; + public int x, y; + public int override_redirect; + } + + class XConfigureEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public int x, y; + public int width, height; + public int border_width; + public Window above; + public int override_redirect; + } + + class XGravityEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public int x, y; + } + + class XResizeRequestEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public int width, height; + } + + class XConfigureRequestEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window parent; + public Window window; + public int x, y; + public int width, height; + public int border_width; + public Window above; + public int detail; // Above, Below, TopIf, BottomIf, Opposite + public NativeLong value_mask; + } + + class XCirculateEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window event; + public Window window; + public int place; // PlaceOnTop, PlaceOnBottom + } + + class XCirculateRequestEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window parent; + public Window window; + public int place; // PlaceOnTop, PlaceOnBottom + } + + class XPropertyEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public Atom atom; + public NativeLong time; + public int state; // NewValue, Deleted + } + + class XSelectionClearEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public Atom selection; + public NativeLong time; + } + + class XSelectionRequestEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window owner; + public Window requestor; + public Atom selection; + public Atom target; + Atom property; + public NativeLong time; + } + + class XSelectionEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window requestor; + public Atom selection; + public Atom target; + public Atom property; // ATOM or None + public NativeLong time; + } + + class XColormapEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public Colormap colormap; // COLORMAP or None + public int c_new; // C++ + public int state; // ColormapInstalled, ColormapUninstalled + } + + class XMappingEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; // unused + public int request; // one of MappingModifier, MappingKeyboard, MappingPointer + public int first_keycode; // first keycode + public int count; // defines range of change w. first_keycode*/ + } + + class XErrorEvent extends Structure { + public int type; + public Display display; // Display the event was read from + public XID resourceid; // resource id + public NativeLong serial; // serial number of failed request + public byte error_code; // error code of failed request + public byte request_code; // Major op-code of failed request + public byte minor_code; // Minor op-code of failed request + } + + // generated on EnterWindow and FocusIn when KeyMapState selected + class XKeymapEvent extends Structure { + public int type; + public NativeLong serial; // # of last request processed by server + public int send_event; // true if this came from a SendEvent request + public Display display; // Display the event was read from + public Window window; + public byte key_vector[] = new byte[32]; + } + + int XSelectInput(Display display, Window window, NativeLong eventMask); + int XSendEvent(Display display, Window w, int propagate, NativeLong event_mask, XEvent event_send); + + int XNextEvent(Display display, XEvent event_return); + + int XPeekEvent(Display display, XEvent event_return); + int XWindowEvent(Display display, Window w, NativeLong event_mask, XEvent event_return); + boolean XCheckWindowEvent(Display display, Window w, NativeLong event_mask, XEvent event_return); + int XMaskEvent(Display display, NativeLong event_mask, XEvent event_return); + boolean XCheckMaskEvent(Display display, NativeLong event_mask, XEvent event_return); + boolean XCheckTypedEvent(Display display, int event_type, XEvent event_return); + boolean XCheckTypedWindowEvent(Display display, Window w, int event_type, XEvent event_return); + + /** Returns an {@link XWMHints} which must be freed by {@link #XFree}. */ + XWMHints XGetWMHints(Display display, Window window); + int XGetWMName(Display display, Window window, + XTextProperty text_property_return); + /** Returns an array of {@link XVisualInfo} which must be freed by {@link #XFree}. + * Use {@link XVisualInfo#toArray(int) + * toArray(nitems_return.getValue()} to obtain the array. + */ + XVisualInfo XGetVisualInfo(Display display, NativeLong vinfo_mask, + XVisualInfo vinfo_template, + IntByReference nitems_return); + Colormap XCreateColormap(Display display, Window w, Visual visual, int alloc); + int XGetWindowProperty(Display display, Window w, Atom property, + NativeLong long_offset, + NativeLong long_length, boolean delete, + Atom reg_type, + AtomByReference actual_type_return, + IntByReference actual_format_return, + NativeLongByReference nitems_return, + NativeLongByReference bytes_after_return, + PointerByReference prop_return); + int XChangeProperty(Display display, Window w, Atom property, Atom type, + int format, int mode, Pointer data, int nelements); + int XDeleteProperty(Display display, Window w, Atom property); + // Atom XInternAtom(Display *display, char *atom_name, Bool only_if_exists); + Atom XInternAtom(Display display, String name, boolean only_if_exists); + // char *XGetAtomName(Display *display, Atom atom); + String XGetAtomName(Display display, Atom atom); + int XCopyArea(Display dpy, Drawable src, Drawable dst, GC gc, + int src_x, int src_y, int w, int h, int dst_x, int dst_y); + + XImage XCreateImage(Display dpy, Visual visual, int depth, int format, + int offset, Pointer data, int width, int height, + int bitmap_pad, int bytes_per_line); + int XPutImage(Display dpy, Drawable d, GC gc, XImage image, + int src_x, int src_y, int dest_x, int dest_y, + int width, int height); + int XDestroyImage(XImage image); + + + /***************************************************************** + * KeySyms, Keycodes, Keymaps + *****************************************************************/ + + String XKeysymToString(KeySym keysym); + KeySym XStringToKeysym(String string); + byte XKeysymToKeycode(Display display, KeySym keysym); + KeySym XKeycodeToKeysym(Display display, byte keycode, int index); + + //int XChangeKeyboardMapping(Display display, int first_keycode, int keysyms_per_keycode, KeySym *keysyms, int num_codes); + /** Defines the symbols for the specified number of KeyCodes starting with first_keycode. The symbols for KeyCodes outside this range remain unchanged. The number of elements in keysyms must be: num_codes * keysyms_per_keycode. The specified first_keycode must be greater than or equal to min_keycode returned by XDisplayKeycodes, or a BadValue error results. In addition, the following expression must be less than or equal to max_keycode as returned by XDisplayKeycodes, or a BadValue error results: first_keycode + num_codes - 1. */ + int XChangeKeyboardMapping(Display display, int first_keycode, int keysyms_per_keycode, KeySym[] keysyms, int num_codes); + /** Returns the symbols for the specified number of KeyCodes starting with first_keycode. The value specified in first_keycode must be greater than or equal to min_keycode as returned by XDisplayKeycodes, or a BadValue error results. In addition, the following expression must be less than or equal to max_keycode as returned by XDisplayKeycodes: first_keycode + keycode_count - 1. If this is not the case, a BadValue error results. The number of elements in the KeySyms list is: keycode_count * keysyms_per_keycode_return. KeySym number N, counting from zero, for KeyCode K has the following index in the list, counting from zero: (K - first_code) * keysyms_per_code_return + N. The X server arbitrarily chooses the keysyms_per_keycode_return value to be large enough to report all requested symbols. A special KeySym value of NoSymbol is used to fill in unused elements for individual KeyCodes. To free the storage returned by XGetKeyboardMapping, use XFree. */ + KeySym XGetKeyboardMapping(Display display, byte first_keycode, int keycode_count, IntByReference keysyms_per_keycode_return); + /** Returns the min-keycodes and max-keycodes supported by the specified display. The minimum number of KeyCodes returned is never less than 8, and the maximum number of KeyCodes returned is never greater than 255. Not all KeyCodes in this range are required to have corresponding keys. */ + int XDisplayKeycodes(Display display, IntByReference min_keycodes_return, IntByReference max_keycodes_return); + /** Specifies the KeyCodes of the keys (if any) that are to be used as modifiers. If it succeeds, the X server generates a MappingNotify event, and XSetModifierMapping returns MappingSuccess. X permits at most 8 modifier keys. If more than 8 are specified in the XModifierKeymap structure, a BadLength error results. */ + int XSetModifierMapping(Display display, XModifierKeymapRef modmap); + /** The XGetModifierMapping function returns a pointer to a newly created XModifierKeymap structure that contains the keys being used as modifiers. The structure should be freed after use by calling XFreeModifiermap. If only zero values appear in the set for any modifier, that modifier is disabled. */ + XModifierKeymapRef XGetModifierMapping(Display display); + /** Returns a pointer to XModifierKeymap structure for later use. */ + XModifierKeymapRef XNewModifiermap(int max_keys_per_mod); + /** Adds the specified KeyCode to the set that controls the specified modifier and returns the resulting XModifierKeymap structure (expanded as needed). */ + XModifierKeymapRef XInsertModifiermapEntry(XModifierKeymapRef modmap, byte keycode_entry, int modifier); + /** Deletes the specified KeyCode from the set that controls the specified modifier and returns a pointer to the resulting XModifierKeymap structure. */ + XModifierKeymapRef XDeleteModifiermapEntry(XModifierKeymapRef modmap, byte keycode_entry, int modifier); + /** Frees the specified XModifierKeymap structure. */ + int XFreeModifiermap(XModifierKeymapRef modmap); + + + /** Changes the keyboard control state. + * @param display display + * @param value_mask disjunction of KBKeyClickPercent, KBBellPercent, KBBellPitch, KBBellDuration, KBLed, KBLedMode, KBKey, KBAutoRepeatMode + */ + int XChangeKeyboardControl(Display display, NativeLong value_mask, XKeyboardControlRef values); + /** Returns the current control values for the keyboard to the XKeyboardState structure. */ + int XGetKeyboardControl(Display display, XKeyboardStateRef values_return); + /** Turns on auto-repeat for the keyboard on the specified display. */ + int XAutoRepeatOn(Display display); + /** Turns off auto-repeat for the keyboard on the specified display. */ + int XAutoRepeatOff(Display display); + /** Rings the bell on the keyboard on the specified display, if possible. The specified volume is relative to the base volume for the keyboard. If the value for the percent argument is not in the range -100 to 100 inclusive, a BadValue error results. The volume at which the bell rings when the percent argument is nonnegative is: base - [(base * percent) / 100] + percent. The volume at which the bell rings when the percent argument is negative is: base + [(base * percent) / 100]. To change the base volume of the bell, use XChangeKeyboardControl. */ + int XBell(Display display, int percent); + /** Returns a bit vector for the logical state of the keyboard, where each bit set to 1 indicates that the corresponding key is currently pressed down. The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7 with the least significant bit in the byte representing key 8N. Note that the logical state of a device (as seen by client applications) may lag the physical state if device event processing is frozen. */ + int XQueryKeymap(Display display, byte[] keys_return); + + /** The modifiermap member of the XModifierKeymap structure contains 8 sets of max_keypermod KeyCodes, one for each modifier in the order Shift, Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5. Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are ignored. In addition, all of the nonzero KeyCodes must be in the range specified by min_keycode and max_keycode in the Display structure, or a BadValue error results. */ + class XModifierKeymapRef extends Structure implements Structure.ByReference{ + public int max_keypermod; /* The server's max # of keys per modifier */ + public Pointer modifiermap; /* An 8 by max_keypermod array of modifiers */ + } + + class XKeyboardControlRef extends Structure implements Structure.ByReference { + /** Volume for key clicks between 0 (off) and 100 (loud) inclusive, if possible. A setting of -1 restores the default. */ + public int key_click_percent; + /** Base volume for the bell between 0 (off) and 100 (loud) inclusive, if possible. A setting of -1 restores the default. */ + public int bell_percent; + /** Pitch (specified in Hz) of the bell, if possible. A setting of -1 restores the default. */ + public int bell_pitch; + /** Duration of the bell specified in milliseconds, if possible. A setting of -1 restores the default. */ + public int bell_duration; + /** State of the LEDs. At most 32 LEDs numbered from one are supported. */ + public int led; + /** LED mode: LedModeOn or LedModeOff. */ + public int led_mode; + /** auto_repeat_mode can change the auto repeat settings of this key. */ + public int key; + /** AutoRepeatModeOff, AutoRepeatModeOn, AutoRepeatModeDefault. */ + public int auto_repeat_mode; + + public String toString() { + return "XKeyboardControlByReference{" + + "key_click_percent=" + key_click_percent + + ", bell_percent=" + bell_percent + + ", bell_pitch=" + bell_pitch + + ", bell_duration=" + bell_duration + + ", led=" + led + + ", led_mode=" + led_mode + + ", key=" + key + + ", auto_repeat_mode=" + auto_repeat_mode + + '}'; + } + } + + class XKeyboardStateRef extends Structure implements Structure.ByReference { + /** Volume for key clicks between 0 (off) and 100 (loud) inclusive, if possible. */ + public int key_click_percent; + /** Base volume for the bell between 0 (off) and 100 (loud) inclusive, if possible. */ + public int bell_percent; + /** Pitch (specified in Hz) of the bell, if possible. A setting of -1 restores the default. */ + public int bell_pitch; + /** Duration of the bell specified in milliseconds, if possible. A setting of -1 restores the default. */ + public int bell_duration; + /** State of the LEDs. At most 32 LEDs numbered from one are supported. */ + public NativeLong led_mask; + /** Global auto repeat mode: AutoRepeatModeOff or AutoRepeatModeOn. */ + public int global_auto_repeat; + /** Bit vector. Each bit set to 1 indicates that auto-repeat is enabled for the corresponding key. The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7 with the least significant bit in the byte representing key 8N. */ + public byte auto_repeats[] = new byte[32]; + + public String toString() { + return "XKeyboardStateByReference{" + + "key_click_percent=" + key_click_percent + + ", bell_percent=" + bell_percent + + ", bell_pitch=" + bell_pitch + + ", bell_duration=" + bell_duration + + ", led_mask=" + led_mask + + ", global_auto_repeat=" + global_auto_repeat + + ", auto_repeats=" + auto_repeats + + '}'; + } + } +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/ApplicationChooserFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/ApplicationChooserFieldEditor.java new file mode 100644 index 0000000..2a28759 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/ApplicationChooserFieldEditor.java @@ -0,0 +1,149 @@ +package com.agynamix.platform.frontend.preferences; + +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +import java.io.File; + +import org.eclipse.jface.preference.FileFieldEditor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; + +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.infra.SimidudeUtils; + +public class ApplicationChooserFieldEditor extends FileFieldEditor { + + /** + * Indicates whether the path must be absolute; + * false by default. + */ + private boolean enforceAbsolute = false; + + /** + * Creates a new file field editor + */ + protected ApplicationChooserFieldEditor() + { + } + + /** + * Creates a file field editor. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param parent + * the parent of the field editor's control + */ + public ApplicationChooserFieldEditor(String name, String labelText, Composite parent) + { + this(name, labelText, false, parent); + } + + /** + * Creates a file field editor. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param enforceAbsolute + * true if the file path must be absolute, and false otherwise + * @param parent + * the parent of the field editor's control + */ + public ApplicationChooserFieldEditor(String name, String labelText, boolean enforceAbsolute, Composite parent) + { + this(name, labelText, enforceAbsolute, FileFieldEditor.VALIDATE_ON_FOCUS_LOST, parent); + } + + /** + * Creates a file field editor. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param enforceAbsolute + * true if the file path must be absolute, and false otherwise + * @param validationStrategy + * either {@link StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE} to perform on the fly checking, or + * {@link StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST} (the default) to perform validation only after the + * text has been typed in + * @param parent + * the parent of the field editor's control. + * @since 3.4 + * @see StringButtonFieldEditor#VALIDATE_ON_KEY_STROKE + * @see StringButtonFieldEditor#VALIDATE_ON_FOCUS_LOST + */ + public ApplicationChooserFieldEditor(String name, String labelText, boolean enforceAbsolute, int validationStrategy, + Composite parent) + { + super(name, labelText, enforceAbsolute, validationStrategy, parent); + this.enforceAbsolute = enforceAbsolute; + init(name, labelText); + } + + /* + * (non-Javadoc) Method declared on StringFieldEditor. Checks whether the text input field specifies an existing file. + */ + protected boolean checkState() + { + + String msg = null; + + String path = getTextControl().getText(); + if (path != null) + { + path = path.trim(); + } else + { + path = "";//$NON-NLS-1$ + } + if (path.length() == 0) + { + if (!isEmptyStringAllowed()) + { + msg = getErrorMessage(); + } + } else + { + File file = new File(path); + if ((file.isFile()) || ((PlatformUtils.isMacOs()) && (file.isDirectory()))) + { + if (enforceAbsolute && !file.isAbsolute()) + { + msg = JFaceResources.getString("FileFieldEditor.errorMessage2");//$NON-NLS-1$ + } + } else { + if (SimidudeUtils.findProgram(path) == null) + { + msg = getErrorMessage(); + } + } + } + + if (msg != null) + { // error + showErrorMessage(msg); + return false; + } + + // OK! + clearErrorMessage(); + return true; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceDialog.java b/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceDialog.java new file mode 100644 index 0000000..79736e8 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceDialog.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.preference.PreferenceDialog; +import org.eclipse.jface.preference.PreferenceManager; +import org.eclipse.jface.preference.PreferenceNode; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.impl.PreferenceConfigAdapterImpl; + +/** + * SimiDude application preference setup + * + * @version $Revision: 23 $ $Date: 2004-11-20 14:36:31 +0100 (Sa, 20 Nov 2004) $ + * @author tuhlmann + */ +public class ApplicationPreferenceDialog implements IPreferenceDialogListener { + + Shell shell; + + List preferenceDialogListeners = new ArrayList(); + + public ApplicationPreferenceDialog(Shell shell) + { + this.shell = shell; + initialize(); + } + + protected void initialize() + { + } + + public int open() + { + PreferenceConfigAdapterImpl configAdapter = new PreferenceConfigAdapterImpl(); + ApplicationPreferenceStore store = new ApplicationPreferenceStore(configAdapter); // AppConfigUtil.getPreferencesFile()); + + store.addPropertyChangeListener(configAdapter); + + PreferenceManager manager = new PreferenceManager(); + + GlobalPreferencePageDefaults defaultPage = new GlobalPreferencePageDefaults(configAdapter); + defaultPage.addPreferenceDialogListener(this); + PreferenceNode defaultsNode = new PreferenceNode("defaultsPage"); + GlobalPreferencePageNetwork networkPage = new GlobalPreferencePageNetwork(configAdapter); + networkPage.addPreferenceDialogListener(this); + PreferenceNode networkNode = new PreferenceNode("networkPage"); + defaultsNode.setPage(defaultPage); + manager.addToRoot(defaultsNode); + networkNode.setPage(networkPage); + manager.addToRoot(networkNode); + + PreferenceDialog dialog = new PreferenceDialog(shell, manager); + dialog.setPreferenceStore(store); + int result = dialog.open(); + for (IPreferenceDialogListener l : preferenceDialogListeners) + { + l.dialogClosed(result); + } + return result; + } + + public void addPreferenceDialogListener(IPreferenceDialogListener preferenceDialogListener) + { + preferenceDialogListeners.add(preferenceDialogListener); + } + + public void removePreferenceDialogListener(IPreferenceDialogListener preferenceDialogListener) + { + preferenceDialogListeners.remove(preferenceDialogListener); + } + + public void propertyChange(PropertyChangeEvent event) + { + // propagate the change event + for (IPreferenceDialogListener l : preferenceDialogListeners) + { + l.propertyChange(event); + } + } + + public void dialogClosed(int result) + { + } + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceStore.java b/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceStore.java new file mode 100644 index 0000000..def76b1 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/ApplicationPreferenceStore.java @@ -0,0 +1,568 @@ + /******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.agynamix.platform.frontend.preferences; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jface.preference.IPersistentPreferenceStore; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +import com.agynamix.platform.infra.IPreferenceConfigAdapter; + + +/** + * I used the Eclipse PreferenceStore here and modified it so that it + * works together with the applications overall preference mechanism. + * + * @see IPreferenceStore + */ +public class ApplicationPreferenceStore implements IPersistentPreferenceStore { + /** + * List of registered listeners (element type: + * IPropertyChangeListener). These listeners are to be + * informed when the current value of a preference changes. + */ + private ListenerList listeners = new ListenerList(); + /** + * The mapping from preference name to preference value (represented as + * strings). + */ + private Properties properties; + /** + * The mapping from preference name to default preference value (represented + * as strings); null if none. + */ + private Properties defaultProperties; + /** + * Indicates whether a value as been changed by setToDefault + * or setValue; initially false. + */ + private boolean dirty = false; + + final IPreferenceConfigAdapter configAdapter; + + /** + * Creates an empty preference store. + *

+ * Use the methods load(InputStream) and + * save(InputStream) to load and store this preference store. + *

+ * + * @see #load(InputStream) + * @see #save(OutputStream, String) + */ + public ApplicationPreferenceStore(IPreferenceConfigAdapter configAdapter) { + this.configAdapter = configAdapter; + defaultProperties = new Properties(); + this.loadDefaults(configAdapter.loadDefaultProperties()); + properties = new Properties(defaultProperties); + this.load(configAdapter.loadProperties()); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) { + listeners.add(listener); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public boolean contains(String name) { + return (properties.containsKey(name) || defaultProperties + .containsKey(name)); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { + final Object[] finalListeners = this.listeners.getListeners(); + // Do we need to fire an event. + if (finalListeners.length > 0 + && (oldValue == null || !oldValue.equals(newValue))) { + final PropertyChangeEvent pe = new PropertyChangeEvent(this, name, oldValue, newValue); + for (int i = 0; i < finalListeners.length; ++i) { + IPropertyChangeListener l = (IPropertyChangeListener) finalListeners[i]; + l.propertyChange(pe); + } + // } + // }); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public boolean getBoolean(String name) { + return getBoolean(properties, name); + } + /** + * Helper function: gets boolean for a given name. + * + * @param p + * @param name + * @return boolean + */ + private boolean getBoolean(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return BOOLEAN_DEFAULT_DEFAULT; + if (value.equals(IPreferenceStore.TRUE)) + return true; + return false; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public boolean getDefaultBoolean(String name) { + return getBoolean(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public double getDefaultDouble(String name) { + return getDouble(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public float getDefaultFloat(String name) { + return getFloat(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public int getDefaultInt(String name) { + return getInt(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public long getDefaultLong(String name) { + return getLong(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public String getDefaultString(String name) { + return getString(defaultProperties, name); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public double getDouble(String name) { + return getDouble(properties, name); + } + /** + * Helper function: gets double for a given name. + * + * @param p + * @param name + * @return double + */ + private double getDouble(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return DOUBLE_DEFAULT_DEFAULT; + double ival = DOUBLE_DEFAULT_DEFAULT; + try { + ival = new Double(value).doubleValue(); + } catch (NumberFormatException e) { + } + return ival; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public float getFloat(String name) { + return getFloat(properties, name); + } + /** + * Helper function: gets float for a given name. + * + * @param p + * @param name + * @return float + */ + private float getFloat(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return FLOAT_DEFAULT_DEFAULT; + float ival = FLOAT_DEFAULT_DEFAULT; + try { + ival = new Float(value).floatValue(); + } catch (NumberFormatException e) { + } + return ival; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public int getInt(String name) { + return getInt(properties, name); + } + /** + * Helper function: gets int for a given name. + * + * @param p + * @param name + * @return int + */ + private int getInt(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return INT_DEFAULT_DEFAULT; + int ival = 0; + try { + ival = Integer.parseInt(value); + } catch (NumberFormatException e) { + } + return ival; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public long getLong(String name) { + return getLong(properties, name); + } + /** + * Helper function: gets long for a given name. + * + * @param p + * @param name + * @return + */ + private long getLong(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return LONG_DEFAULT_DEFAULT; + long ival = LONG_DEFAULT_DEFAULT; + try { + ival = Long.parseLong(value); + } catch (NumberFormatException e) { + } + return ival; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public String getString(String name) { + return getString(properties, name); + } + /** + * Helper function: gets string for a given name. + * + * @param p + * @param name + * @return + */ + private String getString(Properties p, String name) { + String value = p != null ? p.getProperty(name) : null; + if (value == null) + return STRING_DEFAULT_DEFAULT; + return value; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public boolean isDefault(String name) { + return (!properties.containsKey(name) && defaultProperties + .containsKey(name)); + } + /** + * Prints the contents of this preference store to the given print stream. + * + * @param out + * the print stream + */ + public void list(PrintStream out) { + properties.list(out); + } + /** + * Prints the contents of this preference store to the given print writer. + * + * @param out + * the print writer + */ + public void list(PrintWriter out) { + properties.list(out); + } + + protected void load(Properties in) { + for (Iterator it = in.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + properties.setProperty(key, in.getProperty(key)); + } + dirty = false; + } + + protected void loadDefaults(Properties in) { + for (Iterator it = in.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + defaultProperties.setProperty(key, in.getProperty(key)); + } + } + + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public boolean needsSaving() { + return dirty; + } + /** + * Returns an enumeration of all preferences known to this store which have + * current values other than their default value. + * + * @return an array of preference names + */ + public String[] preferenceNames() { + ArrayList list = new ArrayList(); + Enumeration names = properties.propertyNames(); + while (names.hasMoreElements()) { + list.add(names.nextElement()); + } + return (String[]) list.toArray(new String[list.size()]); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void putValue(String name, String value) { + String oldValue = getString(name); + if (oldValue == null || !oldValue.equals(value)) { + setValue(properties, name, value); + dirty = true; + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void removePropertyChangeListener(IPropertyChangeListener listener) { + listeners.remove(listener); + } + /** + * Saves the non-default-valued preferences known to this preference store + * to the file from which they were originally loaded. + */ + public void save() { + configAdapter.saveProperties(properties); + dirty = false; + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, double value) { + setValue(defaultProperties, name, value); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, float value) { + setValue(defaultProperties, name, value); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, int value) { + setValue(defaultProperties, name, value); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, long value) { + setValue(defaultProperties, name, value); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, String value) { + setValue(defaultProperties, name, value); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setDefault(String name, boolean value) { + setValue(defaultProperties, name, value); + } + /** + * Sets the name of the file used when loading and storing this preference + * store. + *

+ * Afterward, the methods load() and save() + * can be used to load and store this preference store. + *

+ * + * @param name + * the file name + * @see #load() + * @see #save() + */ + public void setFilename(String name) { + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setToDefault(String name) { + Object oldValue = properties.get(name); + properties.remove(name); + dirty = true; + Object newValue = null; + if (defaultProperties != null) + newValue = defaultProperties.get(name); + firePropertyChangeEvent(name, oldValue, newValue); + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, double value) { + double oldValue = getDouble(name); + if (oldValue != value) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, new Double(oldValue), new Double( + value)); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, float value) { + float oldValue = getFloat(name); + if (oldValue != value) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, new Float(oldValue), new Float(value)); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, int value) { + int oldValue = getInt(name); + if (oldValue != value) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, new Integer(oldValue), new Integer( + value)); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, long value) { + long oldValue = getLong(name); + if (oldValue != value) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, new Long(oldValue), new Long(value)); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, String value) { + String oldValue = getString(name); + if (oldValue == null || !oldValue.equals(value)) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, oldValue, value); + } + } + /* + * (non-Javadoc) Method declared on IPreferenceStore. + */ + public void setValue(String name, boolean value) { + boolean oldValue = getBoolean(name); + if (oldValue != value) { + setValue(properties, name, value); + dirty = true; + firePropertyChangeEvent(name, Boolean.valueOf(oldValue), Boolean.valueOf(value)); + } + } + /** + * Helper method: sets value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, double value) { + Assert.isTrue(p != null); + p.put(name, Double.toString(value)); + } + /** + * Helper method: sets value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, float value) { + Assert.isTrue(p != null); + p.put(name, Float.toString(value)); + } + /** + * Helper method: sets value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, int value) { + Assert.isTrue(p != null); + p.put(name, Integer.toString(value)); + } + /** + * Helper method: sets the value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, long value) { + Assert.isTrue(p != null); + p.put(name, Long.toString(value)); + } + /** + * Helper method: sets the value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, String value) { + Assert.isTrue(p != null && value != null); + p.put(name, value); + } + /** + * Helper method: sets the value for a given name. + * + * @param p + * @param name + * @param value + */ + private void setValue(Properties p, String name, boolean value) { + Assert.isTrue(p != null); + p.put(name, value == true + ? IPreferenceStore.TRUE + : IPreferenceStore.FALSE); + } + } + + diff --git a/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageDefaults.java b/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageDefaults.java new file mode 100644 index 0000000..2556605 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageDefaults.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.ComboFieldEditor; +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.frontend.gui.HotkeyRegistrarFactory; +import com.agynamix.platform.frontend.gui.IHotkeyRegistrar; +import com.agynamix.platform.infra.IPreferenceConfigAdapter; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.infra.PlatformUtils.OS; +import com.agynamix.simidude.frontend.action.SimidudeHotkeyActions; +import com.agynamix.simidude.infra.SimidudeUtils; +import com.install4j.api.update.UpdateSchedule; +import com.install4j.api.update.UpdateScheduleRegistry; + + +class GlobalPreferencePageDefaults extends PlatformFieldEditorPreferencePage { + + final IPreferenceConfigAdapter configAdapter; + + FieldEditor startMinimized; + BooleanFieldEditor restoreLatestEntry; + BooleanFieldEditor showBalloonTooltip; + ComboFieldEditor updateSchedule; + + ComboFieldEditor modifierKey; + + ApplicationChooserFieldEditor defaultTextEditor; + ApplicationChooserFieldEditor defaultImageViewer; + ApplicationChooserFieldEditor defaultFileBrowser; + + HotkeyFieldEditor bringSimidudeToFront; + HotkeyFieldEditor activateLastEntry; + + BooleanFieldEditor autoActivateNewEntry; + BooleanFieldEditor autoDownloadContents; + + BooleanFieldEditor showDownloadErrorDialog; + BooleanFieldEditor showHostNotFoundDialog; + + + String[][] modifierKeyNames = null; + + String oldBringSimidudeToFront; + String oldActivateLastEntry; + + + public GlobalPreferencePageDefaults(IPreferenceConfigAdapter configAdapter) { + super("Application Settings", FieldEditorPreferencePage.FLAT); + this.configAdapter = configAdapter; + setDescription("Use this preference dialog to change Simidude's behavior.\n" + + "\nPlease restart Simidude after making changes."); + } + + protected void createFieldEditors() { + startMinimized = new BooleanFieldEditor(IPreferenceConstants.START_MINIMIZED, "Start minimized", + getFieldEditorParent()); + restoreLatestEntry = new BooleanFieldEditor(IPreferenceConstants.RESTORE_LATEST_ENTRY, + "Restore the latest Clipboard entry after a system restart", getFieldEditorParent()); + showBalloonTooltip = new BooleanFieldEditor(IPreferenceConstants.SHOW_BALLOON_TOOLTIP, + "Show tooltips when new items arrive", getFieldEditorParent()); + updateSchedule = new ComboFieldEditor(IPreferenceConstants.UPDATE_SCHEDULE, "Update Schedule", new String[][] { + { "On Every Start", IPreferenceConstants.UPD_ON_EVERY_START }, { "Weekly", IPreferenceConstants.UPD_WEEKLY }, + { "Never", IPreferenceConstants.UPD_NEVER } }, getFieldEditorParent()); + + modifierKeyNames = new String[][] {{SimidudeUtils.getKeyCodeName(SWT.SHIFT), ""+SWT.SHIFT}, + {SimidudeUtils.getKeyCodeName(SWT.MOD1), ""+SWT.MOD1}, {SimidudeUtils.getKeyCodeName(SWT.ALT), ""+SWT.ALT}}; + modifierKey = new ComboFieldEditor(IPreferenceConstants.MODIFIER_KEY, "The Modifier Key", modifierKeyNames, getFieldEditorParent()); + + defaultTextEditor = new ApplicationChooserFieldEditor(IPreferenceConstants.DEFAULT_TEXT_EDITOR , "Text Editor for text entries", getFieldEditorParent()); + defaultImageViewer = new ApplicationChooserFieldEditor(IPreferenceConstants.DEFAULT_IMAGE_EDITOR, "Image Editor for image entries", getFieldEditorParent()); + defaultFileBrowser = new ApplicationChooserFieldEditor(IPreferenceConstants.DEFAULT_FILE_BROWSER, "File Browser for files/directories", getFieldEditorParent()); + + defaultTextEditor.setEmptyStringAllowed(true); + defaultImageViewer.setEmptyStringAllowed(true); + defaultFileBrowser.setEmptyStringAllowed(true); + + OS os = PlatformUtils.getOsName(); + + switch (os) + { + case win32: + case win64: + defaultTextEditor.setFileExtensions(new String[] {"*.exe; *.com; *.bat; *.cmd", "*.*"}); + defaultImageViewer.setFileExtensions(new String[] {"*.exe; *.com; *.bat; *.cmd", "*.*"}); + defaultFileBrowser.setFileExtensions(new String[] {"*.exe; *.com; *.bat; *.cmd", "*.*"}); + break; + case macosx: + case macosx64: + defaultTextEditor.setFileExtensions(new String[] {"*.app; *.sh", "*.*"}); + defaultImageViewer.setFileExtensions(new String[] {"*.app; *.sh", "*.*"}); + defaultFileBrowser.setFileExtensions(new String[] {"*.app; *.sh", "*.*"}); + break; + } + + IHotkeyRegistrar hotkeyRegistrar = HotkeyRegistrarFactory.getHotkeyRegistrarInstance(); + + if (hotkeyRegistrar.isEnabled()) + { + bringSimidudeToFront = new HotkeyFieldEditor(IPreferenceConstants.HOTKEY_BRING_SIMIDUDE_TO_FRONT, + "HotKey to make Simidude visible (clear to disable)", getFieldEditorParent()); + + String msg = "HotKey to paste the latest Simidude entry (clear to disable)"; +// if (os != OS.win32) +// { +// msg = "HotKey to activate the lastest Simidude entry (clear to disable)"; +// } + + activateLastEntry = new HotkeyFieldEditor(IPreferenceConstants.HOTKEY_ACTIVATE_LAST_ENTRY, msg, getFieldEditorParent()); + } + + autoActivateNewEntry = new BooleanFieldEditor(IPreferenceConstants.AUTO_ACTIVATE_NEW_ENTRY, + "Automatically copy items to clipboard when they arrive", getFieldEditorParent()); + + autoDownloadContents = new BooleanFieldEditor(IPreferenceConstants.AUTO_DOWNLOAD_CONTENTS, + "Automatically download contents from remote computers", getFieldEditorParent()); + + showDownloadErrorDialog = new BooleanFieldEditor(IPreferenceConstants.DIALOG_DOWNLOAD_ERR_SHOW, + "Do not show a message when a file cannot be downloaded", getFieldEditorParent()); + + showHostNotFoundDialog = new BooleanFieldEditor(IPreferenceConstants.DIALOG_HOST_NOT_FOUND_ERR_SHOW, + "Do not show a message when a host cannot be contacted", getFieldEditorParent()); + + addField(startMinimized); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(restoreLatestEntry); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(showBalloonTooltip); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(updateSchedule); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(defaultTextEditor); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(defaultImageViewer); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(defaultFileBrowser); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(modifierKey); + + + if (hotkeyRegistrar.isEnabled()) + { + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(bringSimidudeToFront); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(activateLastEntry); + } + + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(autoActivateNewEntry); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(autoDownloadContents); + + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(showDownloadErrorDialog); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(showHostNotFoundDialog); + + addPropertyChangeListener(updateSchedule, new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) + { + UpdateSchedule schedule = null; + String v = (String) event.getNewValue(); + if (v.equals(IPreferenceConstants.UPD_ON_EVERY_START)) + { + schedule = UpdateSchedule.ON_EVERY_START; + } else if (v.equals(IPreferenceConstants.UPD_WEEKLY)) + { + schedule = UpdateSchedule.WEEKLY; + } else if (v.equals(IPreferenceConstants.UPD_NEVER)) + { + schedule = UpdateSchedule.NEVER; + } + UpdateScheduleRegistry.setUpdateSchedule(schedule); + } + }); + + if (hotkeyRegistrar.isEnabled()) + { + //Listen to events from the PreferenceStore which are emitted when save or apply is pushed + configAdapter.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + //System.out.println("propertyChanged Called"); + String newBringSimidudeToFront = bringSimidudeToFront.getStringValue(); + String newActivateLastEntry = activateLastEntry.getStringValue(); + if ((!oldBringSimidudeToFront.equals(newBringSimidudeToFront)) || (!oldActivateLastEntry.equals(newActivateLastEntry))) + { + // System.out.println("Unregister and register new hotkeys"); + SimidudeHotkeyActions.unregisterHotkeys(); + SimidudeHotkeyActions.registerHotkeys(); + oldBringSimidudeToFront = newBringSimidudeToFront; + oldActivateLastEntry = newActivateLastEntry; + } + } + }); + } + } + + /** + * @see org.eclipse.jface.preference.FieldEditorPreferencePage#initialize() + */ + protected void initialize() { + super.initialize(); + oldBringSimidudeToFront = getPreferenceStore().getString(IPreferenceConstants.HOTKEY_BRING_SIMIDUDE_TO_FRONT); + oldActivateLastEntry = getPreferenceStore().getString(IPreferenceConstants.HOTKEY_ACTIVATE_LAST_ENTRY); + + if (oldBringSimidudeToFront == null) oldBringSimidudeToFront = ""; + if (oldActivateLastEntry == null) oldActivateLastEntry = ""; + +// String textEditor = getPreferenceStore().getString(IPreferenceConstants.DEFAULT_TEXT_EDITOR); +// if (isEmpty(textEditor)) +// { +// Program p = Program.findProgram(".txt"); +// defaultTextEditor.setStringValue(p.getName()); +// } +// String imageEditor = getPreferenceStore().getString(IPreferenceConstants.DEFAULT_IMAGE_EDITOR); +// if (isEmpty(imageEditor)) +// { +// Program p = Program.findProgram(".jpg"); +// defaultImageViewer.setStringValue(p.getName()); +// } + } + +} + diff --git a/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageNetwork.java b/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageNetwork.java new file mode 100644 index 0000000..71f6f15 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/GlobalPreferencePageNetwork.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IntegerFieldEditor; +import org.eclipse.jface.preference.StringFieldEditor; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +import com.agynamix.platform.infra.IPreferenceConfigAdapter; +import com.agynamix.platform.infra.PlatformUtils; +import com.install4j.api.update.UpdateSchedule; +import com.install4j.api.update.UpdateScheduleRegistry; + +class GlobalPreferencePageNetwork extends PlatformFieldEditorPreferencePage { + + final IPreferenceConfigAdapter configAdapter; + + StringFieldEditor groupName; + PasswordFieldEditor groupPassword; + IntegerFieldEditor helloPort; + IntegerFieldEditor serverPort; + BooleanFieldEditor startHttpServer; + IntegerFieldEditor httpServerPort; + StringFieldEditor myOwnIPAddress; + + + NetworkAddressListFieldEditor networkAddrList; + NetworkAddressListFieldEditor ignoreAddrList; + + public GlobalPreferencePageNetwork(IPreferenceConfigAdapter configAdapter) + { + super("Network Settings", FieldEditorPreferencePage.GRID); + this.configAdapter = configAdapter; + setDescription("Use this preference dialog to change Simidude's network behavior.\n" + + "The default settings work out in most cases, " + + "anyway you might want to check the group name and password settings, " + + "especially if you are using Simidude in a corporate network.\n\nPlease restart Simidude after making changes."); + } + + protected void createFieldEditors() + { + groupName = new StringFieldEditor(IPreferenceConstants.NODE_GROUP_NAME, "Name of the group you want to join", + getFieldEditorParent()); + groupPassword = new PasswordFieldEditor(IPreferenceConstants.NODE_GROUP_PWD, + "Password for the group you want to join", getFieldEditorParent()); + helloPort = new IntegerFieldEditor(IPreferenceConstants.HELLO_PORT, "The Port where Broadcasts are sent to", + getFieldEditorParent()); + helloPort.setValidRange(IPreferenceConstants.MIN_ALLOWED_PORT, IPreferenceConstants.MAX_ALLOWED_PORT); + helloPort.setErrorMessage("The value for this port must be between " + IPreferenceConstants.MIN_ALLOWED_PORT + + " and " + IPreferenceConstants.MAX_ALLOWED_PORT); + serverPort = new IntegerFieldEditor(IPreferenceConstants.SERVER_PORT, "The communication port", + getFieldEditorParent()); + serverPort.setValidRange(IPreferenceConstants.MIN_ALLOWED_PORT, IPreferenceConstants.MAX_ALLOWED_PORT); + serverPort.setErrorMessage("The value for this port must be between " + IPreferenceConstants.MIN_ALLOWED_PORT + + " and " + IPreferenceConstants.MAX_ALLOWED_PORT); + startHttpServer = new BooleanFieldEditor(IPreferenceConstants.START_HTTP_SERVER, "Access Simidude via Browser", + getFieldEditorParent()); + httpServerPort = new IntegerFieldEditor(IPreferenceConstants.HTTP_SERVER_PORT, "The Port used by the HTTP server", + getFieldEditorParent()); + httpServerPort.setValidRange(IPreferenceConstants.MIN_ALLOWED_PORT, IPreferenceConstants.MAX_ALLOWED_PORT); + httpServerPort.setErrorMessage("The value for this port must be between " + IPreferenceConstants.MIN_ALLOWED_PORT + + " and " + IPreferenceConstants.MAX_ALLOWED_PORT); + + myOwnIPAddress = new StringFieldEditor(IPreferenceConstants.OWN_IP_ADRESS, "This machine's IP address. Leave empty for auto detect.", getFieldEditorParent()); + + networkAddrList = new NetworkAddressListFieldEditor(IPreferenceConstants.PERMANENT_NETWORK_ADDRESSES, "Add permanent IP addresses or network names here:", "Enter IP address or name", getFieldEditorParent()); + + ignoreAddrList = new NetworkAddressListFieldEditor(IPreferenceConstants.IGNORE_NETWORK_ADDRESSES, "Ignore these IP addresses or network names:", "Enter IP address or name", getFieldEditorParent()); + + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(groupName); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(groupPassword); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(helloPort); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(serverPort); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(startHttpServer); + addField(httpServerPort); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(myOwnIPAddress); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(networkAddrList); + addField(new SpacerFieldEditor(getFieldEditorParent())); + addField(ignoreAddrList); + + addPropertyChangeListener(startHttpServer, new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) + { + httpServerPort.setEnabled(startHttpServer.getBooleanValue(), getFieldEditorParent()); + } + }); + + addPropertyChangeListener(helloPort, new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) + { + setValid(checkPortsUnique()); + } + }); + + addPropertyChangeListener(serverPort, new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) + { + setValid(checkPortsUnique()); + } + }); + + addPropertyChangeListener(httpServerPort, new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) + { + setValid(checkPortsUnique()); + } + }); + + } + + private boolean checkPortsUnique() + { + boolean unique = true; + boolean oldValid = isValid(); + try + { + int a = helloPort.getIntValue(); + int b = serverPort.getIntValue(); + int c = httpServerPort.getIntValue(); + + if ((a == b) || (a == c) || (b == c)) + { + unique = false; + } + + if ((!unique) && (oldValid)) + { + showPortNotUniqueError(); + } + + } catch (Exception e) + { + unique = false; + } + + return unique; + } + + private void showPortNotUniqueError() + { + PlatformUtils.showErrorMessage("Port not unique", "Please change to port settings so that each one is unique."); + setValid(false); + } + + protected void initializeUpdateSchedule() + { + if (UpdateScheduleRegistry.getUpdateSchedule() == null) + { + UpdateScheduleRegistry.setUpdateSchedule(UpdateSchedule.ON_EVERY_START); + } + } + + /** + * @see org.eclipse.jface.preference.FieldEditorPreferencePage#initialize() + */ + protected void initialize() + { + super.initialize(); + // boolean isStartAsServer = + // startAsServer.getPreferenceStore().getBoolean(IPreferenceConstants.START_AS_SERVER); + initializeUpdateSchedule(); + boolean isStartHttpServer = startHttpServer.getPreferenceStore().getBoolean(IPreferenceConstants.START_HTTP_SERVER); + httpServerPort.setEnabled(isStartHttpServer, getFieldEditorParent()); + + } + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/HotkeyFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/HotkeyFieldEditor.java new file mode 100644 index 0000000..d426912 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/HotkeyFieldEditor.java @@ -0,0 +1,121 @@ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.StringFieldEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.simidude.infra.SimidudeUtils; + +public class HotkeyFieldEditor extends StringFieldEditor { + + final Composite parent; + + public HotkeyFieldEditor(String name, String labelText, Composite parent) + { + super(name, labelText, parent); + this.parent = parent; + initialize(); + } + + private void initialize() + { + final Text text = getTextControl(parent); + text.setEditable(true); + text.setBackground(text.getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + text.addKeyListener(new KeyAdapter(){ + @Override + public void keyReleased(KeyEvent e) + { + String s = getKeyText(e); + if (s != null) + { + text.setText(s); + } + } + }); + } + + private String getKeyText(KeyEvent e) + { + if ((e.keyCode == SWT.DEL) || (e.keyCode == 8)) + { + return ""; + } + + String keyStr = ""; + + if ((e.keyCode > 31) && (e.keyCode < 256)) + { + StringBuilder sb = new StringBuilder(); + + if ((e.stateMask & SWT.COMMAND) > 0) + { + sb.append(SimidudeUtils.getKeyCodeName(SWT.COMMAND)).append("+"); + } + + if ((e.stateMask & SWT.CONTROL) > 0) + { + sb.append(SimidudeUtils.getKeyCodeName(SWT.CONTROL)).append("+"); + } + + if ((e.stateMask & SWT.SHIFT) > 0) + { + sb.append(SimidudeUtils.getKeyCodeName(SWT.SHIFT)).append("+"); + } + + if ((e.stateMask & SWT.ALT) > 0) + { + sb.append(SimidudeUtils.getKeyCodeName(SWT.ALT)).append("+"); + } + + if (isStringChar((char)e.keyCode)) + { + keyStr = ""+(char)e.keyCode; + } else { + return null; + } + + sb.append(keyStr.toUpperCase()); + + return sb.toString(); + } else { + return null; + } + } + + /** + * Return true if the character is printable IN ASCII. Not using + * Character.isLetterOrDigit(); applies to all unicode ranges + */ + protected boolean isStringChar(char ch) { + if (ch >= 'a' && ch <= 'z') + return true; + if (ch >= 'A' && ch <= 'Z') + return true; + if (ch >= '0' && ch <= '9') + return true; + switch (ch) { + case '/': + case '-': + case ':': + case '.': + case ',': + case '_': + case '$': + case '%': + case '\'': + case '(': + case ')': + case '[': + case ']': + case '<': + case '>': + return true; + } + return false; + } + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/IPreferenceConstants.java b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceConstants.java new file mode 100644 index 0000000..1576eb4 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceConstants.java @@ -0,0 +1,73 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + + +public interface IPreferenceConstants { + + String START_MINIMIZED = "app.start_minimized"; + String SHOW_SPLASH = "app.show_splash"; + String RESTORE_LATEST_ENTRY = "app.restore_latest_clp_entry"; + String SHOW_BALLOON_TOOLTIP = "app.show_balloon_tooltip"; + String SERVER_PORT = "app.server_port"; + String UPDATE_SCHEDULE = "app.update_schedule"; + + String TOGGLE_CLIPBOARD_MONITOR = "app.is_monitor_clipboard"; + String TOGGLE_CLIPBOARD_MONITOR_TEXT = "app.is_monitor_clipboard_text"; + String TOGGLE_CLIPBOARD_MONITOR_IMAGES = "app.is_monitor_clipboard_images"; + String TOGGLE_CLIPBOARD_MONITOR_FILES = "app.is_monitor_clipboard_files"; + String TOGGLE_SHOW_TOOLBAR = "app.is_toolbar_shown"; + String TOGGLE_SHOW_STATUSLINE = "app.is_statusline_shown"; + String IS_FIRST_RUN = "app.is_first_run"; + String MODIFIER_KEY = "app.modifier_key"; + + String NODE_GROUP_NAME = "app.node_group_name"; + String NODE_GROUP_PWD = "app.node_group_pwd"; + String HELLO_PORT = "app.broadcast_port"; + String CLIPBOARDTABLE_LAST_SAVED_DIR_PATH = "ClipboardTable.Last.Saved.Directory.Path"; + String CLIPBOARDTABLE_LAST_SAVED_FILE_PATH = "ClipboardTable.Last.Saved.File.Path"; + String UPD_ON_EVERY_START = "ON_EVERY_START"; + String UPD_WEEKLY = "WEEKLY"; + String UPD_NEVER = "NEVER"; + String GUI_POSITION = "app.window.position"; + String START_HTTP_SERVER = "app.start_http_server"; + String HTTP_SERVER_PORT = "app.http_server_port"; + String PERMANENT_NETWORK_ADDRESSES = "app.permanent_network_addresses"; + String IGNORE_NETWORK_ADDRESSES = "app.ignore_network_addresses"; + String OWN_IP_ADRESS = "app.own_ip_address"; + + String DEFAULT_TEXT_EDITOR = "app.default_text_editor"; + String DEFAULT_IMAGE_EDITOR = "app.default_image_editor"; + String DEFAULT_FILE_BROWSER = "app.default_file_browser"; + + String HOTKEY_BRING_SIMIDUDE_TO_FRONT = "app.hotkey.activate_simidude_window"; + String HOTKEY_ACTIVATE_LAST_ENTRY = "app.hotkey.activate_last_entry"; + + String AUTO_ACTIVATE_NEW_ENTRY = "app.auto.activate_last_entry"; + String AUTO_DOWNLOAD_CONTENTS = "app.auto.download_contents"; + + String DIALOG_DOWNLOAD_ERR_SHOW = "app.dialog.download_error.show"; + String DIALOG_HOST_NOT_FOUND_ERR_SHOW = "app.dialog.host_not_found_error.show"; + + /** + * Path to the css file used for serving http. Searched for in the CLASSPATH + */ + String CSS_FILE_PATH = "style.css"; + String FAVICON_PATH = "favicon.ico"; + String SAVED_CLP_ITEM_FILE_NAME = "clpitem.sav"; + int MIN_ALLOWED_PORT = 1; + int MAX_ALLOWED_PORT = 65535; + + String CACHE_DIR_NAME = "cache"; + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListener.java b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListener.java new file mode 100644 index 0000000..dadfc91 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListener.java @@ -0,0 +1,31 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.util.PropertyChangeEvent; + +public interface IPreferenceDialogListener { + + /** + * Tell the world that some property has been changed. + * @param event + */ + void propertyChange(PropertyChangeEvent event); + + /** + * The dialog has been closed. + * @param result the close result, either Window.OK or Windows.CANCEL + */ + void dialogClosed(int result); + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListenerSource.java b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListenerSource.java new file mode 100644 index 0000000..4e73c0a --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/IPreferenceDialogListenerSource.java @@ -0,0 +1,21 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +public interface IPreferenceDialogListenerSource { + + void addPreferenceDialogListener(IPreferenceDialogListener dialogListener); + + void removePreferenceDialogListener(IPreferenceDialogListener dialogListener); + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/LabelFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/LabelFieldEditor.java new file mode 100644 index 0000000..134fe04 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/LabelFieldEditor.java @@ -0,0 +1,53 @@ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +/** + * A field editor for displaying labels not associated with other widgets. + */ +public class LabelFieldEditor extends FieldEditor { + + private Label label; + + // All labels can use the same preference name since they don't + // store any preference. + public LabelFieldEditor(String value, Composite parent) { + super("label", value, parent); + } + + // Adjusts the field editor to be displayed correctly + // for the given number of columns. + protected void adjustForNumColumns(int numColumns) { + ((GridData) label.getLayoutData()).horizontalSpan = numColumns; + } + + // Fills the field editor's controls into the given parent. + protected void doFillIntoGrid(Composite parent, int numColumns) { + label = getLabelControl(parent); + + GridData gridData = new GridData(); + gridData.horizontalSpan = numColumns; + gridData.horizontalAlignment = GridData.FILL; + gridData.grabExcessHorizontalSpace = false; + gridData.verticalAlignment = GridData.CENTER; + gridData.grabExcessVerticalSpace = false; + + label.setLayoutData(gridData); + } + + // Returns the number of controls in the field editor. + public int getNumberOfControls() { + return 1; + } + + // Labels do not persist any preferences, so these methods are empty. + protected void doLoad() { + } + protected void doLoadDefault() { + } + protected void doStore() { + } +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/NetworkAddressListFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/NetworkAddressListFieldEditor.java new file mode 100644 index 0000000..a3be442 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/NetworkAddressListFieldEditor.java @@ -0,0 +1,105 @@ +package com.agynamix.platform.frontend.preferences; + +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.preference.ListEditor; +import org.eclipse.swt.widgets.Composite; + +import com.agynamix.platform.frontend.dialogs.InputNetworkAddressDialog; + +/** + * A field editor to edit directory paths. + */ +public class NetworkAddressListFieldEditor extends ListEditor { + + /** + * Creates a new path field editor + */ + protected NetworkAddressListFieldEditor() + { + } + + /** + * Creates a path field editor. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param dirChooserLabelText + * the label text displayed for the directory chooser + * @param parent + * the parent of the field editor's control + */ + public NetworkAddressListFieldEditor(String name, String labelText, String dirChooserLabelText, Composite parent) + { + init(name, labelText); + createControl(parent); + } + + /* + * (non-Javadoc) Method declared on ListEditor. Creates a single string from the given array by separating each string + * with the appropriate OS-specific path separator. + */ + protected String createList(String[] items) + { + StringBuilder networkAddresses = new StringBuilder("");//$NON-NLS-1$ + + for (String s : items) + { + networkAddresses.append(s); + networkAddresses.append(","); + } + return networkAddresses.toString(); + } + + /* + * (non-Javadoc) Method declared on ListEditor. Creates a new path element by means of a directory dialog. + */ + protected String getNewInputObject() + { + InputNetworkAddressDialog addrDialog = new InputNetworkAddressDialog(getShell()); + String address = null; + if (addrDialog.open() == IDialogConstants.OK_ID) + { + address = addrDialog.getText(); + if (address != null) + { + address = address.trim(); + if (address.length() == 0) + { + return null; + } + } + } + return address; + } + + /* + * (non-Javadoc) Method declared on ListEditor. + */ + protected String[] parseString(String stringList) + { + StringTokenizer st = new StringTokenizer(stringList, ",");//$NON-NLS-1$ + List v = new ArrayList(); + while (st.hasMoreTokens()) + { + v.add(st.nextToken()); + } + return (String[]) v.toArray(new String[v.size()]); + } +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/PasswordFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/PasswordFieldEditor.java new file mode 100644 index 0000000..8a10d8e --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/PasswordFieldEditor.java @@ -0,0 +1,544 @@ +/* + * + * + * Copyright (c) 2004 FORTHnet, S.A. All Rights Reserved. + * + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR + * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS + * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, + * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER + * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF + * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * This software is not designed or intended for use in on-line control of + * aircraft, air traffic, aircraft navigation or aircraft communications; or in + * the design, construction, operation or maintenance of any nuclear + * facility. Licensee represents and warrants that it will not use or + * redistribute the Software for such purposes. + */ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.Assert; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; + +/** + * @author Filippos Slavik + * @version $Id: PasswordFieldEditor.java 10 2004-11-17 12:30:10Z tuhlmann $ + */ +public class PasswordFieldEditor extends FieldEditor { + + /** + * Validation strategy constant (value 0) indicating that + * the editor should perform validation after every key stroke. + * + * @see #setValidateStrategy + */ + public static final int VALIDATE_ON_KEY_STROKE = 0; + + /** + * Validation strategy constant (value 1) indicating that + * the editor should perform validation only when the text widget loses + * focus. + * + * @see #setValidateStrategy + */ + public static final int VALIDATE_ON_FOCUS_LOST = 1; + + /** + * Text limit constant (value -1) indicating unlimited text + * limit and width. + */ + public static int UNLIMITED = -1; + + /** + * Cached valid state. + */ + private boolean isValid; + + /** + * Old text value. + */ + private String oldValue; + + /** + * The text field, or null if none. + */ + Text textField; + + /** + * Width of text field in characters; initially unlimited. + */ + private int widthInChars = UNLIMITED; + + /** + * Text limit of text field in characters; initially unlimited. + */ + private int textLimit = UNLIMITED; + + /** + * The error message, or null if none. + */ + private String errorMessage; + + /** + * Indicates whether the empty string is legal; true by + * default. + */ + private boolean emptyStringAllowed = true; + + /** + * The validation strategy; VALIDATE_ON_KEY_STROKE by + * default. + */ + private int validateStrategy = VALIDATE_ON_KEY_STROKE; + + /** + * Creates a new string field editor + */ + protected PasswordFieldEditor() { + } + + /** + * Creates a string field editor. Use the method setTextLimit + * to limit the text. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param width + * the width of the text input field in characters, or + * UNLIMITED for no limit + * @param strategy + * either VALIDATE_ON_KEY_STROKE to perform on the + * fly checking (the default), or + * VALIDATE_ON_FOCUS_LOST to perform validation + * only after the text has been typed in + * @param parent + * the parent of the field editor's control + * @since 2.0 + */ + public PasswordFieldEditor(String name, String labelText, int width, int strategy, Composite parent) { + init(name, labelText); + widthInChars = width; + setValidateStrategy(strategy); + isValid = false; + errorMessage = JFaceResources.getString("StringFieldEditor.errorMessage");//$NON-NLS-1$ + createControl(parent); + } + + /** + * Creates a string field editor. Use the method setTextLimit + * to limit the text. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param width + * the width of the text input field in characters, or + * UNLIMITED for no limit + * @param parent + * the parent of the field editor's control + */ + public PasswordFieldEditor(String name, String labelText, int width, Composite parent) { + this(name, labelText, width, VALIDATE_ON_KEY_STROKE, parent); + } + + /** + * Creates a string field editor of unlimited width. Use the method + * setTextLimit to limit the text. + * + * @param name + * the name of the preference this field editor works on + * @param labelText + * the label text of the field editor + * @param parent + * the parent of the field editor's control + */ + public PasswordFieldEditor(String name, String labelText, Composite parent) { + this(name, labelText, UNLIMITED, parent); + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + protected void adjustForNumColumns(int numColumns) { + GridData gd = (GridData) textField.getLayoutData(); + gd.horizontalSpan = numColumns - 1; + // We only grab excess space if we have to + // If another field editor has more columns then + // we assume it is setting the width. + gd.grabExcessHorizontalSpace = gd.horizontalSpan == 1; + } + + /** + * Checks whether the text input field contains a valid value or not. + * + * @return true if the field value is valid, and + * false if invalid + */ + protected boolean checkState() { + boolean result = false; + if (emptyStringAllowed) result = true; + + if (textField == null) result = false; + + String txt = textField.getText(); + + if (txt == null) result = false; + + result = (txt.trim().length() > 0) || emptyStringAllowed; + + // call hook for subclasses + result = result && doCheckState(); + + if (result) + clearErrorMessage(); + else showErrorMessage(errorMessage); + + return result; + } + + /** + * Hook for subclasses to do specific state checks. + *

+ * The default implementation of this framework method does nothing and + * returns true. Subclasses should override this method to + * specific state checks. + *

+ * + * @return true if the field value is valid, and + * false if invalid + */ + protected boolean doCheckState() { + return true; + } + + /** + * Fills this field editor's basic controls into the given parent. + *

+ * The string field implementation of this FieldEditor + * framework method contributes the text field. Subclasses may override but + * must call super.doFillIntoGrid. + *

+ */ + protected void doFillIntoGrid(Composite parent, int numColumns) { + getLabelControl(parent); + + textField = getTextControl(parent); + GridData gd = new GridData(); + gd.horizontalSpan = numColumns - 1; + if (widthInChars != UNLIMITED) { + GC gc = new GC(textField); + try { + Point extent = gc.textExtent("X");//$NON-NLS-1$ + gd.widthHint = widthInChars * extent.x; + } finally { + gc.dispose(); + } + } else { + gd.horizontalAlignment = GridData.FILL; + gd.grabExcessHorizontalSpace = true; + } + textField.setLayoutData(gd); + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + protected void doLoad() { + if (textField != null) { + String value = getPreferenceStore().getString(getPreferenceName()); + textField.setText(value); + oldValue = value; + } + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + protected void doLoadDefault() { + if (textField != null) { + String value = getPreferenceStore().getDefaultString(getPreferenceName()); + textField.setText(value); + } + valueChanged(); + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + protected void doStore() { + getPreferenceStore().setValue(getPreferenceName(), textField.getText()); + } + + /** + * Returns the error message that will be displayed when and if an error + * occurs. + * + * @return the error message, or null if none + */ + public String getErrorMessage() { + return errorMessage; + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + public int getNumberOfControls() { + return 2; + } + + /** + * Returns the field editor's value. + * + * @return the current value + */ + public String getStringValue() { + if (textField != null) + return textField.getText(); + else return getPreferenceStore().getString(getPreferenceName()); + } + + /** + * Returns this field editor's text control. + * + * @return the text control, or null if no text field is + * created yet + */ + protected Text getTextControl() { + return textField; + } + + /** + * Returns this field editor's text control. + *

+ * The control is created if it does not yet exist + *

+ * + * @param parent + * the parent + * @return the text control + */ + public Text getTextControl(Composite parent) { + if (textField == null) { + textField = new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD); + textField.setFont(parent.getFont()); + switch (validateStrategy) { + case VALIDATE_ON_KEY_STROKE : + textField.addKeyListener(new KeyAdapter() { + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent) + */ + public void keyReleased(KeyEvent e) { + valueChanged(); + } + }); + + break; + case VALIDATE_ON_FOCUS_LOST : + textField.addKeyListener(new KeyAdapter() { + + public void keyPressed(KeyEvent e) { + clearErrorMessage(); + } + }); + textField.addFocusListener(new FocusAdapter() { + + public void focusGained(FocusEvent e) { + refreshValidState(); + } + + public void focusLost(FocusEvent e) { + valueChanged(); + clearErrorMessage(); + } + }); + break; + default : + Assert.isTrue(false, "Unknown validate strategy");//$NON-NLS-1$ + } + textField.addDisposeListener(new DisposeListener() { + + public void widgetDisposed(DisposeEvent event) { + textField = null; + } + }); + if (textLimit > 0) {//Only set limits above 0 - see SWT spec + textField.setTextLimit(textLimit); + } + } else { + checkParent(textField, parent); + } + return textField; + } + + /** + * Returns whether an empty string is a valid value. + * + * @return true if an empty string is a valid value, and + * false if an empty string is invalid + * @see #setEmptyStringAllowed + */ + public boolean isEmptyStringAllowed() { + return emptyStringAllowed; + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + public boolean isValid() { + return isValid; + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + protected void refreshValidState() { + isValid = checkState(); + } + + /** + * Sets whether the empty string is a valid value or not. + * + * @param b + * true if the empty string is allowed, and + * false if it is considered invalid + */ + public void setEmptyStringAllowed(boolean b) { + emptyStringAllowed = b; + } + + /** + * Sets the error message that will be displayed when and if an error + * occurs. + * + * @param message + * the error message + */ + public void setErrorMessage(String message) { + errorMessage = message; + } + + /* + * (non-Javadoc) Method declared on FieldEditor. + */ + public void setFocus() { + if (textField != null) { + textField.setFocus(); + } + } + + /** + * Sets this field editor's value. + * + * @param value + * the new value, or null meaning the empty string + */ + public void setStringValue(String value) { + if (textField != null) { + if (value == null) value = "";//$NON-NLS-1$ + oldValue = textField.getText(); + if (!oldValue.equals(value)) { + textField.setText(value); + valueChanged(); + } + } + } + + /** + * Sets this text field's text limit. + * + * @param limit + * the limit on the number of character in the text input field, + * or UNLIMITED for no limit + * + */ + public void setTextLimit(int limit) { + textLimit = limit; + if (textField != null) textField.setTextLimit(limit); + } + + /** + * Sets the strategy for validating the text. + *

+ * Calling this method has no effect after createPartControl + * is called. Thus this method is really only useful for subclasses to call + * in their constructor. However, it has public visibility for backward + * compatibility. + *

+ * + * @param value + * either VALIDATE_ON_KEY_STROKE to perform on the + * fly checking (the default), or + * VALIDATE_ON_FOCUS_LOST to perform validation + * only after the text has been typed in + */ + public void setValidateStrategy(int value) { + Assert.isTrue(value == VALIDATE_ON_FOCUS_LOST || value == VALIDATE_ON_KEY_STROKE); + validateStrategy = value; + } + + /** + * Shows the error message set via setErrorMessage. + */ + public void showErrorMessage() { + showErrorMessage(errorMessage); + } + + /** + * Informs this field editor's listener, if it has one, about a change to + * the value (VALUE property) provided that the old and new + * values are different. + *

+ * This hook is not called when the text is initialized (or reset + * to the default value) from the preference store. + *

+ */ + protected void valueChanged() { + setPresentsDefaultValue(false); + boolean oldState = isValid; + refreshValidState(); + + if (isValid != oldState) fireStateChanged(IS_VALID, oldState, isValid); + + String newValue = textField.getText(); + if (!newValue.equals(oldValue)) { + fireValueChanged(VALUE, oldValue, newValue); + oldValue = newValue; + } + } + + /* + * @see FieldEditor.setEnabled(boolean,Composite). + */ + public void setEnabled(boolean enabled, Composite parent) { + super.setEnabled(enabled, parent); + getTextControl(parent).setEnabled(enabled); + } +} + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/frontend/preferences/PlatformFieldEditorPreferencePage.java b/src/java/com/agynamix/platform/frontend/preferences/PlatformFieldEditorPreferencePage.java new file mode 100644 index 0000000..844b2a2 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/PlatformFieldEditorPreferencePage.java @@ -0,0 +1,91 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.frontend.preferences; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +public abstract class PlatformFieldEditorPreferencePage extends FieldEditorPreferencePage implements IPreferenceDialogListenerSource { + + List preferenceDialogListeners = new ArrayList(); + + /** + * Map> + */ + private Map> listeners = new HashMap>(); + + public PlatformFieldEditorPreferencePage(String title, int style) + { + super(title, style); + } + + public void addPropertyChangeListener(FieldEditor editor, IPropertyChangeListener listener) + { + List l = listeners.get(editor); + if (l == null) + { + l = new ArrayList(); + } + if (!l.contains(listener)) + { + l.add(listener); + } + listeners.put(editor, l); + } + + public void addPreferenceDialogListener(IPreferenceDialogListener dialogListener) + { + preferenceDialogListeners.add(dialogListener); + } + + public void removePreferenceDialogListener(IPreferenceDialogListener dialogListener) + { + preferenceDialogListeners.remove(dialogListener); + } + + public void propertyChange(PropertyChangeEvent event) + { + super.propertyChange(event); + if (!event.getNewValue().equals(event.getOldValue())) + { + FieldEditor fe = (FieldEditor) event.getSource(); + List l = listeners.get(fe); + if (l != null) + { + for (IPropertyChangeListener listener : l) + { + listener.propertyChange(event); + } + } + // call IPreferenceDialogListeners + for (IPreferenceDialogListener listener : preferenceDialogListeners) + { + listener.propertyChange(event); + } + } + } + + public boolean isEmpty(String string) + { + return ((string == null) || (string.length() == 0)); + } + + +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/SeparatorFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/SeparatorFieldEditor.java new file mode 100644 index 0000000..9b0ffe4 --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/SeparatorFieldEditor.java @@ -0,0 +1,55 @@ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +/** + * A field editor for displaying labels not associated with other widgets. + */ +public class SeparatorFieldEditor extends FieldEditor { + + private Label label; + + // All labels can use the same preference name since they don't + // store any preference. + public SeparatorFieldEditor(Composite parent) { + super("separator", "separator", parent); + } + + // Adjusts the field editor to be displayed correctly + // for the given number of columns. + protected void adjustForNumColumns(int numColumns) { + ((GridData) label.getLayoutData()).horizontalSpan = numColumns; + } + + // Fills the field editor's controls into the given parent. + protected void doFillIntoGrid(Composite parent, int numColumns) { +// label = getLabelControl(parent); + label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + + GridData gridData = new GridData(); + gridData.horizontalSpan = numColumns; + gridData.horizontalAlignment = GridData.FILL; + gridData.grabExcessHorizontalSpace = true; + gridData.verticalAlignment = GridData.CENTER; + gridData.grabExcessVerticalSpace = false; + + label.setLayoutData(gridData); + } + + // Returns the number of controls in the field editor. + public int getNumberOfControls() { + return 1; + } + + // Labels do not persist any preferences, so these methods are empty. + protected void doLoad() { + } + protected void doLoadDefault() { + } + protected void doStore() { + } +} diff --git a/src/java/com/agynamix/platform/frontend/preferences/SpacerFieldEditor.java b/src/java/com/agynamix/platform/frontend/preferences/SpacerFieldEditor.java new file mode 100644 index 0000000..68b11bd --- /dev/null +++ b/src/java/com/agynamix/platform/frontend/preferences/SpacerFieldEditor.java @@ -0,0 +1,15 @@ +package com.agynamix.platform.frontend.preferences; + +import org.eclipse.swt.widgets.Composite; + + + +/** + * A field editor for adding space to a preference page. + */ +public class SpacerFieldEditor extends LabelFieldEditor { + // Implemented as an empty label field editor. + public SpacerFieldEditor(Composite parent) { + super("", parent); + } +} diff --git a/src/java/com/agynamix/platform/httpd/HTTPResponse.java b/src/java/com/agynamix/platform/httpd/HTTPResponse.java new file mode 100644 index 0000000..72aa299 --- /dev/null +++ b/src/java/com/agynamix/platform/httpd/HTTPResponse.java @@ -0,0 +1,81 @@ +package com.agynamix.platform.httpd; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Properties; + +/** + * HTTP response. + * Return one of these from serve(). + */ +public class HTTPResponse +{ + /** + * Default constructor: response = HTTP_OK, data = mime = 'null' + */ + public HTTPResponse() + { + this.status = HTTPUtils.HTTP_OK; + } + + /** + * Basic constructor. + */ + public HTTPResponse( String status, String mimeType, InputStream data ) + { + this.status = status; + this.mimeType = mimeType; + this.data = data; + } + + /** + * Convenience method that makes an InputStream out of + * given text. + */ + public HTTPResponse( String status, String mimeType, String txt ) + { + this.status = status; + this.mimeType = mimeType; + this.data = new ByteArrayInputStream( txt.getBytes()); + } + + /** + * Convenience method that makes an InputStream out of + * given byte array. + */ + public HTTPResponse( String status, String mimeType, byte[] buffer ) + { + this.status = status; + this.mimeType = mimeType; + this.data = new ByteArrayInputStream( buffer); + } + + /** + * Adds given line to the header. + */ + public void addHeader( String name, String value ) + { + header.put( name, value ); + } + + /** + * HTTP status code after processing, e.g. "200 OK", HTTP_OK + */ + public String status; + + /** + * MIME type of content, e.g. "text/html" + */ + public String mimeType; + + /** + * Data of the response, may be null. + */ + public InputStream data; + + /** + * Headers for the HTTP response. Use addHeader() + * to add lines. + */ + public Properties header = new Properties(); +} diff --git a/src/java/com/agynamix/platform/httpd/HTTPSession.java b/src/java/com/agynamix/platform/httpd/HTTPSession.java new file mode 100644 index 0000000..5f0d0fd --- /dev/null +++ b/src/java/com/agynamix/platform/httpd/HTTPSession.java @@ -0,0 +1,678 @@ +package com.agynamix.platform.httpd; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.UUID; +import java.util.logging.Logger; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.HtmlUtils; +import com.agynamix.platform.infra.ZipUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.SourceDataStub; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + +public class HTTPSession extends HTTPSessionBase { + + Logger log = ApplicationLog.getLogger(HTTPSession.class); + + public final static String ctrl_none = "none"; + public final static String ctrl_list = "list"; + public final static String ctrl_download = "download"; + public final static String ctrl_compress = "compress"; + + public final static int Thumbnail_Width = 100; + + private static String cssContents = null; + private static Object cssLoadMutex = new Object(); + + public HTTPSession(Properties environment, Socket s) + { + super(environment, s); + } + + @Override + protected boolean postProcessRequestHeader(Properties environment, Properties header) throws InterruptedException, + IOException + { + String envUser = environment.getProperty(HTTPUtils.HTTP_USER, "guest"); + String envPw = environment.getProperty(HTTPUtils.HTTP_PASSWORD, "guest"); + + String value = header.getProperty("authorization"); + if (value != null) + { + StringTokenizer st = new StringTokenizer(value); + String method = st.nextToken(); + if (method.equalsIgnoreCase("basic")) + { + String auth = st.nextToken(); + if ((auth != null) && (auth.length() > 0)) + { + String plain = new String(new BASE64Decoder().decodeBuffer(auth)); + int pos = plain.indexOf(':'); + if (pos > 0) + { + String user = plain.substring(0, pos); + String pw = plain.substring(pos + 1); + // Connect to real group name and password + if ((envUser.equals(user)) && (envPw.equals(pw))) + { + return true; + } + } + } + } + } + httpUtils.sendNotAuthorized("Simidude"); + return false; + } + + @Override + /* + * Override this to customize the server.

+ * + * (By default, this delegates to serveFile() and allows directory listing.) + * + * @parm uri Percent-decoded URI without parameters, for example "/index.cgi" + * + * @parm method "GET", "POST" etc. + * + * @parm parms Parsed, percent decoded parameters from URI and, in case of + * POST, data. + * + * @parm header Header entries, percent decoded + * + * @return HTTP response, see class Response for details + */ + public HTTPResponse serve(String uri, String method, Properties header, Properties parms) + { +// System.out.println(method + " '" + uri + "' "); + + Enumeration e = header.propertyNames(); + while (e.hasMoreElements()) + { + String value = (String) e.nextElement(); +// System.out.println(" HDR: '" + value + "' = '" + header.getProperty(value) + "'"); + } + e = parms.propertyNames(); + while (e.hasMoreElements()) + { + String value = (String) e.nextElement(); +// System.out.println(" PRM: '" + value + "' = '" + parms.getProperty(value) + "'"); + } + + // Remove URL arguments + uri = uri.trim().replace(File.separatorChar, '/'); + if (uri.indexOf('?') >= 0) + { + uri = uri.substring(0, uri.indexOf('?')); + } + + // Prohibit getting out of current directory + if (uri.startsWith("..") || uri.endsWith("..") || uri.indexOf("../") >= 0) + { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "FORBIDDEN: Won't serve ../ for security reasons."); + } + + if (log != null) // Strange bug on Ubuntu 8.04, Sun Java 1.6 throws NPE here + { + log.fine("URI=|"+uri+"|"); + } + + if (uri.equals("") || (uri.equals("/"))) + { + return serveAllEntries(header); + } else { + String controller = getController(uri); + if (controller.equals(ctrl_none)) + { + return serveSpecialEntry(uri, header); + } else if (controller.equals(ctrl_list)) + { + return serveEntry(uri, header); + } else if (controller.equals(ctrl_download)) { + return serveDownloadEntry(uri, header, false); + } else if (controller.equals(ctrl_compress)) { + return serveDownloadEntry(uri, header, true); + } else { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "FORBIDDEN: Action "+controller+" not allowed."); + } + } + + } + + private HTTPResponse serveAllEntries(Properties header) + { + SourceDataManager sourceDataManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + + List items = sourceDataManager.getClipboardItems(); + if (items == null) + { + items = new ArrayList(); + } + StringBuilder sb = new StringBuilder(htmlHeader("list_all")); + sb.append("

"); + sb.append(items.size()).append(" Simidude "); + if (items.size() == 1) + { + sb.append("Entry "); + } else { + sb.append("Entries "); + } + sb.append("found.

"); + sb.append("

    "); + + int count = 0; + + for (IClipboardItem item : items) + { + String rowClass = "even"; + if (count%2 != 0) + { + rowClass = "odd"; + } + String tableClass = "table_"+rowClass; + sb.append("
  • "); + String fragment = ""; + switch (item.getType()) + { + case TEXT: + fragment = serveListingText(header, item, tableClass, false); + break; + case IMAGE: + fragment = serveListingImage(header, item, tableClass, false); + break; + case FILE: + fragment = serveListingFile(header, item, tableClass, false); + break; + } + + sb.append(fragment); + sb.append("
  • "); + +// ISourceData sourceData = item.getSourceData(); +// sb.append(""+sourceData.getSourceId()+"
    "); +// sb.append(""+item.getShortDescription()+""); +// sb.append(""); + + count++; + } + + sb.append("

"); + return new HTTPResponse(HTTPUtils.HTTP_OK, HTTPUtils.MIME_HTML, sb.toString()); + } + + private String htmlHeader(String bodyClass) + { + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append(""); + sb.append("Simidude Remote Access"); + + // read (cached) CSS and fill in + sb.append(""); + + sb.append(""); + sb.append(""); + return sb.toString(); + } + + private String loadCssFile(String cssFilePath) + { + synchronized (cssLoadMutex) + { + if (cssContents == null) + { + byte[] buffer = FileUtils.loadFile(this.getClass().getClassLoader().getResourceAsStream(cssFilePath), cssFilePath); + cssContents = new String(buffer); + } + } + return cssContents; + } + + /** + * To serve an entry the uuid of that entry must be given after an initial /. + * @param uri + * @param header + * @return + */ + private HTTPResponse serveEntry(String uri, Properties header) + { + String uuidStr = getUUID(uri); + + try { + UUID uuid = UUID.fromString(uuidStr); + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getClipboardItem(new SourceDataStub(uuid)); + if (item != null) + { + String fragment = ""; + switch (item.getType()) + { + case TEXT: + fragment = serveListingText(header, item, "table_single", true); + break; + case FILE: + fragment = serveListingFile(header, item, "table_single", true); + break; + case IMAGE: + fragment = serveListingImage(header, item, "table_single", true); + break; + default: + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "This Entry type is not implemented yet."); + } + return new HTTPResponse(HTTPUtils.HTTP_OK, HTTPUtils.MIME_HTML, buildSingleListing(fragment)); + } else { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "Error: The specified item could not be found. Maybe it was deleted?"); + } + + } catch (Exception e) { + e.printStackTrace(); + return new HTTPResponse(HTTPUtils.HTTP_INTERNALERROR, HTTPUtils.MIME_PLAINTEXT, "INTERNAL ERRROR: "+uuidStr+" is not a valid identifier."); + } + + } + + /** + * To serve an entry the uuid of that entry must be given after an initial /. + * @param uri + * @param header + * @return + */ + private HTTPResponse serveDownloadEntry(String uri, Properties header, boolean compress) + { + String uuidStr = getUUID(uri); + + try { + UUID uuid = UUID.fromString(uuidStr); + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + IClipboardItem item = sdm.getClipboardItem(new SourceDataStub(uuid)); + if (item != null) + { + switch (item.getType()) + { + case TEXT: + return serveDownloadText(header, item, compress); + case IMAGE: + return serveDownloadImage(header, item, compress); + case FILE: + return serveDownloadFile(header, item, compress); + default: + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "Not yet."); + } + } else { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "Error: The specified item could not be found. Maybe it was deleted?"); + } + + } catch (Exception e) { + e.printStackTrace(); + return new HTTPResponse(HTTPUtils.HTTP_INTERNALERROR, HTTPUtils.MIME_PLAINTEXT, "INTERNAL ERRROR: "+uuidStr+" is not a valid identifier."); + } + + } + + private String buildSingleListing(String fragment) + { + StringBuilder sb = new StringBuilder(); + sb.append(htmlHeader("list_single")); + sb.append("

"); + sb.append("Simidude Entry listing.

"); + sb.append("

Back

"); + sb.append("

"); + sb.append(fragment); + sb.append("

"); + return sb.toString(); + } + + private String getUUID(String uri) + { + String neoUri = uri; + String uuidStr = ""; + if (uri.lastIndexOf("/") == uri.length()-1) + { + neoUri = uri.substring(0, uri.length()-1); + } + + int pos = neoUri.lastIndexOf("/"); + if (pos > -1) + { + uuidStr = neoUri.substring(pos+1); +// System.out.println("UUID="+uuidStr); + } + return uuidStr; + } + + private String getController(String uri) + { + String controller = "none"; + int pos1 = uri.indexOf("/"); + if (pos1 > -1) + { + int pos2 = uri.indexOf("/", pos1+1); + if (pos2 > -1) + { +// System.out.println("uri="+uri+", pos1="+pos1+", pos2="+pos2); + controller = uri.substring(pos1+1, pos2); + } + } + return controller; + } + + private String serveListingText(Properties header, IClipboardItem item, String tableClass, boolean singleListing) + { + StringBuilder sb = new StringBuilder(); + if (singleListing) + { + sb.append("
"); + } else { + sb.append("
"); + } + + TextSourceData tsd = (TextSourceData) item.getSourceData(); + + sb.append(""); + if (singleListing) + { + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append("
"); + sb.append(""); + sb.append(embeddImage(item.getImage().getImageData(), "image_thumb", "Thumbnail")); + sb.append(""); + sb.append(""); + sb.append("Clipboard Text"+""); + sb.append("
 Download Text"+"Download Compressed"+"
"); + sb.append("
");
+      sb.append(HtmlUtils.escapeHtmlFull(tsd.getText()));      
+    } else {
+      sb.append("
 "); + sb.append("
");
+      sb.append(HtmlUtils.escapeHtmlFull(item.getShortDescription()));      
+    }
+    sb.append("
"); + sb.append("
 Download Text"+"Download Compressed"+"
"); + sb.append("
"); + + return sb.toString(); + } + + private String serveListingFile(Properties header, IClipboardItem item, String tableClass, boolean singleListing) + { + StringBuilder sb = new StringBuilder(); + if (singleListing) + { + sb.append("
"); + } else { + sb.append("
"); + } + + FileSourceData fsd = (FileSourceData) item.getSourceData(); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append("
"); + sb.append(""); + sb.append(embeddImage(item.getImage().getImageData(), "image_thumb", "Thumbnail")); + sb.append(""); + sb.append(""); + sb.append(""+fsd.getFilename()+""); + sb.append("
 Download"+"Download Compressed"+"
"); + sb.append("
"); + + return sb.toString(); + } + + private String serveListingImage(Properties header, IClipboardItem item, String tableClass, boolean singleListing) + { + StringBuilder sb = new StringBuilder(); + if (singleListing) + { + sb.append("
"); + } else { + sb.append("
"); + } + + ImageSourceData isd = (ImageSourceData) item.getSourceData(); + + sb.append(""); + if (singleListing) + { + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append("
"); + sb.append(""); + sb.append(embeddImage(item.getImage().getImageData(), "image_thumb", "Thumbnail")); + sb.append(""); + sb.append(""); + sb.append("Clipboard Image"+""); + sb.append("
 Download Image as JPG"+"Download Compressed"+"
"); + sb.append(""); + sb.append(embeddImage(isd.getImageData(), "image", "Full Image")); + sb.append(""); + } + sb.append("
 Dimension: "); + ImageData imgData = isd.getImageData(); + String dimStr = "?"; + if (imgData != null) + { + dimStr = ""+imgData.width + " x "+imgData.height + " pixel"; + } + sb.append(dimStr).append("
 Download Image as JPG"+"Download Compressed"+"
"); + sb.append("
"); + + return sb.toString(); + } + + private HTTPResponse serveDownloadFile(Properties header, IClipboardItem item, boolean compress) + { + FileSourceData fsd = (FileSourceData) item.getSourceData(); + + if (fsd.isDirectory()) + { + compress = true; + } + + // Download from a remote Simidude if necessary + SourceDataManager sourceDataManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + + if ((sourceDataManager.isRetrieveContentsNeeded(item)) && (!sourceDataManager.isDownloadInProgress(item.getSourceData()))) + { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.retrieveContentsForProxyObject(item.getSourceData()); + // Wait until data arrived + try + { + Thread.sleep(200); + while ((sourceDataManager.isRetrieveContentsNeeded(item)) && (sourceDataManager.isDownloadInProgress(item.getSourceData()))) + { + Thread.sleep(100); + } + } catch (InterruptedException e) + { + e.printStackTrace(); + } + if (sourceDataManager.isRetrieveContentsNeeded(item)) + { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "A problem occured downloading "+fsd.getFilename()+" from a remote Simidude."); + } + } + + File f = new File(fsd.getLocalFilename()); + String filename = f.getName(); + + try + { + if (compress) + { + filename = FileUtils.replaceLastExtension(f.getName(), ".zip"); + f = ZipUtils.zipFile(f, CacheManagerFactory.createTempFile(".zip")); + } + + // Get MIME type from file name extension, if possible + String mime = null; + int dot = f.getCanonicalPath().lastIndexOf('.'); + if (dot >= 0) + { + mime = (String) httpUtils.theMimeTypes.get(f.getCanonicalPath().substring(dot + 1).toLowerCase()); + } + if (mime == null) + { + mime = HTTPUtils.MIME_DEFAULT_BINARY; + } + + // Support (simple) skipping: + long startFrom = 0; + String range = header.getProperty("Range"); + if (range != null) + { + if (range.startsWith("bytes=")) + { + range = range.substring("bytes=".length()); + int minus = range.indexOf('-'); + if (minus > 0) + range = range.substring(0, minus); + try + { + startFrom = Long.parseLong(range); + } catch (NumberFormatException nfe) + { + } + } + } + + FileInputStream fis = new FileInputStream(f); + fis.skip(startFrom); + HTTPResponse r = new HTTPResponse(HTTPUtils.HTTP_OK, mime, fis); + r.addHeader("Content-Disposition", "attachment; filename=\""+filename+"\""); + r.addHeader("Content-length", "" + (f.length() - startFrom)); + r.addHeader("Content-range", "" + startFrom + "-" + (f.length() - 1) + "/" + f.length()); + return r; + } catch (IOException ioe) + { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "FORBIDDEN: Reading file failed."); + } + } + + private HTTPResponse serveDownloadText(Properties header, IClipboardItem item, boolean compress) + { + TextSourceData tsd = (TextSourceData) item.getSourceData(); + + String text = tsd.getText(); + String filename; + byte[] buffer; + + if (compress) + { + buffer = ZipUtils.zipBuffer("ClipboardText.txt", text.getBytes()); + filename = "ClipboardText.zip"; + } else { + buffer = text.getBytes(); + filename = "ClipboardText.txt"; + } + + return serveDownloadBuffer(header, buffer, filename); + } + + private HTTPResponse serveDownloadImage(Properties header, IClipboardItem item, boolean compress) + { + ImageSourceData isd = (ImageSourceData) item.getSourceData(); + + byte[] buf = FileUtils.readImage(isd.getImageData(), SWT.IMAGE_JPEG); + String filename = "ClipboardImage.jpg"; + + if (compress) + { + buf = ZipUtils.zipBuffer("ClipboardImage.jpg", buf); + filename = "ClipboardImage.zip"; + } + + return serveDownloadBuffer(header, buf, filename); + } + + private HTTPResponse serveDownloadBuffer(Properties header, byte[] buffer, String filename) + { + HTTPResponse r = new HTTPResponse(HTTPUtils.HTTP_OK, HTTPUtils.MIME_DEFAULT_BINARY, buffer); + r.addHeader("Content-Disposition", "attachment; filename=\""+filename+"\""); + r.addHeader("Content-length", "" + buffer.length); + r.addHeader("Content-range", "" + 0 + "-" + (buffer.length - 1) + "/" + buffer.length); + return r; + } + + private HTTPResponse serveSpecialEntry(String uri, Properties header) + { + if (uri.equalsIgnoreCase("/favicon.ico")) + { + byte[] buffer = FileUtils.loadFile(this.getClass().getClassLoader().getResourceAsStream(IPreferenceConstants.FAVICON_PATH), IPreferenceConstants.FAVICON_PATH); + return serveDownloadBuffer(header, buffer, "favicon.ico"); + } else { + return new HTTPResponse(HTTPUtils.HTTP_FORBIDDEN, HTTPUtils.MIME_PLAINTEXT, "FORBIDDEN: Unknown URI: "+uri); + } + } + + private String embeddImage(ImageData imgData, String cssClass, String altText) + { + BASE64Encoder encoder = new BASE64Encoder(); + String str = encoder.encode(FileUtils.readImage(imgData, SWT.IMAGE_JPEG)); + String result = "\""+altText+"\"/"; + return result; + } + + + + +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/httpd/HTTPSessionBase.java b/src/java/com/agynamix/platform/httpd/HTTPSessionBase.java new file mode 100644 index 0000000..2a28688 --- /dev/null +++ b/src/java/com/agynamix/platform/httpd/HTTPSessionBase.java @@ -0,0 +1,220 @@ +package com.agynamix.platform.httpd; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.Socket; +import java.net.URLEncoder; +import java.util.Properties; +import java.util.StringTokenizer; + +import java.io.BufferedReader; + +/** + * Handles one session, i.e. parses the HTTP request + * and returns the response. + */ +public abstract class HTTPSessionBase implements Runnable +{ + + protected HTTPUtils httpUtils; + protected Socket mySocket; + + protected Properties environment; + + protected abstract boolean postProcessRequestHeader(Properties environment, Properties header) throws InterruptedException, IOException; + protected abstract HTTPResponse serve(String uri, String method, Properties header, Properties parms); + + public HTTPSessionBase( Properties environment, Socket s ) + { + mySocket = s; + this.environment = environment; + httpUtils = new HTTPUtils(s); + Thread t = new Thread( this ); + t.setDaemon( true ); + t.start(); + } + + public void run() + { + try + { + InputStream is = mySocket.getInputStream(); + if ( is == null) return; + BufferedReader in = new BufferedReader( new InputStreamReader( is )); + + // Read the request line + StringTokenizer st = new StringTokenizer( in.readLine()); + if ( !st.hasMoreTokens()) + httpUtils.sendError( HTTPUtils.HTTP_BADREQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html" ); + + String method = st.nextToken(); + + if ( !st.hasMoreTokens()) + httpUtils.sendError( HTTPUtils.HTTP_BADREQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html" ); + + String uri = st.nextToken(); + + // Decode parameters from the URI + Properties parms = new Properties(); + int qmi = uri.indexOf( '?' ); + if ( qmi >= 0 ) + { + decodeParms( uri.substring( qmi+1 ), parms ); + uri = decodePercent( uri.substring( 0, qmi )); + } + else uri = decodePercent(uri); + + + // If there's another token, it's protocol version, + // followed by HTTP headers. Ignore version but parse headers. + // NOTE: this now forces header names uppercase since they are + // case insensitive and vary by client. + Properties header = new Properties(); + if ( st.hasMoreTokens()) + { + String line = in.readLine(); + while ( line.trim().length() > 0 ) + { + int p = line.indexOf( ':' ); + header.put( line.substring(0,p).trim().toLowerCase(), line.substring(p+1).trim()); + line = in.readLine(); + } + } + + // If the method is POST, there may be parameters + // in data section, too, read it: + if ( method.equalsIgnoreCase( "POST" )) + { + long size = 0x7FFFFFFFFFFFFFFFl; + String contentLength = header.getProperty("content-length"); + if (contentLength != null) + { + try { size = Integer.parseInt(contentLength); } + catch (NumberFormatException ex) {} + } + String postLine = ""; + char buf[] = new char[512]; + int read = in.read(buf); + while ( read >= 0 && size > 0 && !postLine.endsWith("\r\n") ) + { + size -= read; + postLine += String.valueOf(buf, 0, read); + if ( size > 0 ) + read = in.read(buf); + } + postLine = postLine.trim(); + decodeParms( postLine, parms ); + } + + if (postProcessRequestHeader(environment, header)) + { + // Ok, now do the serve() + HTTPResponse r = serve( uri, method, header, parms ); + if ( r == null ) + { + httpUtils.sendError( HTTPUtils.HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: Serve() returned a null response." ); + } else { + httpUtils.sendResponse( r.status, r.mimeType, r.header, r.data ); + } + } + + in.close(); + } + catch ( IOException ioe ) + { + try + { + httpUtils.sendError( HTTPUtils.HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); + } + catch ( Throwable t ) {} + } + catch ( InterruptedException ie ) + { + // Thrown by sendError, ignore and exit the thread. + } + } + + /** + * Decodes the percent encoding scheme.
+ * For example: "an+example%20string" -> "an example string" + */ + protected String decodePercent( String str ) throws InterruptedException + { + try + { + StringBuffer sb = new StringBuffer(); + for( int i=0; i (String)MIME_TYPE + */ + public static Hashtable theMimeTypes = new Hashtable(); + + static + { + gmtFrmt = new java.text.SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + + StringTokenizer st = new StringTokenizer( + "htm text/html "+ + "html text/html "+ + "txt text/plain "+ + "asc text/plain "+ + "gif image/gif "+ + "jpg image/jpeg "+ + "jpeg image/jpeg "+ + "png image/png "+ + "mp3 audio/mpeg "+ + "m3u audio/mpeg-url " + + "pdf application/pdf "+ + "doc application/msword "+ + "ogg application/x-ogg "+ + "zip application/octet-stream "+ + "exe application/octet-stream "+ + "class application/octet-stream " ); + while ( st.hasMoreTokens()) + { + theMimeTypes.put( st.nextToken(), st.nextToken()); + } + + } + + public HTTPUtils(Socket s) + { + mySocket = s; + } + + /** + * Returns an error message as a HTTP response and throws InterruptedException + * to stop further request processing. + */ + public void sendError(String status, String msg) throws InterruptedException + { + sendResponse(status, HTTPUtils.MIME_PLAINTEXT, null, new ByteArrayInputStream(msg.getBytes())); + throw new InterruptedException(); + } + + public void sendNotAuthorized(String realm) + { + Properties p = new Properties(); + p.setProperty("WWW-Authenticate", "Basic realm=\""+realm+"\""); + sendResponse(HTTPUtils.HTTP_UNAUTHORIZED, HTTPUtils.MIME_PLAINTEXT, p, new ByteArrayInputStream("Not Authorized".getBytes())); + } + + /** + * Sends given response to the socket. + */ + public void sendResponse(String status, String mime, Properties header, InputStream data) + { + try + { + if (status == null) + throw new Error("sendResponse(): Status can't be null."); + + OutputStream out = mySocket.getOutputStream(); + PrintWriter pw = new PrintWriter(out); + pw.print("HTTP/1.0 " + status + " \r\n"); + + if (mime != null) + pw.print("Content-Type: " + mime + "\r\n"); + + if (header == null || header.getProperty("Date") == null) + pw.print("Date: " + gmtFrmt.format(new Date()) + "\r\n"); + + if (header != null) + { + Enumeration e = header.keys(); + while (e.hasMoreElements()) + { + String key = (String) e.nextElement(); + String value = header.getProperty(key); + pw.print(key + ": " + value + "\r\n"); + } + } + + pw.print("\r\n"); + pw.flush(); + + if (data != null) + { + byte[] buff = new byte[2048]; + while (true) + { + int read = data.read(buff, 0, 2048); + if (read <= 0) + break; + out.write(buff, 0, read); + } + } + out.flush(); + out.close(); + if (data != null) + data.close(); + } catch (IOException ioe) + { + // Couldn't write? No can do. + try + { + mySocket.close(); + } catch (Throwable t) + { + } + } + } + +} diff --git a/src/java/com/agynamix/platform/httpd/HttpServer.java b/src/java/com/agynamix/platform/httpd/HttpServer.java new file mode 100644 index 0000000..0474d2d --- /dev/null +++ b/src/java/com/agynamix/platform/httpd/HttpServer.java @@ -0,0 +1,110 @@ +package com.agynamix.platform.httpd; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.Properties; + +/** + * License: + * Copyright (C) 2001,2005-2008 by Jarno Elonen + * 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. The name of the author may not + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * A simple, tiny, nicely embeddable HTTP 1.0 server in Java + * + *

+ * NanoHTTPD version 1.11, Copyright © 2001,2005-2008 Jarno Elonen + * (elonen@iki.fi, http://iki.fi/elonen/) + * + *

+ * Features + limitations: + *

    + * + *
  • Only one Java file
  • + *
  • Java 1.1 compatible
  • + *
  • Released as open source, Modified BSD licence
  • + *
  • No fixed config files, logging, authorization etc. (Implement yourself if + * you need them.)
  • + *
  • Supports parameter parsing of GET and POST methods
  • + *
  • Supports both dynamic content and file serving
  • + *
  • Never caches anything
  • + *
  • Doesn't limit bandwidth, request time or simultaneous connections
  • + *
  • Default code serves files and shows all HTTP parameters and headers
  • + *
  • File server supports directory listing, index.html and index.htm
  • + *
  • File server does the 301 redirection trick for directories without '/'
  • + *
  • File server supports simple skipping for files (continue download)
  • + *
  • File server uses current directory as a web root
  • + *
  • File server serves also very long files without memory overhead
  • + *
  • Contains a built-in list of most common mime types
  • + *
  • All header names are converted lowercase so they don't vary between + * browsers/clients
  • + * + *
+ * + *

+ * Ways to use: + *

    + * + *
  • Run as a standalone app, serves files from current directory and shows + * requests
  • + *
  • Subclass serve() and embed to your own program
  • + *
  • Call serveFile() from serve() with your own base directory
  • + * + *
+ * + * See the end of the source file for distribution license (Modified BSD + * licence) + */ +public class HttpServer { + + private Properties environment; + + /** + * Starts a HTTP server to given port. + *

+ * Throws an IOException if the socket is already in use + */ + public HttpServer(Properties env) throws IOException + { + environment = env; + + int myTcpPort = Integer.parseInt(environment.getProperty(HTTPUtils.HTTP_PORT)); + + final ServerSocket ss = new ServerSocket(myTcpPort); + Thread t = new Thread(new Runnable() { + public void run() + { + try + { + while (true) + { + new HTTPSession(environment, ss.accept()); + } + } catch (IOException ioe) + { + } + } + }); + t.setDaemon(true); + t.start(); + } + +} diff --git a/src/java/com/agynamix/platform/icons/Generic_Document.png b/src/java/com/agynamix/platform/icons/Generic_Document.png new file mode 100644 index 0000000..0835dee Binary files /dev/null and b/src/java/com/agynamix/platform/icons/Generic_Document.png differ diff --git a/src/java/com/agynamix/platform/icons/Icon_16.png b/src/java/com/agynamix/platform/icons/Icon_16.png new file mode 100644 index 0000000..beba1b0 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/Icon_16.png differ diff --git a/src/java/com/agynamix/platform/icons/Icon_16_bw.png b/src/java/com/agynamix/platform/icons/Icon_16_bw.png new file mode 100644 index 0000000..bb7c9dc Binary files /dev/null and b/src/java/com/agynamix/platform/icons/Icon_16_bw.png differ diff --git a/src/java/com/agynamix/platform/icons/PlatformIcons.java b/src/java/com/agynamix/platform/icons/PlatformIcons.java new file mode 100644 index 0000000..d26a3c7 --- /dev/null +++ b/src/java/com/agynamix/platform/icons/PlatformIcons.java @@ -0,0 +1,123 @@ +package com.agynamix.platform.icons; + +import java.io.InputStream; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +import com.agynamix.platform.infra.ApplicationBase; + + +public class PlatformIcons { + + private static ImageRegistry imageRegistry = null; + + public static final String SIMIDUDE_WND_ICN = "Icon_16.png"; + public static final String SIMIDUDE_MAC_ICN = "Icon_16_bw.png"; + + public static final String HOME = "home_nav.gif"; + public static final String HELP = "linkto_help.gif"; + public static final String EXIT = "exit.gif"; + public static final String SEARCH = "search.gif"; + public static final String TRASH = "trash.gif"; + public static final String TOGGLE_MONITOR_CLIPBOARD = "toggle_monitor_clipboard.gif"; + public static final String SELECT_MONITORED_CLIPBOARD_ITEMS = "select_monitored_items.gif"; + public static final String TOGGLE_SHOW_TOOLBAR = "show_toolbar.gif"; + public static final String CLEAR_CLIPBOARD = "clear_clipboard.gif"; + public static final String NETWORK_CLEAR_CLIPBOARD = "network_clear_clipboard.gif"; + public static final String REMOVE_SELECTED_CLIPBOARD_ENTRY = "remove_selected_clipboard_entry.gif"; + public static final String NETWORK_REMOVE_SELECTED_CLIPBOARD_ENTRY = "network_remove_selected_clipboard_entry.gif"; + public static final String ACTIVATE_TABLE_ENTRY = "activate_table_entry.gif"; + public static final String INPUT_TEXT = "input_text.gif"; + public static final String DOWNLOAD_CONTENTS_TABLE_ENTRY = "download_contents.gif"; + public static final String SAVE_CONTENTS_AS_TABLE_ENTRY = "save_as.gif"; + public static final String SAVE_CONTENTS_COMPRESSED_TABLE_ENTRY = "save_compressed.gif"; + public static final String OPEN_TABLE_ENTRY = "open_entry.gif"; + public static final String UPDATE = "update.gif"; + public static final String COPY = "copy.gif"; + public static final String CUT = "cut.gif"; + + public static final String COLIMG_TEXT = "Text-Edit.png"; + public static final String COLIMG_URI = "uri.png"; + public static final String COLIMG_FILE = "file.png"; + public static final String COLIMG_FOLDER = "folder.png"; + public static final String COLIMG_DOWNLOAD_NEEDED_FOLDER = "folder_needs_download.png"; + public static final String COLIMG_DOWNLOAD_NEEDED_FILE = "file_needs_download.png"; + public static final String COLIMG_IMAGE_UNDEF = "undefined.png"; + public static final String DOWNLOAD_NEEDED_OVERLAY = "download_needed_overlay.gif"; + + public static final String SIMIDUDE_LOGO = "Simidude_Logo.jpg"; + + public static final String BUGZSCOUT_DIALOG = "bugzscout_dialog.gif"; + public static final String SUBMIT_BUG_REPORT = "bug_report.gif"; + + + + + + + + + + + + + + + + + + + + public static void disposeAll() + { + getImageRegistry().dispose(); + } + + public static Image get(String filename) + { + Image image = getImageRegistry().get(filename); + if (image == null) + { + InputStream in = PlatformIcons.class.getResourceAsStream(filename); + if (in == null) + { + return null; + } + image = new Image(Display.getCurrent(), in); + getImageRegistry().put(filename, image); + } + return image; + } + + public static ImageDescriptor getDescriptor(String filename) + { + ImageDescriptor desc = getImageRegistry().getDescriptor(filename); + if (desc == null) + { + desc = ImageDescriptor.createFromFile(PlatformIcons.class, filename); + getImageRegistry().put(filename, desc); + } + return desc; + } + + public static Image getDisabled(String filename) + { + return get(filename.replaceFirst("\\.gif", "-d.gif")); + } + + private static ImageRegistry getImageRegistry() + { + if (imageRegistry == null) + { + imageRegistry = ApplicationBase.getContext().getImageRegistry(); + } + return imageRegistry; + } + + private PlatformIcons() + { + } +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/icons/Simidude_Logo.jpg b/src/java/com/agynamix/platform/icons/Simidude_Logo.jpg new file mode 100644 index 0000000..4982255 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/Simidude_Logo.jpg differ diff --git a/src/java/com/agynamix/platform/icons/Text-Edit.png b/src/java/com/agynamix/platform/icons/Text-Edit.png new file mode 100644 index 0000000..5dc265c Binary files /dev/null and b/src/java/com/agynamix/platform/icons/Text-Edit.png differ diff --git a/src/java/com/agynamix/platform/icons/activate_table_entry.gif b/src/java/com/agynamix/platform/icons/activate_table_entry.gif new file mode 100644 index 0000000..c753995 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/activate_table_entry.gif differ diff --git a/src/java/com/agynamix/platform/icons/bug_report.gif b/src/java/com/agynamix/platform/icons/bug_report.gif new file mode 100755 index 0000000..54525a7 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/bug_report.gif differ diff --git a/src/java/com/agynamix/platform/icons/bugzscout_dialog.gif b/src/java/com/agynamix/platform/icons/bugzscout_dialog.gif new file mode 100644 index 0000000..639b00c Binary files /dev/null and b/src/java/com/agynamix/platform/icons/bugzscout_dialog.gif differ diff --git a/src/java/com/agynamix/platform/icons/clear_clipboard.gif b/src/java/com/agynamix/platform/icons/clear_clipboard.gif new file mode 100644 index 0000000..cbb71be Binary files /dev/null and b/src/java/com/agynamix/platform/icons/clear_clipboard.gif differ diff --git a/src/java/com/agynamix/platform/icons/copy.gif b/src/java/com/agynamix/platform/icons/copy.gif new file mode 100644 index 0000000..71d7c95 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/copy.gif differ diff --git a/src/java/com/agynamix/platform/icons/cut.gif b/src/java/com/agynamix/platform/icons/cut.gif new file mode 100644 index 0000000..d044e59 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/cut.gif differ diff --git a/src/java/com/agynamix/platform/icons/download_contents.gif b/src/java/com/agynamix/platform/icons/download_contents.gif new file mode 100644 index 0000000..a0b7b91 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/download_contents.gif differ diff --git a/src/java/com/agynamix/platform/icons/download_needed_overlay.gif b/src/java/com/agynamix/platform/icons/download_needed_overlay.gif new file mode 100644 index 0000000..261f626 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/download_needed_overlay.gif differ diff --git a/src/java/com/agynamix/platform/icons/exit.gif b/src/java/com/agynamix/platform/icons/exit.gif new file mode 100644 index 0000000..b6922ac Binary files /dev/null and b/src/java/com/agynamix/platform/icons/exit.gif differ diff --git a/src/java/com/agynamix/platform/icons/exit.png b/src/java/com/agynamix/platform/icons/exit.png new file mode 100644 index 0000000..f42091d Binary files /dev/null and b/src/java/com/agynamix/platform/icons/exit.png differ diff --git a/src/java/com/agynamix/platform/icons/file.png b/src/java/com/agynamix/platform/icons/file.png new file mode 100644 index 0000000..7db64ee Binary files /dev/null and b/src/java/com/agynamix/platform/icons/file.png differ diff --git a/src/java/com/agynamix/platform/icons/file_needs_download.png b/src/java/com/agynamix/platform/icons/file_needs_download.png new file mode 100644 index 0000000..29f1e0b Binary files /dev/null and b/src/java/com/agynamix/platform/icons/file_needs_download.png differ diff --git a/src/java/com/agynamix/platform/icons/folder.png b/src/java/com/agynamix/platform/icons/folder.png new file mode 100644 index 0000000..6907cc3 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/folder.png differ diff --git a/src/java/com/agynamix/platform/icons/folder_needs_download.png b/src/java/com/agynamix/platform/icons/folder_needs_download.png new file mode 100644 index 0000000..42a286f Binary files /dev/null and b/src/java/com/agynamix/platform/icons/folder_needs_download.png differ diff --git a/src/java/com/agynamix/platform/icons/home_nav.gif b/src/java/com/agynamix/platform/icons/home_nav.gif new file mode 100644 index 0000000..4472e8c Binary files /dev/null and b/src/java/com/agynamix/platform/icons/home_nav.gif differ diff --git a/src/java/com/agynamix/platform/icons/input_text.gif b/src/java/com/agynamix/platform/icons/input_text.gif new file mode 100644 index 0000000..922306c Binary files /dev/null and b/src/java/com/agynamix/platform/icons/input_text.gif differ diff --git a/src/java/com/agynamix/platform/icons/linkto_help.gif b/src/java/com/agynamix/platform/icons/linkto_help.gif new file mode 100644 index 0000000..86550fe Binary files /dev/null and b/src/java/com/agynamix/platform/icons/linkto_help.gif differ diff --git a/src/java/com/agynamix/platform/icons/network_clear_clipboard.gif b/src/java/com/agynamix/platform/icons/network_clear_clipboard.gif new file mode 100644 index 0000000..8c4aec4 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/network_clear_clipboard.gif differ diff --git a/src/java/com/agynamix/platform/icons/network_remove_selected_clipboard_entry.gif b/src/java/com/agynamix/platform/icons/network_remove_selected_clipboard_entry.gif new file mode 100644 index 0000000..c56e245 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/network_remove_selected_clipboard_entry.gif differ diff --git a/src/java/com/agynamix/platform/icons/open_entry.gif b/src/java/com/agynamix/platform/icons/open_entry.gif new file mode 100644 index 0000000..d6b3bdc Binary files /dev/null and b/src/java/com/agynamix/platform/icons/open_entry.gif differ diff --git a/src/java/com/agynamix/platform/icons/remove_selected_clipboard_entry.gif b/src/java/com/agynamix/platform/icons/remove_selected_clipboard_entry.gif new file mode 100644 index 0000000..35d1d1b Binary files /dev/null and b/src/java/com/agynamix/platform/icons/remove_selected_clipboard_entry.gif differ diff --git a/src/java/com/agynamix/platform/icons/save_as.gif b/src/java/com/agynamix/platform/icons/save_as.gif new file mode 100644 index 0000000..466bfb1 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/save_as.gif differ diff --git a/src/java/com/agynamix/platform/icons/save_compressed.gif b/src/java/com/agynamix/platform/icons/save_compressed.gif new file mode 100755 index 0000000..a159667 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/save_compressed.gif differ diff --git a/src/java/com/agynamix/platform/icons/search.gif b/src/java/com/agynamix/platform/icons/search.gif new file mode 100644 index 0000000..d540a01 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/search.gif differ diff --git a/src/java/com/agynamix/platform/icons/select_monitored_items.gif b/src/java/com/agynamix/platform/icons/select_monitored_items.gif new file mode 100755 index 0000000..2b347ac Binary files /dev/null and b/src/java/com/agynamix/platform/icons/select_monitored_items.gif differ diff --git a/src/java/com/agynamix/platform/icons/show_toolbar.gif b/src/java/com/agynamix/platform/icons/show_toolbar.gif new file mode 100755 index 0000000..43e524d Binary files /dev/null and b/src/java/com/agynamix/platform/icons/show_toolbar.gif differ diff --git a/src/java/com/agynamix/platform/icons/toggle_monitor_clipboard.gif b/src/java/com/agynamix/platform/icons/toggle_monitor_clipboard.gif new file mode 100644 index 0000000..331995d Binary files /dev/null and b/src/java/com/agynamix/platform/icons/toggle_monitor_clipboard.gif differ diff --git a/src/java/com/agynamix/platform/icons/trash.gif b/src/java/com/agynamix/platform/icons/trash.gif new file mode 100644 index 0000000..bf961b3 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/trash.gif differ diff --git a/src/java/com/agynamix/platform/icons/undefined.png b/src/java/com/agynamix/platform/icons/undefined.png new file mode 100644 index 0000000..05e3f6a Binary files /dev/null and b/src/java/com/agynamix/platform/icons/undefined.png differ diff --git a/src/java/com/agynamix/platform/icons/update.gif b/src/java/com/agynamix/platform/icons/update.gif new file mode 100644 index 0000000..be33d14 Binary files /dev/null and b/src/java/com/agynamix/platform/icons/update.gif differ diff --git a/src/java/com/agynamix/platform/icons/uri.png b/src/java/com/agynamix/platform/icons/uri.png new file mode 100644 index 0000000..079712b Binary files /dev/null and b/src/java/com/agynamix/platform/icons/uri.png differ diff --git a/src/java/com/agynamix/platform/impl/ConfigurationImpl.java b/src/java/com/agynamix/platform/impl/ConfigurationImpl.java new file mode 100644 index 0000000..9a3c4da --- /dev/null +++ b/src/java/com/agynamix/platform/impl/ConfigurationImpl.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +import org.eclipse.swt.graphics.Rectangle; + +import com.agynamix.platform.infra.IConfiguration; +import com.agynamix.platform.log.ApplicationLog; + +public class ConfigurationImpl implements IConfiguration { + + ConfigurationImpl configuration; + Preferences userPrefs; + final Properties defaultValues = new Properties(); + + Logger log = ApplicationLog.getLogger(ConfigurationImpl.class); + + public ConfigurationImpl getInstance() + { + if (configuration == null) + { + configuration = new ConfigurationImpl(); + } + return configuration; + } + + public ConfigurationImpl() + { + String path = classname2path(IConfiguration.class.getName()); + log.fine("Check Path "+path); + try + { + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(IConfiguration.CONFIG_FILE); + if (ins != null) + { + defaultValues.load(ins); + ins.close(); + userPrefs = Preferences.userNodeForPackage(IConfiguration.class); + for (Object key : defaultValues.keySet()) + { + if (userPrefs.get((String)key, null) == null) + { + String value = defaultValues.getProperty((String)key); + log.fine("Insert default value into Preferences for key "+key+": "+value); + userPrefs.put((String)key, value); + } + } + } + } catch (IOException e) + { + e.printStackTrace(); + } + userPrefs = Preferences.userNodeForPackage(IConfiguration.class); + } + + private static String classname2path(String classname) + { + int pos = classname.lastIndexOf("."); + String part = classname.substring(0, pos); + part = part.replace('.', '/'); + return '/' + part; + } + + public void save() + { + // Nothing to do here. + } + + public Properties exportProperties() + { + Properties props = new Properties(); + try + { + String[] keys = userPrefs.keys(); + for (String key : keys) + { + String value = userPrefs.get(key, null); + props.setProperty(key, value); + } + } catch (BackingStoreException e) + { + e.printStackTrace(); + } + return props; + } + + public Properties exportDefaultProperties() + { + Properties p = new Properties(); + for (Object key : defaultValues.keySet()) + { + p.setProperty((String) key, defaultValues.getProperty((String) key)); + } + return p; + } + + public String getProperty(String key) + { + return userPrefs.get(key, getStringDefault(key)); + } + + public List getProperyList(String key) + { + String value = userPrefs.get(key, getStringDefault(key)); + if ((value != null) && (value.length() > 0)) + { + StringTokenizer st = new StringTokenizer(value, ","); + List v = new ArrayList(); + while (st.hasMoreTokens()) + { + v.add(st.nextToken()); + } + return v; + } + return new ArrayList(); + } + + public int getInteger(String key) + { + return userPrefs.getInt(key, getIntDefault(key)); + } + + public void setInteger(String key, int value) + { + userPrefs.putInt(key, value); + } + + public byte[] getByteArray(String key) + { + return userPrefs.getByteArray(key, getByteArrayDefault(key)); + } + + public long getLong(String key) + { + return userPrefs.getLong(key, getLongDefault(key)); + } + + public Rectangle getRectangle(String key) + { + String value = userPrefs.get(key, getStringDefault(key)); + if (value != null) + { + StringTokenizer st = new StringTokenizer(value, "-"); + int[] v = new int[4]; + int i = 0; + try { + while (st.hasMoreTokens()) + { + String s = st.nextToken(); + v[i] = Integer.parseInt(s); + i++; + } + } catch (Exception e) + { + log.log(Level.WARNING, "Rectangle property could not be read: "+e.getMessage(), e); + return null; + } + return new Rectangle(v[0], v[1], v[2], v[3]); + } + return null; + } + + public void setByteArray(String key, byte[] value) + { + userPrefs.putByteArray(key, value); + } + + public void setLong(String key, long value) + { + userPrefs.putLong(key, value); + } + + public boolean getBoolean(String key) + { + return userPrefs.getBoolean(key, getBooleanDefault(key)); + } + + public void setBoolean(String key, boolean value) + { + userPrefs.putBoolean(key, value); + } + + public void setProperty(String key, String value) + { + userPrefs.put(key, value); + } + + public void setRectangle(String key, Rectangle rectangle) + { + StringBuilder sb = new StringBuilder(); + sb.append(rectangle.x).append("-").append(rectangle.y).append("-").append(rectangle.width).append("-").append(rectangle.height); + userPrefs.put(key, sb.toString()); + } + + public void setProperty(String key, Object value) + { + if (value instanceof Boolean) + { + setBoolean(key, ((Boolean) value)); + } else if (value instanceof Integer) + { + setInteger(key, ((Integer) value)); + } else if (value instanceof Long) + { + setLong(key, ((Long) value)); + } else if (value instanceof Rectangle) + { + setRectangle(key, (Rectangle)value); + } else { + if (value != null) + { + setProperty(key, value.toString()); + } + } + } + + public String getStringDefault(String key) + { + return defaultValues.getProperty(key); + } + + public byte[] getByteArrayDefault(String key) + { + String s = getStringDefault(key); + return s != null ? s.getBytes() : null; + } + + public int getIntDefault(String key) + { + return (int) getLongDefault(key); + } + + public long getLongDefault(String key) + { + String s = getStringDefault(key); + try + { + return s != null ? Long.parseLong(s): 0; + } catch (Exception e) + { + e.printStackTrace(); + return 0; + } + } + + public boolean getBooleanDefault(String key) + { + String s = getStringDefault(key); + if (s != null) + { + return Boolean.parseBoolean(s); + } + return false; + } + + +} diff --git a/src/java/com/agynamix/platform/impl/ConfigurationUtil.java b/src/java/com/agynamix/platform/impl/ConfigurationUtil.java new file mode 100644 index 0000000..eadeb8a --- /dev/null +++ b/src/java/com/agynamix/platform/impl/ConfigurationUtil.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.agynamix.platform.infra.ApplicationInfo; +import com.agynamix.platform.infra.PlatformUtils; + +/** + * static utility functions that help configuring the system + * + * @version $Revision: 27 $ $Date: 2004-11-27 22:42:44 +0100 (Sa, 27 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class ConfigurationUtil { + + static final String CFG_FILE_EXT = "cfg.xml"; + + static String configFile = null; + + /** + * @return a platform dependant directory where user preference data is stored. + * This will be: + * ~/.Simidude on Unix + * ~/Library/Preferences/Simidude on Mac + * ~/.Simidude on Windows (needs fixing!). + */ + public static String getConfigDir() + { + String commonPath = System.getProperty("user.home") + File.separator; + String platformPath = "." + ApplicationInfo.getApplicationName() + File.separator; + if (PlatformUtils.isMacOs()) + { + platformPath = "Library" + File.separator + "Preferences" + File.separator + + ApplicationInfo.getApplicationName() + File.separator; + } + return commonPath + platformPath; + } + + public static void main(String[] args) + { + System.out.println(ConfigurationUtil.getConfigDir()); + } + + public static String getConfigFile() + { + if (configFile == null) + { + String file = ApplicationInfo.getApplicationName(); + configFile = getConfigDir() + file + CFG_FILE_EXT; + + File cfg = new File(configFile); + if (!cfg.exists()) + { + // copy template over to the file location + File tpl = new File("etc/" + file + CFG_FILE_EXT); + if (tpl.exists()) + { + copyFile(tpl, cfg); + } + } + } + return configFile; + } + + private static void copyFile(File src, File dst) + { + dst.getParentFile().mkdirs(); + try { + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst); + + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (IOException e) + { + System.out.println("Could not create config file "+dst.getAbsolutePath()); + } + } + +} diff --git a/src/java/com/agynamix/platform/impl/PreferenceConfigAdapterImpl.java b/src/java/com/agynamix/platform/impl/PreferenceConfigAdapterImpl.java new file mode 100644 index 0000000..a15833d --- /dev/null +++ b/src/java/com/agynamix/platform/impl/PreferenceConfigAdapterImpl.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.impl; + +import java.util.Properties; + +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IConfiguration; +import com.agynamix.platform.infra.IPreferenceConfigAdapter; + +/** + * Adapter that takes changed properties and writes them back to the application property store + * + * @version $Revision: 23 $ $Date: 2004-11-20 14:36:31 +0100 (Sa, 20 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class PreferenceConfigAdapterImpl implements IPropertyChangeListener, IPreferenceConfigAdapter { + + final IConfiguration config; + + static final String SPECIAL_CHAR = ":\\"; + + /** + * List of registered listeners (element type: IPropertyChangeListener). These listeners are to be + * informed when the current value of a preference changes. + */ + private ListenerList listeners = new ListenerList(); + + public PreferenceConfigAdapterImpl() + { + config = ApplicationBase.getContext().getConfiguration(); + } + + /** + * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent event) + { + String property = event.getProperty(); + config.setProperty(property, event.getNewValue()); + propagatePropertyChangeEvent(event); + } + + public Properties loadDefaultProperties() + { + return config.exportDefaultProperties(); + } + + public Properties loadProperties() + { + return config.exportProperties(); + } + + public void saveProperties(Properties p) + { + // Properties are already written into XML through the Listener, now persist them + config.save(); + } + + protected String escapeSpecials(String in) + { + StringBuffer out = new StringBuffer(); + for (int i = 0, j = in.length(); i < j; i++) + { + if (SPECIAL_CHAR.indexOf(in.charAt(i)) != -1) + { + out.append("\\"); + } + out.append(in.charAt(i)); + } + return out.toString(); + } + + /** + * Forward this event to other registered listeners + * + * @param event + * PropertyChangeEvent + */ + void propagatePropertyChangeEvent(PropertyChangeEvent event) + { + final Object[] finalListeners = this.listeners.getListeners(); + for (int i = 0; i < finalListeners.length; ++i) + { + IPropertyChangeListener l = (IPropertyChangeListener) finalListeners[i]; + l.propertyChange(event); + } + } + + /** + * @see com.agynamix.simidude.infra.PreferenceConfigAdapter#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener) + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) + { + listeners.add(listener); + } + + public void removePropertyChangeListener(IPropertyChangeListener listener) + { + listeners.remove(listener); + } + +} diff --git a/src/java/com/agynamix/platform/impl/QueueManagerImpl.java b/src/java/com/agynamix/platform/impl/QueueManagerImpl.java new file mode 100644 index 0000000..72e8722 --- /dev/null +++ b/src/java/com/agynamix/platform/impl/QueueManagerImpl.java @@ -0,0 +1,112 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.platform.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import com.agynamix.platform.infra.IQueueManager; + +@SuppressWarnings("unchecked") +public class QueueManagerImpl implements IQueueManager { + + public final static int QUEUE_MAX_CAPACITY = 500; + + Map queueMap = new HashMap(); + +// BlockingQueue queue = new LinkedBlockingQueue(); + + public QueueManagerImpl() + { + } + + public void put(String queueName, Object o) + { + if (o != null) + { + BlockingQueue queue = getQueueByName(queueName); + try + { + queue.put(o); + } catch (InterruptedException e) + { +// e.printStackTrace(); + } + } + } + + public void putAll(String queueName, List items) + { + if (items != null) + { + for (Object item : items) + { + put(queueName, item); + } + } + } + + public void putAllReverse(String queueName, List items) + { + if (items != null) + { + for (int i = items.size()-1; i >= 0; i--) + { + put(queueName, items.get(i)); + } + } + } + + public void putAll(String queueName, Object[] items) + { + if (items != null) + { + for (Object item : items) + { + put(queueName, item); + } + } + } + + public Object take(String queueName) + { + BlockingQueue queue = getQueueByName(queueName); + try + { + return queue.take(); + } catch (InterruptedException e) + { + return null; + } + } + + public void emptyQueue(String queueName) + { + BlockingQueue queue = getQueueByName(queueName); + queue.clear(); + } + + private BlockingQueue getQueueByName(String queueName) + { + BlockingQueue queue = queueMap.get(queueName); + if (queue == null) + { + queue = new LinkedBlockingQueue(QUEUE_MAX_CAPACITY); + queueMap.put(queueName, queue); + } + return queue; + } + +} diff --git a/src/java/com/agynamix/platform/infra/ApplicationBase.java b/src/java/com/agynamix/platform/infra/ApplicationBase.java new file mode 100644 index 0000000..339bc9d --- /dev/null +++ b/src/java/com/agynamix/platform/infra/ApplicationBase.java @@ -0,0 +1,283 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.util.EventObject; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManager; +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.log.ApplicationLog; + +public abstract class ApplicationBase { + + static ApplicationBase itsApplicationInstance; + + private ApplicationContext applicationContext; + String[] args; + + List exitListeners = new CopyOnWriteArrayList(); + + static Logger log = ApplicationLog.getLogger(ApplicationBase.class); + + static boolean isNormalShutdown = false; + + public ApplicationBase() + { + } + + public static ApplicationContext getContext() + { + if (itsApplicationInstance == null) + { + throw new NullPointerException("No Application instance registered"); + } + return itsApplicationInstance.applicationContext; + } + + private void setContext(ApplicationContext contextInstance) + { + this.applicationContext = contextInstance; + } + + public static ApplicationBase getInstance() + { + if (itsApplicationInstance == null) + { + throw new NullPointerException("No Application instance registered"); + } + return itsApplicationInstance; + } + + protected void setArgs(String[] args) + { + this.args = args; + } + + public static void launch(Class applicationClass, ApplicationContext contextInstance, + String[] args) + { + try + { + Object o = applicationClass.newInstance(); + itsApplicationInstance = (ApplicationBase) o; + itsApplicationInstance.setContext(contextInstance); + itsApplicationInstance.setArgs(args); + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler()); + Runtime.getRuntime().addShutdownHook(new ShutdownHandler()); + + itsApplicationInstance.setup(); + itsApplicationInstance.initialize(); + itsApplicationInstance.run(); + + } catch (InstantiationException e) + { + throw new PlatformException(e); + } catch (IllegalAccessException e) + { + throw new PlatformException(e); + } + } + + protected abstract void applicationSetup(); + + /** + * First step in application initialization. During this step all required components should be created. All + * initialization that possibly involves other components should be deferred until the initialization phase. + */ + private final void setup() + { + // Out setup stuff + ThreadManager tm = new ThreadManager(); + getContext().registerService(ThreadManager.SERVICE_NAME, tm); + + ApplicationGUI gui = createApplicationGUI(); + getContext().registerService(ApplicationGUI.SERVICE_NAME, gui); + applicationSetup(); + } + + /** + * Supposed to be overwritten by the implementing class. + */ + protected void applicationInitialize() + { + + } + + private final void initialize() + { + ApplicationGUI gui = getContext().getApplicationGUI(); + gui.initializeApplicationGUI(); + applicationInitialize(); + } + + /** + * Starts base mechanisms + */ + private void internalRun() + { + getContext().getThreadManager().startRegisteredServices(); + } + + protected abstract void startup(); + + protected abstract void prepareRun(); + + protected abstract ApplicationGUI createApplicationGUI(); + + private void run() + { + internalRun(); + + startup(); + + getContext().getApplicationGUI().startup(); + + prepareRun(); + + getContext().getApplicationGUI().run(); + } + + /** + * Called by the implementing application when the app is about to exit. Fires ExitListeners to all interested + * parties. Eventually calls shutdown() to shut down the application. + */ + public void exit() + { + if (!fireCanExit()) + { + return; + } + fireWillExit(); + shutdown(); + System.exit(IPlatformConstants.RC_OK); + } + + protected void shutdown() + { + getContext().getConfiguration().save(); + getContext().getThreadManager().shutdownNow(); + try + { + Thread.sleep(1000); + } catch (InterruptedException ignore) + { + } + getContext().shutdown(); + isNormalShutdown = true; + } + + public void addExitListener(IExitListener listener) + { + this.exitListeners.add(listener); + } + + public void removeExitListener(IExitListener listener) + { + this.exitListeners.remove(listener); + } + + /** + * Tell the Exit listeners that we want to exit and ask if they allow. + * + * @return true if all ExitListeners allow exit, false otherwise. + */ + private boolean fireCanExit() + { + for (int i = exitListeners.size() - 1; i >= 0; i--) + { + IExitListener l = exitListeners.get(i); + if (!(l.canExit(new EventObject(this)))) + { + return false; + } + } + return true; + } + + /** + * Tell all ExitListeners that we will exit. + */ + private void fireWillExit() + { + for (int i = exitListeners.size() - 1; i >= 0; i--) + { + IExitListener l = exitListeners.get(i); + l.willExit(new EventObject(this)); + } + } + + /** + * The shutdown hook is called by the JVM when the system is going down. It will be used to cleanup and closed used + * ressources.
+ * However, the hook MUST be registered with the JVM through Runtime.addShutdownHook() in order to + * be called! + */ + static class ShutdownHandler extends Thread { + + public ShutdownHandler() + { + super(); + } + + public void run() + { + try + { + Thread.sleep(500); + System.out.println("Shutting down Simidude..."); +// try +// { +// if (!isNormalShutdown) +// { +// System.out.println("Emergency Shutdown..."); +// if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.RESTORE_LATEST_ENTRY)) +// { +// SourceDataManager sdm = ((SimidudeApplicationContext) ApplicationBase.getContext()) +// .getSourceDataManager(); +// IClipboardItem item = sdm.getNewestClipboardItem(); +// FileUtils.serialize(item.getSourceData(), PlatformUtils.getApplicationDataDir() + "/" +// + IPreferenceConstants.SAVED_CLP_ITEM_FILE_NAME); +// } +// getContext().getConfiguration().save(); +// getContext().getThreadManager().shutdownNow(); +// } +// } catch (Exception ee) +// { +// ee.printStackTrace(); +// } + } catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + + public void uncaughtException(Thread t, Throwable e) + { + e.printStackTrace(); + String err = String.format("Fatal error occured: {0}, {1}, {2}, {3}, {4}", + t.getName(), e.toString(), e.getStackTrace()[0].getLineNumber(), + e.getStackTrace()[0].getFileName()); + System.out.println(err); + System.exit(1); + } + + } + +} diff --git a/src/java/com/agynamix/platform/infra/ApplicationContext.java b/src/java/com/agynamix/platform/infra/ApplicationContext.java new file mode 100644 index 0000000..112e15c --- /dev/null +++ b/src/java/com/agynamix/platform/infra/ApplicationContext.java @@ -0,0 +1,204 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.FontRegistry; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.widgets.Display; + +import com.agynamix.platform.concurrent.ThreadManager; +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.impl.ConfigurationImpl; + +/** + * This class holds all the context information for this application + * + * @author tuhlmann + * + */ +public class ApplicationContext { + + ImageRegistry imageRegistry; + FontRegistry fontRegistry; + ColorRegistry colorRegistry; + Clipboard clipboard; + + IConfiguration configuration; + + @SuppressWarnings("unchecked") + protected Map locatorMap = new ConcurrentHashMap(10); + + public ApplicationContext() + { + } + + @SuppressWarnings("unchecked") + public synchronized void registerService(String name, Object service) + { + if (!locatorMap.containsKey(name)) + { + locatorMap.put(name, service); + } + } + + public synchronized void deregisterService(String name) + { + if (locatorMap.containsKey(name)) + { + locatorMap.remove(name); + } + } + + public synchronized Object getService(String name) + { + if (locatorMap.containsKey(name)) + { + return locatorMap.get(name); + } else + { + throw new IllegalStateException("Der Dienst " + name + " wurde vom ServiceLocator nicht gefunden!"); + } + } + + public ImageRegistry getImageRegistry() + { + if (imageRegistry == null) + { + imageRegistry = new ImageRegistry(Display.getDefault()); + } + return imageRegistry; + } + + public FontRegistry getFontRegistry() + { + if (fontRegistry == null) + { + fontRegistry = new FontRegistry(Display.getDefault()); + } + return fontRegistry; + } + + public ColorRegistry getColorRegistry() + { + if (colorRegistry == null) + { + colorRegistry = new ColorRegistry(Display.getDefault()); + } + return colorRegistry; + } + + public Clipboard getClipboard() + { + if (clipboard == null) + { + PlatformUtils.safeSyncRunnable(new Runnable() { + public void run() + { + clipboard = new Clipboard(Display.getDefault()); + } + }); + } + return clipboard; + } + + public IConfiguration getConfiguration() + { + if (configuration == null) + { + configuration = new ConfigurationImpl(); + } + return configuration; + } + + public void shutdown() + { + if (clipboard != null) + { + try + { + PlatformUtils.safeSyncRunnable(new Runnable() { + public void run() + { + if ((clipboard != null) && (!clipboard.isDisposed()) && (!Display.getCurrent().isDisposed())) + { + clipboard.dispose(); + clipboard = null; + } + } + }); + } catch (Exception e) + { + System.out.println("Exception while shutting down: " + e.getMessage()); + } + } + } + + public ThreadManager getThreadManager() + { + return (ThreadManager) getService(ThreadManager.SERVICE_NAME); + } + + public ApplicationGUI getApplicationGUI() + { + return (ApplicationGUI) getService(ApplicationGUI.SERVICE_NAME); + } + + /* + * FIXME: See Ticket http://192.168.0.201/FogBugz/default.asp?4987 + */ + public String[] getHostAddresses() + { + List ipAddresses = new ArrayList(); + try + { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) + { + NetworkInterface ni = interfaces.nextElement(); + Enumeration addresses = ni.getInetAddresses(); + while (addresses.hasMoreElements()) + { + InetAddress addr = addresses.nextElement(); + if (!addr.isLoopbackAddress()) + { + if (addr instanceof Inet4Address) + { + ipAddresses.add(addr.getHostAddress()); + } + } + } + } + } catch (SocketException e) + { + e.printStackTrace(); + } + if (ipAddresses.size() == 0) + { + ipAddresses.add("localhost"); + } + return ipAddresses.toArray(new String[ipAddresses.size()]); + } + +} diff --git a/src/java/com/agynamix/platform/infra/ApplicationInfo.java b/src/java/com/agynamix/platform/infra/ApplicationInfo.java new file mode 100644 index 0000000..7f84c90 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/ApplicationInfo.java @@ -0,0 +1,127 @@ +package com.agynamix.platform.infra; + +import java.io.IOException; +import java.util.Properties; + +public class ApplicationInfo { + + public final static String APPLICATION_NAME = "Application-Name"; + public final static String APPLICATION_VERSION = "Application-Version"; + public final static String APPLICATION_YEARS = "Application-Years"; + public final static String COMPANY_NAME = "Company-Name"; + public final static String COMPANY_EMAIL = "Company-Email"; + public final static String COMPANY_WWW = "Company-WWW"; + public final static String COMPANY_ORDER_URL = "Company-Order-Url"; + public final static String REPOSITORY_REV = "Repository-Revision"; + public final static String BUILD_NUMBER = "Build-Number"; + public final static String BUILD_TIME = "Build-Time"; + + public final static String VALUE_FOR_UNKNOWN_KEY = ""; + + public final static String APP_INFO_FILE = "/appinfo.txt"; + + static String[] systemProps = new String[] { "java.runtime.name", "java.vm.version", "java.vm.vendor", "java.vendor.url", + "java.vm.name", "user.country", "java.runtime.version", "os.arch", "os.name", "sun.jnu.encoding", + "sun.management.compiler", "os.version", "http.nonProxyHosts", "file.encoding", "user.language", + "java.version", "java.vendor" }; + + final static Properties properties; + + static + { + properties = new Properties(); + try + { + properties.load(ApplicationInfo.class.getResourceAsStream(APP_INFO_FILE)); + } catch (IOException e) + { + } + } + + private ApplicationInfo() + { + } + + public static String getApplicationName() + { + return saveGet(APPLICATION_NAME); + } + + public static String getApplicationVersion() + { + return saveGet(APPLICATION_VERSION); + } + + public static String getApplicationYears() + { + return saveGet(APPLICATION_YEARS); + } + + public static String getCompanyName() + { + return saveGet(COMPANY_NAME); + } + + public static String getCompanyEmail() + { + return saveGet(COMPANY_EMAIL); + } + + public static String getCompanyWww() + { + return saveGet(COMPANY_WWW); + } + + public static String getCompanyOrderUrl() + { + return saveGet(COMPANY_ORDER_URL); + } + + public static String getRepoRevision() + { + return saveGet(REPOSITORY_REV); + } + + public static String getBuildNumber() + { + return saveGet(BUILD_NUMBER); + } + + public static String getBuildTime() + { + return saveGet(BUILD_TIME); + } + + private static String saveGet(String key) + { + String value = properties.getProperty(key); + if (value != null) + { + return value.trim(); + } else { + return VALUE_FOR_UNKNOWN_KEY; + } + } + + /** + * @return Copy all of the application info into a string + */ + public static String getApplicationInfo() + { + StringBuilder sb = new StringBuilder(); + sb.append("== Application Information: =="); + for (Object key : properties.keySet()) + { + sb.append("\n"); + sb.append(key).append("=").append(properties.get(key)); + } + sb.append("\n\n== System Properties: =="); + for (String key : systemProps) + { + sb.append("\n"); + sb.append(key).append("=").append(System.getProperty(key)); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/infra/DateUtils.java b/src/java/com/agynamix/platform/infra/DateUtils.java new file mode 100644 index 0000000..68bd6f2 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/DateUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +public class DateUtils { + + static Map formatMaps = new HashMap(); + + public static String date2string(String format, Date date) + { + return getDateFormatter(formatMaps, format).format(date); + } + + public static Date string2date(String format, String dateStr) + { + try { + SimpleDateFormat df = getDateFormatter(formatMaps, format); + Date date = df.parse(dateStr); + return date; + } catch (ParseException e) { + throw new IllegalArgumentException("Cannot parse date: " + dateStr); + } + } + + private static SimpleDateFormat getDateFormatter(Map formatMaps, String format) + { + SimpleDateFormat df = formatMaps.get(format); + if (df == null) { + df = new SimpleDateFormat(format); + formatMaps.put(format, df); + } + return df; + } + + + +} diff --git a/src/java/com/agynamix/platform/infra/ExecutorUtils.java b/src/java/com/agynamix/platform/infra/ExecutorUtils.java new file mode 100644 index 0000000..1878d73 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/ExecutorUtils.java @@ -0,0 +1,44 @@ +package com.agynamix.platform.infra; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class ExecutorUtils { + + private static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10); + private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(20); + private static ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); + + public static void addScheduledService(Runnable command, long initialDelay, long delay, TimeUnit timeUnit) + { + scheduledThreadPool.scheduleWithFixedDelay(command, initialDelay, delay, timeUnit); + } + + public static void addFixedService(Runnable command) + { + fixedThreadPool.execute(command); + } + + public static void addParallelTask(Runnable command) + { + cachedThreadPool.execute(command); + } + + public static void shutdownScheduledService() + { + scheduledThreadPool.shutdownNow(); + } + + public static void shutdownFixedService() + { + fixedThreadPool.shutdownNow(); + } + + public static void shutdownParallelTasks() + { + cachedThreadPool.shutdownNow(); + } + +} diff --git a/src/java/com/agynamix/platform/infra/FileUtils.java b/src/java/com/agynamix/platform/infra/FileUtils.java new file mode 100644 index 0000000..7c3522b --- /dev/null +++ b/src/java/com/agynamix/platform/infra/FileUtils.java @@ -0,0 +1,488 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; + +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.impl.ContentsCacheInfo; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + +public class FileUtils { + + static Logger log = ApplicationLog.getLogger(FileUtils.class); + + public final static String[] imageFileExtensions = new String[] { "*.jpg", "*.png", "*.bmp", "*.ico" }; + public final static String[] textFileExtensions = new String[] { "*.txt" }; + public final static String[] zipExtension = new String[] { "*.zip" }; + + public static final String DEFAULT_TEXT_FILE_EXTENSION = ".txt"; + public static final String DEFAULT_IMAGE_FILE_EXTENSION = ".jpg"; + public static final String DEFAULT_ZIP_EXTENSION = ".zip"; + + /** + * This function will copy files or directories from one location to another. note that the source and the destination + * must be mutually exclusive. This function can not be used to copy a directory to a sub directory of itself. The + * function will also have problems if the destination files already exist. + * + * @param src + * -- A File object that represents the source for the copy + * @param dest + * -- A File object that represents the destination for the copy. + * @throws IOException + * if unable to copy. + */ + public static void copyRecursive(File src, File dest) throws IOException + { + // Check to ensure that the source is valid... + if (!src.exists()) + { + throw new IOException("copyFiles: Can not find source: " + src.getAbsolutePath() + "."); + } else if (!src.canRead()) + { // check to ensure we have rights to the source... + throw new IOException("copyFiles: No right to source: " + src.getAbsolutePath() + "."); + } + // is this a directory copy? + if (src.isDirectory()) + { + if (!dest.exists()) + { // does the destination already exist? + // if not we need to make it exist if possible (note this is mkdirs not mkdir) + if (!dest.mkdirs()) + { + throw new IOException("copyFiles: Could not create direcotry: " + dest.getAbsolutePath() + "."); + } + } + // get a listing of files... + String list[] = src.list(); + // copy all the files in the list. + for (int i = 0; i < list.length; i++) + { + File dest1 = new File(dest, list[i]); + File src1 = new File(src, list[i]); + copyRecursive(src1, dest1); + } + } else + { + // This was not a directory, so lets just copy the file + FileInputStream fin = null; + FileOutputStream fout = null; + byte[] buffer = new byte[4096]; // Buffer 4K at a time (you can change this). + int bytesRead; + try + { + // open the files for input and output + fin = new FileInputStream(src); + fout = new FileOutputStream(dest); + // while bytesRead indicates a successful read, lets write... + while ((bytesRead = fin.read(buffer)) >= 0) + { + fout.write(buffer, 0, bytesRead); + } + } catch (IOException e) + { // Error copying file... + IOException wrapper = new IOException("copyFiles: Unable to copy file: " + src.getAbsolutePath() + " to " + + dest.getAbsolutePath() + "."); + wrapper.initCause(e); + wrapper.setStackTrace(e.getStackTrace()); + throw wrapper; + } finally + { // Ensure that the files are closed (if they were open). + if (fin != null) + { + fin.close(); + } + if (fout != null) + { + fout.close(); + } + } + } + } + + /** + * Copies a file + * + * @param in source file + * @param out target file + * @return boolean on success + */ + public static synchronized boolean copyFile(final InputStream in, final OutputStream out) { + try { + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + return true; + } catch (final Exception e) { + log.log(Level.SEVERE, "Failed copying file: " + in + " -> " + out, e); + return false; + } + } + + public static synchronized boolean copyFile(final String in, final String out) { + try { + File outFile = new File(out); + if (!outFile.exists()) { + if (!outFile.createNewFile()) { + return false; + } + } + return copyFile(ClassLoader.getSystemClassLoader() + .getResourceAsStream(in), + new FileOutputStream(outFile)); + } catch (final Exception e) { + log.log(Level.CONFIG, "Failed copying file: " + in + " -> " + out, e); + return false; + } + } + + + /** + * Writes a textstring to a file + * @param f teh file to write to + * @param text the text buffer to write + * @param compress true if the contents should be compressed prior to writing. + * @throws IOException + */ + public static void writeTextToFile(File f, String entryName, String text, boolean compress) throws IOException + { + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f)); + if (compress) + { + byte[] buffer = ZipUtils.zipBuffer(entryName, text.getBytes()); + out.write(buffer); + } else { + out.write(text.getBytes()); + } + out.close(); + } + + private void writeFile(File f, byte[] bytes) + { + try + { + BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(f)); + os.write(bytes); + os.close(); + } catch (IOException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + } + + public static void writeImageToFile(File f, String entryName, ImageData imageData, boolean compress) throws IOException + { + int imageType = getImageTypeFromFilename(entryName); + byte[] imgBuffer = readImage(imageData, imageType); + + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f)); + if (compress) + { + byte[] bufferZipped = ZipUtils.zipBuffer(entryName, imgBuffer); + out.write(bufferZipped); + } else { + out.write(imgBuffer); + } + out.close(); + } + + public static byte[] readImage(ImageData imgData, int imgFormat) + { + ImageLoader imageLoader = new ImageLoader(); + imageLoader.data = new ImageData[] { imgData }; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + imageLoader.save(bos, imgFormat); + + byte[] buf = bos.toByteArray(); + try + { + bos.close(); + } catch (IOException IGNORE) { } + + return buf; + } + + public static byte[] loadFile(InputStream inStream, String symbolicName) + { + if (inStream == null) { + throw new IllegalStateException("Resource " + symbolicName + " not found."); + } + try { + byte[] buffer = new byte[inStream.available()]; + inStream.read(buffer); + inStream.close(); + return buffer; + } catch (IOException e) { + throw new IllegalStateException("Could not read file " + symbolicName + ": " + e.getMessage()); + } + } + + private static int getImageTypeFromFilename(String filename) + { + int pos = filename.lastIndexOf("."); + if ((pos > -1) && (pos < filename.length() - 1)) + { + String ext = filename.substring(pos + 1).toLowerCase(); + if ((ext.equals("jpg")) || (ext.equals("jpeg")) || (ext.equals("zip"))) + { + return SWT.IMAGE_JPEG; + } else if (ext.equals("png")) + { + return SWT.IMAGE_PNG; + } else if ((ext.equals("tif")) || (ext.equals("tiff"))) + { + return SWT.IMAGE_TIFF; + } else if (ext.equals("bmp")) + { + return SWT.IMAGE_BMP; + } else if (ext.equals("gif")) + { + return SWT.IMAGE_GIF; + } else if (ext.equals("ico")) + { + return SWT.IMAGE_ICO; + } + } + return SWT.IMAGE_COPY; + } + + public static String[] getTextFileExtensions(boolean compress) + { + if (compress) + { + return zipExtension; + } else { + return textFileExtensions; + } + } + + public static String[] getImageFileExtensions() + { + return imageFileExtensions; + } + +// private static String[] appendExtension(String[] extensions, String extToAppend) +// { +// String[] re = new String[extensions.length]; +// for (int i = 0; i < extensions.length; i++) +// { +// re[i] = extensions[i] + extToAppend; +// } +// return re; +// } + + public static File writeTextToTempFile(TextSourceData tsd) throws IOException + { + File f = null; + if (!tsd.isCached()) + { + f = CacheManagerFactory.createTempFile(".txt"); + writeTextToFile(f, "ClipboardText.txt", tsd.getText(), false); + f.setReadOnly(); + tsd.setContentsCacheInfo(new ContentsCacheInfo(new Date(), f)); + } else { + f = new File(tsd.getContentsCacheInfo().getFilenameInCache()); + } + return f; + } + + public static File writeImageToTempFile(ImageSourceData isd) throws IOException + { + File f = null; + if (!isd.isCached()) + { + f = CacheManagerFactory.createTempFile(".jpg"); + writeImageToFile(f, "ClipboardImage.jpg", isd.getImageData(), false); + f.setReadOnly(); + isd.setContentsCacheInfo(new ContentsCacheInfo(new Date(), f)); + } else { + f = new File(isd.getContentsCacheInfo().getFilenameInCache()); + } + return f; + } + + /** + * This function will recursivly delete directories and files. + * + * @param path + * File or Directory to be deleted + * @return true indicates success. + */ + public static boolean deleteRecursive(File path) + { + if ((path.exists()) && (path.isDirectory())) + { + File[] files = path.listFiles(); + if (files != null) + { + for (int i = 0; i < files.length; i++) + { + if (files[i].isDirectory()) + { + deleteRecursive(files[i]); + } else + { + files[i].delete(); + } + } + } + } + return (path.delete()); + } + + public static String replaceLastExtension(String filename, String extension) + { + if (filename == null) return null; + + String re; + + int pos = filename.lastIndexOf("."); + if (pos > -1) + { + re = filename.substring(0, pos) + extension; + } else { + re = filename + extension; + } + return re; + } + + /** + * Java on windows will change the slashes back to backslashes, so we replace again. + * @param name the file path + * @return the file path with backslashes replaced by slashes. + */ + public static String getCommonSourcePath(String name) + { + File f = new File(name.replace('\\', '/')); + String s = f.getParent(); + if (s == null) + { + s = ""; + } + return s.replace('\\', '/'); + } + + /** + * Extracts the part of the file name that needs to be written into the cache. + * + * @param commonSourcePath + * the part of the name that is replaced by the cache directory name. + * @param name + * the complete path to a file + * @return the name part of the file + */ + public static String getRelativePath(String commonSourcePath, String name) + { + // File f = new File(); + String nameReplaced = name.replace('\\', '/'); + if (!nameReplaced.startsWith(commonSourcePath)) + { + log.config("The file " + name + " does not start with " + commonSourcePath); + return nameReplaced; + } + String sub = nameReplaced.substring(commonSourcePath.length()); + if (sub.length() > 1) + { + if (sub.charAt(0) == '/') + { + sub = sub.substring(1); + } + } + return sub; + } + + /** + * Serialize an Object to a file. + * @param item + * @param applicationDataDir + * @param savedClpItemFileName + */ + public static void serialize(Object obj, String filename) + { + try { + FileOutputStream fout = new FileOutputStream(filename); + ObjectOutputStream oos = new ObjectOutputStream(fout); + oos.writeObject(obj); + oos.close(); + } catch (Exception e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + } + + /** + * Deserialize an object which was serialized before. + * @param filename the file that is supposed to hold the serialized object + * @return the object from the file or null if the file could not be found or read. + */ + public static Object deserialize(String filename) + { + try { + FileInputStream fin = new FileInputStream(filename); + ObjectInputStream ois = new ObjectInputStream(fin); + Object obj = ois.readObject(); + ois.close(); + return obj; + } catch (Exception e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + return null; + } + +// Nicht fertig entwickelt. +// /** +// * Checks if the given file has an extension added. If not we add it here. +// * @param file the file to check. +// * @param extension the extension to add in case there is none. An extension is marked by a '.'. +// * @return the old file if nothing was changed or a new File instance with the extension added. +// */ +// public static File checkForMissingExtension(File file, String extension) +// { +// String filename = file.getAbsolutePath(); +// int len = filename.length(); +// int pos = filename.lastIndexOf("."); +// if (pos > (len - 5)) +// { +// return file; +// } +// +// return new File() +// } + + + + +} diff --git a/src/java/com/agynamix/platform/infra/HtmlUtils.java b/src/java/com/agynamix/platform/infra/HtmlUtils.java new file mode 100644 index 0000000..59208d9 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/HtmlUtils.java @@ -0,0 +1,55 @@ +package com.agynamix.platform.infra; + +public class HtmlUtils { + + public static String escapeHtmlFull(String s) + { + StringBuilder b = new StringBuilder(s.length()); + for (int i = 0; i < s.length(); i++) + { + char ch = s.charAt(i); + if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9') + { + // safe + b.append(ch); + } else if (Character.isWhitespace(ch)) + { + // paranoid version: whitespaces are unsafe - escape + // conversion of (int)ch is naive + b.append("&#").append((int) ch).append(";"); + } else if (Character.isISOControl(ch)) + { + // paranoid version:isISOControl which are not isWhitespace removed ! + // do nothing do not include in output ! + } else if (Character.isHighSurrogate(ch)) + { + int codePoint; + if (i + 1 < s.length() && Character.isSurrogatePair(ch, s.charAt(i + 1)) + && Character.isDefined(codePoint = (Character.toCodePoint(ch, s.charAt(i + 1))))) + { + b.append("&#").append(codePoint).append(";"); + } else + { + System.out.println("bug:isHighSurrogate"); + } + i++; // in both ways move forward + } else if (Character.isLowSurrogate(ch)) + { + // wrong char[] sequence, //TODO: LOG !!! + System.out.println("bug:isLowSurrogate"); + i++; // move forward,do nothing do not include in output ! + } else + { + if (Character.isDefined(ch)) + { + // paranoid version + // the rest is unsafe, including <127 control chars + b.append("&#").append((int) ch).append(";"); + } + // do nothing do not include undefined in output! + } + } + return b.toString(); + } + +} diff --git a/src/java/com/agynamix/platform/infra/IConfiguration.java b/src/java/com/agynamix/platform/infra/IConfiguration.java new file mode 100644 index 0000000..5f07128 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IConfiguration.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.util.List; +import java.util.Properties; + +import org.eclipse.swt.graphics.Rectangle; + + + +/** + * Configuration encapsulates services for configuring the application. + * It should be implementation independent. + */ +public interface IConfiguration { + + String CONFIG_FILE = "config.properties"; + + String getProperty(String key); + int getInteger(String key); + long getLong(String key); + boolean getBoolean(String key); + byte[] getByteArray(String key); + + List getProperyList(String permanentNetworkAddresses); + + void setProperty(String key, String value); + void setInteger(String key, int value); + void setLong(String key, long value); + void setBoolean(String key, boolean value); + void setByteArray(String key, byte[] value); + + void setRectangle(String key, Rectangle rectangle); + Rectangle getRectangle(String key); + + /** + * Convenience method that checks the value type and calls the appropriate set function. + * @param key the key of the property + * @param value its value object + */ + void setProperty(String key, Object value); + + /** + * Save the configuration. + * + */ + void save(); + + /** + * + * @return Exports the properties. + */ + Properties exportProperties(); + Properties exportDefaultProperties(); + +} + diff --git a/src/java/com/agynamix/platform/infra/IExitListener.java b/src/java/com/agynamix/platform/infra/IExitListener.java new file mode 100644 index 0000000..ebfd266 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IExitListener.java @@ -0,0 +1,23 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.util.EventObject; + +public interface IExitListener { + + boolean canExit(EventObject e); + + void willExit(EventObject e); + +} diff --git a/src/java/com/agynamix/platform/infra/IGuiControl.java b/src/java/com/agynamix/platform/infra/IGuiControl.java new file mode 100644 index 0000000..3db2092 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IGuiControl.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import org.eclipse.swt.widgets.Composite; + + +/** + * Interface to gather gui information in one place. This Interface is given to the Plugin + * and provides gui information about the plugin's environment. + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + */ +public interface IGuiControl { + + Composite getParent(); + +} diff --git a/src/java/com/agynamix/platform/infra/IPlatformConstants.java b/src/java/com/agynamix/platform/infra/IPlatformConstants.java new file mode 100644 index 0000000..9addeb8 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IPlatformConstants.java @@ -0,0 +1,20 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +public interface IPlatformConstants { + + public final static int RC_OK = 0; + public final static int RC_ERROR = 99; + +} diff --git a/src/java/com/agynamix/platform/infra/IPluginMenuAction.java b/src/java/com/agynamix/platform/infra/IPluginMenuAction.java new file mode 100644 index 0000000..f5f29d1 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IPluginMenuAction.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import org.eclipse.swt.widgets.MenuItem; + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + */ +public interface IPluginMenuAction { + /** + * execute a menu action. + * @throws PluginException If something goes wrong + * + */ + void run(MenuItem menuItem); +} diff --git a/src/java/com/agynamix/platform/infra/IPreferenceConfigAdapter.java b/src/java/com/agynamix/platform/infra/IPreferenceConfigAdapter.java new file mode 100644 index 0000000..d743fe2 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IPreferenceConfigAdapter.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.util.Properties; + +import org.eclipse.jface.util.IPropertyChangeListener; + + +/** + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public interface IPreferenceConfigAdapter { + + Properties loadDefaultProperties(); + Properties loadProperties(); + + void saveProperties(Properties p); + + void addPropertyChangeListener(IPropertyChangeListener listener); + void removePropertyChangeListener(IPropertyChangeListener listener); + + +} + diff --git a/src/java/com/agynamix/platform/infra/IQueueManager.java b/src/java/com/agynamix/platform/infra/IQueueManager.java new file mode 100644 index 0000000..8de7cd2 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/IQueueManager.java @@ -0,0 +1,59 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.platform.infra; + +import java.util.List; + + +public interface IQueueManager { + + String SERVICE_NAME = "QueueManager"; + + /** + * The queue where new ISourceData items are put in and taken from + */ + String QUEUE_SOURCE_DATA_MONITOR = "sourceDataMonitorQueue"; + + /** + * The queue for the RemoteServer to sync on incoming SourceDataContents objects from clients. + */ + String QUEUE_SOURCE_DATA_CONTENTS = "sourceDataContentsQueue"; + + /** + * Put new data into the Queue + * @param sourceData + */ + void put(String queueName, Object data); + + void putAll(String queueName, List items); + + void putAll(String queueName, Object[] items); + + /** + * Put all received items in the queue but in reverse order. The last item + * ist put first in the queue. + * @param queueName + * @param items + */ + void putAllReverse(String queueName, List items); + + Object take(String queueName); + + /** + * Empty the queue with the given name. + * @param queueName name of the queue that should be empty. + */ + void emptyQueue(String queueName); + + + +} diff --git a/src/java/com/agynamix/platform/infra/MD5Calc.java b/src/java/com/agynamix/platform/infra/MD5Calc.java new file mode 100644 index 0000000..bdc5ca9 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/MD5Calc.java @@ -0,0 +1,60 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Calc { + + private final static String algorithm = "MD5"; + + private MessageDigest md5; + private byte[] digest; + + public MD5Calc() + { + try { + md5 = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + } + } + + public String toHexString(byte b) + { + int value = (b & 0x7F) + (b < 0 ? 128 : 0); + + String ret = (value < 16 ? "0" : ""); + ret += Integer.toHexString(value).toUpperCase(); + + return ret; + } + + public String checksum(String data) + { + StringBuilder strbuf = new StringBuilder(); + + md5.update(data.getBytes(), 0, data.length()); + digest = md5.digest(); + + for (int i = 0; i < digest.length; i++) + { + strbuf.append(toHexString(digest[i])); + } + + return strbuf.toString(); + } + +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/infra/PlatformColors.java b/src/java/com/agynamix/platform/infra/PlatformColors.java new file mode 100644 index 0000000..8bf1808 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/PlatformColors.java @@ -0,0 +1,52 @@ +package com.agynamix.platform.infra; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; + + +public class PlatformColors { + + private static ColorRegistry colorRegistry = null; + + public static final String TRANSFER_TABLE_ALT_COLOR = "transferTableAltColor"; + + public static final Map colorMap = new HashMap(); + + static { + colorMap.put(TRANSFER_TABLE_ALT_COLOR, new RGB(251, 255, 223)); + } + + public static Color get(String colordef) + { + Color c = getColorRegistry().get(colordef); + if (c == null) + { + RGB rgb = colorMap.get(colordef); + if (rgb == null) + { + throw new IllegalStateException("Color for "+colordef+" not defined."); + } + c = new Color(Display.getDefault(), rgb); + getColorRegistry().put(colordef, c.getRGB()); + } + return c; + } + + private static ColorRegistry getColorRegistry() + { + if (colorRegistry == null) + { + colorRegistry = ApplicationBase.getContext().getColorRegistry(); + } + return colorRegistry; + } + + private PlatformColors() + { + } +} \ No newline at end of file diff --git a/src/java/com/agynamix/platform/infra/PlatformException.java b/src/java/com/agynamix/platform/infra/PlatformException.java new file mode 100644 index 0000000..eb7f92a --- /dev/null +++ b/src/java/com/agynamix/platform/infra/PlatformException.java @@ -0,0 +1,34 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +public class PlatformException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public PlatformException(String msg) + { + super(msg); + } + + public PlatformException(Throwable cause) + { + super(cause); + } + + public PlatformException(String msg, Throwable cause) + { + super(msg, cause); + } + +} diff --git a/src/java/com/agynamix/platform/infra/PlatformUtils.java b/src/java/com/agynamix/platform/infra/PlatformUtils.java new file mode 100644 index 0000000..af92e00 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/PlatformUtils.java @@ -0,0 +1,422 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IContributionManager; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.action.SubStatusLineManager; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.MessageDialogWithToggle; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; + +import com.agynamix.platform.frontend.dialogs.ExceptionDetailsDialog; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; + +public class PlatformUtils { + + public enum OS { + unknown("Unknown", "Unknown"), + win32("Windows", "x86"), + win64(new String[] { "Windows" }, new String[] { "x86_64", "amd64" }), + macosx(new String[] { "Mac OS X" }, new String[] { "i386", "ppc" }), + macosx64("Mac OS X", "x86_64"), + linux_x86("Linux", "i386"), + linux_x86_64(new String[] { "Linux" }, new String[] { "x86_64", "amd64" }), + solaris_x86( "SunOS" , "x86"); + + final List osname = new ArrayList(); + final List osarch = new ArrayList(); + + OS(String osname, String osarch) + { + this.osname.add(osname.toLowerCase()); + this.osarch.add(osarch.toLowerCase()); + } + + OS(String[] osname, String[] osarch) + { + for (String s : osname) + { + this.osname.add(s.toLowerCase()); + } + for (String s : osarch) + { + this.osarch.add(s.toLowerCase()); + } + } + + private boolean isCompatible(String osname, String osarch) + { + if (isOsNameCompatible(osname)) + { + if (isOsArchCompatible(osarch)) + { + return true; + } + } + return false; + } + + private boolean isOsNameCompatible(String osname) + { + for (String s : this.osname) + { + if (osname.toLowerCase().indexOf(s) > -1) + { + return true; + } + } + return false; + } + + private boolean isOsArchCompatible(String osarch) + { + for (String s : this.osarch) + { + if (osarch.toLowerCase().indexOf(s) > -1) + { + return true; + } + } + return false; + } + + public static OS parseOs(String osname, String osarch) + { + for (OS os : OS.values()) + { + if (os.isCompatible(osname, osarch)) + { + return os; + } + } + return OS.unknown; + } + + @Override + public String toString() + { + return osname + "/" + osarch; + } + }; + + public static OS getOsName() + { + String osname = System.getProperty("os.name"); + String osarch = System.getProperty("os.arch"); + OS os = OS.parseOs(osname, osarch); + // System.out.println("OS="+os); + return os; + } + + public static boolean isMacOs() + { + OS os = getOsName(); + if ((os == OS.macosx) || (os == OS.macosx64)) + { + return true; + } else + { + return false; + } + } + + static Object syncThreadResult = null; + + /** + * + * @return The root of the application data directory. This is for instance .Simidude on Unix or somewhere in Library + * on the Mac. + */ + public static synchronized String getApplicationDataDir() + { + String commonPath = System.getProperty("user.home") + File.separator; + String extensionPath = ApplicationInfo.getApplicationName() + File.separator; + String platformPath = "."; + if (PlatformUtils.isMacOs()) + { + platformPath = "Library" + File.separator + "Application Support" + File.separator; + } + + String dataDir = commonPath + platformPath + extensionPath; + File fDataDir = new File(dataDir); + if (!fDataDir.exists()) + { + if (!fDataDir.mkdirs()) + { + throw new IllegalStateException("Can not create application data directory " + dataDir); + } + } + return dataDir; + } + + public static String getApplicationCacheDir() + { + String extensionPath = IPreferenceConstants.CACHE_DIR_NAME + File.separator; + return PlatformUtils.getApplicationDataDir() + extensionPath; + } + + public static String getApplicationBasedir() + { + return System.getProperty("user.dir"); + } + + public static void setStatusLineContribution(final String msg) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + IStatusLineManager statusLine = getStatusLine(); + if (statusLine != null) + { + statusLine.setMessage(msg); + } + } + }); + } + + public static void setStatusLineErrorMsg(final String msg) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + IStatusLineManager statusLine = getStatusLine(); + if (statusLine != null) + { + statusLine.setErrorMessage(msg); + } + } + }); + } + + protected static IStatusLineManager getStatusLine() + { + IStatusLineManager statusLine = getStatusLineManager(); + if (statusLine != null) + { + while (statusLine instanceof SubStatusLineManager) + { + IContributionManager cb = ((SubStatusLineManager) statusLine).getParent(); + if (!(cb instanceof IStatusLineManager)) + { + break; + } + statusLine = (IStatusLineManager) cb; + } + } + return statusLine; + } + + protected static IStatusLineManager getStatusLineManager() + { + return ApplicationBase.getContext().getApplicationGUI().getStatusLineManager(); + } + + public static void setConnectionBroken() + { + setStatusLineErrorMsg("Connection broken."); + } + + public static void setConnected(String client) + { + setStatusLineErrorMsg(null); + setStatusLineContribution("Connected to " + client); + } + + public static void setConnected(int clientCount) + { + setStatusLineErrorMsg(null); + setStatusLineContribution("Connected to " + clientCount + " clients"); + } + + public static void setNotConnected() + { + setStatusLineErrorMsg(null); + setStatusLineContribution("Not connected."); + } + + // public static void showConnectionBrokenDialog(final + // ConnectionBrokenException e) + // { + // safeAsyncRunnable(new Runnable() { + // public void run() + // { + // new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), "Verbindung zeitweilig unterbrochen", null, //$NON-NLS-1$ + // e.getMessage(), e).open(); //$NON-NLS-1$ + // } + // }); + // } + + public static void showErrorMessageWithException(final String title, final String msg, final Throwable t) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), title, null, msg, new Status(IStatus.ERROR, + ApplicationInfo.getApplicationName(), IStatus.OK, msg, t)).open(); + } + }); + } + + public static void showWarningMessageWithException(final String title, final String msg, final Throwable t) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), title, null, msg, new Status(IStatus.WARNING, + ApplicationInfo.getApplicationName(), IStatus.OK, msg, t)).open(); + } + }); + } + + public static void showInfoMessage(final String title, final String msg) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), title, null, msg, new Status(IStatus.INFO, + ApplicationInfo.getApplicationName(), IStatus.OK, msg, null)).open(); + } + }); + } + + public static void showWarningMessage(final String title, final String msg) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), title, null, msg, new Status(IStatus.WARNING, + ApplicationInfo.getApplicationName(), IStatus.OK, msg, null)).open(); + } + }); + } + + public static void showWarningMessage(final String title, final String msg, final String strDetails) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), title, null, msg, new Status(IStatus.WARNING, + ApplicationInfo.getApplicationName(), IStatus.OK, msg, null), strDetails).open(); + } + }); + } + + public static void showErrorMessage(final String title, final String msg) + { + safeAsyncRunnable(new Runnable() { + public void run() + { + MessageDialog.openError(Display.getDefault().getActiveShell(), title, msg); + // new ExceptionDetailsDialog(Display.getDefault().getActiveShell(), + // title, null, msg, + // new Status(IStatus.ERROR, ApplicationInfo.getApplicationName(), + // IStatus.OK, msg, null)).open(); + } + }); + } + + public static void showToggleErrorMessage(final String title, final String msg, final String configKey) + { + if (!ApplicationBase.getContext().getConfiguration().getBoolean(configKey)) { + safeAsyncRunnable(new Runnable() { + public void run() + { + MessageDialogWithToggle d = MessageDialogWithToggle.openError(Display.getDefault().getActiveShell(), title, msg, + "Don't show this message again", false, null, null); + ApplicationBase.getContext().getConfiguration().setBoolean(configKey, d.getToggleState()); + } + }); + } + } + + public static boolean showOverwriteFilesDialog(final File dest) + { + safeSyncRunnable(new Runnable() { + public void run() + { + String whatUpper = dest.isDirectory() ? "Directory" : "File"; + String what = dest.isDirectory() ? "directory" : "file"; + MessageBox box = new MessageBox(Display.getDefault().getActiveShell(), SWT.ICON_WARNING | SWT.OK | SWT.CANCEL); + box.setText("Overwrite Existing " + whatUpper + "?"); + box.setMessage("The " + what + " " + dest.getAbsolutePath() + + " already exists. Click \"OK\" to overwrite all existing contents."); + int rc = box.open(); + if (rc == SWT.OK) + { + syncThreadResult = Boolean.TRUE; + } else + { + syncThreadResult = Boolean.FALSE; + } + } + }); + Boolean result = (Boolean) syncThreadResult; + return result.booleanValue(); + } + + public static void safeAsyncRunnable(final Runnable runnable) + { + Display display = Display.getCurrent(); + if (display == null) + { + display = Display.getDefault(); + } + if (display != null) + { + if (!display.isDisposed()) + { + try + { + display.asyncExec(runnable); + } catch (final Exception e) + { + System.out.println("Error while executing: " + e.getMessage()); + e.printStackTrace(); + } + } + } + } + + public static void safeSyncRunnable(final Runnable runnable) + { + Display display = Display.getCurrent(); + if (display == null) + { + display = Display.getDefault(); + } + if (display != null) + { + if (!display.isDisposed()) + { + try + { + display.syncExec(runnable); + } catch (final Exception e) + { + System.out.println("Error while executing: " + e.getMessage()); + e.printStackTrace(); + } + } + } + } + +} diff --git a/src/java/com/agynamix/platform/infra/PluginException.java b/src/java/com/agynamix/platform/infra/PluginException.java new file mode 100644 index 0000000..ceb6f22 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/PluginException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +/** + * Covers exceptions occuring in and around plugins. + * + * @version $Revision: 32 $ $Date: 2004-11-28 18:23:55 +0100 (So, 28 Nov 2004) $ + * @author tuhlmann + */ +public class PluginException extends Exception { + + private static final long serialVersionUID = 1L; + + public PluginException(String msg, Throwable cause) + { + super(msg, cause); + } + + public PluginException(String msg) + { + super(msg); + } + +} + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/platform/infra/PluginMenuEntry.java b/src/java/com/agynamix/platform/infra/PluginMenuEntry.java new file mode 100644 index 0000000..675a6d3 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/PluginMenuEntry.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004 agynamiX.com. All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamiX.com (http://www.agynamix.com) + */ +package com.agynamix.platform.infra; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.MenuItem; + + + + +/** + * PluginMenuItem provides all necessary information to create Items in tray or tool bar + * @version $Revision: 10 $ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + */ +public class PluginMenuEntry { + + final Image image; + final String mEntry; + final int buttonStyle; + final boolean checkButton; + + boolean checked; + + IPluginMenuAction menuAction; + + public PluginMenuEntry(Image image, String mEntry) { + this(image, mEntry, false); + } + + public PluginMenuEntry(Image image, String mEntry, boolean isCheckButton) { + this.image = image; + this.mEntry = mEntry; + this.checkButton = isCheckButton; + this.buttonStyle = isCheckButton ? SWT.CHECK : SWT.PUSH; + } + + /** + * Get the text of this menu icon + */ + public String getText() { + return mEntry; + } + + /** + * get the Image of this menu entry. + */ + public Image getImage() { + return image; + } + + public int getButtonStyle() + { + return this.buttonStyle; + } + + public boolean isCheckButton() { + return this.checkButton; + } + + public void setPluginMenuAction(IPluginMenuAction a) { + this.menuAction = a; + } + + public void action(final MenuItem menuItem) { + menuAction.run(menuItem); + } + + public void setChecked(boolean checked) + { + this.checked = checked; + } + + public boolean getChecked() + { + return this.checked; + } + +} + diff --git a/src/java/com/agynamix/platform/infra/Tupel.java b/src/java/com/agynamix/platform/infra/Tupel.java new file mode 100644 index 0000000..a125322 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/Tupel.java @@ -0,0 +1,24 @@ +package com.agynamix.platform.infra; + +public class Tupel { + + private final S1 value1; + private final S2 value2; + + public Tupel(S1 value1, S2 value2) + { + this.value1 = value1; + this.value2 = value2; + } + + public S1 getValue1() + { + return value1; + } + + public S2 getValue2() + { + return value2; + } + +} diff --git a/src/java/com/agynamix/platform/infra/ZipUtils.java b/src/java/com/agynamix/platform/infra/ZipUtils.java new file mode 100644 index 0000000..be0ea60 --- /dev/null +++ b/src/java/com/agynamix/platform/infra/ZipUtils.java @@ -0,0 +1,116 @@ +package com.agynamix.platform.infra; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import com.agynamix.platform.log.ApplicationLog; + +public class ZipUtils { + + static Logger log = ApplicationLog.getLogger(ZipUtils.class.getName()); + + public static synchronized byte[] zipBuffer(String entryName, byte[] buffer) + { + try + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zout = new ZipOutputStream(bos); + + zout.putNextEntry(new ZipEntry(entryName)); + zout.write(buffer); + zout.closeEntry(); + zout.close(); + return bos.toByteArray(); + } catch (IOException e) + { + log.log(Level.WARNING, e.getMessage(), e); + return null; + } + } + + /** + * Zips a file or directory (recursively) and returns a reference to the + * created file. + * + * @param filename + * Name of the file to create + * @param file + * The parent file to compress + * @return a reference to the compressed file. + */ + public static synchronized File zipFile(File inFile, File destFile) + { + try + { + // Create the ZIP file + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destFile)); + + String commonSourcePath = FileUtils.getCommonSourcePath(inFile.getAbsolutePath()); + + if (inFile.isDirectory()) + { + zipDirectory(inFile, commonSourcePath, zos); + } else { + zipFileEntry(inFile, commonSourcePath, zos); + } + + zos.close(); + return destFile; + } catch (IOException e) + { + e.printStackTrace(); + log.log(Level.WARNING, e.getMessage(), e); + return null; + } + + } + + public static synchronized void zipDirectory(File zipDir, String commonSourcePath, ZipOutputStream zos) throws IOException + { + String[] dirList = zipDir.list(); + if ((dirList == null) || (dirList.length == 0)) + { + String path = FileUtils.getRelativePath(commonSourcePath, zipDir.getAbsolutePath()) + "/"; + zos.putNextEntry(new ZipEntry(path)); + zos.closeEntry(); + } else { + for (int i = 0; i < dirList.length; i++) + { + File f = new File(zipDir, dirList[i]); + if (f.isDirectory()) + { + zipDirectory(f, commonSourcePath, zos); + } else + { + zipFileEntry(f, commonSourcePath, zos); + } + } + } + } + + public static synchronized void zipFileEntry(File zipFile, String commonSourcePath, ZipOutputStream zos) throws IOException + { + byte[] readBuffer = new byte[4096]; + int bytesIn = 0; + FileInputStream fis = new FileInputStream(zipFile); + + String path = FileUtils.getRelativePath(commonSourcePath, zipFile.getAbsolutePath()); + zos.putNextEntry(new ZipEntry(path)); + // now write the content of the file to the ZipOutputStream + while ((bytesIn = fis.read(readBuffer)) > 0) + { + zos.write(readBuffer, 0, bytesIn); + } + fis.close(); + zos.closeEntry(); + } + + +} diff --git a/src/java/com/agynamix/platform/log/ApplicationLog.java b/src/java/com/agynamix/platform/log/ApplicationLog.java new file mode 100755 index 0000000..3ffa6a4 --- /dev/null +++ b/src/java/com/agynamix/platform/log/ApplicationLog.java @@ -0,0 +1,64 @@ +/* + * Class LogFactory + * Created on 07.01.2005 + * + * $Id: GuardianLog.java 265 2005-11-07 18:41:27Z tuhlmann $ + * $LastChangedBy: tuhlmann $ + * $LastChangedDate: 2005-11-07 19:41:27 +0100 (Mo, 07 Nov 2005) $ + * $LastChangedRevision: 265 $ + * + * This file is copyrighted by AGYNAMIX Design. + * Please refer to the license of our products for details. + */ +package com.agynamix.platform.log; + +import java.io.InputStream; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.PlatformUtils; + +/** + * @author tuhlmann + * @since + */ +public class ApplicationLog { + + static String logDirectory; + + static + { + initializeLogger(); + } + + public static Logger getLogger(Class cls) + { + return getLogger(cls.getName()); + } + + public static Logger getLogger(String str) + { + return Logger.getLogger(str); + } + + static void initializeLogger() + { + logDirectory = PlatformUtils.getApplicationDataDir(); + System.setProperty("log.dir", logDirectory); + try + { + InputStream ins = ApplicationLog.class.getResourceAsStream("/logging.properties"); + if (ins != null) + { + LogManager.getLogManager().readConfiguration(ins); + } else { + System.out.println("Could not find logging.properties"); + } + } catch (Exception e) + { + System.out.println("Could not read logging.properties file"); + e.printStackTrace(); + } + } + +} diff --git a/src/java/com/agynamix/platform/log/ClipboardItemDebugInfo.java b/src/java/com/agynamix/platform/log/ClipboardItemDebugInfo.java new file mode 100644 index 0000000..f929a34 --- /dev/null +++ b/src/java/com/agynamix/platform/log/ClipboardItemDebugInfo.java @@ -0,0 +1,47 @@ +package com.agynamix.platform.log; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.IConnector; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; + +public class ClipboardItemDebugInfo { + + final IClipboardItem item; + final ISourceData sourceData; + + final IConnector connector; + + public ClipboardItemDebugInfo(IClipboardItem item) + { + this.item = item; + this.sourceData = item.getSourceData(); + this.connector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector().getConnector(); + } + + @Override + public String toString() + { + ClientNode originatorClientNode = connector.getClientNode(sourceData.getSenderId()); + + StringBuilder sb = new StringBuilder(); + sb.append("Clipboard Item of Type: "+item.getType()+": "+sourceData.getSourceId()+"\n"); + + if (originatorClientNode != null) + { + sb.append("Originated from Client with IP "+originatorClientNode.getAddress().getHostAddress()+" ("+sourceData.getSenderId()+")\n"); + } else { + sb.append("Originated from not connected client with UUID: "+sourceData.getSenderId()+"\n"); + } + + sb.append("Item Transport Type: "+sourceData.getTransportType()+"\n"); + sb.append("Item created: "+sourceData.getCreationDate()+"\n"); + sb.append("\nItem Short description\n"); + sb.append("======================\n"); + sb.append(item.getShortDescription()+"\n\n"); + return sb.toString(); + } + +} diff --git a/src/java/com/agynamix/platform/log/ConnectionLog.java b/src/java/com/agynamix/platform/log/ConnectionLog.java new file mode 100644 index 0000000..5cb89c5 --- /dev/null +++ b/src/java/com/agynamix/platform/log/ConnectionLog.java @@ -0,0 +1,91 @@ +package com.agynamix.platform.log; + +import java.net.InetAddress; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.IConnector; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceDataListener; + +public class ConnectionLog implements ISourceDataListener { + + public static final String SERVICE_NAME = "ConnectionLog"; + + public static final int STATISTICS_MAP_MAX_DURATION = 12; // 12 hours max. + + RemoteConnector remoteConnector; + IConnector connector; + + Map nodeStatistics = new HashMap(); + + public void sourceDataChanged(ISourceData data) + { + ClientNode node = getConnector().getClientNode(data.getSenderId()); + if ((node != null) && (isRemoteNode(node))) + { +// System.out.println("ConnectionLog: Data from "+node.getAddress().getHostAddress()); + addToStatisticsMap(nodeStatistics, node, data); + removeExpiredEntries(nodeStatistics); + } + } + + private void addToStatisticsMap(Map nodeStatistics, ClientNode node, ISourceData data) + { + ConnectionLogNodeStatistic ns = nodeStatistics.get(node.getAddress()); + if (ns == null) + { + ns = new ConnectionLogNodeStatistic(STATISTICS_MAP_MAX_DURATION, node); + nodeStatistics.put(node.getAddress(), ns); + } + + ns.addEntry(node, data); + + } + + private void removeExpiredEntries(Map nodeStatistics) + { + for (ConnectionLogNodeStatistic ns : nodeStatistics.values()) + { + ns.removeExpiredEntries(); + } + + } + + private boolean isRemoteNode(ClientNode node) + { + return !getConnector().getMyOwnNode().getNodeId().equals(node.getNodeId()); + } + + private RemoteConnector getRemoteConnector() + { + if (remoteConnector == null) + { + remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + } + return remoteConnector; + + } + + private IConnector getConnector() + { + if (connector == null) + { + connector = getRemoteConnector().getConnector(); + } + return connector; + } + + public Map getNodeStatisticsEntries() + { + return Collections.unmodifiableMap(nodeStatistics); + } + + +} diff --git a/src/java/com/agynamix/platform/log/ConnectionLogNodeStatistic.java b/src/java/com/agynamix/platform/log/ConnectionLogNodeStatistic.java new file mode 100644 index 0000000..5e51e6e --- /dev/null +++ b/src/java/com/agynamix/platform/log/ConnectionLogNodeStatistic.java @@ -0,0 +1,89 @@ +package com.agynamix.platform.log; + +import java.net.InetAddress; +import java.util.Date; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.UUID; + +import com.agynamix.platform.net.ClientNode; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; + +public class ConnectionLogNodeStatistic { + + final long statisticsMapMaxDurationMillis; + + SortedMap statisticsEntryMap = new TreeMap(); + + final UUID senderId; + final InetAddress senderAddress; + + final long firstContactTime; + + + public ConnectionLogNodeStatistic(int statisticsMapMaxDuration, ClientNode node) + { + this.statisticsMapMaxDurationMillis = (long)statisticsMapMaxDuration * 3600000l; + this.senderId = node.getNodeId(); + this.senderAddress = node.getAddress(); + this.firstContactTime = getCurrentTimeMillis(); + } + + public void addEntry(ClientNode node, ISourceData data) + { + NodeStatisticsEntry entry = new NodeStatisticsEntry(node, data); + Long t = getCurrentTimeMillisLong(); + statisticsEntryMap.put(t, entry); + } + + /** + * Remove entries that are older than statisticsMapMaxDuration. + */ + public void removeExpiredEntries() + { + long lastTimestamp = getCurrentTimeMillis() - statisticsMapMaxDurationMillis; + boolean allClear = false; + while ((!allClear) && (statisticsEntryMap.size() > 0)) + { + Long lastKey = statisticsEntryMap.lastKey(); + if (lastKey.longValue() < lastTimestamp) + { +// System.out.println("Remove Entry with date "+new Date(lastKey.longValue())); + statisticsEntryMap.remove(lastKey); + } else { + allClear = true; + } + } + + } + + private long getCurrentTimeMillis() + { + return System.currentTimeMillis(); + } + + private long getCurrentTimeMillisLong() + { + return new Long(getCurrentTimeMillis()); + } + + public int getEntryCountBySourceType(SourceType sourceType) + { + removeExpiredEntries(); + + int count = 0; + + for (NodeStatisticsEntry entry : statisticsEntryMap.values()) + { + if (entry.getSourceType() == sourceType) + { + count++; + } + } + + return count; + } + + +} diff --git a/src/java/com/agynamix/platform/log/FileHandler.java b/src/java/com/agynamix/platform/log/FileHandler.java new file mode 100755 index 0000000..a2cd10e --- /dev/null +++ b/src/java/com/agynamix/platform/log/FileHandler.java @@ -0,0 +1,100 @@ +/* + * Class FileHandler + * Created on 26.10.2005 + * + * This file is copyrighted by AGYNAMIX. + * Please refer to the license of our products for details. + */ +package com.agynamix.platform.log; + +import java.io.IOException; +import java.util.logging.LogManager; + + +public class FileHandler extends java.util.logging.FileHandler { + + public final static String VARIABLE_START = "${"; + public final static String VARIABLE_END = "}"; + + public FileHandler() throws IOException, SecurityException + { + super(configurePattern(), getLimit(), getCount()); + } + + private static int getLimit() + { + int limit = 0; + String cname = FileHandler.class.getName(); + LogManager manager = LogManager.getLogManager(); + String limitStr = manager.getProperty(cname + ".limit"); + if ((limitStr != null) && (limitStr.length() > 0)) + { + try { + limit = Integer.parseInt(limitStr); + } catch (Exception e) {} + } + return limit; + } + + private static int getCount() + { + int count = 1; + String cname = FileHandler.class.getName(); + LogManager manager = LogManager.getLogManager(); + String countStr = manager.getProperty(cname + ".count"); + if ((countStr != null) && (countStr.length() > 0)) + { + try { + count = Integer.parseInt(countStr); + } catch (Exception e) {} + } + return count; + } + + private static String configurePattern() + { + String cname = FileHandler.class.getName(); + LogManager manager = LogManager.getLogManager(); + String pattern = manager.getProperty(cname + ".pattern"); + if ((pattern == null) || (pattern.length() == 0)) + { + throw new IllegalStateException("Kein Pattern angegeben."); + } + + return resolveVariables(pattern); + } + + private static String resolveVariables(String pattern) + { + StringBuilder sb = new StringBuilder(); + int oldPos = 0; + int pos1 = pattern.indexOf(VARIABLE_START); + int pos2 = 0; + while (pos1 > -1) + { + if (pos1 > oldPos) + { + sb.append(pattern.substring(oldPos, pos1)); + } + pos2 = pattern.indexOf(VARIABLE_END, pos1); + if (pos2 > -1) + { + String variable = pattern.substring(pos1+2, pos2); + String substitute = System.getProperty(variable); + if (substitute == null) + { + substitute = "["+variable+"]"; + } + sb.append(substitute); + oldPos = pos2+1; + } else { + oldPos = pos1; + } + pos1 = pattern.indexOf(VARIABLE_START, pos1+2); + } + sb.append(pattern.substring(oldPos)); +// System.out.println("[DEBUG] Pattern: "+sb); + return sb.toString(); + } + +} diff --git a/src/java/com/agynamix/platform/log/NodeStatisticsEntry.java b/src/java/com/agynamix/platform/log/NodeStatisticsEntry.java new file mode 100644 index 0000000..8ca13fa --- /dev/null +++ b/src/java/com/agynamix/platform/log/NodeStatisticsEntry.java @@ -0,0 +1,23 @@ +package com.agynamix.platform.log; + +import com.agynamix.platform.net.ClientNode; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; + +public class NodeStatisticsEntry { + + final SourceType sourceType; + + + public NodeStatisticsEntry(ClientNode node, ISourceData data) + { + this.sourceType = data.getType(); + } + + + public SourceType getSourceType() + { + return sourceType; + } + +} diff --git a/src/java/com/agynamix/platform/net/AbstractRemoteCommand.java b/src/java/com/agynamix/platform/net/AbstractRemoteCommand.java new file mode 100644 index 0000000..05c65be --- /dev/null +++ b/src/java/com/agynamix/platform/net/AbstractRemoteCommand.java @@ -0,0 +1,19 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +public abstract class AbstractRemoteCommand implements IRemoteCommand { + + private static final long serialVersionUID = 1L; + +} diff --git a/src/java/com/agynamix/platform/net/ClientListSynchronizer.java b/src/java/com/agynamix/platform/net/ClientListSynchronizer.java new file mode 100644 index 0000000..22cd67d --- /dev/null +++ b/src/java/com/agynamix/platform/net/ClientListSynchronizer.java @@ -0,0 +1,122 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.log.ApplicationLog; + +public class ClientListSynchronizer implements ThreadManagerAware { + + Logger log = ApplicationLog.getLogger(ClientListSynchronizer.class); + + final IConnector connector; + + boolean shouldStop = false; + + public ClientListSynchronizer(IConnector connector) + { + this.connector = connector; + } + + /** + * This Service is run at scheduled intervalls. + * It will contact all connected clients, get their client lists, sync them with ours and + * send the delta back to the peer. + */ + public void run() + { + if (!shouldStop) + { + List clients = connector.getConnectedClientList(); + ConnectionUtils.clearInactiveFromClientList(connector, clients); + if (clients.size() > 1) // we are in there as well + { + for (ClientNode client : clients) + { + if ((!client.equals(connector.getMyOwnNode())) && (!client.isShutdown())) // its not us + { + ConnectionCtx connectionCtx = null; + try { + connectionCtx = ConnectionUtils.connectTo(connector, client); + List peerClientList = getPeerClientList(connectionCtx); + List clientsOnlyWeHaveList = synchronizeClientLists(connector, peerClientList); + sendDeltaClientList(connectionCtx, clientsOnlyWeHaveList); + connectionCtx.disconnect(); + } catch (IOException e) + { + log.info("Communication with "+client.getAddress().getHostAddress()+" not possible"); + } catch (NetworkAuthException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } catch (NetworkProtocolException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + } + } + } + } + } + + private List getPeerClientList(ConnectionCtx connectionCtx) throws IOException, NetworkProtocolException + { + return (List) connectionCtx.invoke(new TransportClientListCommand()); + } + + private List synchronizeClientLists(IConnector connector, List peerClientList) + { + List clientsOnlyWeHave = new ArrayList(); + List ourClientList = connector.getConnectedClientList(); + for (ClientNode node : ourClientList) + { + if (!peerClientList.contains(node)) + { + clientsOnlyWeHave.add(node); + } + } + for (ClientNode node : peerClientList) + { + if (!ourClientList.contains(node)) + { + ourClientList.add(node); + } + } + return clientsOnlyWeHave; + } + + + private void sendDeltaClientList(ConnectionCtx connectionCtx, List deltaList) throws IOException, NetworkProtocolException + { + if ((deltaList != null) && (deltaList.size() > 0)) + { + connectionCtx.invoke(new TransportClientListCommand(deltaList)); + } + } + + public String getId() + { + return "ClientListSynchronizer"; + } + + public void shutdown() + { + this.shouldStop = true; + } + +} diff --git a/src/java/com/agynamix/platform/net/ClientNode.java b/src/java/com/agynamix/platform/net/ClientNode.java new file mode 100644 index 0000000..7cb1b71 --- /dev/null +++ b/src/java/com/agynamix/platform/net/ClientNode.java @@ -0,0 +1,152 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.Serializable; +import java.net.InetAddress; +import java.util.Date; +import java.util.UUID; + +/** + * ClientNode encapsulates the information a node stores about other nodes. + * This information is used to connect to the described node and send data. + * @author tuhlmann + * + */ +public class ClientNode implements Serializable { + + private static final long serialVersionUID = 1L; + + private volatile int hashCode; + + final UUID nodeId; + final String groupname; + final InetAddress address; + final int port; + final Date creationDate; + + Date inactiveSince = null; + Date shutdownDate = null; + + public ClientNode(UUID nodeId, String groupname, InetAddress nodeAddress, int nodePort) + { + this.nodeId = nodeId; + this.groupname = groupname; + this.address = nodeAddress; + this.port = nodePort; + this.creationDate = new Date(); + } + + public InetAddress getAddress() + { + return this.address; + } + + public int getPort() + { + return this.port; + } + + @Override + public String toString() + { + return address.getHostAddress()+":"+port+"/"+nodeId+"@"+groupname; + } + + public UUID getNodeId() + { + return nodeId; + } + + public String getGroupname() + { + return groupname; + } + + @Override + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (!(o instanceof ClientNode)) + { + return false; + } + ClientNode node = (ClientNode) o; + return this.nodeId.equals(node.nodeId) && this.groupname.equals(node.groupname); +// && this.address.equals(node.address) && this.port == node.port; + } + + @Override + public int hashCode() + { + int result = hashCode; + if (result == 0) + { + result = 17; + result = 31 * result + nodeId.hashCode(); + result = 31 * result + groupname.hashCode(); +// result = 31 * result + address.hashCode(); +// result = 31 * result + port; + hashCode = result; + } + return result; + } + + public void setNodeInactive() + { + if (inactiveSince == null) + { + inactiveSince = new Date(); + } + } + + public void setNodeActive() + { + inactiveSince = null; + } + + public boolean isNodeActive() + { + return inactiveSince == null; + } + + public Date getInactiveSince() + { + return inactiveSince; + } + + public void shutdown() + { + shutdownDate = new Date(); + } + + public Date getShutdownDate() + { + return this.shutdownDate; + } + + public Date getCreationDate() + { + return this.creationDate; + } + + public boolean isShutdown() + { + return shutdownDate != null; + } + + +} diff --git a/src/java/com/agynamix/platform/net/ConnectionCtx.java b/src/java/com/agynamix/platform/net/ConnectionCtx.java new file mode 100644 index 0000000..d688649 --- /dev/null +++ b/src/java/com/agynamix/platform/net/ConnectionCtx.java @@ -0,0 +1,101 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.net.Socket; + +import com.agynamix.platform.net.protocol.NodeCommandUtils; + +public class ConnectionCtx implements IStreamSuplier{ + + final Socket socket; + final BufferedInputStream istream; + final BufferedOutputStream ostream; + + final NodeCommandUtils nodeCommandUtils; + final IConnector connector; + + + public ConnectionCtx(IConnector connector, Socket socket) + { + this.socket = socket; + try + { + ostream = new BufferedOutputStream(socket.getOutputStream()); + istream = new BufferedInputStream(socket.getInputStream()); + } catch (IOException e) + { + throw new FatalNetworkException(e); + } + + this.connector = connector; + this.nodeCommandUtils = new NodeCommandUtils(connector, this); + } + + public void disconnect() + { + try + { + getNodeCommandUtils().sendQuit(); + close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + + public void close() + { + try + { + socket.close(); + } catch (IOException e) + { + // Already closed. + } + } + + public BufferedOutputStream getOutputStream() + { + return ostream; + } + + public BufferedInputStream getInputStream() + { + return istream; + } + + public String getHostAddress() + { + return socket.getInetAddress().getHostAddress(); + } + + public NodeCommandUtils getNodeCommandUtils() + { + return nodeCommandUtils; + } + + public IConnector getConnector() + { + return connector; + } + + public Object invoke(IRemoteCommand command) throws IOException, NetworkProtocolException + { + return getNodeCommandUtils().invoke(command); + } + +} diff --git a/src/java/com/agynamix/platform/net/ConnectionUtils.java b/src/java/com/agynamix/platform/net/ConnectionUtils.java new file mode 100644 index 0000000..0eb4f3f --- /dev/null +++ b/src/java/com/agynamix/platform/net/ConnectionUtils.java @@ -0,0 +1,264 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.protocol.ICommands; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; + +public class ConnectionUtils { + + static Logger log = ApplicationLog.getLogger(ConnectionUtils.class); + + private static Object connectSemaphore = new Object(); + private static Object toByteSemaphore = new Object(); + private static Object miscSemaphore = new Object(); + + public final static int CONNECT_TIMEOUT = 3000; + + /** + * FIXME: Move into a different utility class + */ + public static void safeAddToClientList(List peerClientList, List connectedClientList) + { + synchronized (miscSemaphore) + { + for (ClientNode node : peerClientList) + { + safeAddToClientList(node, connectedClientList); + } + } + } + + /** + * FIXME: Move into a different utility class + * Check the current connector list. + * If it contains the requestors node id, replace the entry with the new one, + * else add the new node to the list. + * We must make sure that we tag our own ClientNode with the isSelf tag, otherwise + * we would send us our own love letters. + * @param newNode the ClientNode object of a just received connect request. + * @param connectedClientList the list of currently connected clients. + */ + public static void safeAddToClientList(ClientNode newNode, List connectedClientList) + { + synchronized (miscSemaphore) + { + boolean shouldAdd = true; + if (connectedClientList.size() > 0) + { + for (int i = connectedClientList.size()-1; i >= 0; i--) + { + ClientNode node = connectedClientList.get(i); + if (node.getNodeId().equals(newNode.getNodeId())) + { + if (node.isShutdown()) + { + if (node.getShutdownDate().before(newNode.getCreationDate())) + { + log.log(Level.WARNING, "Shutdown bevor CreationDate for node "+node); + connectedClientList.remove(i); + } else { + shouldAdd = false; + } + } else { + if (!node.isNodeActive()) + { + connectedClientList.remove(i); + } else { + shouldAdd = false; + } + } + } + } + } + if (shouldAdd) + { + connectedClientList.add(newNode); +// System.out.println("My Client List now:"); +// for (ClientNode node : connectedClientList) +// { +// System.out.println("Node: "+node); +// } + } + } + } + + public static byte[] toByteArray(String... fields) + { + StringBuilder sb = new StringBuilder(); + for (String s : fields) + { + if (sb.length() > 0) + { + sb.append(ICommands.FIELD_SEP); + } + sb.append(s); + } + return sb.toString().getBytes(); + } + + public static void clearInactiveFromClientList(IConnector connector, List clients) + { + synchronized (miscSemaphore) + { + long time = System.currentTimeMillis() - 300000; // minus 5 Minuten + Date threshold = new Date(time); + for (int i = clients.size()-1; i >= 0; i--) + { + ClientNode node = clients.get(i); + if (!node.equals(connector.getMyOwnNode())) + { + Date inactiveSince = node.getInactiveSince(); + Date shutdownDate = node.getShutdownDate(); + boolean isRemoved = false; + if (inactiveSince != null) + { + if (inactiveSince.before(threshold)) + { +// System.out.println("Clearing out (inactive): "+node); + clients.remove(i); + isRemoved = true; + } + } + if ((!isRemoved) && (shutdownDate != null)) + { + clients.remove(i); + isRemoved = true; + } + } + } + setConnectionStatus(clients); + } + } + + /** + * @param connector interface to our connector + * @param node client to connect to + * @return a new and authenticated connection to a peer + * @throws IOException + * @throws NetworkAuthException + */ + public static ConnectionCtx connectTo(IConnector connector, ClientNode node) throws IOException, NetworkAuthException + { + try { + Socket socket = connectSocket(node.getAddress(), node.getPort()); + ConnectionCtx connectionCtx = new ConnectionCtx(connector, socket); + connectionCtx.getNodeCommandUtils().authenticate(); + node.setNodeActive(); + return connectionCtx; + } catch (NetworkProtocolException e) + { + log.log(Level.INFO, "Error connecting with "+node, e); + node.setNodeInactive(); + throw new IOException(e.getMessage()); + } catch (IOException e) + { + log.log(Level.INFO, "Error connecting with "+node, e); + node.setNodeInactive(); + throw e; + } + } + + /** + * @param connector interface to our connector + * @param node client to connect to + * @return a new and authenticated connection to a peer + * @throws IOException + * @throws NetworkAuthException + */ + public static ClientNode requestClientId(IConnector connector, String address, int port) throws IOException, NetworkAuthException + { + try { + log.fine("request ClientId from "+address+":"+port); + Socket socket = connectSocket(address, port); + ConnectionCtx connectionCtx = new ConnectionCtx(connector, socket); + connectionCtx.getNodeCommandUtils().authenticate(); + UUID uuid = (UUID) connectionCtx.getNodeCommandUtils().invoke(new RequestClientIdCommand()); + if (uuid != null) + { + ClientNode node = new ClientNode(uuid, connector.getGroupName(), socket.getInetAddress(), port); + return node; + } + return null; + } catch (Exception e) + { + log.log(Level.WARNING, "Error connecting with "+address+":"+port, e); +// e.printStackTrace(); + return null; + } + } + + protected static Socket connectSocket(String address, int port) throws IOException + { + return connectSocket(new InetSocketAddress(address, port)); + } + + protected static Socket connectSocket(InetAddress address, int port) throws IOException + { + return connectSocket(new InetSocketAddress(address, port)); + } + + protected static Socket connectSocket(InetSocketAddress socketAddress) throws IOException + { + Socket socket = new Socket(); + socket.connect(socketAddress, CONNECT_TIMEOUT); + return socket; + } + + public static void setConnectionStatus(List clientList) + { + if (clientList.size() > 1) + { + if (clientList.size() == 2) + { + RemoteConnector c = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + ClientNode myOwnNode = c.getConnector().getMyOwnNode(); + String address = findConnectedClient(myOwnNode, clientList); + PlatformUtils.setConnected(address); + } else { + PlatformUtils.setConnected(clientList.size()-1); + } + } else { + PlatformUtils.setNotConnected(); + } + } + + private static String findConnectedClient(ClientNode myOwnNode, List clientList) + { + for (ClientNode node : clientList) + { + if (!node.equals(myOwnNode)) + { + return node.getAddress().getHostAddress(); + } + } + return "unknown"; + } + + + +} diff --git a/src/java/com/agynamix/platform/net/Connector.java b/src/java/com/agynamix/platform/net/Connector.java new file mode 100644 index 0000000..6c477d8 --- /dev/null +++ b/src/java/com/agynamix/platform/net/Connector.java @@ -0,0 +1,223 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.ExecutorUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.protocol.NodeCommand; + +/** + * This is a testbed for a user friendly peer-to-peer connector. + * How does the connector work? + * The Connector will regularly advertise itself (broadcast) to the network. + * @author tuhlmann + * + */ +public class Connector implements IConnector { + + protected final String groupName; + protected final String groupPassword; + protected final int helloPort; + protected final int serverPort; + private final UUID nodeId; + + private final BlockingQueue requestorQueue = new LinkedBlockingQueue(); + + private PingService pingService; + private PingServiceListener pingListener; + private ClientListSynchronizer clientListSynchronizer; + private ConnectorServer connectorServer; + private ContactRequestorService contactRequestorService; + + private ClientNode myOwnNode; + + private List connectedClients = new CopyOnWriteArrayList(); + + private List packetReceivedListeners = new ArrayList(); + + static Logger log = ApplicationLog.getLogger(Connector.class); + + public Connector(UUID applicationId, String groupName, String groupPassword, int helloPort, int serverPort) + { + this.nodeId = applicationId; + this.groupName = groupName; + this.groupPassword = groupPassword; + this.helloPort = helloPort; + this.serverPort = serverPort; + } + + public void initialize() + { + myOwnNode = new ClientNode(nodeId, getGroupName(), NetUtils.getPrimaryHostAddress(), getServerPort()); + ConnectionUtils.safeAddToClientList(myOwnNode, getConnectedClientList()); + pingService = new PingService(this); + pingListener = new PingServiceListener(this); + contactRequestorService = new ContactRequestorService(this); + connectorServer = new ConnectorServer(this); + clientListSynchronizer = new ClientListSynchronizer(this); + } + + public void run() + { + ExecutorUtils.addFixedService(connectorServer); + ExecutorUtils.addFixedService(pingListener); + ExecutorUtils.addFixedService(contactRequestorService); + ExecutorUtils.addScheduledService(pingService, 2, 60, TimeUnit.SECONDS); + ExecutorUtils.addScheduledService(clientListSynchronizer, 20, 120, TimeUnit.SECONDS); + } + + public void shutdown() + { + pingListener.shutdown(); + connectorServer.shutdown(); + contactRequestorService.shutdown(); + ExecutorUtils.shutdownScheduledService(); + ExecutorUtils.shutdownFixedService(); + // Signal all connected Clients that we are leaving + signalGoodBye(); + log.info("Executors shut down."); + } + + public static class ConnectorShutdownHook extends Thread { + @Override + public void run() + { + log.info("ShutdownHook called"); + } + } + + public ClientNode getMyOwnNode() + { + return myOwnNode; + } + + public boolean isMyOwnNode(ClientNode node) + { + return node.getNodeId().equals(getMyOwnNode().getNodeId()); + } + + public int getHelloPort() + { + return this.helloPort; + } + + public BlockingQueue getRequestorQueue() + { + return this.requestorQueue; + } + + public List getConnectedClientList() + { + return connectedClients; + } + + public ClientNode getClientNode(UUID nodeId) + { + for (ClientNode node : getConnectedClientList()) + { + if (node.getNodeId().equals(nodeId)) + { + return node; + } + } + return null; + } + + public int getServerPort() + { + return this.serverPort; + } + + public String getGroupName() + { + return this.groupName; + } + + public String getGroupPassword() + { + return this.groupPassword; + } + + public UUID getNodeId() + { + return this.nodeId; + } + + public void addPacketReceivedListener(IPacketReceivedListener listener) + { + packetReceivedListeners.add(listener); + } + + public void removePacketReceivedListener(IPacketReceivedListener listener) + { + packetReceivedListeners.remove(listener); + } + + public void firePacketReceived(NodeCommand command) + { + for (IPacketReceivedListener listener : packetReceivedListeners) + { + listener.packetReceived(command); + } + } + + /** + * Signal all connected clients that we are leaving. + */ + protected void signalGoodBye() + { + for (ClientNode node : getConnectedClientList()) + { + if ((!node.equals(getMyOwnNode())) && (!node.isShutdown())) + { + signalGoodBye(node); + } + } + } + + protected void signalGoodBye(ClientNode node) + { + try + { + ConnectionCtx connectionCtx = ConnectionUtils.connectTo(this, node); + connectionCtx.invoke(new SignalGoodByeCommand(getMyOwnNode())); + connectionCtx.disconnect(); + } catch (Exception e) + { + log.warning("Problem connecting to "+node+": "+e.getMessage()); + } + } + + public void shutdownNode(ClientNode nodeToShutdown) + { + for (ClientNode node : getConnectedClientList()) + { + if (node.equals(nodeToShutdown)) + { + log.info("Shutdown node "+node); + node.shutdown(); + } + } + } + + +} diff --git a/src/java/com/agynamix/platform/net/ConnectorServer.java b/src/java/com/agynamix/platform/net/ConnectorServer.java new file mode 100644 index 0000000..2d732fb --- /dev/null +++ b/src/java/com/agynamix/platform/net/ConnectorServer.java @@ -0,0 +1,88 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.log.ApplicationLog; + +public class ConnectorServer implements ThreadManagerAware { + + final ExecutorService serverHandlerService = Executors.newFixedThreadPool(10); + + final IConnector connector; + ServerSocket serverSocket; + + boolean shouldStop = false; + + private static Logger log = ApplicationLog.getLogger(ConnectorServer.class); + + public ConnectorServer(IConnector connector) + { + this.connector = connector; + try + { + // 23-08-2011: changed backlog from 1 to 100 + // don't bind to all addresses, only to the primary one. + log.config("Try to bind to "+NetUtils.getPrimaryHostAddress()+" at port "+connector.getServerPort()); + serverSocket = new ServerSocket(connector.getServerPort(), 100, NetUtils.getPrimaryHostAddress()); + serverSocket.setSoTimeout(1000); + } catch (IOException e) + { + e.printStackTrace(); + throw new FatalNetworkException(e); + } + } + + public void run() + { + while (!shouldStop) + { + try { + Socket socket = serverSocket.accept(); +// System.out.println("Accept Client connecting from "+socket.getInetAddress()); +// serverHandlerService.execute(new ConnectorServerHandler(connector, socket)); + new Thread(new ConnectorServerHandler(connector, socket)).start(); + } catch (SocketTimeoutException e) + { + // Timeout occured + } catch (IOException e) + { + //e.printStackTrace(); + } + try + { + Thread.sleep(2000); + } catch (InterruptedException e) { } + } + } + + public String getId() + { + return "ConnectorService"; + } + + public void shutdown() + { + serverHandlerService.shutdownNow(); + shouldStop = true; + } + +} diff --git a/src/java/com/agynamix/platform/net/ConnectorServerHandler.java b/src/java/com/agynamix/platform/net/ConnectorServerHandler.java new file mode 100644 index 0000000..bc15f26 --- /dev/null +++ b/src/java/com/agynamix/platform/net/ConnectorServerHandler.java @@ -0,0 +1,164 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.protocol.Auth; +import com.agynamix.platform.net.protocol.Expt; +import com.agynamix.platform.net.protocol.ICommands; +import com.agynamix.platform.net.protocol.NodeCommand; +import com.agynamix.platform.net.protocol.Rcmd; +import com.agynamix.simidude.source.SourceDataContents; + +public class ConnectorServerHandler implements IConnectorServerHandler, Runnable { + + final ConnectionCtx connectionCtx; + final IConnector connector; + + Logger log = ApplicationLog.getLogger(ConnectorServerHandler.class); + + ExecutorService parallelTasks = Executors.newCachedThreadPool(); + + public ConnectorServerHandler(IConnector connector, Socket socket) + { + this.connector = connector; + this.connectionCtx = new ConnectionCtx(connector, socket); + } + + public void run() + { + try { + NodeCommand command = connectionCtx.getNodeCommandUtils().receiveCommand(ICommands.AUTH); + if (ICommands.AUTH.equals(command.getCommand())) + { + Auth auth = (Auth) command; + if (isNodeAuthenticated(auth)) + { + connectionCtx.getNodeCommandUtils().sendAcpt(connector.getMyOwnNode().getNodeId()); + receive(); + } else { + connectionCtx.getNodeCommandUtils().sendRejt(); + connectionCtx.close(); + return; + } + } else { + log.log(Level.WARNING, "Command not recognized: "+command.getCommand()); + connectionCtx.getNodeCommandUtils().sendRejt(); + connectionCtx.close(); + return; + } + } catch (Exception e) + { + log.log(Level.WARNING, "Error receiving from client: "+e.getMessage(), e); + } + } + + private boolean isNodeAuthenticated(Auth authCommand) + { + if (connector.getGroupName().equals(authCommand.getGroupname())) + { + if (connector.getGroupPassword().equals(authCommand.getPassword())) + { + return true; + } + } + return false; + } + + /** + * Receive is the main method that will take contents from a client. + * This method is called after the client has been authorized. It will + * run in a loop until the client closes the connection. + * @throws IOException + */ + private void receive() throws IOException + { + boolean isConnected = true; + while (isConnected) + { + String methodName = "unknown"; + try + { + NodeCommand command = connectionCtx.getNodeCommandUtils().receiveCommand(); + methodName = "handle"+command.getCommand(); + Method handleMethod = this.getClass().getDeclaredMethod(methodName, NodeCommand.class); + isConnected = (Boolean) handleMethod.invoke(this, command); +// System.out.println("isConnected = "+isConnected); + connector.firePacketReceived(command); + } catch (NetworkProtocolException e) + { + log.log(Level.WARNING, e.getMessage()); + } catch (Exception e) + { + log.log(Level.WARNING, "Error calling method "+methodName, e); + } + } + } + + protected boolean handleQUIT(NodeCommand command) + { +// System.out.println("Received quit command. Close socket and leave handler."); + try { + connectionCtx.close(); + } catch (Exception ignore) {} + return false; + } + + protected boolean handleRCMD(NodeCommand command) + { + try { + Rcmd rcmd = (Rcmd) command; + Object result = rcmd.getRemoteCommand().invoke(this); + connectionCtx.getNodeCommandUtils().sendObjt(result); + return true; + } catch (Exception e) + { + e.printStackTrace(); + return false; + } + } + + protected boolean handleEXPT(NodeCommand command) + { + Expt expt = (Expt) command; + Exception e = expt.getException(); + System.out.println("Peer sent Exception: "+e.getMessage()); + e.printStackTrace(); + return true; + } + + public void executeParallel(Runnable task) + { + parallelTasks.execute(task); + } + + public void sendSourceDataContents(SourceDataContents contents) throws IOException + { + connectionCtx.getNodeCommandUtils().sendObjt(contents); + } + + public void sendException(Exception exception) throws IOException + { + connectionCtx.getNodeCommandUtils().sendExpt(exception); + } + + +} diff --git a/src/java/com/agynamix/platform/net/ContactRequestorService.java b/src/java/com/agynamix/platform/net/ContactRequestorService.java new file mode 100644 index 0000000..8f51e8d --- /dev/null +++ b/src/java/com/agynamix/platform/net/ContactRequestorService.java @@ -0,0 +1,92 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.util.List; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.log.ApplicationLog; + +public class ContactRequestorService implements ThreadManagerAware { + + Logger log = ApplicationLog.getLogger(ContactRequestorService.class); + + boolean shouldStop = false; + + final IConnector connector; + + public ContactRequestorService(IConnector connector) + { + this.connector = connector; + } + + public void run() + { + while (!shouldStop) + { + try + { + ClientNode requestor = connector.getRequestorQueue().take(); + if (requestor != null) + { + log.fine("Connecting with client on this address: "+requestor); + List clientList = connector.getConnectedClientList(); + ConnectionUtils.clearInactiveFromClientList(connector, clientList); + ConnectionUtils.safeAddToClientList(requestor, clientList); + ConnectionUtils.setConnectionStatus(connector.getConnectedClientList()); + sendConnectedClientList(requestor, clientList); + } + } catch (InterruptedException e) + { + // Interruption occurs when the connector is shutting down. + } + } + } + + public synchronized void sendConnectedClientList(ClientNode requestor, List connectedClientList) + { + ConnectionCtx connectionCtx = null; + try { + connectionCtx = ConnectionUtils.connectTo(connector, requestor); + connectionCtx.invoke(new TransportClientListCommand(connectedClientList)); + connectionCtx.disconnect(); + } catch (NetworkAuthException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } catch (NetworkProtocolException e) + { + e.printStackTrace(); + } finally { + if (connectionCtx != null) + { + connectionCtx.close(); + } + } + } + + public String getId() + { + return "ContactRequestorService"; + } + + public void shutdown() + { + this.shouldStop = true; + } + +} diff --git a/src/java/com/agynamix/platform/net/FatalNetworkException.java b/src/java/com/agynamix/platform/net/FatalNetworkException.java new file mode 100644 index 0000000..b9ed8cf --- /dev/null +++ b/src/java/com/agynamix/platform/net/FatalNetworkException.java @@ -0,0 +1,39 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +public class FatalNetworkException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public FatalNetworkException() + { + super(); + } + + public FatalNetworkException(String message) + { + super(message); + } + + public FatalNetworkException(Throwable cause) + { + super(cause); + } + + public FatalNetworkException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/src/java/com/agynamix/platform/net/IConnector.java b/src/java/com/agynamix/platform/net/IConnector.java new file mode 100644 index 0000000..64160d7 --- /dev/null +++ b/src/java/com/agynamix/platform/net/IConnector.java @@ -0,0 +1,90 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; + +import com.agynamix.platform.net.protocol.NodeCommand; + +public interface IConnector { + + /** + * + * @return the Hello port for broadcasting that should be used. + */ + int getHelloPort(); + + /** + * + * @return the server port that is used for exchanging messages. + */ + int getServerPort(); + + /** + * This queue is used to store addresses of clients that have just advertised. + * @return + */ + BlockingQueue getRequestorQueue(); + + /** + * + * @return a List of all clients we know of. + */ + List getConnectedClientList(); + + /** + * @return the node of this running instance. + */ + ClientNode getMyOwnNode(); + + /** + * Checks if the given node is my own + * @return true if the given node is my own node, false otherwise. + */ + boolean isMyOwnNode(ClientNode node); + + String getGroupPassword(); + + String getGroupName(); + + UUID getNodeId(); + + public void addPacketReceivedListener(IPacketReceivedListener listener); + + public void removePacketReceivedListener(IPacketReceivedListener listener); + + /** + * Notify listeners that we received a command + * @param command the received command + */ + void firePacketReceived(NodeCommand command); + + /** + * Get the ClientNode with the specified UUID + * @param nodeId the wanted UUID + * @return the ClientNode that holds the wanted UUID or null if it can't be found + */ + ClientNode getClientNode(UUID nodeId); + + /** + * Tells the Connector that a specific node had been shutdown. + * @param node the node that was shut down. + */ + void shutdownNode(ClientNode node); + + + + +} diff --git a/src/java/com/agynamix/platform/net/IConnectorServerHandler.java b/src/java/com/agynamix/platform/net/IConnectorServerHandler.java new file mode 100644 index 0000000..513e0d4 --- /dev/null +++ b/src/java/com/agynamix/platform/net/IConnectorServerHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; + +import com.agynamix.simidude.source.SourceDataContents; + + +public interface IConnectorServerHandler { + + /** + * Execute a Runnable in a separate thread. + * @param task the runnable to execute + */ + void executeParallel(Runnable task); + + /** + * Send DATA packages to the connected peer. + * @param contents the package to send + */ + public void sendSourceDataContents(SourceDataContents contents) throws IOException; + + /** + * Send an exception that occured on this side over to the peer. + * @throws IOException + */ + void sendException(Exception exception) throws IOException; + +} diff --git a/src/java/com/agynamix/platform/net/IPacketReceivedListener.java b/src/java/com/agynamix/platform/net/IPacketReceivedListener.java new file mode 100644 index 0000000..d6a70c3 --- /dev/null +++ b/src/java/com/agynamix/platform/net/IPacketReceivedListener.java @@ -0,0 +1,21 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import com.agynamix.platform.net.protocol.NodeCommand; + +public interface IPacketReceivedListener { + + void packetReceived(NodeCommand command); + +} diff --git a/src/java/com/agynamix/platform/net/IRemoteCommand.java b/src/java/com/agynamix/platform/net/IRemoteCommand.java new file mode 100644 index 0000000..4439bfc --- /dev/null +++ b/src/java/com/agynamix/platform/net/IRemoteCommand.java @@ -0,0 +1,25 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.Serializable; + +public interface IRemoteCommand extends Serializable { + + /** + * The invoke method is called on the remote client. + * @return the result of the invoke method is returned to the caller. + */ + Object invoke(IConnectorServerHandler connectorServerHandler); + +} diff --git a/src/java/com/agynamix/platform/net/IStreamSuplier.java b/src/java/com/agynamix/platform/net/IStreamSuplier.java new file mode 100644 index 0000000..d50a1c0 --- /dev/null +++ b/src/java/com/agynamix/platform/net/IStreamSuplier.java @@ -0,0 +1,23 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; + +public interface IStreamSuplier { + + public BufferedOutputStream getOutputStream(); + public BufferedInputStream getInputStream(); + +} diff --git a/src/java/com/agynamix/platform/net/NetUtils.java b/src/java/com/agynamix/platform/net/NetUtils.java new file mode 100644 index 0000000..9b45458 --- /dev/null +++ b/src/java/com/agynamix/platform/net/NetUtils.java @@ -0,0 +1,335 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.protocol.ICommands; + +public class NetUtils { + + private static Logger log = ApplicationLog.getLogger(NetUtils.class); + + public static List getHostAddresses() + { + List ipAddresses = new ArrayList(); + + try { + InetAddress customAddress = getCustomAddressFromPreferences(); + if (customAddress != null) { + ipAddresses.add(customAddress); + return ipAddresses; + } + } catch (Exception e) { + log.log(Level.WARNING, e.getMessage(), e); + } + + try + { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) + { + NetworkInterface ni = interfaces.nextElement(); + Enumeration addresses = ni.getInetAddresses(); + while (addresses.hasMoreElements()) + { + InetAddress addr = addresses.nextElement(); + if (!addr.isLoopbackAddress()) + { + if (addr instanceof Inet4Address) // Fixme: Only IP4 at this time. + { + if (!matchesIgnoreAddressesFromPreferences(addr)) + { + // if (addr.isReachable(10000)) + // { + // System.out.println("Address "+addr+" is reachable"); + log.fine("My address: "+addr.getHostAddress()); + ipAddresses.add(addr); + } + // } + } + } + } + } +// addCustomAddressFromPreferences(ipAddresses); + } catch (SocketException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } catch (IOException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + if (ipAddresses.size() == 0) + { + try + { + ipAddresses.add(InetAddress.getLocalHost()); + } catch (UnknownHostException e) + { + e.printStackTrace(); + throw new FatalNetworkException(e); + } + } + return ipAddresses; + } + + public static InetAddress getPrimaryHostAddress() + { + try { + InetAddress customAddress = getCustomAddressFromPreferences(); + if (customAddress != null) { + return customAddress; + } + } catch (Exception e) { + log.log(Level.WARNING, e.getMessage(), e); + } + try { + return getHostAddresses().get(0); + } catch (Exception e) { + try + { + return Inet4Address.getByName("127.0.0.1"); + } catch (UnknownHostException e1) + { + return null; + } + } + } + + public static String getLocalHostAddress() + { + try { + InetAddress customAddress = getCustomAddressFromPreferences(); + if (customAddress != null) { + return customAddress.getHostAddress(); + } +// InetAddress addr = InetAddress.getLocalHost(); +// System.out.println("Found local address: "+addr.getHostAddress()); +// return addr.getHostAddress(); + List addresses = getHostAddresses(); +// for (InetAddress a : addresses) +// { +// System.out.println("Address: "+a.getHostAddress()); +// } + InetAddress hostname = addresses.get(0); + return hostname.getHostAddress(); + } catch (Exception e) { + e.printStackTrace(); + return "127.0.0.1"; + } + } + + /** + * Convert a received buffer from a broadcast to a ClientNode instance + * + * @param buffer + * the received byte buffer + * @return a ClientNode instance + */ + public static ClientNode bcBufferToNode(byte[] buffer) + { + try + { + UUID nodeId = UUID.fromString(NetUtils.decodeField(buffer, 0, 0)); + String groupname = NetUtils.decodeField(buffer, 0, 1); + String ip = NetUtils.decodeField(buffer, 0, 2); + int port = Integer.parseInt(NetUtils.decodeField(buffer, 0, 3)); + return new ClientNode(nodeId, groupname, InetAddress.getByName(ip), port); + } catch (Exception e) + { + e.printStackTrace(); + return null; + } + } + + public static byte[] nodeToBcBuffer(ClientNode node) + { + StringBuilder sb = new StringBuilder(); + sb.append(NetUtils.encodeField(node.getNodeId().toString())); + sb.append(ICommands.FIELD_SEP); + sb.append(NetUtils.encodeField(node.getGroupname())); + sb.append(ICommands.FIELD_SEP); + sb.append(NetUtils.encodeField(node.getAddress().getHostAddress())); + sb.append(ICommands.FIELD_SEP); + sb.append(NetUtils.encodeField("" + node.getPort())); + byte[] b = sb.toString().getBytes(); + byte[] buffer = new byte[ICommands.BC_BUFFER_SIZE]; + System.arraycopy(b, 0, buffer, 0, b.length); + return buffer; + } + + public static String encodeField(String str) + { + try + { + return URLEncoder.encode(str, ICommands.CMD_CHARSET); + } catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e); + } + } + + public static String decodeField(String encoded) + { + try { + return URLDecoder.decode(encoded.trim(), ICommands.CMD_CHARSET); + } catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e); + } + } + + /** + * Receives a byte buffer that contains quoted fields. + * We scan through the buffer starting at offset until we find + * the elemIdx'th occurence of ICommands.FIELD_SEP. We strip + * the seperator from the found field and return the found part as a new String + * @param buffer the byte buffer + * @param offset the offset where the actual payload starts. + * @param elemIdx the number of the required field starting with 0. + * @return + */ + public static String decodeField(byte[] buffer, int offset, int elemIdx) + { + byte[] sepBuffer = ICommands.FIELD_SEP.getBytes(); + int foundCount = 0; + int startOffset = offset; + int endOffset = -1; + for (int i = offset; i < buffer.length; i++) + { + if (isFieldSeparator(buffer, i, sepBuffer)) + { + foundCount++; + if (foundCount == elemIdx) + { + startOffset = i+sepBuffer.length; + } else if (foundCount == elemIdx+1) + { + endOffset = i; + return decodeField(new String(buffer, startOffset, endOffset - startOffset)); + } + } + } + // End of string reached + return decodeField(new String(buffer, startOffset, buffer.length - startOffset)); + } + + private static boolean isFieldSeparator(byte[] buffer, int idx, byte[] separator) + { + for (int i = 0; i < separator.length; i++) + { + if (buffer[idx+i] != separator[i]) + { + return false; + } + } + return true; + } + + public static final byte[] intToByteArray(int value) + { + return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value }; + } + + public static final int byteArrayToInt(byte[] b, int offset) + { + return (b[offset] << 24) + ((b[offset+1] & 0xFF) << 16) + ((b[offset+2] & 0xFF) << 8) + (b[offset+3] & 0xFF); + } + + public static InetAddress getCustomAddressFromPreferences() throws UnknownHostException + { + String address = ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.OWN_IP_ADRESS); + if ((address == null) || (address.length() == 0)) + { + return null; + } + return Inet4Address.getByName(address); + } + + private static boolean matchesIgnoreAddressesFromPreferences(InetAddress address) + { + List ignoreAddresses = ApplicationBase.getContext().getConfiguration().getProperyList(IPreferenceConstants.IGNORE_NETWORK_ADDRESSES); + for (String ignoreAddress : ignoreAddresses) + { + try + { + InetAddress a = Inet4Address.getByName(ignoreAddress); + if (matchesAddressPattern(a, address)) + { + return true; + } + } catch (UnknownHostException e) + { + e.printStackTrace(); + } + } + return false; + } + + private static boolean matchesAddressPattern(InetAddress pattern, InetAddress address) + { + byte[] patternArr = pattern.getAddress(); + byte[] addressArr = address.getAddress(); + + for (int i = 0; i<4; i++) + { + short patternS = (short) (patternArr[i] & 255); + short addressS = (short) (addressArr[i] & 255); + + if (patternS == 255) + { + continue; + } + if (patternS != addressS) + { + log.fine("Pattern matches NOT: "+pattern+" vs. "+address); + return false; + } + } + log.fine("Pattern matches: "+pattern+" vs. "+address); + return true; + } + + private static void addCustomAddressFromPreferences(List ipAddresses) throws UnknownHostException + { + InetAddress customAddress = getCustomAddressFromPreferences(); + if (customAddress != null) + { + if (!ipAddresses.contains(customAddress)) + { + log.fine("Add custom address from prefs: "+customAddress.getHostAddress()); + ipAddresses.add(customAddress); + } + } + } + + + +} diff --git a/src/java/com/agynamix/platform/net/NetworkAnalyzer.java b/src/java/com/agynamix/platform/net/NetworkAnalyzer.java new file mode 100644 index 0000000..e188374 --- /dev/null +++ b/src/java/com/agynamix/platform/net/NetworkAnalyzer.java @@ -0,0 +1,311 @@ +package com.agynamix.platform.net; + +import java.net.InetAddress; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.log.ConnectionLog; +import com.agynamix.platform.log.ConnectionLogNodeStatistic; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; +import com.agynamix.simidude.source.ISourceData.SourceType; + +public class NetworkAnalyzer { + + List myAddresses; + InetAddress primaryAddress; + InetAddress customPrefsAddress; + + int helloPort; + int serverPort; + int httpPort; + + boolean isHttpEnabled; + + Throwable exceptionOcured = null; + + RemoteConnector remoteConnector; + IConnector connector; + + ConnectionLog connectionLog; + + Map probedClients = null; + + Date timeNow; + + public void run() + { + try { + + timeNow = new Date(); + + remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + connector = remoteConnector.getConnector(); + + myAddresses = NetUtils.getHostAddresses(); + primaryAddress = NetUtils.getPrimaryHostAddress(); + customPrefsAddress = NetUtils.getCustomAddressFromPreferences(); + + helloPort = connector.getHelloPort(); + serverPort = connector.getServerPort(); + isHttpEnabled = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.START_HTTP_SERVER); + httpPort = ApplicationBase.getContext().getConfiguration().getInteger(IPreferenceConstants.HTTP_SERVER_PORT); + + connectionLog = (ConnectionLog) ApplicationBase.getContext().getService(ConnectionLog.SERVICE_NAME); + + probedClients = probeClientNodes(connector.getConnectedClientList()); + + } catch (Exception e) { + exceptionOcured = e; + } + } + + public String asString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("Information about this machine:\n"); + sb.append("===============================\n\n"); + sb.append(infoAboutMyIpAddress()); + sb.append(infoAboutCommunicationPorts()); + sb.append("\n\n"); + + sb.append(infoAboutConnectedClients()); + + + sb.append(connectionLogAsString(connectionLog)); + + sb.append("\n"); + + return sb.toString(); + } + + private String infoAboutMyIpAddress() + { + StringBuilder sb = new StringBuilder(); + + if (customPrefsAddress != null) + { + sb.append("IP address you entered in Network Prefs: "+customPrefsAddress.getHostAddress()+"\n"); + if (primaryAddress == null) + { + sb.append("INTERNAL PROBLEM: Primary IP address is NULL\n"); + } else { + if (!primaryAddress.equals(customPrefsAddress)) + { + sb.append("PROBLEM: The primary address does not match the address you have entered: "+primaryAddress.getHostAddress()+"\n"); + } + } + if (myAddresses == null) + { + sb.append("INTERNAL PROBLEM: My IP addresses list is NULL\n"); + } else { + if (myAddresses.size() > 1) + { + sb.append("PROBLEM: My IP addresses contains more addresses then the one you entered:\n"); + sb.append(listAddresses(myAddresses)).append("\n"); + } else if (myAddresses.size() == 1) { + if (!myAddresses.get(0).equals(customPrefsAddress)) + { + sb.append("PROBLEM: The address from my addresses does not match the address you have entered: "+primaryAddress.getHostAddress()+"\n"); + } + } else { + sb.append("PROBLEM: My IP addresses list is empty!\n"); + } + } + } else { + if (primaryAddress == null) + { + sb.append("INTERNAL PROBLEM: Primary IP address is NULL\n"); + } else { + sb.append("Primary IP address: "+primaryAddress.getHostAddress()+"\n"); + } + if (myAddresses == null) + { + sb.append("INTERNAL PROBLEM: My IP addresses list is NULL\n"); + } else { + sb.append("My IP addresses list:\n"); + sb.append(listAddresses(myAddresses)).append("\n"); + } + } + return sb.toString(); + } + + private String infoAboutCommunicationPorts() + { + StringBuilder sb = new StringBuilder(); + + sb.append("Communication Ports:\n"); + sb.append("====================\n\n"); + sb.append("Broadcast Port: "+helloPort+"\n"); + sb.append("Communication Port: "+serverPort+"\n"); + if (isHttpEnabled) + { + sb.append("HTTP access enabled at: "); + sb.append("http://" + NetUtils.getLocalHostAddress() + ":" + httpPort); + } else { + sb.append("HTTP access disabled\n"); + } + + + return sb.toString(); + } + + private String infoAboutConnectedClients() + { + StringBuilder sb = new StringBuilder(); + + if (connector.getConnectedClientList().size() > 1) // our own node is stored in here as well + { + sb.append("Connected Clients:\n"); + sb.append("==================\n\n"); + } + + for (ClientNode node : connector.getConnectedClientList()) + { + if (!connector.isMyOwnNode(node)) + { + sb.append("IP: "+node.getAddress().getHostAddress()+ " ("+node.getAddress().getHostName()+"), ID: "+node.getNodeId()+"\n"); + sb.append("Connected Since: "+node.getCreationDate() +"\n"); + if (probedClients.get(node) != null) + { + if (probedClients.get(node) == true) + { + sb.append("Connection to the client successfully established.\n"); + } else { + sb.append("Could not connect to the client.\n"); + } + } else { + sb.append("No Connection info for that client available.\n"); + } + if (node.getInactiveSince() != null) + { + sb.append("Inactive Since: "+calculateTimeDifference(timeNow, node.getInactiveSince())+" (Since: "+node.getInactiveSince() +")\n"); + } + if (node.getShutdownDate() != null) + { + sb.append("Shutdown Date: "+node.getShutdownDate() +"\n"); + } + if ((node.getInactiveSince() == null) && (node.getShutdownDate() == null)) + { + sb.append("Client seems to be active.\n"); + } + sb.append("\n"); + } + } + + return sb.toString(); + } + + private String calculateTimeDifference(Date timeNow, Date eventTime) + { + long diffMillis = timeNow.getTime() - eventTime.getTime(); + long diffSec = diffMillis / 1000; + long diffMin = diffSec / 60; + long diffHour = diffMin / 60; + + int sec = (int)diffSec % 60; + int min = (int)diffMin % 60; + int hour = (int)diffHour % 60; + + return hour+":"+min+":"+sec+"s"; + } + + private String listAddresses(List addresses) + { + boolean first = true; + StringBuilder sb = new StringBuilder(); + if (addresses != null) + { + for (InetAddress a : addresses) + { + if (!first) + { + sb.append(", "); + } else { + first = false; + } + sb.append(a.getHostAddress()); + } + } + return sb.toString(); + } + + private Object connectionLogAsString(ConnectionLog connectionLog) + { + StringBuilder sb = new StringBuilder(); + + Map nodeStatisticsEntries = connectionLog.getNodeStatisticsEntries(); + + if (nodeStatisticsEntries.size() > 0) + { + sb.append("Connection History:\n"); + sb.append("===================\n\n"); + + for (InetAddress address : nodeStatisticsEntries.keySet()) + { + ConnectionLogNodeStatistic nodeStatistic = nodeStatisticsEntries.get(address); + + sb.append(connectionLogEntryAsString(address, nodeStatistic)); + + } + } + return sb.toString(); + } + + private String connectionLogEntryAsString(InetAddress address, ConnectionLogNodeStatistic nodeStatistic) + { + StringBuilder sb = new StringBuilder(); + + sb.append("IP: "+address.getHostAddress()+"\n"); + sb.append("-------------------\n"); + + int textClips = nodeStatistic.getEntryCountBySourceType(SourceType.TEXT); + int imageClips = nodeStatistic.getEntryCountBySourceType(SourceType.IMAGE); + int fileClips = nodeStatistic.getEntryCountBySourceType(SourceType.FILE); + + sb.append("Received (during last 12 hours):\n"); + sb.append("Text Clips: "+textClips+"\n"); + sb.append("Image Clips: "+imageClips+"\n"); + sb.append("File/Directory Clips: "+fileClips+"\n"); + + sb.append("\n"); + + return sb.toString(); + } + + private Map probeClientNodes(List connectedClientList) + { + Map probedClients = new HashMap(); + for (ClientNode node : connectedClientList) + { + if (!connector.isMyOwnNode(node)) + { + // Connect to Client and disconnect + try + { + ConnectionCtx ctx = ConnectionUtils.connectTo(connector, node); + ctx.close(); + probedClients.put(node, true); + } catch (Exception couldNotConnect) + { + probedClients.put(node, false); + } + } + } + return probedClients; + } + + public void close() + { + probedClients = null; + } + + + +} diff --git a/src/java/com/agynamix/platform/net/NetworkAuthException.java b/src/java/com/agynamix/platform/net/NetworkAuthException.java new file mode 100644 index 0000000..6312447 --- /dev/null +++ b/src/java/com/agynamix/platform/net/NetworkAuthException.java @@ -0,0 +1,27 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +public class NetworkAuthException extends Exception { + + public NetworkAuthException(String msg) + { + super(msg); + } + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/src/java/com/agynamix/platform/net/NetworkProtocolException.java b/src/java/com/agynamix/platform/net/NetworkProtocolException.java new file mode 100644 index 0000000..ed25e70 --- /dev/null +++ b/src/java/com/agynamix/platform/net/NetworkProtocolException.java @@ -0,0 +1,39 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +public class NetworkProtocolException extends Exception { + + private static final long serialVersionUID = 1L; + + public NetworkProtocolException() + { + super(); + } + + public NetworkProtocolException(String message) + { + super(message); + } + + public NetworkProtocolException(Throwable cause) + { + super(cause); + } + + public NetworkProtocolException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/src/java/com/agynamix/platform/net/PingService.java b/src/java/com/agynamix/platform/net/PingService.java new file mode 100644 index 0000000..b9172c6 --- /dev/null +++ b/src/java/com/agynamix/platform/net/PingService.java @@ -0,0 +1,116 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.List; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.log.ApplicationLog; + +public class PingService implements ThreadManagerAware { + + final IConnector connector; + + boolean shouldStop = false; + + Logger log = ApplicationLog.getLogger(PingService.class); + + public PingService(IConnector connector) + { + this.connector = connector; + } + + /** + * Thread only send one ping. The thread is managed by a scheduled Executor service who will trigger + * the thread itself. + */ + public void run() + { + if (!shouldStop) + { + advertise(); + } + } + + private void advertise() + { + try + { + List myAddresses = NetUtils.getHostAddresses(); + for (InetAddress myAddr : myAddresses) + { + byte[] buffer = NetUtils.nodeToBcBuffer(connector.getMyOwnNode()); + String ip = myAddr.getHostAddress(); + InetAddress bcAddr = getBroadcastAddress(myAddr); +// InetAddress bcAddr = InetAddress.getByName("255.255.255.255"); +// System.arraycopy(ip.getBytes(), 0, buffer, 0, ip.length()); + DatagramSocket s = new DatagramSocket(null); + DatagramPacket dp = new DatagramPacket(buffer, buffer.length, bcAddr, connector.getHelloPort()); + log.fine("Send Broadcast to "+bcAddr); + s.send(dp); + } + } catch (SocketException e) + { + e.printStackTrace(); + } catch (UnknownHostException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + private InetAddress getBroadcastAddress(InetAddress myAddr) + { + InetAddress re = myAddr; + if (myAddr instanceof Inet4Address) + { + try + { + byte[] ip = myAddr.getAddress(); +// ip[0] = (byte)255; +// ip[1] = (byte)255; +// ip[2] = (byte)255; + ip[3] = (byte)255; + re = InetAddress.getByAddress(ip); +// System.out.println("BC address is "+re.getHostAddress()); + } catch (UnknownHostException e) + { + e.printStackTrace(); + } + } + return re; + } + + public String getId() + { + return "PingService"; + } + + public void shutdown() + { + this.shouldStop = true; + } + + +} diff --git a/src/java/com/agynamix/platform/net/PingServiceListener.java b/src/java/com/agynamix/platform/net/PingServiceListener.java new file mode 100644 index 0000000..64afa67 --- /dev/null +++ b/src/java/com/agynamix/platform/net/PingServiceListener.java @@ -0,0 +1,148 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.protocol.ICommands; + +public class PingServiceListener implements ThreadManagerAware { + + boolean shouldStop = false; + + final IConnector connector; + + DatagramSocket listenSocket; + List myAddresses = new ArrayList(); + + Logger log = ApplicationLog.getLogger(PingServiceListener.class); + + public PingServiceListener(IConnector connector) + { + this.connector = connector; + try + { + myAddresses = NetUtils.getHostAddresses(); + listenSocket = new DatagramSocket(connector.getHelloPort()); + listenSocket.setSoTimeout(1000); + } catch (SocketException e) + { + log.severe("Error registering port "+connector.getHelloPort()+": "+e.getMessage()); + new FatalNetworkException(e); + } + } + + public void run() + { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + while (!shouldStop) + { + listenForPing(); + } + } + + private void listenForPing() + { + try + { + byte[] buffer = new byte[ICommands.BC_BUFFER_SIZE]; + DatagramPacket dp = new DatagramPacket(buffer, buffer.length); + listenSocket.receive(dp); + ClientNode requestor = NetUtils.bcBufferToNode(buffer); + if (areWeInterested(dp, requestor)) + { + log.fine("We are interested in ping from "+dp.getAddress().getHostAddress()); +// System.out.println("We received interesting BC from "+dp.getAddress().getHostAddress()); + if (requestor != null) + { + // Replace the IP from the buffer with the one we received the packet from. + //ClientNode requestor2 = new ClientNode(requestor.getNodeId(), requestor.getGroupname(), dp.getAddress(), requestor.getPort()); +// log.fine("Connection request from "+dp.getAddress().getHostAddress()); + log.fine("Connection request from "+requestor.getAddress()); + // FIXME: Test using the address from the buffer + connector.getRequestorQueue().put(requestor); // Try with the address from the buffer + } else { + log.info("The received bc buffer could not be decoded: "+new String(buffer)); + } + } + } catch (SocketTimeoutException e) + { + // Nothing came, no problem though, just the timeout expired + } catch (SocketException e) + { + //e.printStackTrace(); + } catch (IOException e) + { + //e.printStackTrace(); + } catch (InterruptedException e) + { + } + } + + private boolean areWeInterested(DatagramPacket dp, ClientNode requestor) + { +// System.out.println("areWeInterested: Are we interested in "+requestor); + if (dp.getAddress().isLoopbackAddress()) + { + log.log(Level.WARNING, "Loopback address submitted: "+dp.getAddress().getHostAddress()); + return false; + } + if (myAddresses.contains(dp.getAddress())) + { + return false; + } + if (myAddresses.contains(requestor.getAddress())) + { + return false; + } + if (!connector.getMyOwnNode().getGroupname().equals(requestor.getGroupname())) + { + // Wrong Simidude Group + return false; + } + return true; + +// if (connector.getConnectedClientList().contains(requestor)) +// { +// System.out.println("areWeInterested: We already know this Client: "+requestor); +// return false; +// } +// return true; + } + + public String getId() + { + return "PingServiceListener"; + } + + public void shutdown() + { + this.shouldStop = true; + } + +} diff --git a/src/java/com/agynamix/platform/net/RequestClientIdCommand.java b/src/java/com/agynamix/platform/net/RequestClientIdCommand.java new file mode 100644 index 0000000..be37d7b --- /dev/null +++ b/src/java/com/agynamix/platform/net/RequestClientIdCommand.java @@ -0,0 +1,33 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; + +public class RequestClientIdCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + public RequestClientIdCommand() + { + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + return remoteConnector.getConnector().getNodeId(); + } + +} diff --git a/src/java/com/agynamix/platform/net/SignalGoodByeCommand.java b/src/java/com/agynamix/platform/net/SignalGoodByeCommand.java new file mode 100644 index 0000000..1a3fa4b --- /dev/null +++ b/src/java/com/agynamix/platform/net/SignalGoodByeCommand.java @@ -0,0 +1,37 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; + +public class SignalGoodByeCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + private final ClientNode myOwnNode; + + public SignalGoodByeCommand(ClientNode myOwnNode) + { + this.myOwnNode = myOwnNode; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + remoteConnector.getConnector().shutdownNode(myOwnNode); + return Boolean.TRUE; + } + +} diff --git a/src/java/com/agynamix/platform/net/TransportClientListCommand.java b/src/java/com/agynamix/platform/net/TransportClientListCommand.java new file mode 100644 index 0000000..7064d41 --- /dev/null +++ b/src/java/com/agynamix/platform/net/TransportClientListCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net; + +import java.util.ArrayList; +import java.util.List; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; + +public class TransportClientListCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + final List localClientList; + + public TransportClientListCommand() + { + this.localClientList = null; + } + + public TransportClientListCommand(List clientList) + { + this.localClientList = clientList; + } + + /** + * This command server two purposes: + *
    + *
  • First it will transport a local client list (optional) to the peer.
  • + *
  • Secondly it will return the peers client list with the freshly sent nodes included.
  • + *
+ */ + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + List clientList = null; + RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + if (remoteConnector != null) + { + clientList = remoteConnector.getConnector().getConnectedClientList(); + if (localClientList != null) + { + ConnectionUtils.safeAddToClientList(localClientList, clientList); + ConnectionUtils.setConnectionStatus(clientList); + } + } else { + clientList = new ArrayList(); + } + return clientList; + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Ackn.java b/src/java/com/agynamix/platform/net/protocol/Ackn.java new file mode 100644 index 0000000..c326cb6 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Ackn.java @@ -0,0 +1,22 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +public class Ackn extends NodeCommand { + + public Ackn() + { + super(ICommands.ACKN); + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Acpt.java b/src/java/com/agynamix/platform/net/protocol/Acpt.java new file mode 100644 index 0000000..166e443 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Acpt.java @@ -0,0 +1,45 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import java.util.UUID; + +public class Acpt extends NodeCommand { + + final UUID nodeId; + + public Acpt(UUID nodeId) + { + super(ICommands.ACPT); + this.nodeId = nodeId; + } + + public Acpt(byte[] buffer, int offset, int packetSize) + { + super(ICommands.ACPT); + nodeId = UUID.fromString(decodeField(buffer, offset, 0)); + } + + public UUID getNodeId() + { + return this.nodeId; + } + + @Override + public byte[] toByteArray() + { + return toByteArray(encodeField(nodeId.toString())); + } + + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Auth.java b/src/java/com/agynamix/platform/net/protocol/Auth.java new file mode 100644 index 0000000..e557113 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Auth.java @@ -0,0 +1,60 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import com.agynamix.platform.net.FatalNetworkException; + +public class Auth extends NodeCommand { + + final String groupname; + final String password; + + public Auth(String groupName, String password) + { + super(ICommands.AUTH); + this.groupname = groupName; + this.password = password; + } + + public Auth(byte[] buffer, int offset, int packetSize) + { + super(ICommands.AUTH); + String protocolVersion = decodeField(buffer, offset, 0); + if (!ICommands.PROTOCOL_VERSION.equals(protocolVersion)) + { + throw new FatalNetworkException("received protocol version is not compatible. Ours: " + +ICommands.PROTOCOL_VERSION+", received: "+protocolVersion); + } + groupname = decodeField(buffer, offset, 1); + password = decodeField(buffer, offset, 2); + } + + @Override + public byte[] toByteArray() + { + return toByteArray(encodeField(ICommands.PROTOCOL_VERSION), encodeField(groupname), encodeField(password)); + } + + public String getGroupname() + { + return groupname; + } + + public String getPassword() + { + return password; + } + + + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Data.java b/src/java/com/agynamix/platform/net/protocol/Data.java new file mode 100644 index 0000000..6c50ea6 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Data.java @@ -0,0 +1,52 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + + + +public class Data extends NodeCommand { + + final String filename; + final long length; + + public Data(String filename, long length) + { + super(ICommands.DATA); + this.filename = filename; + this.length = length; + } + + public Data(byte[] buffer, int offset, int packetSize) + { + super(ICommands.DATA); + filename = decodeField(buffer, offset, 0); + length = Long.parseLong(decodeField(buffer, offset, 1)); + } + + public String getFilename() + { + return filename; + } + + public long getFileSize() + { + return length; + } + + @Override + public byte[] toByteArray() + { + return toByteArray(encodeField(filename), encodeField(""+length)); + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Expt.java b/src/java/com/agynamix/platform/net/protocol/Expt.java new file mode 100644 index 0000000..54c5b9f --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Expt.java @@ -0,0 +1,34 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + + +public class Expt extends SerializedDataCommand { + + public Expt(Exception exception) + { + super(ICommands.EXPT, exception); + } + + public Expt(byte[] buffer, int offset, int packetSize) + { + super(ICommands.EXPT, buffer, offset, packetSize); + } + + public Exception getException() + { + return (Exception) getObject(); + } + + +} diff --git a/src/java/com/agynamix/platform/net/protocol/ICommands.java b/src/java/com/agynamix/platform/net/protocol/ICommands.java new file mode 100644 index 0000000..7fc4ffa --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/ICommands.java @@ -0,0 +1,89 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +public interface ICommands { + + String PROTOCOL_VERSION = "V1"; + + int COMMAND_SIZE = 4; + int PAYLOAD_COUNTER_SIZE = 4; // Do not change!!! + int PACKET_HEADER_SIZE = COMMAND_SIZE + PAYLOAD_COUNTER_SIZE; + + /** + * Versuche eine Authentifizierung am Server + */ + String AUTH = "AUTH"; + + /** + * Akzeptiere eine Verbindungsaufnahme + */ + String ACPT = "ACPT"; + + /** + * Lehne eine Verbindungsaufnahme ab. + */ + String REJT = "REJT"; + + /** + * Send an Exception that occured on one end to the connected peer. + */ + String EXPT = "EXPT"; + + /** + * OK + */ + String ACKN = "ACKN"; + + /** + * Beende Verbindung + */ + String QUIT = "QUIT"; + + /** + * Sende ein Objekt innerhalb eines benutzerspezifischen Paketes + */ + String OBJT = "OBJT"; + + /** + * Sende Daten innerhalb eines benutzerspezifischen Paketes + */ + String DATA = "DATA"; + + /** + * Invoke remote command + */ + String RCMD = "RCMD"; + + String REQ_SEND_CLIENT_LIST = "sendClientList"; + + String EMPTY_FIELD = ""; + + /** + * Wie sind Felder eines Kommandozeile getrennt. + */ + String FIELD_SEP = " "; + + String CMD_CHARSET = "ISO-8859-1"; + + public static final int BC_BUFFER_SIZE = 512; + + + + + + + + + +} diff --git a/src/java/com/agynamix/platform/net/protocol/NodeCommand.java b/src/java/com/agynamix/platform/net/protocol/NodeCommand.java new file mode 100644 index 0000000..c1ef146 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/NodeCommand.java @@ -0,0 +1,86 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import com.agynamix.platform.net.ConnectionUtils; +import com.agynamix.platform.net.NetUtils; + +public abstract class NodeCommand { + + public final String command; + + public NodeCommand(String command) + { + this.command = command; + } + + public String getCommand() + { + return command; + } + + /** + * + * @return the payload as a byte array suitable for transport over the wire. + */ + public byte[] toByteArray() + { + return null; + } + + protected byte[] toByteArray(String... fields) + { + return ConnectionUtils.toByteArray(fields); + } + + /** + * Creates a valid packet to send the command over the wire. + * It will write the command then it will write the size of the actual data to send and will + * then delegate to the sub class to write the actual payload. + * @return a valid packet to send over the wire. + */ + public byte[] toPacket() + { + int packetSize = 0; + byte[] payload = toByteArray(); + if (payload != null) + { + packetSize = payload.length; + } + byte[] buffer = new byte[packetSize + ICommands.PACKET_HEADER_SIZE]; + System.arraycopy(getCommand().getBytes(), 0, buffer, 0, ICommands.COMMAND_SIZE); + System.arraycopy(NetUtils.intToByteArray(packetSize), 0, buffer, ICommands.COMMAND_SIZE, ICommands.PAYLOAD_COUNTER_SIZE); + if (packetSize > 0) + { + System.arraycopy(toByteArray(), 0, buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } + return buffer; + } + + protected String decodeField(byte[] buffer, int offset, int pos) + { + return NetUtils.decodeField(buffer, offset, pos); + } + + protected String encodeField(String value) + { + return NetUtils.encodeField(value); + } + + protected String decodeField(String value) + { + return NetUtils.decodeField(value); + } + + +} diff --git a/src/java/com/agynamix/platform/net/protocol/NodeCommandFactory.java b/src/java/com/agynamix/platform/net/protocol/NodeCommandFactory.java new file mode 100644 index 0000000..d3e984e --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/NodeCommandFactory.java @@ -0,0 +1,80 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import com.agynamix.platform.net.FatalNetworkException; +import com.agynamix.platform.net.NetUtils; + +public class NodeCommandFactory { + + /** + * Takes apart the received string and creates a NodeCommand of it. + * @param buffer + * @return + */ + public static NodeCommand toProtocol(byte[] buffer) + { + NodeCommand command = null; + if (buffer != null) + { + String cmd = getCommand(buffer); + int packetSize = getPacketSize(buffer); + if (ICommands.AUTH.equals(cmd)) + { + command = new Auth(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else if (ICommands.ACPT.equals(cmd)) + { + command = new Acpt(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else if (ICommands.REJT.equals(cmd)) + { + command = new Rejt(); + } else if (ICommands.ACKN.equals(cmd)) + { + command = new Ackn(); + } else if (ICommands.QUIT.equals(cmd)) + { + command = new Quit(); + } else if (ICommands.OBJT.equals(cmd)) + { + command = new Objt(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else if (ICommands.DATA.equals(cmd)) + { + command = new Data(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else if (ICommands.RCMD.equals(cmd)) + { + command = new Rcmd(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else if (ICommands.EXPT.equals(cmd)) + { + command = new Expt(buffer, ICommands.PACKET_HEADER_SIZE, packetSize); + } else { + throw new FatalNetworkException("Unknown Command: "+cmd); + } + } + return command; + } + + private static int getPacketSize(byte[] buffer) + { + return NetUtils.byteArrayToInt(buffer, ICommands.COMMAND_SIZE); + } + + /** + * + * @return The command is always the first 4 bytes of a line + */ + public static String getCommand(byte[] buffer) + { + return new String(buffer, 0, ICommands.COMMAND_SIZE); + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/NodeCommandUtils.java b/src/java/com/agynamix/platform/net/protocol/NodeCommandUtils.java new file mode 100644 index 0000000..3bf4003 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/NodeCommandUtils.java @@ -0,0 +1,264 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.IConnector; +import com.agynamix.platform.net.IRemoteCommand; +import com.agynamix.platform.net.NetUtils; +import com.agynamix.platform.net.NetworkAuthException; +import com.agynamix.platform.net.NetworkProtocolException; + +/** + * FIXME: NodeCommandUtils should be given an instance per Handler, so that several threads + * should not have to wait on each other. + * @author tuhlmann + * + */ +public class NodeCommandUtils { + + final ConnectionCtx connectionCtx; + final IConnector connector; + + public NodeCommandUtils(IConnector connector, ConnectionCtx connectionCtx) + { + this.connectionCtx = connectionCtx; + this.connector = connector; + } + + public void sendQuit() throws IOException + { + Quit quit = new Quit(); + sendPacket(quit); + } + + public void sendAcpt(UUID nodeId) throws IOException + { + Acpt acpt = new Acpt(nodeId); + sendPacket(acpt); + } + + public void sendRejt() throws IOException + { + Rejt rejt = new Rejt(); + sendPacket(rejt); + } + + public void sendExpt(Exception exception) throws IOException + { + Expt expt = new Expt(exception); + sendPacket(expt); + } + + public void sendAckn() throws IOException + { + Ackn ackn = new Ackn(); + sendPacket(ackn); + } + + public void sendObjt(Object obj) throws IOException + { + Objt o = new Objt(obj); + sendPacket(o); + } + + public void sendData(File file) throws IOException + { + Data data = new Data(file.getAbsolutePath(), file.length()); + sendPacket(data); + } + + /** + * Invoke remote command + * @param command auszuführendes Kommando + * @return das Ergebnis der ausgeführten Funktion + * @throws IOException + * @throws NetworkProtocolException + */ + public Object invoke(IRemoteCommand command) throws IOException, NetworkProtocolException + { + Rcmd rcmd = new Rcmd(command); + sendPacket(rcmd); + return readObjt(); + } + + public void readAckn() throws NetworkProtocolException, IOException + { + NodeCommand command = receiveCommand(); + if (ICommands.ACKN.equals(command.getCommand())) + { +// System.out.println("read ACKN"); + } else { + System.out.println("did not read ACKN"); + throw new NetworkProtocolException("Peer did not reply with ACKN"); + } + } + + public Object readObjt() throws NetworkProtocolException, IOException + { + NodeCommand command = receiveCommand(); + if (ICommands.OBJT.equals(command.getCommand())) + { +// System.out.println("read OBJT"); + Objt objt = (Objt) command; + return objt.getObject(); + } else { +// System.out.println("did not read OBJT"); + throw new NetworkProtocolException("Peer did not reply on RCMD with OBJT"); + } + } + + public NodeCommand receiveCommand() throws IOException, NetworkProtocolException + { + return receiveCommand((String[]) null); + } + + public NodeCommand receiveCommand(String... recognizedCommands) throws IOException, NetworkProtocolException + { + return NodeCommandFactory.toProtocol(receivePacket(recognizedCommands)); + } + + /** + * Read a packet from the wire. + * @param inputStream + * @return + * @throws IOException + * @throws NetworkProtocolException + */ + public byte[] receivePacket() throws IOException, NetworkProtocolException + { + return receivePacket((String[]) null); + } + + + /** + * Read a packet from the wire. + * @param inputStream + * @return + * @throws IOException + * @throws NetworkProtocolException + */ + public byte[] receivePacket(String... recognizedCommands) throws IOException, NetworkProtocolException + { + byte[] payload = null; + byte[] header = readPacket(null, ICommands.PACKET_HEADER_SIZE); + String command = NodeCommandFactory.getCommand(header); + if (recognizedCommands != null) + { + if (!isRecognizedCommand(command, recognizedCommands)) + { + throw new NetworkProtocolException("Command not recognized at this point: "+command); + } + } + int packetSize = NetUtils.byteArrayToInt(header, 4); + if (packetSize > 0) + { + payload = readPacket(header, packetSize); + } + byte[] buffer = new byte[ICommands.PACKET_HEADER_SIZE+packetSize]; + System.arraycopy(header, 0, buffer, 0, header.length); + if (packetSize > 0) + { + System.arraycopy(payload, 0, buffer, header.length, payload.length); + } + +// System.out.println("received("+packetSize+"): "+new String(buffer)); + return buffer; + } + + private boolean isRecognizedCommand(String command, String[] recognizedCommands) + { + if (recognizedCommands != null) + { + for (String s : recognizedCommands) + { + if (s.equals(command)) + { + return true; + } + } + } + return false; + } + + /** + * Read a fixed amount of bytes from the input stream + * @param istream the input stream + * @param len the amount of bytes to read + * @return the byte buffer of read bytes. + * @throws IOException if we cannot read from the stream + */ + private byte[] readPacket(byte[] header, int len) throws IOException + { + byte[] buffer = new byte[len]; + int offset = 0; + int numRead = 0; + while (offset < buffer.length && (numRead = connectionCtx.getInputStream().read(buffer, offset, buffer.length-offset)) >=0 ) + { + offset += numRead; + } + if (offset < buffer.length) + { + String s = "Could not read specified number of bytes from the InputStream. Should read: "+len+", Actually read: "+offset; + if (header != null) + { + s += ", Header was: "+new String(header); + } else { + s += ", Try to read header."; + } +// throw new IOException(s); + System.out.println(s); + System.out.println("Simulate QUIT"); + Quit quit = new Quit(); // Simulate quit command and return this. + return quit.toPacket(); + } + return buffer; + } + + /** + * Send a protocol packet. The packet is pretty simple. It consists of + *
    + *
  • 4 Byte command sequence
  • + *
  • 4 Byte specifying the length of the packet (excluding the first 8 byte)
  • + *
  • data of the length defined by the 4 bytes before
  • + *
+ * a packet command handler will then interpret the received packet + * @param ostream + * @param command + * @throws IOException + */ + public void sendPacket(NodeCommand command) throws IOException + { + byte[] buffer = command.toPacket(); +// System.out.println("Send command: "+new String(buffer)); + connectionCtx.getOutputStream().write(buffer); + connectionCtx.getOutputStream().flush(); + } + + public void authenticate() throws IOException, NetworkAuthException, NetworkProtocolException + { + sendPacket(new Auth(connector.getGroupName(), connector.getGroupPassword())); + NodeCommand command = NodeCommandFactory.toProtocol(receivePacket()); + if (ICommands.ACPT.equals(command.getCommand())) + { +// System.out.println("Node authenticated: "+((Acpt)command).getNodeId()); + } else { + throw new NetworkAuthException("Could not authenticate with node at "+connectionCtx.getHostAddress()); + } + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Objt.java b/src/java/com/agynamix/platform/net/protocol/Objt.java new file mode 100644 index 0000000..a06459c --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Objt.java @@ -0,0 +1,33 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + + +public class Objt extends SerializedDataCommand { + + public Objt(Object object) + { + super(ICommands.OBJT, object); + } + + public Objt(byte[] buffer, int offset, int packetSize) + { + super(ICommands.OBJT, buffer, offset, packetSize); + } + + public Object getObject() + { + return this.object; + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Quit.java b/src/java/com/agynamix/platform/net/protocol/Quit.java new file mode 100644 index 0000000..4656bcd --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Quit.java @@ -0,0 +1,22 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +public class Quit extends NodeCommand { + + public Quit() + { + super(ICommands.QUIT); + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Rcmd.java b/src/java/com/agynamix/platform/net/protocol/Rcmd.java new file mode 100644 index 0000000..6955da5 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Rcmd.java @@ -0,0 +1,34 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import com.agynamix.platform.net.IRemoteCommand; + +public class Rcmd extends SerializedDataCommand { + + public Rcmd(IRemoteCommand command) + { + super(ICommands.RCMD, command); + } + + public Rcmd(byte[] buffer, int offset, int packetSize) + { + super(ICommands.RCMD, buffer, offset, packetSize); + } + + public IRemoteCommand getRemoteCommand() + { + return (IRemoteCommand) this.object; + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/Rejt.java b/src/java/com/agynamix/platform/net/protocol/Rejt.java new file mode 100644 index 0000000..00e48af --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/Rejt.java @@ -0,0 +1,22 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +public class Rejt extends NodeCommand { + + public Rejt() + { + super(ICommands.REJT); + } + +} diff --git a/src/java/com/agynamix/platform/net/protocol/SerializedDataCommand.java b/src/java/com/agynamix/platform/net/protocol/SerializedDataCommand.java new file mode 100644 index 0000000..0ef0023 --- /dev/null +++ b/src/java/com/agynamix/platform/net/protocol/SerializedDataCommand.java @@ -0,0 +1,79 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.platform.net.protocol; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import com.agynamix.platform.net.FatalNetworkException; + +public abstract class SerializedDataCommand extends NodeCommand { + + final Object object; + + public SerializedDataCommand(String command, Object object) + { + super(command); + this.object = object; + } + + public SerializedDataCommand(String command, byte[] buffer, int offset, int packetSize) + { + super(command); + try + { + if (packetSize > 0) + { + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer, offset, packetSize)); + object = ois.readObject(); + ois.close(); + } else { + object = null; + } + } catch (IOException e) + { + throw new FatalNetworkException(e); + } catch (ClassNotFoundException e) + { + throw new FatalNetworkException(e); + } + } + + @Override + public byte[] toByteArray() + { + try + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + if (object != null) + { + oos.writeObject(object); + } + oos.close(); + return bos.toByteArray(); + } catch (IOException e) + { + throw new FatalNetworkException(e); + } + } + + public Object getObject() + { + return this.object; + } + +} diff --git a/src/java/com/agynamix/simidude/ScrapbookPage.jpage b/src/java/com/agynamix/simidude/ScrapbookPage.jpage new file mode 100644 index 0000000..a085b9c --- /dev/null +++ b/src/java/com/agynamix/simidude/ScrapbookPage.jpage @@ -0,0 +1,3 @@ + java.net.InetAddress a = java.net.Inet4Address.getByName("192.168.1.0"); + +System.out.println(a) \ No newline at end of file diff --git a/src/java/com/agynamix/simidude/Simidude.java b/src/java/com/agynamix/simidude/Simidude.java new file mode 100644 index 0000000..7747895 --- /dev/null +++ b/src/java/com/agynamix/simidude/Simidude.java @@ -0,0 +1,335 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude; + +import java.io.IOException; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.frontend.gui.HotkeyRegistrarFactory; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.httpd.HTTPUtils; +import com.agynamix.platform.httpd.HttpServer; +import com.agynamix.platform.impl.QueueManagerImpl; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ExecutorUtils; +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.log.ConnectionLog; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.simidude.clipboard.AutomaticDownloadHandler; +import com.agynamix.simidude.clipboard.ClipboardItemFactory; +import com.agynamix.simidude.clipboard.ClipboardMonitorFactory; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.IClipboardMonitor; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.action.SimidudeHotkeyActions; +import com.agynamix.simidude.frontend.gui.SimidudeGUI; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.infra.IItemActivationListener; +import com.agynamix.simidude.infra.ISimidudePreferences; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.remote.RemoteConnector; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceDataListener; +import com.agynamix.simidude.source.SourceQueueService; +import com.agynamix.simidude.source.ISourceData.TransportType; +import com.agynamix.simidude.source.impl.SourceListener; +import com.install4j.api.launcher.ApplicationLauncher; +import com.install4j.api.update.UpdateSchedule; +import com.install4j.api.update.UpdateScheduleRegistry; + +public class Simidude extends ApplicationBase { + + SourceDataManager sourceDataManager; + IClipboardMonitor clipboardMonitor; + + Logger log = ApplicationLog.getLogger(Simidude.class); + + /** + * Generated by install4j. Needs to match the one from the installer. + */ + public final static String UPDATER_ID = "288"; + public final static String MANUAL_UPDATER_ID = "322"; + + /** + * Step one in setting up the application. No other components might be + * available. So this step only creates stuff. Initialization is deferred. + */ + @Override + protected void applicationSetup() + { + IQueueManager qm = new QueueManagerImpl(); + getContext().registerService(IQueueManager.SERVICE_NAME, qm); + + SourceQueueService sourceDispatcher = new SourceQueueService("SourceQueueListener"); + sourceDispatcher.initialize(); + + UUID senderId = getSenderId(); + ModelProvider m = new ModelProvider(senderId); + getContext().registerService(ModelProvider.SERVICE_NAME, m); + + clipboardMonitor = ClipboardMonitorFactory.newClipboardMonitor(); + sourceDataManager = new SourceDataManager(clipboardMonitor); + getContext().registerService(SourceDataManager.SERVICE_NAME, sourceDataManager); + + checkForUpdates(); + } + + private void checkForUpdates() + { + try + { + if (UpdateScheduleRegistry.getUpdateSchedule() == null) + { + UpdateScheduleRegistry.setUpdateSchedule(UpdateSchedule.ON_EVERY_START); + } + if (UpdateScheduleRegistry.checkAndReset()) + { + ApplicationLauncher.launchApplication(UPDATER_ID, null, false, new ApplicationLauncher.Callback() { + public void exited(int exitValue) { } + + public void prepareShutdown() + { + try + { + ApplicationGUI gui = ApplicationBase.getContext().getApplicationGUI(); + gui.close(); + } catch (Exception ignore) + { + } + } + }); + } + } catch (Exception ignore) { } + } + + private UUID getSenderId() + { + UUID senderId; + String senderIdStr = getContext().getConfiguration().getProperty(ISimidudePreferences.SENDER_ID); + if ((senderIdStr == null) || (senderIdStr.length() == 0)) + { + senderId = UUID.randomUUID(); + getContext().getConfiguration().setProperty(ISimidudePreferences.SENDER_ID, senderId.toString()); + } else + { + senderId = UUID.fromString(senderIdStr); + } + return senderId; + } + + /** + * Step Two in setting up the application. All referenced components should be + * available. + */ + @Override + protected void applicationInitialize() + { + SourceListener sourceListener = new SourceListener("ClipboardListener", clipboardMonitor); + sourceListener.initialize(); + SourceQueueService sourceQueueService = (SourceQueueService) ApplicationBase.getContext().getService(SourceQueueService.SERVICE_NAME); + sourceQueueService.addSourceDataListener(sourceDataManager); + + sourceQueueService.addSourceDataListener(new ISourceDataListener() { + + public void sourceDataChanged(ISourceData data) + { + conditionalSaveClipboardItem(data, true); + } + }); + + sourceDataManager.addItemActivationListener(new IItemActivationListener() { + public void itemActivated(IClipboardItem item) + { + if (item != null) + { + conditionalSaveClipboardItem(item.getSourceData(), false); + } + } + }); + + } + + private void conditionalSaveClipboardItem(ISourceData data, boolean onlyOwnItems) + { + if ((data != null) && (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.RESTORE_LATEST_ENTRY))) + { + ClientNode myOwnNode = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector().getConnector().getMyOwnNode(); + if (((data.getSenderId().equals(myOwnNode.getNodeId())) && (data.getTransportType() == TransportType.local)) || (!onlyOwnItems)) + { + FileUtils.serialize(data, PlatformUtils.getApplicationDataDir() + "/" + IPreferenceConstants.SAVED_CLP_ITEM_FILE_NAME); + } + } + } + + @Override + protected void startup() + { + } + + @Override + protected void shutdown() + { + RemoteConnector connector = ((SimidudeApplicationContext) getContext()).getRemoteConnector(); + connector.shutdown(); + HotkeyRegistrarFactory.getHotkeyRegistrarInstance().unregisterHotkeys(); + super.shutdown(); + } + + @Override + protected void prepareRun() + { + final ModelProvider m = (ModelProvider) getContext().getService(ModelProvider.SERVICE_NAME); + RemoteConnector connector = new RemoteConnector(); + connector.initializeConnector(m); + connector.establishConnection(); + ApplicationBase.getContext().registerService(RemoteConnector.SERVICE_NAME, connector); + connector.contactPermanentNetworkAddresses(); + + // Startup HTTPD + checkHTTPDStart(); + + // Check if we should load a saved Clipboard Item + checkRestoreClipboardItem(); + + // Register a HotKey listener + SimidudeHotkeyActions.registerHotkeys(); + + AutomaticDownloadHandler downloadHandler = + new AutomaticDownloadHandler(((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(), m.getSenderId()); + ApplicationBase.getContext().registerService(AutomaticDownloadHandler.SERVICE_NAME, downloadHandler); + + // Register a CacheCleaner Thread + ExecutorUtils.addScheduledService(CacheManagerFactory.newCacheCleaner(), 5, 3600, TimeUnit.SECONDS); + + // Register a ConnectionLog, an object that keeps track of sent data. Currently used for diagnostic purposes + initializeConnectionLog(); + + } + + private void checkHTTPDStart() { + if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.START_HTTP_SERVER)) + { + log.config("Try to start HTTP server."); + HttpServer nh = null; + Properties env = new Properties(); + env.setProperty(HTTPUtils.HTTP_PORT, ApplicationBase.getContext().getConfiguration().getProperty( + IPreferenceConstants.HTTP_SERVER_PORT)); + env.setProperty(HTTPUtils.HTTP_USER, ApplicationBase.getContext().getConfiguration().getProperty( + IPreferenceConstants.NODE_GROUP_NAME)); + env.setProperty(HTTPUtils.HTTP_PASSWORD, ApplicationBase.getContext().getConfiguration().getProperty( + IPreferenceConstants.NODE_GROUP_PWD)); + try + { + nh = new HttpServer(env); + log.config("Start HTTP server at port " + + ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.HTTP_SERVER_PORT)); + } catch (IOException ioe) + { + log.log(Level.WARNING, "Could not start HTTP server.", ioe); + } + } else + { + log.config("HTTP server is configured not to be started."); + } + } + + private void initializeConnectionLog() + { + ConnectionLog connectionLog = new ConnectionLog(); + SourceQueueService qs = (SourceQueueService) ApplicationBase.getContext().getService(SourceQueueService.SERVICE_NAME); + qs.addSourceDataListener(connectionLog); + ApplicationBase.getContext().registerService(ConnectionLog.SERVICE_NAME, connectionLog); + } + + private void checkRestoreClipboardItem() { + try + { + SourceDataManager sdm = ((SimidudeApplicationContext) ApplicationBase.getContext()).getSourceDataManager(); + // sdm.emptyClipboard(); + if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.RESTORE_LATEST_ENTRY)) + { + // System.out.println("Should restore latest entry"); + if (sdm.isClipboardMonitorEnabled()) + { + if (sdm.isClipboardEmpty()) + { + // System.out.println("Clipboard is empty"); + ISourceData sourceData = (ISourceData) FileUtils.deserialize(PlatformUtils.getApplicationDataDir() + "/" + + IPreferenceConstants.SAVED_CLP_ITEM_FILE_NAME); + if (sourceData != null) + { + IClipboardItem item = ClipboardItemFactory.createItemFromSourceData(sdm, sourceData); + ((SimidudeApplicationContext) ApplicationBase.getContext()).getQueueManager().put( + IQueueManager.QUEUE_SOURCE_DATA_MONITOR, sourceData); + // sdm.sourceDataChanged(sourceData); + sdm.activateItem(item); + } + } + } + } + } catch (Exception e) + { + log.log(Level.WARNING, "A saved clipboard contents file could not be restored.", e); + } + } + + + // FIXME: register RemoteConnector to ClipboardEvents, when event occurs + // check if we have just put this item on the clipboard: yes => nothing + // no: + // - Client: Send the item to the server + // - Server: Send a notification to the clients + + // FIXME: + // Server: Receives a new item from a client + // - put item into InputQueue + + // Client: Receives a notification from the server + // - NotificationFilter: only events that originated somewhere else + // + // - put item into InputQueue. !!!Item must be marked as received remotely, + // so that item will not be resent to the server!!! + + /** + * Creates an implementation of ApplicationGUI which implements this + * appplications specifics. An ApplicationGUI extends the JFace + * ApplicationWindow class and is the primary constructor of the visible part + * of the user interface. Called only once. + * + */ + @Override + protected ApplicationGUI createApplicationGUI() + { + return new SimidudeGUI(); + } + + /** + * Launch this application + * + * @param args + */ + public static void main(String[] args) + { + launch(Simidude.class, new SimidudeApplicationContext(), args); + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/AutomaticDownloadHandler.java b/src/java/com/agynamix/simidude/clipboard/AutomaticDownloadHandler.java new file mode 100644 index 0000000..db49161 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/AutomaticDownloadHandler.java @@ -0,0 +1,101 @@ +package com.agynamix.simidude.clipboard; + +import java.util.UUID; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.IItemAddedListener; +import com.agynamix.simidude.infra.ModelProvider; + +public class AutomaticDownloadHandler implements IItemAddedListener { + + final SourceDataManager sourceDataManager; + final UUID senderId; + + public static final String SERVICE_NAME = "AutomaticDownloadHandler"; + + public AutomaticDownloadHandler(SourceDataManager sourceDataManager, UUID mySenderId) + { + this.sourceDataManager = sourceDataManager; + this.senderId = mySenderId; + sourceDataManager.addItemAddedListener(this); + } + + /** + * A new item was added to the list of clipboard items. + * Check if we should acvtivate this item and/or automatically download + * contents if that's somewhere remote. + */ + public void itemAdded(int insertPos, IClipboardItem item) + { + boolean isActivateItem = shouldActivateItem(insertPos, item); + if (shouldDownloadContents(item)) + { + downloadContents(item, isActivateItem); + } else { + if (isActivateItem) + { + activateItem(item); + } + } + } + + private boolean shouldDownloadContents(IClipboardItem item) + { + if ((ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.AUTO_DOWNLOAD_CONTENTS)) + && (!senderId.equals(item.getSourceData().getSenderId()))) + { + if ((sourceDataManager.isRetrieveContentsNeeded(item)) && (!sourceDataManager.isDownloadInProgress(item.getSourceData()))) + { + return true; + } + } + return false; + } + + private boolean shouldActivateItem(int insertPos, IClipboardItem item) + { + if (ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.AUTO_ACTIVATE_NEW_ENTRY)) + { + if (insertPos == 0) + { + return true; + } + } + return false; + } + + /** + * TODO When the item is no longer available it should be removed from the item list. A message should be sent to the tray bar icon. + * This can only happen if the item is a file or directory. + * @param item + * @param isActivateItem + */ + private void downloadContents(final IClipboardItem item, final boolean isActivateItem) + { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.retrieveContentsForProxyObject(item.getSourceData(), new Runnable() { + + public void run() + { + if (isActivateItem) + { + activateItem(item); + } + } + }); + } + + private void activateItem(final IClipboardItem item) + { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + sourceDataManager.activateItem(item); + } + }); + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardItemFactory.java b/src/java/com/agynamix/simidude/clipboard/ClipboardItemFactory.java new file mode 100644 index 0000000..f0cddf8 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardItemFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + + +public class ClipboardItemFactory { + + public static IClipboardItem createItemFromSourceData(SourceDataManager sourceDataManager, ISourceData data) + { + IClipboardItem item = null; + switch (data.getType()) + { + case TEXT: + item = new TextClipboardItem((TextSourceData) data); + break; + case FILE: + item = new FileClipboardItem(sourceDataManager, (FileSourceData) data); + break; + case IMAGE: + item = new ImageClipboardItem(sourceDataManager, (ImageSourceData) data); + break; + } + return item; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorBase.java b/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorBase.java new file mode 100644 index 0000000..bb1946c --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorBase.java @@ -0,0 +1,158 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import java.util.Map; + +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.graphics.ImageData; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataFactory; +import com.agynamix.simidude.source.ISourceData.SourceType; + +public abstract class ClipboardMonitorBase implements IClipboardMonitor { + + public final static int DEFAULT_SLEEP_TIME = 200; + + ModelProvider modelProvider = null; + + boolean itemActivated = false; + + ISourceData[] sourceDataInTransit = null; + + ISourceData activatedSourceData = null; + + public void itemActivated(ISourceData sourceData) + { +// System.out.println("Item activated"); + activatedSourceData = sourceData; + itemActivated = true; + } + + protected ModelProvider getModelprovider() + { + if (modelProvider == null) + { + modelProvider = (ModelProvider) ApplicationBase.getContext().getService(ModelProvider.SERVICE_NAME); + } + return modelProvider; + } + + public int getSleepTime() + { + return DEFAULT_SLEEP_TIME; + } + + protected synchronized ISourceData[] saveProcessClipboard(final Clipboard clipboard, final Map clpItemsEnabledMap) + { + synchronized (clipboard) + { + PlatformUtils.safeSyncRunnable(new Runnable() { + public void run() + { + sourceDataInTransit = saveProcessClipboard2(clipboard, clpItemsEnabledMap); + } + }); + } + return sourceDataInTransit; + } + + /** + * Take an item from the clipboard. + * We first check if it's available as file, if not then we check if we can get it as text. + * @param clipboard the system clipboard + * @return the ClipboardItem + */ + protected ISourceData[] saveProcessClipboard2(Clipboard clipboard, final Map clpItemsEnabledMap) + { +// int count = 0; +// boolean successful = false; + + ISourceData[] sourceDataList = null; + Transfer fileTransfer = FileTransfer.getInstance(); + Transfer textTransfer = TextTransfer.getInstance(); + Transfer imageTransfer = ImageTransfer.getInstance(); + + TransferData fileTransferData = null; + TransferData textTransferData = null; + TransferData imageTransferData = null; + + TransferData[] availableTypes = clipboard.getAvailableTypes(); + for (TransferData td : availableTypes) + { + if (fileTransfer.isSupportedType(td)) + { + fileTransferData = td; +// System.out.println("Supports FileTransfer "); + } else if (textTransfer.isSupportedType(td)) + { + textTransferData = td; +// System.out.println("Supports TextTransfer "); + } else if (imageTransfer.isSupportedType(td)) + { + imageTransferData = td; +// System.out.println("Supports ImageTransfer "); + } + } + if ((fileTransferData != null) && (isItemTypeEnabled(SourceType.FILE, clpItemsEnabledMap))) + { + String[] fnames = (String[]) clipboard.getContents(fileTransfer); + if ((fnames != null) && (fnames.length > 0)) + { + sourceDataList = new ISourceData[fnames.length]; + for (int i = 0; i < fnames.length; i++) + { + sourceDataList[i] = SourceDataFactory.createFromFile(fnames[i]); + } + } + } else if ((textTransferData != null) && (isItemTypeEnabled(SourceType.TEXT, clpItemsEnabledMap))) + { + String text = (String) clipboard.getContents(textTransfer); + if (text != null) + { + sourceDataList = new ISourceData[1]; + sourceDataList[0] = SourceDataFactory.createFromText(text); + } + } else if ((imageTransferData != null) && (isItemTypeEnabled(SourceType.IMAGE, clpItemsEnabledMap))) + { + ImageData imageData = (ImageData) clipboard.getContents(imageTransfer); + if (imageData != null) + { + sourceDataList = new ISourceData[1]; + sourceDataList[0] = SourceDataFactory.createFromImage(imageData); + } + } + return sourceDataList; + } + + private boolean isItemTypeEnabled(SourceType sourceType, Map clpItemsEnabledMap) + { + Boolean re = clpItemsEnabledMap.get(sourceType); + if (re == null) + { + throw new IllegalStateException("Unknown Item type: "+sourceType); + } + return re; + } + + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorFactory.java b/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorFactory.java new file mode 100644 index 0000000..9fe77c1 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardMonitorFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import com.agynamix.platform.infra.PlatformUtils; + +public class ClipboardMonitorFactory { + + /** + * Factory method to create a platform specific clipboard monitor instance. + * @return + */ + public static IClipboardMonitor newClipboardMonitor() + { + IClipboardMonitor clipboardMonitor = null; + switch (PlatformUtils.getOsName()) + { + case win32: + case win64: + clipboardMonitor = new PollingClipboardMonitor(); +// clipboardMonitor = new WindowsClipboardMonitor(); + break; + case linux_x86: + case linux_x86_64: + clipboardMonitor = new PollingClipboardMonitor(); + break; + case macosx: + case macosx64: + clipboardMonitor = new PollingClipboardMonitor(); + break; + case solaris_x86: + clipboardMonitor = new PollingClipboardMonitor(); + break; + default: + // FIXME: This should open a Bugzscout dialog so that we know about unexpected platforms. + throw new IllegalStateException("Unknown operating system or architecture: os.name="+System.getProperty("os.name")+", os.arch="+System.getProperty("os.arch")); + } + return clipboardMonitor; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardTable.java b/src/java/com/agynamix/simidude/clipboard/ClipboardTable.java new file mode 100644 index 0000000..cdc5b53 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardTable.java @@ -0,0 +1,550 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.window.ToolTip; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import com.agynamix.platform.frontend.dialogs.SimpleInformationViewerDialog; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.PlatformColors; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.log.ClipboardItemDebugInfo; +import com.agynamix.simidude.frontend.gui.ClipboardTableDragSource; +import com.agynamix.simidude.frontend.gui.ClipboardTableDropTarget; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.IModelChangeListener; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.infra.SimidudeUtils; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; +import com.agynamix.simidude.source.impl.TextSourceData.TextType; + +/** + * Wraps the view part for the clipboard table + * + * @author tuhlmann + * + */ +public class ClipboardTable { + + public final static int NAME_COL = 0; + + public final static int columnCount = 1; + + final SourceDataManager sourceDataManager; + final TableViewer tableViewer; + + TableViewerColumn itemColumn; + Composite tableParent; + + private final static int KEY_BACKSPACE = 8; + + boolean dragInProgress = false; + + public ClipboardTable(SourceDataManager sourceDataMan, Composite parent, int style) + { + this.sourceDataManager = sourceDataMan; + + tableViewer = createTableViewer(parent); + sourceDataManager.addModelChangeListener(new IModelChangeListener() { + public void modelChanged(Object oldValue, Object newValue) + { + tableViewer.getTable().getDisplay().syncExec(new Runnable(){ + public void run() + { + tableViewer.setInput(sourceDataManager.getClipboardItems()); + if (tableViewer.getTable().getItemCount() > 0) + { + tableViewer.getTable().setSelection(-1); + tableViewer.getTable().showItem(tableViewer.getTable().getItem(0)); + } +// adjustTableSize(); + } + }); + } + }); + + // hook drag support + new ClipboardTableDragSource(this, sourceDataManager); + new ClipboardTableDropTarget(this, sourceDataManager); + } + + public void addSelectionChangeListener(ISelectionChangedListener l) + { + tableViewer.addSelectionChangedListener(l); + } + + public void removeSelectionChangeListener(ISelectionChangedListener l) + { + tableViewer.removeSelectionChangedListener(l); + } + + private TableViewer createTableViewer(final Composite parent) + { + tableParent = parent; + final TableViewer tableViewer = new TableViewer(tableParent, SWT.SINGLE | SWT.FULL_SELECTION | SWT.HIDE_SELECTION | + SWT.FLAT | SWT.BORDER | SWT.V_SCROLL); + + tableViewer.getTable().setLinesVisible(true); + tableViewer.getTable().setHeaderVisible(false); + + ColumnViewerToolTipSupport.enableFor(tableViewer, ToolTip.NO_RECREATE); + + final OptimizedIndexSearcher searcher = new OptimizedIndexSearcher(); + + itemColumn = new TableViewerColumn(tableViewer, SWT.LEFT, NAME_COL); + itemColumn.getColumn().setText("Item"); + itemColumn.setLabelProvider(new ColumnLabelProvider() { + boolean even = true; + Color oddColor = null; + + @Override + public String getText(Object element) + { + String text = ""; + IClipboardItem item = (IClipboardItem) element; + text = item.getShortDescription(); + return text; + } + + @Override + /** + * Display an icon depending of the type of clipboard entry. + */ + public Image getImage(Object element) + { + return ((IClipboardItem)element).getImage(); + } + + public Color getBackground(Object element) + { + if (even) + { + return null; + } else + { + if (oddColor == null) + { + oddColor = PlatformColors.get(PlatformColors.TRANSFER_TABLE_ALT_COLOR); + } + return oddColor; + } + } + + public String getToolTipText(Object element) { + IClipboardItem item = (IClipboardItem) element; + return item.getTooltip(); + } + + public Point getToolTipShift(Object object) { + return new Point(5, 5); + } + + public int getToolTipDisplayDelayTime(Object object) { + return 200; + } + + public int getToolTipTimeDisplayed(Object object) { + return 10000; + } + + public void update(ViewerCell cell) + { + even = searcher.isEven((TableItem) cell.getItem()); + super.update(cell); + } + }); + + tableViewer.setContentProvider(new ClipboardTableContentProvider()); +// tableViewer.setLabelProvider(new ClipboardTableLabelProvider()); + + tableParent.addControlListener(new ControlAdapter() { + public void controlResized(ControlEvent e) { + adjustTableSize(); + } + }); + + tableViewer.getTable().setMenu(createPopupMenu(tableViewer)); + hookListeners(tableViewer); + + return tableViewer; + } + + public Table getTable() + { + return tableViewer.getTable(); + } + + public TableViewer getTableViewer() + { + return tableViewer; + } + + public boolean isDragInProgress() + { + return this.dragInProgress; + } + + public void setDragInProgress(boolean dragInProgress) + { + this.dragInProgress = dragInProgress; + } + + public void adjustTableSize() + { + Rectangle area = tableParent.getClientArea(); + final Table table = tableViewer.getTable(); + Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT); + int width = area.width - 2*table.getBorderWidth(); + if (preferredSize.y > area.height + table.getHeaderHeight()) { + // Subtract the scrollbar width from the total column width + // if a vertical scrollbar will be required + Point vBarSize = table.getVerticalBar().getSize(); + width -= vBarSize.x; + } + Point oldSize = table.getSize(); + if (oldSize.x > area.width) { + // table is getting smaller so make the columns + // smaller first and then resize the table to + // match the client area width + itemColumn.getColumn().setWidth(width-10); + table.setSize(area.width, area.height); + } else { + // table is getting bigger so make the table + // bigger first and then make the columns wider + // to match the client area width + table.setSize(area.width, area.height); + itemColumn.getColumn().setWidth(width-10); + } + } + + private Menu createPopupMenu(final TableViewer tableViewer) + { + final Menu pop = new Menu(tableViewer.getTable().getShell(), SWT.POP_UP); + final MenuItem activateItem = new MenuItem(pop, SWT.PUSH); + activateItem.setText("Copy Item to Clipboard"); + activateItem.setImage(PlatformIcons.get(PlatformIcons.ACTIVATE_TABLE_ENTRY)); + activateItem.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + IClipboardItem item = (IClipboardItem) selection[0].getData(); +// System.out.println("Selected: "+ti[0].getText()+", Index: "+tableViewer.getTable().getSelectionIndex()); + sourceDataManager.activateItem(item); + } + } + } + }); + + new MenuItem(pop, SWT.SEPARATOR); + + + final MenuItem openWithItem = new MenuItem(pop, SWT.PUSH); + openWithItem.setText("Open With Standard Application"); + openWithItem.setImage(PlatformIcons.get(PlatformIcons.OPEN_TABLE_ENTRY)); + openWithItem.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + IClipboardItem item = (IClipboardItem) selection[0].getData(); + openSelectedEntry(item); + } + } + } + }); + + final MenuItem downloadContentsItem = new MenuItem(pop, SWT.PUSH); + downloadContentsItem.setText("Download Contents"); + downloadContentsItem.setImage(PlatformIcons.get(PlatformIcons.DOWNLOAD_CONTENTS_TABLE_ENTRY)); + downloadContentsItem.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + IClipboardItem item = (IClipboardItem) selection[0].getData(); + if ((sourceDataManager.isRetrieveContentsNeeded(item)) && (!sourceDataManager.isDownloadInProgress(item.getSourceData()))) + { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.retrieveContentsForProxyObject(item.getSourceData()); + } + } + } + } + }); + + final MenuItem saveEntryAsItem = new MenuItem(pop, SWT.PUSH); + saveEntryAsItem.setText("Save As..."); + saveEntryAsItem.setImage(PlatformIcons.get(PlatformIcons.SAVE_CONTENTS_AS_TABLE_ENTRY)); + saveEntryAsItem.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + final IClipboardItem item = (IClipboardItem) selection[0].getData(); + if (item != null) + { + sourceDataManager.saveClipboardItemAs(item, false); + } + } + } + } + }); + + final MenuItem saveEntryAsCompressedItem = new MenuItem(pop, SWT.PUSH); + saveEntryAsCompressedItem.setText("Save Compressed..."); + saveEntryAsCompressedItem.setImage(PlatformIcons.get(PlatformIcons.SAVE_CONTENTS_AS_TABLE_ENTRY)); + saveEntryAsCompressedItem.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + final IClipboardItem item = (IClipboardItem) selection[0].getData(); + if (item != null) + { + sourceDataManager.saveClipboardItemAs(item, true); + } + } + } + } + }); + + new MenuItem(pop, SWT.SEPARATOR); + final MenuItem removeSelectedEntry = new MenuItem(pop, SWT.PUSH); + removeSelectedEntry.setText("Remove Selected Item"); + removeSelectedEntry.setImage(PlatformIcons.get(PlatformIcons.REMOVE_SELECTED_CLIPBOARD_ENTRY)); + removeSelectedEntry.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + IClipboardItem item = (IClipboardItem) selection[0].getData(); + sourceDataManager.removeItem(item); + } + } + } + }); + + new MenuItem(pop, SWT.SEPARATOR); + final MenuItem debugSelectedEntry = new MenuItem(pop, SWT.PUSH); + debugSelectedEntry.setText("Output Debug Info for Entry"); + debugSelectedEntry.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + if (e.getSource() instanceof MenuItem) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + IClipboardItem item = (IClipboardItem) selection[0].getData(); + SimpleInformationViewerDialog d = new SimpleInformationViewerDialog(tableParent.getShell(), "Clipboard Entry Debug Info", + "Output debug information for this clipboard entry that helps diagnosing potential problems.", new ClipboardItemDebugInfo(item).toString()); + d.open(); + } + } + } + }); + + pop.addListener(SWT.Show, new Listener() { + public void handleEvent(Event event) + { + downloadContentsItem.setEnabled(false); + activateItem.setEnabled(false); + int idx = tableViewer.getTable().getSelectionIndex(); + if (idx > -1) + { + IClipboardItem item = sourceDataManager.getClipboardItem(idx); + if ((sourceDataManager.isRetrieveContentsNeeded(item)) && (!sourceDataManager.isDownloadInProgress(item.getSourceData()))) + { + // Prüfen, ob für dieses Item ein Download in Progress ist. Nur falls nicht auf true setzen. + downloadContentsItem.setEnabled(true); + } + activateItem.setEnabled(true); + } + } + }); + + return pop; + } + + private void hookListeners(final TableViewer tableViewer) + { +// tableViewer.addDoubleClickListener(new IDoubleClickListener(){ +// public void doubleClick(DoubleClickEvent event) +// { +// TableItem[] tableItems = tableViewer.getTable().getSelection(); +// if ((tableItems != null) && (tableItems.length > 0)) +// { +// IClipboardItem item = (IClipboardItem) tableItems[0].getData(); +// sourceDataManager.activateItem(item); +// } +// } +// }); + + tableViewer.addDoubleClickListener(new IDoubleClickListener(){ + public void doubleClick(DoubleClickEvent event) + { + if (event.getSelection() instanceof StructuredSelection) + { + StructuredSelection sel = (StructuredSelection) event.getSelection(); + IClipboardItem item = (IClipboardItem) sel.getFirstElement(); + if (SimidudeUtils.isModifierKeyPressed()) + { + sourceDataManager.activateItem(item); + } else { + openSelectedEntry(item); + } + } + } + }); + + tableViewer.getTable().addKeyListener(new KeyAdapter(){ + @Override + public void keyPressed(KeyEvent e) + { + if ((e.keyCode == SWT.DEL) || (e.keyCode == KEY_BACKSPACE)) + { + TableItem[] selection = tableViewer.getTable().getSelection(); + if ((selection != null) && (selection.length > 0)) + { + int currentSelectionIndex = sourceDataManager.getSelectionIndex(); + IClipboardItem item = (IClipboardItem) selection[0].getData(); + boolean isNetworkRemove = SimidudeUtils.isModifierKeyPressed(); + sourceDataManager.removeItem(item); + if ((isNetworkRemove) && (item != null)) + { + ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider().networkRemoveItem(item.getSourceData().getStub()); + } + if (e.keyCode == KEY_BACKSPACE) + { + sourceDataManager.selectPreviousEntry(currentSelectionIndex); + } else { + sourceDataManager.saveSelectEntry(currentSelectionIndex); + } + } + } + } + }); + } + + protected void openSelectedEntry(IClipboardItem item) + { + ISourceData sourceData = item.getSourceData(); + if (sourceData.getType() == SourceType.FILE) + { + final FileSourceData fsd = (FileSourceData) sourceData; + if (!sourceDataManager.isDownloadInProgress(fsd)) + { + if ((sourceDataManager.isRetrieveContentsNeeded(item))) + { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.retrieveContentsForProxyObject(item.getSourceData(), new Runnable() { + public void run() + { + PlatformUtils.safeAsyncRunnable(new Runnable(){ + public void run() + { + SimidudeUtils.launchDefaultFileBowser(fsd); + } + }); + } + }); + } else { + SimidudeUtils.launchDefaultFileBowser(fsd); + } + } + } else if (sourceData.getType() == SourceType.TEXT) + { + TextSourceData tsd = (TextSourceData) sourceData; + if (tsd.getTextType() == TextType.URI) + { + SimidudeUtils.launchURI(tsd); + } else { + try + { + File f = FileUtils.writeTextToTempFile(tsd); + SimidudeUtils.launchDefaultTextEditor(f); + } catch (IOException e) + { + PlatformUtils.showErrorMessageWithException("Error Opening Clipboard Text", "The clipboard text could not be written to a temporary file: "+e.getMessage(), e); + } + } + } else if (sourceData.getType() == SourceType.IMAGE) + { + ImageSourceData isd = (ImageSourceData) sourceData; + try + { + File f = FileUtils.writeImageToTempFile(isd); + SimidudeUtils.launchDefaultImageEditor(f); + } catch (IOException e) + { + PlatformUtils.showErrorMessageWithException("Error Opening Clipboard Image", "The clipboard image could not be written to a temporary file: "+e.getMessage(), e); + } + } + } + +} + diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardTableContentProvider.java b/src/java/com/agynamix/simidude/clipboard/ClipboardTableContentProvider.java new file mode 100644 index 0000000..5475c1f --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardTableContentProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import java.util.List; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; + + +public class ClipboardTableContentProvider implements IStructuredContentProvider { + + + + public void dispose() + { + } + + public void inputChanged(Viewer arg0, Object arg1, Object arg2) + { + } + + @SuppressWarnings("unchecked") + public Object[] getElements(Object items) + { + List l = (List) items; + return l.toArray(); + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardTableLabelProvider.java b/src/java/com/agynamix/simidude/clipboard/ClipboardTableLabelProvider.java new file mode 100644 index 0000000..40a6f2f --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardTableLabelProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.swt.graphics.Image; + + +public class ClipboardTableLabelProvider implements ITableLabelProvider { + + List listeners = new ArrayList(); + + public ClipboardTableLabelProvider() + { + } + + public Image getColumnImage(Object arg0, int arg1) + { + return null; + } + + public String getColumnText(Object element, int columnIndex) + { + String text = ""; + IClipboardItem item = (IClipboardItem) element; + switch (columnIndex) + { + case ClipboardTable.NAME_COL: + text = item.getDescription(); + break; + } + return text; + } + + public void addListener(ILabelProviderListener listener) + { + listeners.add(listener); + } + + public void removeListener(ILabelProviderListener arg0) + { + listeners.remove(listeners); + } + + public boolean isLabelProperty(Object arg0, String arg1) + { + return false; + } + + public void dispose() + { + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardTableListener.java b/src/java/com/agynamix/simidude/clipboard/ClipboardTableListener.java new file mode 100644 index 0000000..5ea3295 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardTableListener.java @@ -0,0 +1,74 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +public class ClipboardTableListener implements Listener { + + final Table itsTable; + + public ClipboardTableListener(Table table) + { + this.itsTable = table; + } + + /* + * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly. Therefore, it is critical for performance that + * these methods be as efficient as possible. + */ + public void handleEvent(Event event) + { + switch (event.type) + { + case SWT.MeasureItem: { + TableItem item = (TableItem) event.item; + String text = getText(item, event.index); + Point size = event.gc.textExtent(text); + event.width = size.x; +// event.height = Math.max(event.height, size.y); + event.height = 40; + break; + } + case SWT.PaintItem: { + TableItem item = (TableItem) event.item; + String text = getText(item, event.index); + Point size = event.gc.textExtent(text); + int offset2 = event.index == 0 ? Math.max(0, (event.height - size.y) / 2) : 0; + event.gc.drawText(text, event.x, event.y + offset2, true); + break; + } + case SWT.EraseItem: { + event.detail &= ~SWT.FOREGROUND; + break; + } + } + } + + String getText(TableItem item, int column) + { + String text = item.getText(column); + if ((text != null) && (text.length() > 100)) + { + text = text.substring(0, 100)+"..."; + } + return text; + } +} + + diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardTableSearchBox.java b/src/java/com/agynamix/simidude/clipboard/ClipboardTableSearchBox.java new file mode 100644 index 0000000..f09a2be --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardTableSearchBox.java @@ -0,0 +1,114 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Text; + +import com.agynamix.platform.icons.PlatformIcons; + +public class ClipboardTableSearchBox { + + final SourceDataManager sourceDataManager; + + public ClipboardTableSearchBox(SourceDataManager sourceDataManager) + { + this.sourceDataManager = sourceDataManager; + } + + public Control createControl(Composite parent) + { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + composite.setLayout(layout); + + final Text searchBox = new Text(composite, SWT.SEARCH | SWT.CANCEL); + GridData data = new GridData(); +// data.widthHint = 250; + searchBox.setLayoutData(data); + + if ((searchBox.getStyle() & SWT.CANCEL) == 0) + { + Button searchBtn = new Button(composite, SWT.PUSH); + searchBtn.setImage(PlatformIcons.get(PlatformIcons.SEARCH)); + searchBtn.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + String text = searchBox.getText(); + if ((text != null) && (text.length() > 0)) + { + sourceDataManager.filterClipboardItems(text); + } + } + }); + + Button cancelBtn = new Button(composite, SWT.PUSH); + cancelBtn.setImage(PlatformIcons.get(PlatformIcons.TRASH)); + cancelBtn.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + searchBox.setText(""); + sourceDataManager.filterClipboardItems(null); + } + }); + } + searchBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + searchBox.addSelectionListener(new SelectionAdapter() { + public void widgetDefaultSelected(SelectionEvent e) + { + if (e.detail == SWT.CANCEL) + { + sourceDataManager.filterClipboardItems(null); + } else + { + sourceDataManager.filterClipboardItems(searchBox.getText()); + } + } + }); + searchBox.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) + { + if (e.character == SWT.ESC) + { + searchBox.setText(""); + sourceDataManager.filterClipboardItems(null); + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (e.character != SWT.ESC) + { + String s = searchBox.getText(); + sourceDataManager.filterClipboardItems(s); + } + } + }); + + return composite; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ClipboardViewerFilter.java b/src/java/com/agynamix/simidude/clipboard/ClipboardViewerFilter.java new file mode 100644 index 0000000..32bc659 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ClipboardViewerFilter.java @@ -0,0 +1,51 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; + +public class ClipboardViewerFilter extends ViewerFilter { + + final String searchStr; + + public ClipboardViewerFilter(String searchStr) + { + this.searchStr = searchStr.toLowerCase(); + } + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) + { + IClipboardItem item = (IClipboardItem) element; + String desc = item.getDescription(); + if (desc != null) + { + return (desc.toLowerCase().indexOf(searchStr) > -1); + } else { + return true; + } + } + + public String getSearchString() + { + return searchStr; + } + + @Override + public String toString() + { + return getSearchString(); + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/FileClipboardItem.java b/src/java/com/agynamix/simidude/clipboard/FileClipboardItem.java new file mode 100644 index 0000000..cbc13ab --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/FileClipboardItem.java @@ -0,0 +1,152 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.widgets.Display; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.FileSourceData; + +public class FileClipboardItem implements IClipboardItem { + + final FileSourceData sourceData; + final transient SourceDataManager sourceDataManager; + transient Image thumbnail = null; + transient Image downloadNeededThumbnail = null; + + public FileClipboardItem(SourceDataManager sourceDataManager, FileSourceData sourceData) + { + this.sourceDataManager = sourceDataManager; + this.sourceData = sourceData; + } + + public String getDescription() + { + return sourceData.getFilename(); + } + + public String getShortDescription() + { + return sourceData.getFilename(); + } + + public Image getImage() + { + boolean isDownloadContent = sourceDataManager.isRetrieveContentsNeeded(this); + if (sourceData.isImage()) + { + ImageRegistry imReg = ApplicationBase.getContext().getImageRegistry(); + if (isDownloadContent) + { + if (downloadNeededThumbnail == null) + { + if (sourceData != null) + { + ImageData imageData = sourceData.getThumbnail(); + if (imageData != null) + { + Image img = imReg.get(sourceData.getSourceId().toString()+"-download-needed"); + if (img == null) + { + img = new Image(Display.getDefault(), imageData); + downloadNeededThumbnail = new Image(Display.getDefault(), img, SWT.IMAGE_GRAY); + img.dispose(); + imReg.put(sourceData.getSourceId().toString()+"-download-needed", downloadNeededThumbnail); + } else { + downloadNeededThumbnail = img; + } + } + } + } + return downloadNeededThumbnail; + } else { + if (thumbnail == null) + { + if (sourceData != null) + { + ImageData imageData = sourceData.getThumbnail(); + if (imageData != null) + { + thumbnail = imReg.get(sourceData.getSourceId().toString()); + if (thumbnail == null) + { + thumbnail = new Image(Display.getDefault(), imageData); + imReg.put(sourceData.getSourceId().toString(), thumbnail); + } + } + } + } + return thumbnail; + } + } + if (isDirectory()) + { + if (isDownloadContent) + { + return PlatformIcons.get(PlatformIcons.COLIMG_DOWNLOAD_NEEDED_FOLDER); + } else { + return PlatformIcons.get(PlatformIcons.COLIMG_FOLDER); + } + } else { + if (isDownloadContent) + { + return PlatformIcons.get(PlatformIcons.COLIMG_DOWNLOAD_NEEDED_FILE); + } else { + return PlatformIcons.get(PlatformIcons.COLIMG_FILE); + } + } + } + + public String getTooltip() + { + return sourceData.getFilename(); + } + + public SourceType getType() + { + return sourceData.getType(); + } + + public boolean isDirectory() + { + return sourceData.isDirectory(); + } + + public ISourceData getSourceData() + { + return sourceData; + } + + public Object getData() + { + return sourceData.getFilename(); + } + + public IClipboardItem deleteContents() + { + sourceData.deleteContents(); + ImageRegistry imReg = ApplicationBase.getContext().getImageRegistry(); + imReg.remove(sourceData.getSourceId().toString()); + imReg.remove(sourceData.getSourceId().toString()+"-download-needed"); + return this; + } + +} + diff --git a/src/java/com/agynamix/simidude/clipboard/IClipboardItem.java b/src/java/com/agynamix/simidude/clipboard/IClipboardItem.java new file mode 100644 index 0000000..b83b2cb --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/IClipboardItem.java @@ -0,0 +1,70 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import org.eclipse.swt.graphics.Image; + +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; + + +public interface IClipboardItem { + + /** + * + * @return the type of this item. Could be text, image, binary, ... + */ + SourceType getType(); + + /** + * + * @return an description for the current item that is shown in the list of available clipboard items + */ + String getDescription(); + + /** + * + * @return a short description shown in the clipboard table. Linux shows all of the text + * which messes up the table. + */ + String getShortDescription(); + + /** + * + * @return returns the text shown as a tooltip when hovering over the item. + */ + String getTooltip(); + + /** + * Returns an image for the current item. + * @return + */ + Image getImage(); + + /** + * The IClipboardItem is really just a wrapper around the original source data. + * It augments the source data with the visual aspects of presenting the source. + * @return the ISourceData instance that this IClipboardItem wraps. + */ + ISourceData getSourceData(); + + Object getData(); + + /** + * Strip the item off its contents. + * All items are remembered, even when they have been deleted from the list. To safe memory (images + * can take a lot of space) we can strip the item from its contents. + * @return a reference to this item. + */ + IClipboardItem deleteContents(); + +} diff --git a/src/java/com/agynamix/simidude/clipboard/IClipboardMonitor.java b/src/java/com/agynamix/simidude/clipboard/IClipboardMonitor.java new file mode 100644 index 0000000..a2b060f --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/IClipboardMonitor.java @@ -0,0 +1,61 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import com.agynamix.simidude.source.ISource; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; + +/** + * Interfaces whose implementers monitor the system clipboard and inform about changes. + * @author tuhlmann + * + */ +public interface IClipboardMonitor extends ISource { + + /** + * Called when the system itself put something on the clipboard. We don't want these items + * to reoccur. + */ + void itemActivated(ISourceData sourceData); + + /** + * Enable or disable the monitoring of the clipboard + * @param enable true- monitoring will be enabled, false- monitoring will be disabled. + */ + void setClipboardMonitorEnabled(boolean enable); + + /** + * Enable or disable the monitoring of specific item types in the clipboard + * @param enable true- monitoring of the selected type will be enabled, false- monitoring will be disabled. + */ + void setClipboardMonitorTypeEnabled(SourceType sourceType, boolean enable); + + /** + * + * @return true if the monitoring of the clipboard is enabled, false otherwise. + */ + boolean isClipboardMonitorEnabled(); + + /** + * Checks to see if the clipboard currently is empty. + * @return true if the clipboard is empty, false otherwise. + */ + boolean isClipboardEmpty(); + + /** + * Remove the current contents from the clipboard. + */ + void emptyClipboard(); + + +} diff --git a/src/java/com/agynamix/simidude/clipboard/ImageClipboardItem.java b/src/java/com/agynamix/simidude/clipboard/ImageClipboardItem.java new file mode 100644 index 0000000..006cd34 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/ImageClipboardItem.java @@ -0,0 +1,128 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.widgets.Display; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.ImageSourceData; + +public class ImageClipboardItem implements IClipboardItem { + + final ImageSourceData sourceData; + final transient SourceDataManager sourceDataManager; + transient Image cachedThumbnail = null; + String tooltip = null; + + public ImageClipboardItem(SourceDataManager sourceDataManager, ImageSourceData sourceData) + { + this.sourceData = sourceData; + this.sourceDataManager = sourceDataManager; + } + + public String getDescription() + { + return sourceData.getText(); + } + + public Image getImage() + { + if (cachedThumbnail == null) + { + cachedThumbnail = createThumbnail(sourceData); + } + return cachedThumbnail; + } + + public String getShortDescription() + { + return sourceData.getText(); + } + + public ISourceData getSourceData() + { + return sourceData; + } + + public String getTooltip() + { + if (tooltip == null) + { + tooltip = createTooltip(sourceData); + } + return tooltip; + } + + public SourceType getType() + { + return sourceData.getType(); + } + + public Object getData() + { + return sourceData.getImageData(); + } + + private Image createThumbnail(ImageSourceData sourceData) + { + Image img = null; + if (sourceData != null) + { + ImageRegistry imReg = ApplicationBase.getContext().getImageRegistry(); + img = imReg.get(sourceData.getSourceId().toString()); + if (img == null) + { + img = new Image(Display.getDefault(), sourceData.getThumbnail()); + imReg.put(sourceData.getSourceId().toString(), img); + } + } + if (img == null) + { + img = PlatformIcons.get(PlatformIcons.COLIMG_IMAGE_UNDEF); + } + return img; + } + + private String createTooltip(ImageSourceData sourceData) + { + ImageData id = sourceData.getImageData(); + StringBuilder sb = new StringBuilder(); + sb.append("Clipboard Image:\n\n"); + sb.append("Width: ").append(id.width).append("\n"); + sb.append("Height: ").append(id.height).append("\n"); + sb.append("Size: ").append(id.data.length).append(" Bytes\n"); + + + return sb.toString(); + } + + public IClipboardItem deleteContents() + { + sourceData.deleteContents(); + if (cachedThumbnail != null) + { + cachedThumbnail = null; + ImageRegistry imReg = ApplicationBase.getContext().getImageRegistry(); + imReg.remove(sourceData.getSourceId().toString()); + } + tooltip = ""; + return this; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/OptimizedIndexSearcher.java b/src/java/com/agynamix/simidude/clipboard/OptimizedIndexSearcher.java new file mode 100644 index 0000000..6e67b8c --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/OptimizedIndexSearcher.java @@ -0,0 +1,58 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.swt.widgets.TableItem; + +public class OptimizedIndexSearcher { + + private int lastIndex = 0; + + public boolean isEven(TableItem item) + { + TableItem[] items = item.getParent().getItems(); + + // 1. Search the next ten items + for (int i = lastIndex; i < items.length && lastIndex + 10 > i; i++) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + // 2. Search the previous ten items + for (int i = lastIndex; i < items.length && lastIndex - 10 > i; i--) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + // 3. Start from the beginning + for (int i = 0; i < items.length; i++) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + return false; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/PollingClipboardMonitor.java b/src/java/com/agynamix/simidude/clipboard/PollingClipboardMonitor.java new file mode 100644 index 0000000..213b487 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/PollingClipboardMonitor.java @@ -0,0 +1,198 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TransferData; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; + +public class PollingClipboardMonitor extends ClipboardMonitorBase { + + public final static int POLLING_SLEEP_TIME = 2000; + + Clipboard clipboard; + ISourceData[] currentSourceData = null; + ISourceData[] currentCompareSourceData = null; + boolean newDataAvailable = false; + boolean clipboardMonitorEnabled = true; + + Map clpItemtypesEnabledMap = new Hashtable(); + + public PollingClipboardMonitor() + { + clpItemtypesEnabledMap.put(SourceType.TEXT, true); + clpItemtypesEnabledMap.put(SourceType.IMAGE, true); + clpItemtypesEnabledMap.put(SourceType.FILE, true); + } + + public boolean isClipboardMonitorEnabled() + { + return clipboardMonitorEnabled; + } + + public void setClipboardMonitorEnabled(boolean enable) + { + this.clipboardMonitorEnabled = enable; + } + + public void setClipboardMonitorTypeEnabled(SourceType sourceType, boolean enable) + { + clpItemtypesEnabledMap.put(sourceType, enable); +// System.out.println("SET "+sourceType+" to "+clpItemtypesEnabledMap.get(sourceType)+" with Map size "+clpItemtypesEnabledMap.size()); + } + + public boolean isClipboardEmpty() + { + Clipboard clipboard = getClipboard(); + TransferData[] td = clipboard.getAvailableTypes(); + if ((td == null) || (td.length == 0)) + { + return true; + } + return false; + } + + public void emptyClipboard() + { + getClipboard().clearContents(); + } + + public ISourceData[] getData() + { + if (newDataAvailable) + { + newDataAvailable = false; + return currentSourceData; + } + return null; + } + + /** + * Check the current data. Algorithmus: - itemActivated wird gesetzt, wenn im ClipboardTable ein Eintrag aktiviert, + * also ins Clipboard geschrieben wird. - Hier muss so lange gewartet werden, bis dieser aktivierte Eintrag wieder im + * Clipboard erscheint, erst dann darf activateItem wieder zurueckgesetzt werden. + */ + public boolean isDataAvailable() + { + if (!clipboardMonitorEnabled) + { + return false; + } + newDataAvailable = false; + ISourceData[] sourceData = saveProcessClipboard(getClipboard(), clpItemtypesEnabledMap); + if ((sourceData != null) && (sourceData.length > 0) && (sourceData[0] != null)) // at least one entry + { + if (currentSourceData == null) + { + currentSourceData = sourceData; + currentCompareSourceData = createEqualsCopy(sourceData); + if (!itemActivated) // should never happen anyway + { + newDataAvailable = true; + } + } else + { + if (currentSourceData.length != sourceData.length) + { + currentSourceData = sourceData; + currentCompareSourceData = createEqualsCopy(sourceData); + if (!itemActivated) + { + newDataAvailable = true; + } + } else + { + if ((sourceData.length > 0) && (currentCompareSourceData.length > 0)) + { + if (!sourceData[0].getType().equals(currentCompareSourceData[0].getType())) + { + currentSourceData = sourceData; + currentCompareSourceData = createEqualsCopy(sourceData); + if (!itemActivated) + { + newDataAvailable = true; + } + } else + { + if (!sourceData[0].equals(currentCompareSourceData[0])) + { + currentSourceData = sourceData; + currentCompareSourceData = createEqualsCopy(sourceData); + if (!itemActivated) + { +// System.out.println("New SourceData available"); + newDataAvailable = true; + } + } + } + } + } + } + // Check if we have read our own activated item again + if ((itemActivated) && (activatedSourceData != null)) + { + String activatedTxt = activatedSourceData.getText(); + String sourceDataTxt = sourceData[0].getText(); + if ((activatedTxt != null) && (sourceDataTxt != null)) + { + if (activatedTxt.equals(sourceDataTxt)) + { +// System.out.println("Reset itemActivated to false"); + itemActivated = false; + activatedSourceData = null; + } + } + } + } + return newDataAvailable; + } + + @Override + public int getSleepTime() + { + return POLLING_SLEEP_TIME; + } + + private Clipboard getClipboard() + { + if (clipboard == null) + { + clipboard = ApplicationBase.getContext().getClipboard(); + } + return clipboard; + } + + protected ISourceData[] createEqualsCopy(ISourceData[] sourceData) + { + if (sourceData != null) + { + ISourceData[] copied = new ISourceData[sourceData.length]; + for (int i = 0; i < sourceData.length; i++) + { + copied[i] = sourceData[i].equalsCopy(); + } + return copied; + } else { + return null; + } + } + + +} diff --git a/src/java/com/agynamix/simidude/clipboard/SourceDataContentsLoader.java b/src/java/com/agynamix/simidude/clipboard/SourceDataContentsLoader.java new file mode 100644 index 0000000..f5e8fd4 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/SourceDataContentsLoader.java @@ -0,0 +1,175 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.agynamix.simidude.remote.ContentsLoaderException; +import com.agynamix.simidude.source.SourceDataContents; +import com.agynamix.simidude.source.impl.FileSourceData; + +public class SourceDataContentsLoader { + + private static final int BYTE_CHUNK_SIZE = 51200; + + final FileSourceData sourceData; + final File itsFileRoot; + final List fileList; + + int currentFileListIndex = 0; + InputStream currentFileInputStream = null; + long currentFileBytesRead = 0; + long currentFileSize = 0; + + boolean lastPackageSent = false; + + public SourceDataContentsLoader(FileSourceData sourceData) + { + this.sourceData = sourceData; + itsFileRoot = new File(sourceData.getFilename()); + if (!itsFileRoot.exists()) + { + // FIXME: We need robust error handling throughout the application. + throw new IllegalStateException("File " + itsFileRoot.getAbsolutePath() + " does not exist but should."); + } + fileList = listFiles(itsFileRoot); +// System.out.println("File list:"); +// for (File f : fileList) +// { +// System.out.println(f.getAbsolutePath()); +// } + } + + /** + * Load the contents of this proxy object into memory. + * + * @return + * @throws IOException + */ + public SourceDataContents loadContents() + { + SourceDataContents contents = null; + if (lastPackageSent) + { + return null; + } + if (currentFileListIndex >= fileList.size()) + { + contents = new SourceDataContents(sourceData.getSourceId(), true); + lastPackageSent = true; + } else + { + File currentFile = fileList.get(currentFileListIndex); + if (currentFile.isDirectory()) + { + contents = new SourceDataContents(sourceData.getSourceId(), currentFile.getAbsolutePath()); + currentFileListIndex++; + } else + { + contents = loadFileContents(currentFile); + if ((contents.isEndOfFile()) || (contents.isAborted())) + { + currentFileListIndex++; + } + } + } + return contents; + } + + /** + * Load the contents of a file. + * + * @throws ContentsLoaderException + * + */ + private SourceDataContents loadFileContents(File file) + { + SourceDataContents contents = null; + try { + byte[] bytes = new byte[BYTE_CHUNK_SIZE]; // our transport buffer + if (currentFileInputStream == null) + { + currentFileInputStream = new BufferedInputStream(new FileInputStream(file)); + currentFileSize = file.length(); + currentFileBytesRead = 0; + } + byte[] buffer = bytes; + int bytesRead = 0; + if (currentFileSize > 0) + { + bytesRead = currentFileInputStream.read(bytes); + // System.out.println("Read "+bytesRead+" bytes"); + if (bytesRead > -1) + { + if (bytesRead < BYTE_CHUNK_SIZE) + { + buffer = new byte[bytesRead]; + System.arraycopy(bytes, 0, buffer, 0, bytesRead); + } + currentFileBytesRead += bytesRead; + } else + { + System.out.println("Read EOF of " + file.getAbsolutePath()); + buffer = new byte[0]; + } + } else { + buffer = new byte[0]; + } + contents = new SourceDataContents(sourceData.getSourceId(), file.getAbsolutePath(), buffer); + if ((currentFileBytesRead >= currentFileSize) || (bytesRead < 0)) + { + currentFileInputStream.close(); + currentFileInputStream = null; + contents.setEndOfFile(true); + } + return contents; + } catch (IOException e) + { + //throw new ContentsLoaderException(file, e); + contents = new SourceDataContents(sourceData.getSourceId(), file.getAbsolutePath()); + contents.setEndOfFile(true); + contents.setAborted(new ContentsLoaderException(file, e)); + } + return contents; + } + + /** + * Creates a flat list of all entries of this file/directory. If fileRoot is just a file the list contains only one + * entry, otherwise it will contain the flattened down content of the recursive file structure denoted by fileRoot + * + * @param fileRoot + * the root entry to check; + * @return a List of all file/directory entries starting with the file root. + */ + private List listFiles(File fileRoot) + { + List allFilesList = new ArrayList(); + allFilesList.add(fileRoot); + if (fileRoot.isDirectory()) + { + File[] includedFiles = fileRoot.listFiles(); + for (File f : includedFiles) + { + allFilesList.addAll(listFiles(f)); + } + } + return allFilesList; + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/SourceDataManager.java b/src/java/com/agynamix/simidude/clipboard/SourceDataManager.java new file mode 100644 index 0000000..598f6cd --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/SourceDataManager.java @@ -0,0 +1,886 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.DateUtils; +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.IConfiguration; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.infra.Tupel; +import com.agynamix.platform.infra.ZipUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.simidude.frontend.ctrl.SourceDataDialogController; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.IItemActivationListener; +import com.agynamix.simidude.infra.IItemAddedListener; +import com.agynamix.simidude.infra.IModelChangeListener; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceDataListener; +import com.agynamix.simidude.source.SourceDataContents; +import com.agynamix.simidude.source.SourceDataStub; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + +/** + * Our access to clipboard items + * + * @author tuhlmann + * + */ +public class SourceDataManager implements ISourceDataListener { + + public static final String SERVICE_NAME = "SourceDataManager"; + + Logger log = ApplicationLog.getLogger(SourceDataManager.class); + + final IClipboardMonitor clipboardMonitor; + + List clipboardItems = new CopyOnWriteArrayList(); + + /** + * Those items that have been removed from the table. + */ + List removedClipboardItems = new CopyOnWriteArrayList(); + + List downloadsInProgress = new CopyOnWriteArrayList(); + + List modelChangeListeners = new CopyOnWriteArrayList(); + List itemActivationListeners = new CopyOnWriteArrayList(); + List itemAddedListeners = new CopyOnWriteArrayList(); + + Clipboard clipboard; + + ClipboardViewerFilter currentViewerFilter = null; + + private SourceDataDialogController sourceDataDialogController; + + public SourceDataManager(IClipboardMonitor clipboardMonitor) + { + this.clipboardMonitor = clipboardMonitor; + } + + public void addModelChangeListener(IModelChangeListener listener) + { + this.modelChangeListeners.add(listener); + } + + public void removeModelChangeListener(IModelChangeListener listener) + { + this.modelChangeListeners.remove(listener); + } + + public void addItemActivationListener(IItemActivationListener listener) + { + this.itemActivationListeners.add(listener); + } + + public void removeItemActivationListener(IItemActivationListener listener) + { + this.itemActivationListeners.remove(listener); + } + + public void addItemAddedListener(IItemAddedListener listener) + { + this.itemAddedListeners.add(listener); + } + + public void removeItemAddedListener(IItemAddedListener listener) + { + this.itemAddedListeners.remove(listener); + } + + /** + * Add a listener that gets notified when the selection in the Clipboard Entry window changes. + * @param l the listener + */ + public void addSelectionChangedListener(ISelectionChangedListener l) + { + sourceDataDialogController.addSelectionChangedListener(l); + } + + public void removeSelectionChangedListener(ISelectionChangedListener l) + { + sourceDataDialogController.removeSelectionChangedListener(l); + } + + public List getClipboardItems() + { + return Collections.unmodifiableList(clipboardItems); + } + + public synchronized void sourceDataChanged(ISourceData data) + { +// System.out.println("Receive "+data.getTransportType()+" ("+data.getType()+") change for "+data.getSourceId()+": "+data.getText()); + Tupel itemFound = containsItem(getClipboardItems(), data); +// System.out.println("Contains Item "+itemFound.getValue2()+" at pos "+itemFound.getValue1()); + int idx = itemFound.getValue1(); + boolean shouldReplace = itemFound.getValue2(); + if ((idx > -1) && (shouldReplace)) + { +// System.out.println("Remove entry ("+idx+") "+data.getText()); + // move the found entry to the top of the list + clipboardItems.remove(idx); + } + if (shouldReplace) + { +// System.out.println("Insert At "+idx+": "+data.getText()); + List old = getClipboardItems(); + final Tupel newItem = addItemTimeDesc(clipboardItems, data); + if (idx < 0) + { + fireNewItemAdded(newItem.getValue1(), newItem.getValue2()); + } + fireDataChanged(old, getClipboardItems()); + } + } + + /** + * Add the new item to the clipboard item list considering the items time stamp. + * So new items would appear on the top of the list while items synchronized + * from other peers would appear in their appropriate positions. + * @param clipboardItems the list of clipboard items we maintain + * @param data the new arrived ISourceData entry. + */ + private synchronized Tupel addItemTimeDesc(List clipboardItems, ISourceData data) + { + Date dataStamp = data.getCreationDate(); + IClipboardItem clipItem = ClipboardItemFactory.createItemFromSourceData(this, data); +// String clipStr = clipItem.getDescription(); + boolean inserted = false; + int insertPos = 0; + if (clipboardItems.size() > 0) + { + for (int i = 0; i < clipboardItems.size(); i++) + { + IClipboardItem item = clipboardItems.get(i); + Date itemStamp = item.getSourceData().getCreationDate(); + String itemStr = item.getDescription(); +// System.out.println(itemStr+"("+DateUtils.date2string("HH:mm:ss SSS", dataStamp)+") vs "+itemStr+"("+DateUtils.date2string("HH:mm:ss SSS", itemStamp)+")"); + if (dataStamp.getTime() >= itemStamp.getTime()) + { +// System.out.println("Inserting AT POS "+i+": "+data.getSourceId()); + inserted = true; + insertPos = i; + clipboardItems.add(insertPos, clipItem); + break; + } + } + } + if (!inserted) + { + clipboardItems.add(clipItem); +// clipboardItems.add(insertPos, clipItem); +// System.out.println("Inserting ITEM "+data.getSourceId()); + } + return new Tupel(insertPos, clipItem); + } + + private Tupel containsItem(List clipboardItems, ISourceData sourceData) + { + for (int i = 0; i < clipboardItems.size(); i++) + { + IClipboardItem item = clipboardItems.get(i); + if (item.getSourceData().getSourceId().equals(sourceData.getSourceId())) + { + return new Tupel(i, true); + } + if (item.getSourceData().equals(sourceData)) + { + // we keep the newest item + if (item.getSourceData().getCreationDate().getTime() < sourceData.getCreationDate().getTime()) + { + return new Tupel(i, true); + } else { + return new Tupel(i, false); + } + } + } + return new Tupel(-1, true); + } + +// /** +// * Insert a new clipboard item at index 0. +// * @param item new clipboard item +// */ +// public void add(IClipboardItem item) +// { +// List old = getClipboardItems(); +// clipboardItems.add(0, item); +// fireDataChanged(old, getClipboardItems()); +// } + + public synchronized void activateItem(int selectionIndex) + { + if (clipboardItems.size() > selectionIndex) + { + activateItem(clipboardItems.get(selectionIndex)); + } + } + + public IClipboardItem getSelectedItem() + { + ClipboardTable clipboardTable = getSourceDataDialogController().getClipboardTable(); + TableItem[] tableItems = clipboardTable.getTable().getSelection(); + if ((tableItems != null) && (tableItems.length > 0)) + { + return (IClipboardItem) tableItems[0].getData(); + } + return null; + } + + public int getSelectionIndex() + { + ClipboardTable clipboardTable = getSourceDataDialogController().getClipboardTable(); + return clipboardTable.getTable().getSelectionIndex(); + } + + /** + * Activate the selected entry + */ + public void activateItem() + { + IClipboardItem item = getSelectedItem(); + if (item != null) + { + activateItem(item); + } + } + + public void activateItem(IClipboardItem item) + { + ISourceData sourceData = item.getSourceData(); + + try { + clipboardMonitor.itemActivated(sourceData); + + TextTransfer textTransfer = TextTransfer.getInstance(); + FileTransfer fileTransfer = FileTransfer.getInstance(); + ImageTransfer imageTransfer = ImageTransfer.getInstance(); + Object[] contents = null; + Transfer[] transferTypes = null; + switch (item.getType()) + { + case FILE: + FileSourceData fsd = (FileSourceData) item.getSourceData(); + String[] fnames = new String[] {fsd.getLocalFilename()}; + if (isRetrieveContentsNeeded(item)) + { + contents = new Object[] {item.getDescription()}; + transferTypes = new Transfer[] {textTransfer}; + } else { + contents = new Object[] {fnames, item.getDescription()}; + transferTypes = new Transfer[] {fileTransfer, textTransfer}; + } + break; + case TEXT: + contents = new Object[] { item.getDescription() }; + transferTypes = new Transfer[] { textTransfer }; + break; + case IMAGE: + contents = new Object[] { ((ImageSourceData)item.getSourceData()).getImageData() }; + transferTypes = new Transfer[] { imageTransfer }; + break; + } + getClipboard().setContents(contents, transferTypes); + fireDataActivated(item); + } catch (Throwable t) { + log.log(Level.SEVERE, "Error activating item of type "+sourceData.getType()+": "+sourceData.getText(), t); + } + } + + public IClipboardItem removeSelectedEntry() + { + // Get selection index. + ClipboardTable clipboardTable = getSourceDataDialogController().getClipboardTable(); + TableItem[] tableItems = clipboardTable.getTable().getSelection(); + if ((tableItems != null) && (tableItems.length > 0)) + { + IClipboardItem item = (IClipboardItem) tableItems[0].getData(); + return removeItem(item); + } + return null; + } + + public IClipboardItem removeItem(IClipboardItem item) + { + if (item != null) + { + List old = getClipboardItems(); + if (clipboardItems.remove(item)) + { + removedClipboardItems.add(item.deleteContents()); + fireDataChanged(old, getClipboardItems()); + } + } + return item; + } + + public IClipboardItem removeAndDontRemember(SourceDataStub stub) + { + IClipboardItem item = null; + if (stub != null) { + item = getClipboardItem(stub); + if (item != null) + { + List old = getClipboardItems(); + if (clipboardItems.remove(item)) + { + fireDataChanged(old, getClipboardItems()); + } + } + } + return item; + } + + public void removeAll() + { + List old = getClipboardItems(); + if (old.size() > 0) + { + for (IClipboardItem item : old) + { + removedClipboardItems.add(item.deleteContents()); + } + clipboardItems.clear(); + fireDataChanged(old, getClipboardItems()); + } + } + + public void contentsReceived(List failedDownloads) + { + fireDataChanged(getClipboardItems(), getClipboardItems()); + if (!failedDownloads.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (SourceDataContents c : failedDownloads) { + sb.append("File failed: "+c.getName()); + if (c.getException() != null) { + sb.append(": "+getTopLevelException(c.getException()).getMessage()+"\n"); + } + } + sb.append("\n"); + PlatformUtils.showWarningMessage("Download Error", "Not all files could be downloaded successfully.", sb.toString()); + } + } + + private Throwable getTopLevelException(Throwable t) + { + return (t.getCause() != null) ? getTopLevelException(t.getCause()) : t; + } + + private void fireDataChanged(Object oldValue, Object newValue) + { + for (IModelChangeListener listener : modelChangeListeners) + { + listener.modelChanged(oldValue, newValue); + } + } + + private void fireDataActivated(IClipboardItem item) + { + for (IItemActivationListener listener : itemActivationListeners) + { + listener.itemActivated(item); + } + } + + private void fireNewItemAdded(int insertPos, IClipboardItem item) + { + for (IItemAddedListener listener : itemAddedListeners) + { + listener.itemAdded(insertPos, item); + } + } + + private Clipboard getClipboard() + { + if (clipboard == null) + { + clipboard = ApplicationBase.getContext().getClipboard(); + } + return clipboard; + } + + public void setClipboardMonitorEnabled(boolean enable) + { + clipboardMonitor.setClipboardMonitorEnabled(enable); + } + + public boolean isClipboardMonitorEnabled() + { + return clipboardMonitor.isClipboardMonitorEnabled(); + } + + public void setClipboardMonitorTypeEnabled(SourceType sourceType, boolean enable) + { + clipboardMonitor.setClipboardMonitorTypeEnabled(sourceType, enable); + } + + + public boolean isClipboardEmpty() + { + return clipboardMonitor.isClipboardEmpty(); + } + + public void emptyClipboard() + { + clipboardMonitor.emptyClipboard(); + } + + public List getSourceDataStubEntries() + { + List stubList = new ArrayList(); + for (IClipboardItem item : clipboardItems) + { + stubList.add(item.getSourceData().getStub()); + } + return stubList; + } + + public List getRemovedSourceDataStubEntries() + { + List stubList = new ArrayList(); + for (IClipboardItem item : removedClipboardItems) + { + stubList.add(item.getSourceData().getStub()); + } + return stubList; + } + + /** + * Find the clipboard item for this stub + * @param stub a stub instance describeing this clipboard item. + * @return the found clipboard item or null if it can't be found. + */ + public IClipboardItem getClipboardItem(SourceDataStub stub) + { + for (IClipboardItem item : clipboardItems) + { + if (item.getSourceData().getStub().equals(stub)) + { + return item; + } + } + + // Not found here, maybe it was deleted recently + for (IClipboardItem item : removedClipboardItems) + { + if (item.getSourceData().getStub().equals(stub)) + { + return item; + } + } + + // Nothing found + return null; + } + + /** + * Get the latest clipboard item from this machine. + * @return an IClipboardItem instance or null if none was found. + */ + public IClipboardItem getNewestClipboardItem() + { + ClientNode myOwnNode = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector().getConnector().getMyOwnNode(); + return getNewestClipboardItem(myOwnNode); + } + + /** + * Get the latest clipboard item from the machine denoted by this ClientNode. + * @return an IClipboardItem instance or null if none was found. + */ + public IClipboardItem getNewestClipboardItem(ClientNode clientNode) + { + for (IClipboardItem item : getClipboardItems()) + { + if (item.getSourceData().getSenderId().equals(clientNode.getNodeId())) + { + return item; + } + } + return null; + } + + + + public IClipboardItem getClipboardItem(int selectionIndex) + { + if (clipboardItems.size() > selectionIndex) + { + return clipboardItems.get(selectionIndex); + } else { + return null; + } + } + + /** + * Checks if the current item needs to retrieve contents from a remote peer if the user wants + * to drag the file or directory that this item represents. + * @param item the current checked ICLipboardItem + * @return true if we need to retrieve contents prior to a drag, false otherwise. + */ + public boolean isRetrieveContentsNeeded(IClipboardItem item) + { + if (item == null) + { + return false; + } + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + ISourceData sourceData = item.getSourceData(); + if (sourceData.getSenderId().equals(mp.getSenderId())) // local data + { + return false; + } + if (sourceData.getType() == SourceType.FILE) + { + FileSourceData fsd = (FileSourceData) sourceData; + if (!fsd.isCached()) + { + return true; + } + } + return false; + } + + /** + * Tell the SourceDataManager that a download is in progress + * @param sourceData download for this item is in progress + * @param isInProgress true if download is in progress, false if download has finished + */ + public void setDownloadInProgress(ISourceData sourceData, boolean isInProgress) + { + if (isInProgress) + { + downloadsInProgress.add(sourceData); + } else { + downloadsInProgress.remove(sourceData); + } + } + + public boolean isDownloadInProgress(ISourceData sourceData) + { + return downloadsInProgress.contains(sourceData); + } + + public void setSourceDataDialogController(SourceDataDialogController sourceDataController) + { + this.sourceDataDialogController = sourceDataController; + } + + public SourceDataDialogController getSourceDataDialogController() + { + return this.sourceDataDialogController; + } + + public void filterClipboardItems(String searchStr) + { + TableViewer tv = getSourceDataDialogController().getClipboardTable().getTableViewer(); + if (searchStr == null) + { + if (currentViewerFilter != null) + { + tv.removeFilter(currentViewerFilter); + currentViewerFilter = null; + } + return; + } + + if (currentViewerFilter != null) + { + if (currentViewerFilter.getSearchString().equals(searchStr)) + { + return; + } + tv.removeFilter(currentViewerFilter); + } + currentViewerFilter = new ClipboardViewerFilter(searchStr); + tv.addFilter(currentViewerFilter); + } + + public void saveClipboardItemAs(final IClipboardItem item, final boolean compress) + { + final Shell shell = sourceDataDialogController.getClipboardTable().getTable().getShell(); + String path; + IConfiguration config = ApplicationBase.getContext().getConfiguration(); + String entryExtension = FileUtils.DEFAULT_TEXT_FILE_EXTENSION; + + if (item.getType() == SourceType.FILE) + { + FileSourceData fsd = (FileSourceData) item.getSourceData(); + if (fsd.isDirectory()) + { + DirectoryDialog dialog = new DirectoryDialog(shell, SWT.SHEET); + String lastTimeDir = config.getProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_DIR_PATH); + dialog.setFilterPath(lastTimeDir); + String saveTo = dialog.open(); + if (saveTo != null) + { + config.setProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_DIR_PATH, saveTo); + saveTo = saveTo + File.separator + fsd.getFile().getName(); + if (compress) + { + saveTo += FileUtils.DEFAULT_ZIP_EXTENSION; + } + File f = new File(saveTo); + if (f.exists()) + { + if (PlatformUtils.showOverwriteFilesDialog(f)) + { + path = saveTo; + } else { + path = null; + } + } else { + path = saveTo; + } + } else { + path = null; + } + } else { + FileDialog dialog = new FileDialog(shell, SWT.SAVE | SWT.SHEET); + String suggestion = fsd.getFile().getName(); + if (compress) + { + suggestion += FileUtils.DEFAULT_ZIP_EXTENSION; + } + dialog.setFilterPath(config.getProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_FILE_PATH)); + dialog.setFileName(suggestion); + dialog.setOverwrite(true); + path = dialog.open(); + if (path != null) + { + config.setProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_FILE_PATH, new File(path).getParent()); + } + } + // Either Clipboard Text or Image + } else { + String suggestedName = ""; + String[] suggestedExtensions = null; + if (item.getType() == SourceType.TEXT) + { + suggestedName = "ClipboardText"; + if (PlatformUtils.isMacOs()) + { + if (compress) + { + suggestedName += FileUtils.DEFAULT_ZIP_EXTENSION; + } else { + suggestedName += FileUtils.DEFAULT_TEXT_FILE_EXTENSION; + } + } + suggestedExtensions = FileUtils.getTextFileExtensions(compress); + } else if (item.getType() == SourceType.IMAGE) + { + suggestedName = "ClipboardImage"; + if (PlatformUtils.isMacOs()) + { + if (compress) + { + suggestedName += FileUtils.DEFAULT_ZIP_EXTENSION; + } else { + suggestedName += FileUtils.DEFAULT_IMAGE_FILE_EXTENSION; + } + } + suggestedExtensions = FileUtils.getImageFileExtensions(); + entryExtension = FileUtils.DEFAULT_IMAGE_FILE_EXTENSION; + } + FileDialog dialog = new FileDialog(shell, SWT.SAVE | SWT.SHEET); + dialog.setFilterPath(config.getProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_FILE_PATH)); + dialog.setFileName(suggestedName); + dialog.setFilterExtensions(suggestedExtensions); + dialog.setOverwrite(true); + String saveTo = dialog.open(); + if (saveTo != null) + { +// String choosenExtension = suggestedExtensions[dialog.getFilterIndex()]; +// System.out.println(choosenExtension); +// System.out.println(saveTo); + path = saveTo; + config.setProperty(IPreferenceConstants.CLIPBOARDTABLE_LAST_SAVED_FILE_PATH, new File(path).getParent()); + } else { + path = null; + } + } + if (path != null) + { + String entryName = path; + if (compress) + { + entryName = FileUtils.replaceLastExtension(new File(path).getName(), entryExtension); + } + final String entryName2 = entryName; + final String path2 = path; + if ((isRetrieveContentsNeeded(item)) && (!isDownloadInProgress(item.getSourceData()))) + { + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + mp.retrieveContentsForProxyObject(item.getSourceData(), new Runnable(){ + public void run() + { + saveAs(path2, entryName2, item.getSourceData(), compress); + } + }); + } else { + saveAs(path2, entryName2, item.getSourceData(), compress); + } + } + } + + /** + * Save SourceData item to the given location. If the destination already exists, the user has already been + * asked if he wishes to overwrite. If we are here, we know the user clicked yes so we do overwrite existing files + * and directories. + * @param path the destination path. + * @param sourceData the ISourceData entry that should be saved. + */ + public void saveAs(final String path, String entryName, ISourceData sourceData, final boolean compress) + { + final File dest = new File(path); + switch (sourceData.getType()) + { + case FILE: + final FileSourceData fsd = (FileSourceData) sourceData; + final File src = new File(fsd.getLocalFilename()); + final IProgressMonitor pm = ApplicationBase.getContext().getApplicationGUI().getStatusLineManager().getProgressMonitor(); + PlatformUtils.safeSyncRunnable(new Runnable() { + public void run() + { +// System.out.println("before begin task"); + pm.beginTask("Zipping up "+path, IProgressMonitor.UNKNOWN); +// System.out.println("After begin task"); + } + }); +// pm.beginTask("Zipping up "+path, IProgressMonitor.UNKNOWN); + Job copyFileJob = new Job("Zipping up "+path) { + @Override + protected IStatus run(final IProgressMonitor pm) + { + if (compress) + { +// System.out.println("Vor ZIP"); + ZipUtils.zipFile(src, dest); +// System.out.println("Nach Zip"); + } else { + try + { + FileUtils.copyRecursive(src, dest); + } catch (IOException e) + { + PlatformUtils.showErrorMessageWithException("An Error Occured", "An error occured while copying "+ + fsd.getLocalFilename()+" to "+dest.getAbsolutePath(), e); + } + } + return Status.OK_STATUS; + } + }; + copyFileJob.schedule(); + copyFileJob.addJobChangeListener(new JobChangeAdapter(){ + public void done(IJobChangeEvent arg0) + { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { +// System.out.println("Fertig"); + pm.done(); + } + }); + } + }); + break; + case TEXT: + TextSourceData tsd = (TextSourceData) sourceData; + try + { + FileUtils.writeTextToFile(dest, entryName, tsd.getText(), compress); + } catch (IOException e) + { + PlatformUtils.showErrorMessageWithException("An Error Occured", "An error occured while saving a clipboard text entry: "+e.getMessage(), e); + } + break; + case IMAGE: + ImageSourceData isd = (ImageSourceData) sourceData; + try { + FileUtils.writeImageToFile(dest, entryName, isd.getImageData(), compress); + } catch (Exception e) + { + PlatformUtils.showErrorMessageWithException("An Error Occured", "An error occured while saving a clipboard image entry: "+e.getMessage(), e); + } + break; + default: + PlatformUtils.showErrorMessage("An Error Occured", "Tried to save an element of unknown type: "+sourceData.getType().toString()); + } + } + + public void selectPreviousEntry(int currentSelectionIndex) + { + if (currentSelectionIndex > -1) + { + if (currentSelectionIndex > 0) + { + currentSelectionIndex--; + } + saveSelectEntry(currentSelectionIndex); + } + } + + public void saveSelectEntry(int selectionIndex) + { + if (selectionIndex > -1) + { + ClipboardTable clipboardTable = getSourceDataDialogController().getClipboardTable(); + Table table = clipboardTable.getTable(); + if (table.getItemCount() <= selectionIndex) + { + selectionIndex = table.getItemCount() - 1; + } + if (selectionIndex >= 0) + { + table.setSelection(selectionIndex); + } + } + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/SpacerToolbarItem.java b/src/java/com/agynamix/simidude/clipboard/SpacerToolbarItem.java new file mode 100644 index 0000000..5f93022 --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/SpacerToolbarItem.java @@ -0,0 +1,38 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.clipboard; + +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +public class SpacerToolbarItem extends ContributionItem { + + public SpacerToolbarItem() + { + super("Spacer"); + } + + public void fill(ToolBar toolbar, int index) + { + if (index >= 0) + { + new ToolItem(toolbar, SWT.NONE, index); + } else + { + new ToolItem(toolbar, SWT.NONE); + } + } + +} diff --git a/src/java/com/agynamix/simidude/clipboard/TextClipboardItem.java b/src/java/com/agynamix/simidude/clipboard/TextClipboardItem.java new file mode 100644 index 0000000..af7166f --- /dev/null +++ b/src/java/com/agynamix/simidude/clipboard/TextClipboardItem.java @@ -0,0 +1,83 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.clipboard; + +import org.eclipse.swt.graphics.Image; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.TextSourceData; +import com.agynamix.simidude.source.impl.TextSourceData.TextType; + + +public class TextClipboardItem implements IClipboardItem { + + final TextSourceData sourceData; + + public TextClipboardItem(TextSourceData sourceData) + { + this.sourceData = sourceData; + } + + public String getDescription() + { + return sourceData.getText(); + } + + public String getShortDescription() + { + return getSubstring(sourceData.getText(), 80, "..."); + } + + public Image getImage() + { + if (sourceData.getTextType() == TextType.URI) + { + return PlatformIcons.get(PlatformIcons.COLIMG_URI); + } else { + return PlatformIcons.get(PlatformIcons.COLIMG_TEXT); + } + } + + public String getTooltip() + { + return getSubstring(sourceData.getText(), 1000, "..."); + } + + public SourceType getType() + { + return SourceType.TEXT; + } + + public ISourceData getSourceData() + { + return sourceData; + } + + private String getSubstring(String text, int len, String postfix) + { + return (text.length() <= len) ? text : text.substring(0, len) + postfix; + } + + public Object getData() + { + return sourceData.getText(); + } + + public IClipboardItem deleteContents() + { + sourceData.deleteContents(); + return this; + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/action/AboutAction.java b/src/java/com/agynamix/simidude/frontend/action/AboutAction.java new file mode 100644 index 0000000..4759ff8 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/AboutAction.java @@ -0,0 +1,41 @@ +/* + * Class AboutAction + * created on 01.06.2004 + * + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.dialogs.AboutApplicationDialog; + + + + +/** + * @version $Revision: 41 $ $Date: 2005-01-09 18:03:54 +0100 (So, 09 Jan 2005) $ + * @author tuhlmann + * @since V0404 + */ +public class AboutAction extends Action { + + final ApplicationWindow window; + + public AboutAction(ApplicationWindow w) { + this.window = w; + setText("&About Simidude"); + setToolTipText("Show information &about the application"); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + AboutApplicationDialog about = new AboutApplicationDialog(window.getShell()); + about.open(); + } + +} + diff --git a/src/java/com/agynamix/simidude/frontend/action/BuySimidudeAction.java b/src/java/com/agynamix/simidude/frontend/action/BuySimidudeAction.java new file mode 100644 index 0000000..d9c7c2b --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/BuySimidudeAction.java @@ -0,0 +1,41 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.program.Program; + + + +/** + * @version $Revision$ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class BuySimidudeAction extends Action { + + final ApplicationWindow window; + + public BuySimidudeAction(ApplicationWindow w) { + this.window = w; + setText("&Buy Simidude"); + setToolTipText("Opens the Simidude order page. Go ahead and buy..."); +// setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.HELP)); Ø + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + Program.launch("https://sites.fastspring.com/agynamix/instant/simidude"); + } + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/simidude/frontend/action/SelectMonitoredClipboardItemsAction.java b/src/java/com/agynamix/simidude/frontend/action/SelectMonitoredClipboardItemsAction.java new file mode 100644 index 0000000..406c8f0 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/SelectMonitoredClipboardItemsAction.java @@ -0,0 +1,132 @@ +package com.agynamix.simidude.frontend.action; + +import java.util.Iterator; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuCreator; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; + +public class SelectMonitoredClipboardItemsAction extends Action implements IMenuCreator { + + private Menu fMenu; + + final ApplicationWindow window; + + final Action monitorTextAction; + final Action monitorImagesAction; + final Action monitorFilesAction; + + + public SelectMonitoredClipboardItemsAction(ApplicationWindow w) + { + super(null, IAction.AS_DROP_DOWN_MENU); + setText("My Actions"); + setMenuCreator(this); + this.window = w; + setToolTipText("Click and select the clipboard item types that you want to monitor."); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.SELECT_MONITORED_CLIPBOARD_ITEMS)); + + monitorTextAction = new ToggleMonitorClipboardItemTypeAction(ISourceData.SourceType.TEXT, "Text Items", IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR_TEXT); + monitorImagesAction = new ToggleMonitorClipboardItemTypeAction(ISourceData.SourceType.IMAGE, "Image Items", IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR_IMAGES); + monitorFilesAction = new ToggleMonitorClipboardItemTypeAction(ISourceData.SourceType.FILE, "File/Directory Items", IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR_FILES); + +// SourceDataManager tm = ((SimidudeApplicationContext) ApplicationBase.getContext()).getSourceDataManager(); + } + + public Menu getMenu(Menu parent) + { + return null; + } + + public Menu getMenu(Control parent) + { + if (fMenu != null) + { + fMenu.dispose(); + } + + fMenu = new Menu(parent); + addActionToMenu(fMenu, monitorTextAction); + addActionToMenu(fMenu, monitorImagesAction); + addActionToMenu(fMenu, monitorFilesAction); +// new MenuItem(fMenu, SWT.SEPARATOR); + + return fMenu; + } + + protected void addActionToMenu(Menu parent, Action action) + { + ActionContributionItem item = new ActionContributionItem(action); + item.fill(parent, -1); + } + + public void run() + { + Menu menu = getMenu(window.getShell()); + menu.setVisible(true); + } + + /** + * Get's rid of the menu, because the menu hangs on to * the searches, etc. + */ + void clear() + { + dispose(); + } + + public void dispose() + { + if (fMenu != null) + { + fMenu.dispose(); + fMenu = null; + } + } + + public static class ToggleMonitorClipboardItemTypeAction extends Action { + + final String itemTypeDesc; + final String preferenceKey; + final ISourceData.SourceType sourceType; + + public ToggleMonitorClipboardItemTypeAction(ISourceData.SourceType sourceType, String itemTypeDesc, String preferenceKey) + { + super("Monitor "+itemTypeDesc, IAction.AS_CHECK_BOX); + this.sourceType = sourceType; + this.itemTypeDesc = itemTypeDesc; + this.preferenceKey = preferenceKey; + boolean checkStatus = ApplicationBase.getContext().getConfiguration().getBoolean(this.preferenceKey); + setChecked(checkStatus); + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + tm.setClipboardMonitorTypeEnabled(this.sourceType, checkStatus); + } + + public void run() { + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + tm.setClipboardMonitorTypeEnabled(this.sourceType, isChecked()); +// if (isChecked()) +// { +// System.out.println("Clipboard Monitoring ON"); +// } else { +// System.out.println("Clipboard Monitoring OFF"); +// } + ApplicationBase.getContext().getConfiguration().setBoolean(this.preferenceKey, isChecked()); + } + + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/action/ShowLiveBookmarklAction.java b/src/java/com/agynamix/simidude/frontend/action/ShowLiveBookmarklAction.java new file mode 100644 index 0000000..1f6d5ff --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/ShowLiveBookmarklAction.java @@ -0,0 +1,40 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.program.Program; + + + +/** + * @version $Revision$ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class ShowLiveBookmarklAction extends Action { + + final ApplicationWindow window; + + public ShowLiveBookmarklAction(ApplicationWindow w) { + this.window = w; + setText("&LiveBookmark"); + setToolTipText("Opens a html page with the LiveBookmark in your favourite browser."); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + Program.launch("isilo_bookmark.html"); + } + +} + + +// $Log$ \ No newline at end of file diff --git a/src/java/com/agynamix/simidude/frontend/action/ShowOfflineHelpAction.java b/src/java/com/agynamix/simidude/frontend/action/ShowOfflineHelpAction.java new file mode 100644 index 0000000..55e1f76 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/ShowOfflineHelpAction.java @@ -0,0 +1,44 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.infra.SimidudeUtils; + + + +/** + * @version $Revision$ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class ShowOfflineHelpAction extends Action { + + final ApplicationWindow window; + + public ShowOfflineHelpAction(ApplicationWindow w) { + this.window = w; + setText("View &Help"); + setAccelerator(SWT.F1); + setToolTipText("Display Simidude Help Information"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.HELP)); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SimidudeUtils.launchStandardApplication(PlatformUtils.getApplicationBasedir()+"/Simidude User Manual.pdf"); + } + +} + diff --git a/src/java/com/agynamix/simidude/frontend/action/ShowOnlineHelpAction.java b/src/java/com/agynamix/simidude/frontend/action/ShowOnlineHelpAction.java new file mode 100644 index 0000000..72bc2e2 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/ShowOnlineHelpAction.java @@ -0,0 +1,42 @@ +/* + * Class ExitAction + * created on 01.06.2004 + * + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.simidude.infra.SimidudeUtils; + + + +/** + * @version $Revision$ $Date: 2004-11-17 13:30:10 +0100 (Mi, 17 Nov 2004) $ + * @author tuhlmann + * @since V0404 + */ +public class ShowOnlineHelpAction extends Action { + + final ApplicationWindow window; + + public ShowOnlineHelpAction(ApplicationWindow w) { + this.window = w; + setText("View &Help Online"); +// setAccelerator(SWT.F1); + setToolTipText("Where you can find the Simidude manual and user forum"); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.HELP)); + } + + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + SimidudeUtils.launchStandardApplication("http://helpdesk.agynamix.de/index.php?pg=kb.book&id=3"); + } + +} + diff --git a/src/java/com/agynamix/simidude/frontend/action/SimidudeHotkeyActions.java b/src/java/com/agynamix/simidude/frontend/action/SimidudeHotkeyActions.java new file mode 100644 index 0000000..555b743 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/SimidudeHotkeyActions.java @@ -0,0 +1,64 @@ +package com.agynamix.simidude.frontend.action; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.frontend.gui.ApplicationTray; +import com.agynamix.platform.frontend.gui.HotkeyListenerInfo; +import com.agynamix.platform.frontend.gui.HotkeyRegistrarFactory; +import com.agynamix.platform.frontend.gui.IHotkeyListener; +import com.agynamix.platform.frontend.gui.IHotkeyRegistrar; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class SimidudeHotkeyActions { + + public static void unregisterHotkeys() + { + IHotkeyRegistrar hotKeyRegistrar = HotkeyRegistrarFactory.getHotkeyRegistrarInstance(); + hotKeyRegistrar.unregisterHotkeys(); + } + + public static void registerHotkeys() + { + String bringSimidudeToFront = ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.HOTKEY_BRING_SIMIDUDE_TO_FRONT); + String activateLastEntry = ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.HOTKEY_ACTIVATE_LAST_ENTRY); + + IHotkeyRegistrar hotKeyRegistrar = HotkeyRegistrarFactory.getHotkeyRegistrarInstance(); + + if ((bringSimidudeToFront != null) && (bringSimidudeToFront.length() > 0)) + { + hotKeyRegistrar.addHotkeyListener(bringSimidudeToFront, new IHotkeyListener(){ + public void onHotkey(HotkeyListenerInfo listenerInfo) { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + ApplicationGUI gui = ((SimidudeApplicationContext)ApplicationBase.getContext()).getApplicationGUI(); + ApplicationTray tray = gui.getTray(); + tray.toggleMainWindowActive(false); + } + }); + } + }); + } + if ((activateLastEntry != null) && (activateLastEntry.length() > 0)) + { + hotKeyRegistrar.addHotkeyListener(activateLastEntry, new IHotkeyListener(){ + public void onHotkey(final HotkeyListenerInfo listenerInfo) { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sdm.activateItem(0); + listenerInfo.getHotkeyRegistrar().activateGlobalPaste(listenerInfo); + } + }); + } + }); + } + + + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/action/ToggleMonitorClipboardAction.java b/src/java/com/agynamix/simidude/frontend/action/ToggleMonitorClipboardAction.java new file mode 100644 index 0000000..b03d106 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/action/ToggleMonitorClipboardAction.java @@ -0,0 +1,68 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.window.ApplicationWindow; + +import com.agynamix.platform.frontend.action.IActionWithValue; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.install4j.runtime.beans.actions.desktop.AddStartupItemAction; + +public class ToggleMonitorClipboardAction extends Action implements IAction, IActionWithValue { + + final ApplicationWindow window; + + public ToggleMonitorClipboardAction(ApplicationWindow w) { + super("Monitor Clipboard", IAction.AS_CHECK_BOX); + this.window = w; + setToolTipText("Toggles the monitoring of the clipboard of this computer. If off, clipboard items wont be send to computers."); + setImageDescriptor(PlatformIcons.getDescriptor(PlatformIcons.TOGGLE_MONITOR_CLIPBOARD)); + boolean checkStatus = ApplicationBase.getContext().getConfiguration().getBoolean(IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR); + setChecked(checkStatus); + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + tm.setClipboardMonitorEnabled(checkStatus); + } + + /** + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + runWithValue(isChecked()); + } + + public void runWithValue(boolean value) + { + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + tm.setClipboardMonitorEnabled(value); +// if (value) +// { +// System.out.println("Clipboard Monitoring ON"); +// } else { +// System.out.println("Clipboard Monitoring OFF"); +// } + ApplicationBase.getContext().getConfiguration().setBoolean(IPreferenceConstants.TOGGLE_CLIPBOARD_MONITOR, value); + setChecked(value); + } + + public boolean getSelectionValue() + { + return isChecked(); + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/ctrl/SourceDataDialogController.java b/src/java/com/agynamix/simidude/frontend/ctrl/SourceDataDialogController.java new file mode 100644 index 0000000..745d150 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/ctrl/SourceDataDialogController.java @@ -0,0 +1,73 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.ctrl; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.simidude.clipboard.ClipboardTable; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.gui.ISourceDataDialogView; + +public class SourceDataDialogController { + + public static final String SERVICE_NAME = "SourceDataDialogController"; + + protected final ISourceDataDialogView sourceDataDataView; + private final SourceDataManager sourceDataManager; + + public SourceDataDialogController(SourceDataManager sourceDataManager, ISourceDataDialogView transferDataView) + { + this.sourceDataManager = sourceDataManager; + this.sourceDataDataView = transferDataView; + } + + public void addSelectionChangedListener(ISelectionChangedListener l) + { + sourceDataDataView.addSelectionChangedListener(l); + } + + public void removeSelectionChangedListener(ISelectionChangedListener l) + { + sourceDataDataView.removeSelectionChangedListener(l); + } + + /** + * Create the contents to be shown by this dialog + * @param parent + * @return + */ + public Composite createContent(Composite parent) + { + return sourceDataDataView.createContent(parent); + } + + public SourceDataManager getSourceDataManager() + { + return this.sourceDataManager; + } + + public ClipboardTable getClipboardTable() + { + return sourceDataDataView.getClipboardTable(); + } + + public Control getCustomToolbar() + { + return sourceDataDataView.getCustomToolbar(); + } + + + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDragSource.java b/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDragSource.java new file mode 100644 index 0000000..52a8ea7 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDragSource.java @@ -0,0 +1,170 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import java.util.logging.Logger; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.TableItem; + +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.clipboard.ClipboardTable; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; + +public class ClipboardTableDragSource implements DragSourceListener { + + final ClipboardTable clipboardTable; + final TableViewer tableViewer; + final SourceDataManager sourceDataManager; + + final DragSource dragSource; + + Transfer[] currentTransfer = null; + + Logger log = ApplicationLog.getLogger(ClipboardTableDragSource.class); + + public ClipboardTableDragSource(ClipboardTable clipboardTable, SourceDataManager sourceDataManager) + { + this.clipboardTable = clipboardTable; + this.tableViewer = clipboardTable.getTableViewer(); + this.sourceDataManager = sourceDataManager; + dragSource = new DragSource(tableViewer.getControl(), DND.DROP_COPY); + dragSource.setTransfer(new Transfer[] { TextTransfer.getInstance(), FileTransfer.getInstance() }); + dragSource.addDragListener(this); + } + + public void dragStart(DragSourceEvent event) + { + IClipboardItem item = getSelectedItem(); + if (item != null) + { + event.doit = true; + clipboardTable.setDragInProgress(true); + switch (item.getType()) + { + case FILE: + if (sourceDataManager.isRetrieveContentsNeeded(item)) + { + currentTransfer = new Transfer[] { TextTransfer.getInstance() }; + } else { + currentTransfer = new Transfer[] { TextTransfer.getInstance(), FileTransfer.getInstance() }; + } + break; + case TEXT: + currentTransfer = new Transfer[] { TextTransfer.getInstance() }; + break; + case IMAGE: + currentTransfer = new Transfer[] { ImageTransfer.getInstance() }; + break; + } + dragSource.setTransfer(currentTransfer); + } else { + event.doit = false; + } + } + + public void dragSetData(DragSourceEvent event) + { + IClipboardItem item = getSelectedItem(); + if (item == null) + { + return; + } + event.image = item.getImage(); + +// final ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); +// final ISourceData sourceData = item.getSourceData(); + + if (TextTransfer.getInstance().isSupportedType(event.dataType)) + { + switch (item.getType()) + { + case TEXT: + event.data = item.getDescription(); + break; + case FILE: + event.data = item.getDescription(); + break; + } + } else if (FileTransfer.getInstance().isSupportedType(event.dataType)) + { + switch (item.getType()) + { + case FILE: + FileSourceData fsd = (FileSourceData) item.getSourceData(); + event.data = new String[] {fsd.getLocalFilename()}; +// System.out.println("Local Filename: "+fsd.getLocalFilename()); + break; + case TEXT: + // we should not get here. + event.data = new String[] {item.getDescription()}; + break; + } + } else if (ImageTransfer.getInstance().isSupportedType(event.dataType)) + { + if (item.getType() == SourceType.IMAGE) + { + ImageSourceData isd = (ImageSourceData) item.getSourceData(); + event.data = isd.getImageData(); + } else { + log.warning("Cannot support ImageTransfer for Types other than images!"); + } + } + } + + protected IClipboardItem getSelectedItem() + { + ISelection s = tableViewer.getSelection(); + if (s instanceof IStructuredSelection) + { + IStructuredSelection ss = (IStructuredSelection) s; + Object item = ss.getFirstElement(); + if (item instanceof IClipboardItem) + { + return (IClipboardItem) item; + } + } + return null; + } + + public void dragFinished(DragSourceEvent event) + { + if (event.detail == DND.DROP_MOVE) + { + TableItem[] tableItems = tableViewer.getTable().getSelection(); + if ((tableItems != null) && (tableItems.length > 0)) + { + sourceDataManager.removeItem((IClipboardItem) tableItems[0].getData()); + } + } + // We have File.deleteOnExit() enabled, so lets see how this goes. +// IClipboardItem item = getSelectedItem(); +// ((TextSourceData)item.getSourceData()).removeTempFile(); + clipboardTable.setDragInProgress(false); + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDropTarget.java b/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDropTarget.java new file mode 100644 index 0000000..fb34b57 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/ClipboardTableDropTarget.java @@ -0,0 +1,70 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetAdapter; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.simidude.clipboard.ClipboardTable; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataFactory; + +public class ClipboardTableDropTarget extends DropTargetAdapter { + + final ClipboardTable clipboardTable; + final TableViewer tableViewer; + final SourceDataManager transferDataManager; + + public ClipboardTableDropTarget(ClipboardTable clipboardTable, SourceDataManager transferDataManager) + { + this.clipboardTable = clipboardTable; + this.tableViewer = clipboardTable.getTableViewer(); + this.transferDataManager = transferDataManager; + DropTarget target = new DropTarget(tableViewer.getControl(), DND.DROP_MOVE | DND.DROP_COPY); + target.setTransfer(new Transfer[] { TextTransfer.getInstance(), FileTransfer.getInstance(), ImageTransfer.getInstance() }); + target.addDropListener(this); + } + + @Override + public void dragEnter(DropTargetEvent event) + { + if (clipboardTable.isDragInProgress()) + { + event.detail = DND.DROP_NONE; + } + } + + public void drop(DropTargetEvent event) + { + IQueueManager qm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + ISourceData[] items = SourceDataFactory.createFromDropTarget(event); + if (items != null) + { + qm.putAll(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, items); +// transferDataManager.add(item); + } + } + + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/ISourceDataDialogView.java b/src/java/com/agynamix/simidude/frontend/gui/ISourceDataDialogView.java new file mode 100644 index 0000000..80feeab --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/ISourceDataDialogView.java @@ -0,0 +1,38 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.simidude.clipboard.ClipboardTable; + +public interface ISourceDataDialogView { + + /** + * Create the dialogs contents. + * @param parent the parent Composite + * @return the control created by this dialog + */ + Composite createContent(Composite parent); + + ClipboardTable getClipboardTable(); + + Control getCustomToolbar(); + + void addSelectionChangedListener(ISelectionChangedListener l); + + void removeSelectionChangedListener(ISelectionChangedListener l); + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/SimidudeApplicationTray.java b/src/java/com/agynamix/simidude/frontend/gui/SimidudeApplicationTray.java new file mode 100644 index 0000000..c164aef --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/SimidudeApplicationTray.java @@ -0,0 +1,47 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import org.eclipse.jface.window.Window; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.frontend.gui.ApplicationTray; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.IItemAddedListener; + +public class SimidudeApplicationTray extends ApplicationTray { + + public SimidudeApplicationTray(Window w, Shell shell, Image trayImage) + { + super(w, shell, trayImage); + } + + @Override + public void initializeTray() + { + super.initializeTray(); + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sdm.addItemAddedListener(new IItemAddedListener() { + + public void itemAdded(int insertPos, IClipboardItem item) + { + showTooltip(item); + } + }); + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/SimidudeGUI.java b/src/java/com/agynamix/simidude/frontend/gui/SimidudeGUI.java new file mode 100644 index 0000000..9a4edce --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/SimidudeGUI.java @@ -0,0 +1,85 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import org.eclipse.jface.window.Window; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.frontend.gui.ApplicationTray; +import com.agynamix.platform.icons.PlatformIcons; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ApplicationInfo; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.ctrl.SourceDataDialogController; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class SimidudeGUI extends ApplicationGUI { + + SourceDataDialogViewImpl sourceDataView; + SourceDataDialogController sourceDataController; + + @Override + protected Point getInitialShellSize() + { + return new Point(600, 400); + } + + @Override + protected Image getShellImage() + { + if (PlatformUtils.isMacOs()) { + return PlatformIcons.get(PlatformIcons.SIMIDUDE_MAC_ICN); + } + + return PlatformIcons.get(PlatformIcons.SIMIDUDE_WND_ICN); + } + + @Override + protected String getInitialStatusLine() + { + String status = ApplicationInfo.getApplicationName()+", Version "+ApplicationInfo.getApplicationVersion(); + return status; + } + + @Override + protected Control fillMainWindow(Composite parent) + { + SourceDataManager sourceDataManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sourceDataView = new SourceDataDialogViewImpl(); + sourceDataController = new SourceDataDialogController(sourceDataManager, sourceDataView); + sourceDataView.setController(sourceDataController); + sourceDataManager.setSourceDataDialogController(sourceDataController); + final Composite c1 = sourceDataController.createContent(parent); + + return parent; + } + + @Override + protected Control getCustomToolbar() + { + return sourceDataController.getCustomToolbar(); + } + + @Override + protected ApplicationTray createApplicationTray(Window window, Shell shell, Image image) + { + return new SimidudeApplicationTray(window, shell, image); + } + +} diff --git a/src/java/com/agynamix/simidude/frontend/gui/SourceDataDialogViewImpl.java b/src/java/com/agynamix/simidude/frontend/gui/SourceDataDialogViewImpl.java new file mode 100644 index 0000000..a5c0c94 --- /dev/null +++ b/src/java/com/agynamix/simidude/frontend/gui/SourceDataDialogViewImpl.java @@ -0,0 +1,98 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.frontend.gui; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.simidude.clipboard.ClipboardTable; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.ctrl.SourceDataDialogController; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + +public class SourceDataDialogViewImpl implements ISourceDataDialogView { + + private ClipboardTable clipboardTable; + + private SourceDataDialogController itsController; + private Composite toolbar; + + public SourceDataDialogViewImpl() + { + } + + public void setController(SourceDataDialogController itsController) + { + this.itsController = itsController; + } + + public void addSelectionChangedListener(ISelectionChangedListener l) + { + clipboardTable.addSelectionChangeListener(l); + } + + public void removeSelectionChangedListener(ISelectionChangedListener l) + { + clipboardTable.removeSelectionChangeListener(l); + } + + /** + * @param comp + * @return + */ + public Composite createContent(final Composite parent) + { + final Composite c1 = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + c1.setSize(parent.getSize()); + c1.setLayout(layout); + + ApplicationGUI gui = ApplicationBase.getContext().getApplicationGUI(); + toolbar = gui.createCustomToolbar(c1); + + SourceDataManager sourceDataManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + + clipboardTable = new ClipboardTable(sourceDataManager, c1, SWT.BORDER | SWT.FLAT | SWT.V_SCROLL); + clipboardTable.getTableViewer().setInput(sourceDataManager.getClipboardItems()); + + GridData spec = new GridData(); + spec.horizontalAlignment = GridData.FILL; + spec.grabExcessHorizontalSpace = true; + spec.verticalAlignment = GridData.FILL; + spec.grabExcessVerticalSpace = true; + // spec.horizontalSpan = 5; + clipboardTable.getTable().setLayoutData(spec); + + c1.layout(); + + return c1; + } + + public Control getCustomToolbar() + { + return toolbar; + } + + public ClipboardTable getClipboardTable() + { + return clipboardTable; + } + +} diff --git a/src/java/com/agynamix/simidude/impl/CacheCleaner.java b/src/java/com/agynamix/simidude/impl/CacheCleaner.java new file mode 100644 index 0000000..70252bd --- /dev/null +++ b/src/java/com/agynamix/simidude/impl/CacheCleaner.java @@ -0,0 +1,122 @@ +package com.agynamix.simidude.impl; + +import java.io.File; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.infra.IContentsCacheManager; +import com.agynamix.simidude.source.ISourceData; + +public class CacheCleaner implements Runnable { + + private final String cacheRoot; + + Logger log = ApplicationLog.getLogger(CacheCleaner.class); + + public CacheCleaner(String cacheRoot) + { + this.cacheRoot = cacheRoot; + } + + /** + * For each directory in cache: + *
    + *
  • check if it is referenced from any Simidude entry. If not it can be deleted. + *
+ */ + public void run() + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + File root = new File(cacheRoot); + if (root.exists()) + { + File[] children = root.listFiles(); + for (File child : children) + { + if (child.isDirectory()) + { + log.fine("Check dir "+child.getAbsolutePath()); + if ((isCacheEntryDirectory(child)) && (!CacheManagerFactory.isInTransitCacheDirectory(child))) + { + if (!isReferenced(sdm, child.getAbsolutePath())) + { + removeDirectory(child); + } + } + } else { + // check if we have a temp file here + if (isCacheEntryFile(child)) + { + if (!isReferenced(sdm, child.getAbsolutePath())) + { + removeFile(child); + } + } + } + } + } else { + log.info(cacheRoot+" does not exist"); + } + } + + private boolean isCacheEntryDirectory(File cacheDirectory) + { + String name = cacheDirectory.getName(); + return name.matches("^c\\d+$"); + } + + private boolean isCacheEntryFile(File cacheFile) + { + String name = cacheFile.getName(); + if (name.matches(IContentsCacheManager.TEMP_FILE_PREFIX+"\\d+\\..+")) + { + return true; + } else { + return false; + } + } + + private boolean isReferenced(SourceDataManager sdm, String cacheEntry) + { + for (IClipboardItem item : sdm.getClipboardItems()) + { + ISourceData sd = item.getSourceData(); + if (sd.isCached()) + { + if (pathMatches(sd.getContentsCacheInfo().getFilenameInCache(), cacheEntry)) + { + return true; + } + } + } + return false; + } + + private boolean pathMatches(String localFilename, String cacheDirectory) + { + if (localFilename.startsWith(cacheDirectory)) + { + log.fine("MATCH: "+localFilename + " starts with "+cacheDirectory); + return true; + } + return false; + } + + private void removeDirectory(File cacheDirectory) + { + log.fine("Remove Directory "+cacheDirectory); + FileUtils.deleteRecursive(cacheDirectory); + } + + private void removeFile(File cacheFile) + { + log.fine("Remove File "+cacheFile); + cacheFile.delete(); + } + +} diff --git a/src/java/com/agynamix/simidude/impl/ContentsCacheInfo.java b/src/java/com/agynamix/simidude/impl/ContentsCacheInfo.java new file mode 100644 index 0000000..67d494d --- /dev/null +++ b/src/java/com/agynamix/simidude/impl/ContentsCacheInfo.java @@ -0,0 +1,53 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.impl; + +import java.io.File; +import java.util.Date; + +import com.agynamix.simidude.infra.IContentsCacheInfo; + +public class ContentsCacheInfo implements IContentsCacheInfo { + + private static final long serialVersionUID = 1L; + + private final Date creationDate; + private final File itsFile; + + public ContentsCacheInfo(Date creationDate, File file) + { + if ((file == null) || (creationDate == null)) + { + throw new NullPointerException(); + } + this.creationDate = creationDate; + this.itsFile = file; + } + + public String getFilenameInCache() + { + return itsFile.getAbsolutePath(); + } + + public Date getCreationDate() + { + return creationDate; + } + + public boolean isDirectory() + { + return itsFile.isDirectory(); + } + + +} diff --git a/src/java/com/agynamix/simidude/impl/ContentsCacheManagerImpl.java b/src/java/com/agynamix/simidude/impl/ContentsCacheManagerImpl.java new file mode 100644 index 0000000..29c236e --- /dev/null +++ b/src/java/com/agynamix/simidude/impl/ContentsCacheManagerImpl.java @@ -0,0 +1,231 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.impl; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.FileUtils; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.infra.IContentsCacheInfo; +import com.agynamix.simidude.infra.IContentsCacheManager; +import com.agynamix.simidude.source.SourceDataContents; + +/** + * A simple caching solution for remote files. + * + * @author tuhlmann + * + */ +public class ContentsCacheManagerImpl implements IContentsCacheManager { + + Logger log = ApplicationLog.getLogger(ContentsCacheManagerImpl.class); + + final String cacheDirectoryStr; + final File cacheDirectory; + + File itsFileRoot = null; + File firstContentsElementInCache = null; + + /** + * Stores the part of the path of the file/directory which needs to be replaced by our cache path. + */ + String itsCommonSourcePath = null; + boolean isFirstItem = true; + + OutputStream currentOutputStream = null; + + boolean insideTransaction = false; + + public ContentsCacheManagerImpl() + { + log.fine("Inside ContentsCacheManager ctor"); + + cacheDirectoryStr = PlatformUtils.getApplicationCacheDir(); + cacheDirectory = new File(cacheDirectoryStr); + if (!cacheDirectory.exists()) + { + if (!cacheDirectory.mkdirs()) + { + throw new IllegalStateException("Can not create cache directory " + cacheDirectoryStr); + } + } + } + + public synchronized File createTempFile(String suffix) throws IOException + { + File file = new File(cacheDirectory.getAbsolutePath() + "/"+ IContentsCacheManager.TEMP_FILE_PREFIX + System.currentTimeMillis()+suffix); + file.deleteOnExit(); + return file; + } + + public synchronized void begin() + { + if (insideTransaction) + { + throw new IllegalStateException("Already inside a transaction"); + } + insideTransaction = true; + + itsFileRoot = new File(cacheDirectory.getAbsolutePath() + "/c" + System.currentTimeMillis()); + itsFileRoot.deleteOnExit(); + if (!itsFileRoot.mkdirs()) + { + throw new IllegalStateException("Cannot create cache directory " + itsFileRoot.getAbsolutePath()); + } + CacheManagerFactory.addInTransitCacheDirectory(itsFileRoot); + } + + public synchronized IContentsCacheInfo finish() + { + if (!insideTransaction) + { + throw new IllegalStateException("Not inside a transaction."); + } + insideTransaction = false; + + if (currentOutputStream != null) + { + log.fine("OutputStream was open. Should have been closed with endOfFile package!"); + try + { + currentOutputStream.close(); + currentOutputStream = null; + } catch (IOException IGNORE) + { + } + } + + CacheManagerFactory.removeInTransitCacheDirectory(itsFileRoot); + + File f = firstContentsElementInCache; + itsFileRoot = null; + firstContentsElementInCache = null; + + return f != null ? new ContentsCacheInfo(new Date(), f) : null; + } + + public synchronized void abort() + { + if (insideTransaction) + { + if (itsFileRoot != null) + { + if (itsFileRoot.exists()) + { + log.config("Abort transfer for cache dir "+itsFileRoot.getAbsolutePath()); + FileUtils.deleteRecursive(itsFileRoot); + } + CacheManagerFactory.removeInTransitCacheDirectory(itsFileRoot); + itsFileRoot = null; + } + insideTransaction = false; + } + } + + public synchronized void write(SourceDataContents contents) + { + if (isFirstItem) + { + itsCommonSourcePath = FileUtils.getCommonSourcePath(contents.getName()); + firstContentsElementInCache = new File(itsFileRoot.getAbsolutePath() + "/" + + FileUtils.getRelativePath(itsCommonSourcePath, contents.getName())); + isFirstItem = false; + } + if (contents.isFile()) + { + writeFileToCache(itsFileRoot, contents); + } else + { + writeDirectoryToCache(itsFileRoot, contents); + } + } + + private synchronized void writeFileToCache(File fileRoot, SourceDataContents item) + { + File file = new File(fileRoot.getAbsolutePath() + "/" + FileUtils.getRelativePath(itsCommonSourcePath, item.getName())); + file.deleteOnExit(); + writeContentsToFile(file, item); + } + + /** + * SourceDataContents element holds a single directory which needs to be created inside the cache root. + * + * @param fileRoot + * @param item + * @return + */ + private synchronized void writeDirectoryToCache(File fileRoot, SourceDataContents item) + { + File file = new File(fileRoot.getAbsolutePath() + "/" + FileUtils.getRelativePath(itsCommonSourcePath, item.getName())); + file.deleteOnExit(); + if (!file.mkdirs()) + { + throw new IllegalStateException("Cannot create cache directory " + file.getAbsolutePath()); + } + } + + private void writeContentsToFile(File element, SourceDataContents contents) + { + try + { + if (currentOutputStream == null) + { + currentOutputStream = new BufferedOutputStream(new FileOutputStream(element)); + } + byte[] buffer = contents.getFileContents(); + if (buffer.length > 0) + { + currentOutputStream.write(contents.getFileContents()); + } + + if (contents.isEndOfFile()) + { + currentOutputStream.flush(); + currentOutputStream.close(); + currentOutputStream = null; + } + } catch (IOException e) + { + e.printStackTrace(); + throw new IllegalStateException(e); + } + } + + public void removeContentsFromCache(IContentsCacheInfo cacheInfo) + { + if (cacheInfo != null) + { + File f = new File(cacheInfo.getFilenameInCache()); + if (f.exists()) + { + FileUtils.deleteRecursive(f); + } + } + } + + public void removeAbortedItem(SourceDataContents contents) { + if (itsCommonSourcePath != null) { + File file = new File(itsFileRoot.getAbsolutePath() + "/" + FileUtils.getRelativePath(itsCommonSourcePath, contents.getName())); + file.delete(); + } // otherwise nothing had been written yet... + } + +} diff --git a/src/java/com/agynamix/simidude/impl/SimidudeApplicationContext.java b/src/java/com/agynamix/simidude/impl/SimidudeApplicationContext.java new file mode 100644 index 0000000..4b1fe37 --- /dev/null +++ b/src/java/com/agynamix/simidude/impl/SimidudeApplicationContext.java @@ -0,0 +1,44 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.impl; + +import com.agynamix.platform.infra.ApplicationContext; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.frontend.ctrl.SourceDataDialogController; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.remote.RemoteConnector; + +public class SimidudeApplicationContext extends ApplicationContext { + + public IQueueManager getQueueManager() + { + return (IQueueManager) getService(IQueueManager.SERVICE_NAME); + } + + public SourceDataManager getSourceDataManager() + { + return (SourceDataManager) getService(SourceDataManager.SERVICE_NAME); + } + + public ModelProvider getModelProvider() + { + return (ModelProvider) getService(ModelProvider.SERVICE_NAME); + } + + public RemoteConnector getRemoteConnector() + { + return (RemoteConnector) getService(RemoteConnector.SERVICE_NAME); + } + +} diff --git a/src/java/com/agynamix/simidude/infra/CacheManagerFactory.java b/src/java/com/agynamix/simidude/infra/CacheManagerFactory.java new file mode 100644 index 0000000..b2fba7e --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/CacheManagerFactory.java @@ -0,0 +1,106 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.impl.CacheCleaner; +import com.agynamix.simidude.impl.ContentsCacheManagerImpl; + +public class CacheManagerFactory { + + static IContentsCacheManager commonCacheManager = null; + + static List inTransitDirectories = new CopyOnWriteArrayList(); + + /** + * + * For now there is only one cache manager implementation. + * @param sourceData + * @return + */ + public static IContentsCacheManager newContentsCacheManager() + { + return new ContentsCacheManagerImpl(); + } + + public static IContentsCacheManager commonContentsCacheManager() + { + if (commonCacheManager == null) + { + commonCacheManager = new ContentsCacheManagerImpl(); + } + return commonCacheManager; + } + + + public static File createTempFile(String suffix) throws IOException + { + return commonContentsCacheManager().createTempFile(suffix); + } + + /** + * Removes the contents references by this IContentsCacheInfo from the Simidude cache. + * @param cacheInfo the cacheInfo element that points to the local cache. + */ + public static void removeContentsFromCache(IContentsCacheInfo cacheInfo) + { + commonContentsCacheManager().removeContentsFromCache(cacheInfo); + } + + /** + * Is called at the start of the application. + * It will start a thread that runs in the background and deletes all cache directories that + * are left overs from an old run + */ + public static Runnable newCacheCleaner() + { + return new CacheCleaner(PlatformUtils.getApplicationCacheDir()); + } + + /** + * Adds a directory to the in-transit-directory list. + * In-Transit directories are those that just have been created and are being filled + * with data, but the directory has not yet been assigned to an ISourceData entry. + * @param directory + */ + public static void addInTransitCacheDirectory(File directory) + { + inTransitDirectories.add(directory); + } + + /** + * When CacheContents has been downloaded the directory is removed from the In-Transit list + * of directories. + * @param directory + */ + public static void removeInTransitCacheDirectory(File directory) + { + inTransitDirectories.remove(directory); + } + + /** + * Checks if a given directory is currently in transit. + * @param directory the directory to check + * @return true if the directory is in state of transit, false otherwise. + */ + public static boolean isInTransitCacheDirectory(File directory) + { + return inTransitDirectories.contains(directory); + } + +} diff --git a/src/java/com/agynamix/simidude/infra/IContentsCacheInfo.java b/src/java/com/agynamix/simidude/infra/IContentsCacheInfo.java new file mode 100644 index 0000000..6fe85b6 --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/IContentsCacheInfo.java @@ -0,0 +1,31 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +import java.io.Serializable; + +/** + * Holds information about cached files/directories + * @author tuhlmann + * + */ +public interface IContentsCacheInfo extends Serializable { + + /** + * @return the filename that was given to this item in the file cache. + */ + String getFilenameInCache(); + + boolean isDirectory(); + +} diff --git a/src/java/com/agynamix/simidude/infra/IContentsCacheManager.java b/src/java/com/agynamix/simidude/infra/IContentsCacheManager.java new file mode 100644 index 0000000..15432fd --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/IContentsCacheManager.java @@ -0,0 +1,64 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +import java.io.File; +import java.io.IOException; + +import com.agynamix.simidude.source.SourceDataContents; + +public interface IContentsCacheManager { + + String SERVICE_NAME = "ContentsCacheManager"; + String TEMP_FILE_PREFIX = "ClipText_"; + + /** + * Begin a transaction in which multiple write calls can occur to write + * received data packets into the cache. + */ + void begin(); + + /** + * Take a package of received contents and write it to the cache. + * @param contents received contents. This might not be a complete file but just part of it. + */ + void write(SourceDataContents contents); + + + /** + * Ends the current transaction + * @return a IContentsCacheInfo object that represents the stored data + */ + IContentsCacheInfo finish(); + + /** + * Remove the currently written information if the transaction has not been completed, i.e. the finish() + * method has not yet been called. + */ + void abort(); + + File createTempFile(String suffix) throws IOException; + + /** + * Remove contents from the cache + * @param cacheInfo the element that references the previously loaded contents. + */ + void removeContentsFromCache(IContentsCacheInfo cacheInfo); + + /** + * Remove content from the cache when a file or directory transaction was aborted. + * @param content the content to remove. + */ + void removeAbortedItem(SourceDataContents content); + +} diff --git a/src/java/com/agynamix/simidude/infra/IItemActivationListener.java b/src/java/com/agynamix/simidude/infra/IItemActivationListener.java new file mode 100644 index 0000000..31e4d7f --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/IItemActivationListener.java @@ -0,0 +1,9 @@ +package com.agynamix.simidude.infra; + +import com.agynamix.simidude.clipboard.IClipboardItem; + +public interface IItemActivationListener { + + void itemActivated(IClipboardItem item); + +} diff --git a/src/java/com/agynamix/simidude/infra/IItemAddedListener.java b/src/java/com/agynamix/simidude/infra/IItemAddedListener.java new file mode 100644 index 0000000..d9f1d7f --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/IItemAddedListener.java @@ -0,0 +1,9 @@ +package com.agynamix.simidude.infra; + +import com.agynamix.simidude.clipboard.IClipboardItem; + +public interface IItemAddedListener { + + void itemAdded(int insertPos, IClipboardItem item); + +} diff --git a/src/java/com/agynamix/simidude/infra/IModelChangeListener.java b/src/java/com/agynamix/simidude/infra/IModelChangeListener.java new file mode 100644 index 0000000..df644a5 --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/IModelChangeListener.java @@ -0,0 +1,19 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.infra; + + +public interface IModelChangeListener { + + void modelChanged(Object oldValue, Object newValue); + +} diff --git a/src/java/com/agynamix/simidude/infra/ISimidudePreferences.java b/src/java/com/agynamix/simidude/infra/ISimidudePreferences.java new file mode 100644 index 0000000..8b0ba9d --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/ISimidudePreferences.java @@ -0,0 +1,19 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +public interface ISimidudePreferences { + + String SENDER_ID = "simidude.sender_id"; + +} diff --git a/src/java/com/agynamix/simidude/infra/ModelProvider.java b/src/java/com/agynamix/simidude/infra/ModelProvider.java new file mode 100644 index 0000000..b59068c --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/ModelProvider.java @@ -0,0 +1,194 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; + +import com.agynamix.platform.frontend.preferences.ApplicationPreferenceDialog; +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.frontend.preferences.IPreferenceDialogListener; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ExecutorUtils; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.ConnectionUtils; +import com.agynamix.platform.net.NetworkAuthException; +import com.agynamix.platform.net.NetworkProtocolException; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.remote.RemoteConnector; +import com.agynamix.simidude.remote.RemoteRemoveItemCommand; +import com.agynamix.simidude.remote.RequestSourceDataContentCommand; +import com.agynamix.simidude.remote.SourceDataContentsCollector; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataStub; +import com.agynamix.simidude.source.ISourceData.SourceType; +import com.agynamix.simidude.source.impl.FileSourceData; + +/** + * Takes care of all things model. + * The remote onnection is hooked up here as well as the monitoring of it or + * access to model components. + * @author tuhlmann + * + */ +public class ModelProvider { + + public static final String SERVICE_NAME = "Modelprovider"; + + protected final UUID senderId; + + boolean preferenceDialogChanges = false; + + public ModelProvider(UUID senderId) + { + this.senderId = senderId; + } + + public UUID getSenderId() + { + return this.senderId; + } + + public void retrieveContentsForProxyObject(ISourceData sourceData) + { + retrieveContentsForProxyObject(sourceData, null); + } + + /** + * + * @param sourceData the sourceData item whose data should be loaded. + * @param attachedCommand The command that should be run after the data is loaded. + */ + public void retrieveContentsForProxyObject(ISourceData sourceData, Runnable attachedCommand) + { + // if item is not a local one we must ensure it holds its real data + ClientNode sourceNode = null; + try { + if (!sourceData.getSenderId().equals(getSenderId())) + { + if (sourceData.getType() == SourceType.FILE) + { + if (!(sourceData instanceof FileSourceData)) + { + throw new IllegalStateException("We can request contents only for FileSourceData objects."); + } + if (!sourceData.isCached()) + { + FileSourceData fsd = (FileSourceData) sourceData; + RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + sourceNode = remoteConnector.getConnector().getClientNode(fsd.getSenderId()); + if ((sourceNode != null) && (!sourceNode.isShutdown())) + { +// System.out.println("Get data from "+sourceNode); + ConnectionCtx connectionCtx = ConnectionUtils.connectTo(remoteConnector.getConnector(), sourceNode); + Boolean result = (Boolean) connectionCtx.invoke(new RequestSourceDataContentCommand(fsd)); + if (result.booleanValue()) + { + // Expect arriving data + ExecutorUtils.addParallelTask(new SourceDataContentsCollector(connectionCtx, ((FileSourceData)sourceData), attachedCommand)); + } else { + PlatformUtils.showToggleErrorMessage("Client not reachable", "The client with the address "+sourceNode.getAddress().getHostAddress()+" can not be reached.\nMaybe the client is no longer running?", IPreferenceConstants.DIALOG_HOST_NOT_FOUND_ERR_SHOW); + ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager().removeAndDontRemember(sourceData.getStub()); + } + } else { + PlatformUtils.showToggleErrorMessage("Client not found", "The client that recorded this item can no longer be found.\nMaybe it is no longer running?", IPreferenceConstants.DIALOG_DOWNLOAD_ERR_SHOW); + // Remove the item from our list + ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager().removeAndDontRemember(sourceData.getStub()); + } + } + } + } + } catch (NetworkProtocolException e) + { + e.printStackTrace(); + } catch (IOException e) { + if (sourceNode != null) + { + PlatformUtils.showErrorMessageWithException("Client not reachable", "The client with the address "+sourceNode.getAddress().getHostAddress()+" can not be reached.\nMaybe the client is no longer running?", e); + } else { + e.printStackTrace(); + } + } catch (NetworkAuthException e) + { + e.printStackTrace(); + } + + } + + public void openPreferencesDialog(Shell shell) + { + preferenceDialogChanges = false; + ApplicationPreferenceDialog preferences = new ApplicationPreferenceDialog(shell); + preferences.addPreferenceDialogListener(new IPreferenceDialogListener(){ + public void propertyChange(PropertyChangeEvent event) + { + preferenceDialogChanges = true; + } + public void dialogClosed(int result) + { + if ((result == Window.OK) && (preferenceDialogChanges)) + { + // do we need to react on changes + } + } + }); + preferences.open(); + } + + /** + * Calls all connected clients to tell them to remove the given item from their + * ClipboardTable. If the argument is null, all items will be removed. + * This command will be executed in a separate thread in order to not slow down the application. + * @param item the item to remove from all connected clients. If the given item is null then + * all items are removed. + */ + public void networkRemoveItem(final SourceDataStub sourceDataStub) + { + final RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + List connectedClients = remoteConnector.getConnector().getConnectedClientList(); + networkRemoveItem(connectedClients, sourceDataStub); + } + + public void networkRemoveItem(final List connectedClients, final SourceDataStub sourceDataStub) + { + final RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + ExecutorUtils.addParallelTask(new Runnable(){ + public void run() + { + for (ClientNode client : connectedClients) + { + try + { + if (!client.equals(remoteConnector.getConnector().getMyOwnNode())) + { + ConnectionCtx connectionCtx = ConnectionUtils.connectTo(remoteConnector.getConnector(), client); + connectionCtx.invoke(new RemoteRemoveItemCommand(connectedClients, sourceDataStub)); + connectionCtx.disconnect(); + } + } catch (Exception e) + { + e.printStackTrace(); + } + } + } + }); + } + +} diff --git a/src/java/com/agynamix/simidude/infra/SimidudeUtils.java b/src/java/com/agynamix/simidude/infra/SimidudeUtils.java new file mode 100644 index 0000000..c39c6e7 --- /dev/null +++ b/src/java/com/agynamix/simidude/infra/SimidudeUtils.java @@ -0,0 +1,189 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.infra; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.program.Program; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + +public class SimidudeUtils { + + static int currentModifierKey = 0; + + static List mimePrograms = null; + + public static void launchDefaultImageEditor(File f) + { + findAndlaunchApplication(IPreferenceConstants.DEFAULT_IMAGE_EDITOR, f.getAbsolutePath()); + } + + public static void launchDefaultTextEditor(File f) + { + findAndlaunchApplication(IPreferenceConstants.DEFAULT_TEXT_EDITOR, f.getAbsolutePath()); + } + + public static void launchDefaultFileBowser(FileSourceData fileSourceData) + { + findAndlaunchApplication(IPreferenceConstants.DEFAULT_FILE_BROWSER, fileSourceData.getLocalFilename()); + } + + + public static void findAndlaunchApplication(String appTypePrefName, String arg) + { + String defaultApplication = ApplicationBase.getContext().getConfiguration().getProperty(appTypePrefName); + if (isEmpty(defaultApplication)) + { +// System.out.println("Execute Standard Application"); + launchStandardApplication(arg); + } else { + File app = new File(defaultApplication); + if (!app.exists()) + { + Program program = findProgram(defaultApplication); + if (program != null) + { +// System.out.println("Launch Found Program "+program.getName()); + program.execute(arg); + } else { +// System.out.println("No program found, launch standard app"); + launchStandardApplication(arg); + } + } else { +// System.out.println("launch app: "+app); + launchApplication(app, arg); + } + } + } + + public static void launchApplication(File app, String args) + { + try { + String[] cmdArgs = null; + if (PlatformUtils.isMacOs()) + { + cmdArgs = new String[] {"open", "-a", app.getAbsolutePath(), args}; + } else { + cmdArgs = new String[] {app.getAbsolutePath(), args}; + } + Runtime.getRuntime().exec(cmdArgs); + } catch (Exception err) { + err.printStackTrace(); + } + } + + public static List getMimePrograms() + { + if (mimePrograms == null) + { + mimePrograms = new ArrayList(); + for (Program p : Program.getPrograms()) + { + mimePrograms.add(p); + } + } + return mimePrograms; + } + + public static Program findProgram(String appName) + { + for (Program p : getMimePrograms()) + { + if (p.getName().equalsIgnoreCase(appName)) + { + return p; + } + } + return null; + } + + public static void launchURI(TextSourceData textSourceData) + { + Program.launch(textSourceData.getText()); + } + + public static void launchStandardApplication(String arg) + { + Program.launch(arg); + } + + public static synchronized void keyPressed(int keyCode) + { + if (isSupportedModifierKey(keyCode)) + { + currentModifierKey |= keyCode; +// System.out.println("currentModifierKey (pressed)= "+currentModifierKey); + } + } + + public static synchronized void keyReleased(int keyCode) + { + if (isSupportedModifierKey(keyCode)) + { + currentModifierKey = currentModifierKey ^ keyCode; +// System.out.println("currentModifierKey (released)= "+currentModifierKey); + } + } + + public static synchronized boolean isModifierKeyPressed() + { + int modifierKey = ApplicationBase.getContext().getConfiguration().getInteger(IPreferenceConstants.MODIFIER_KEY); +// System.out.println("Modifier: "+modifierKey); + boolean isPressed = (currentModifierKey & modifierKey) != 0; +// System.out.println("Pressed: "+isPressed); + return isPressed; + } + + public static boolean isSupportedModifierKey(int keyCode) + { + return ((keyCode == SWT.SHIFT) || (keyCode == SWT.COMMAND) || (keyCode == SWT.CONTROL) || (keyCode == SWT.ALT)); + } + + public static String getKeyCodeName(int keyCode) + { + String name = "unknown"; + if (keyCode == SWT.SHIFT) + { + name = "Shift"; + } else if (keyCode == SWT.COMMAND) + { + if (PlatformUtils.isMacOs()) + { + name = "Apple"; + } else { + name = "Win"; + } + } else if (keyCode == SWT.CONTROL) + { + name = "Ctrl"; + } else if (keyCode == SWT.ALT) + { + name = "Alt"; + } + return name; + } + + public static boolean isEmpty(String string) + { + return ((string == null) || (string.length() == 0)); + } + +} diff --git a/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsCommand.java b/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsCommand.java new file mode 100644 index 0000000..823be73 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsCommand.java @@ -0,0 +1,81 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.util.ArrayList; +import java.util.List; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.SourceDataStub; + +public class CompareSourceDataStubListsCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + protected final List localSourceDataEntries; + protected final List removedLocalSourceDataEntries; + + public CompareSourceDataStubListsCommand(List localSourceDataEntries, List removedSourceDataEntries) + { + this.localSourceDataEntries = localSourceDataEntries; + this.removedLocalSourceDataEntries = removedSourceDataEntries; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + List remoteSourceDataEntries = sdm.getSourceDataStubEntries(); + List removedRemoteSourceDataEntries = sdm.getRemovedSourceDataStubEntries(); + + CompareSourceDataStubListsResult result = compareStubLists(sdm, localSourceDataEntries, removedLocalSourceDataEntries, + remoteSourceDataEntries, removedRemoteSourceDataEntries); + return result; + } + + private CompareSourceDataStubListsResult compareStubLists(SourceDataManager sdm, + List localSourceDataEntries, List removedLocalSourceDataEntries, + List remoteSourceDataEntries, List removedRemoteSourceDataEntries) + { + // First find out the entries we lack + List locallyMissingEntries = new ArrayList(); + for (SourceDataStub stub : remoteSourceDataEntries) + { + if ((!localSourceDataEntries.contains(stub)) && (!removedLocalSourceDataEntries.contains(stub))) + { + locallyMissingEntries.add(stub); + } + } + + // Now find the entries this peer does not have + List remotelyMissingEntries = new ArrayList(); + for (SourceDataStub stub : localSourceDataEntries) + { + if ((!remoteSourceDataEntries.contains(stub)) && (!removedRemoteSourceDataEntries.contains(stub))) + { + remotelyMissingEntries.add(stub); + } + } + + return new CompareSourceDataStubListsResult(locallyMissingEntries, remotelyMissingEntries); + } + + public List getLocalSourceDataStubs() + { + return this.localSourceDataEntries; + } + +} diff --git a/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsResult.java b/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsResult.java new file mode 100644 index 0000000..2cbb4b1 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/CompareSourceDataStubListsResult.java @@ -0,0 +1,44 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.Serializable; +import java.util.List; + +import com.agynamix.simidude.source.SourceDataStub; + +public class CompareSourceDataStubListsResult implements Serializable { + + private static final long serialVersionUID = 1L; + + protected final List locallyMissingEntries; + protected final List remotelyMissingEntries; + + + public CompareSourceDataStubListsResult(List locallyMissingEntries, List remotelyMissingEntries) + { + this.locallyMissingEntries = locallyMissingEntries; + this.remotelyMissingEntries = remotelyMissingEntries; + } + + public List getLocallyMissingEntries() + { + return this.locallyMissingEntries; + } + + public List getRemotelyMissingEntries() + { + return this.remotelyMissingEntries; + } + +} diff --git a/src/java/com/agynamix/simidude/remote/ContentsLoaderException.java b/src/java/com/agynamix/simidude/remote/ContentsLoaderException.java new file mode 100644 index 0000000..9eb365c --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/ContentsLoaderException.java @@ -0,0 +1,44 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.File; + +public class ContentsLoaderException extends Exception { + + private static final long serialVersionUID = 1L; + + private final File file; + + public ContentsLoaderException(File file, Throwable cause) + { + super(cause); + this.file = file; + } + + public File getFile() + { + return this.file; + } + + public String getFilename() + { + String fname = "unknown"; + if (file != null) + { + fname = file.getAbsolutePath(); + } + return fname; + } + +} diff --git a/src/java/com/agynamix/simidude/remote/RemoteConnector.java b/src/java/com/agynamix/simidude/remote/RemoteConnector.java new file mode 100644 index 0000000..66f0d91 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RemoteConnector.java @@ -0,0 +1,267 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.frontend.preferences.IPreferenceConstants; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.ExecutorUtils; +import com.agynamix.platform.infra.Tupel; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.ConnectionUtils; +import com.agynamix.platform.net.Connector; +import com.agynamix.platform.net.IConnector; +import com.agynamix.platform.net.IPacketReceivedListener; +import com.agynamix.platform.net.NetworkAuthException; +import com.agynamix.platform.net.NetworkProtocolException; +import com.agynamix.platform.net.protocol.NodeCommand; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceDataListener; +import com.agynamix.simidude.source.SourceQueueService; +import com.agynamix.simidude.source.ISourceData.TransportType; + + +public class RemoteConnector implements ISourceDataListener, IPacketReceivedListener { + + public static final String SERVICE_NAME = "RemoteConnector"; + + Connector connector; + SourceDataSynchronizer sourceDataSynchronizer; + + Logger log = ApplicationLog.getLogger(RemoteConnector.class); + + public RemoteConnector() + { + + } + + public void shutdown() + { + if (connector != null) + { + connector.shutdown(); + connector = null; + } + } + + public void initializeConnector(ModelProvider modelProvider) + { + String groupName = ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.NODE_GROUP_NAME); + String groupPassword = ApplicationBase.getContext().getConfiguration().getProperty(IPreferenceConstants.NODE_GROUP_PWD); + int helloPort = ApplicationBase.getContext().getConfiguration().getInteger(IPreferenceConstants.HELLO_PORT); + int serverPort = ApplicationBase.getContext().getConfiguration().getInteger(IPreferenceConstants.SERVER_PORT); + + connector = new Connector(modelProvider.getSenderId(), groupName, groupPassword, helloPort, serverPort); + connector.initialize(); + } + + public void establishConnection() + { + log.info("Start SimiDude's RemoteConnector"); + + connector.run(); + + sourceDataSynchronizer = new SourceDataSynchronizer(this); + ExecutorUtils.addScheduledService(sourceDataSynchronizer, 10, 10, TimeUnit.SECONDS); + + SourceQueueService qs = (SourceQueueService) ApplicationBase.getContext().getService(SourceQueueService.SERVICE_NAME); + qs.addSourceDataListener(this); + +// WorkbenchUtils.setConnected(); + + // Get all existing items from server + +// if (c.getConnectionState() == ConnectionState.BROKEN) +// { +// PlatformUtils.setConnectionBroken(); +// } + +// connector.addPacketReceivedListener(this); + + } + + /** + * In the preferences there is now a possibility to add permanent IP addresses or network names. These addresses are now added to the connector list + * as if they had made a connection attempt. + * @since 1.3.0 + * @param connector + */ + public void contactPermanentNetworkAddresses() + { + ExecutorUtils.addParallelTask(new Runnable() { + public void run() + { + List networkAddresses = ApplicationBase.getContext().getConfiguration().getProperyList(IPreferenceConstants.PERMANENT_NETWORK_ADDRESSES); + for (String address : networkAddresses) + { + Tupel ipAndPort = getIPAddressAndPort(getConnector(), address); + if (ipAndPort != null) + { + if (ipAndPort.getValue1() != null) + { + ClientNode node = requestClientNode(getConnector(), ipAndPort.getValue1(), ipAndPort.getValue2()); + if (node != null) + { + try + { +// System.out.println("ClientNode returned. Put into RequestorQueue"); + getConnector().getRequestorQueue().put(node); + } catch (InterruptedException e) {} +// } else { +// System.out.println("ClientNode returned NULL"); + } + } + } else { + log.warning("Could not parse permanent address: "+address); + } + } + } + }); + + } + + /** + * Connect a remote client and request its ClientNode data + * @param ipAddress the ip address to contact + * @param port the port to contact + * @return a ClientNode instance or null if a connection was unsuccessful + */ + private ClientNode requestClientNode(IConnector connector, String ipAddress, Integer port) + { + try + { + return ConnectionUtils.requestClientId(connector, ipAddress, port); + } catch (Exception e) + { +// e.printStackTrace(); + return null; + } + } + + private Tupel getIPAddressAndPort(IConnector connector, String address) + { + String[] arr = address.split(":"); + java.net.InetAddress inetAdd; + try + { + inetAdd = java.net.InetAddress.getByName(arr[0]); +// System.out.println ("IP Address is for Name "+arr[0]+": " + inetAdd.getHostAddress()); + return new Tupel(inetAdd.getHostAddress(), arr.length == 2 ? Integer.parseInt(arr[1]) : connector.getServerPort()); + } catch (UnknownHostException e) + { +// e.printStackTrace(); + log.log(Level.INFO, "Could not connect to "+address, e); + } + return null; + } + + public IConnector getConnector() + { + return this.connector; + } + + public void sourceDataChanged(ISourceData data) + { + // send received data to server + if (data.getTransportType() != TransportType.remote) + { + transportItem(data); + } + } + + public void transportItem(ISourceData data) + { +// System.out.println("TransportItem: "+data.getText()); + ISourceData sourceData = data.copy(); + sourceData.setTransportType(TransportType.remote); + + IConnector connector = getConnector(); + send(connector.getConnectedClientList(), sourceData); + } + + /** + * Responsible to send data out to other clients + * @param serializer + */ + private void send(List nodes, ISourceData sourceData) + { + for (ClientNode node : nodes) + { + if ((!node.equals(connector.getMyOwnNode())) && (!node.isShutdown())) + { + try { + send(node, sourceData); + } catch (IOException e) + { + log.warning("Communication with "+node.getAddress().getHostAddress()+" not possible"); + } + } + } + } + + private void send(ClientNode node, ISourceData sourceData) throws IOException + { + ConnectionCtx connectionCtx = null; + try { + connectionCtx = ConnectionUtils.connectTo(connector, node); +// System.out.println("Send ISourceData to "+node); + connectionCtx.invoke(new TransportSourceDataCommand(sourceData)); + connectionCtx.disconnect(); + } catch (NetworkAuthException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } catch (NetworkProtocolException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } finally { + if (connectionCtx != null) + { + connectionCtx.close(); + } + } + } + +// public void uploadSourceDataContents(SourceDataContents contents) +// { +// transporter.uploadSourceDataContents(contents); +// } + + public void packetReceived(NodeCommand command) + { +// if (ICommands.CLIE.equals(command.getCommand())) +// { +// System.out.println("packetReceived: CLIE"); +// parallelTasks.submit(new RetrieveExistingSourceDataTask(connector)); +// } + } + +// public SourceDataContents requestContentsForProxyObject(ISourceData sourceData) +// { +// RemoteSourceDataTransportMBean transporter = getRemoteSourceDataTransportDelegate(); +// System.out.println("request contents"); +// SourceDataContents sd = transporter.requestContentsForProxyObject(sourceData); +// System.out.println("Return from request"); +// return sd; +// } + + +} diff --git a/src/java/com/agynamix/simidude/remote/RemoteException.java b/src/java/com/agynamix/simidude/remote/RemoteException.java new file mode 100644 index 0000000..a91ca41 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RemoteException.java @@ -0,0 +1,25 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +public class RemoteException extends Exception { + + private static final long serialVersionUID = 1L; + + public RemoteException(Exception cause) + { + super(cause); + } + + +} diff --git a/src/java/com/agynamix/simidude/remote/RemoteRemoveItemCommand.java b/src/java/com/agynamix/simidude/remote/RemoteRemoveItemCommand.java new file mode 100644 index 0000000..c6942ab --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RemoteRemoveItemCommand.java @@ -0,0 +1,70 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.util.ArrayList; +import java.util.List; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.SourceDataStub; + +public class RemoteRemoveItemCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + private final List connectedClients; + private final SourceDataStub sourceDataStub; + + public RemoteRemoveItemCommand(List connectedClients, SourceDataStub sourceDataStub) + { + this.connectedClients = connectedClients; + this.sourceDataStub = sourceDataStub; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + ModelProvider mp = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + if (sourceDataStub == null) + { + sdm.removeAll(); + } else { + sdm.removeItem(sdm.getClipboardItem(sourceDataStub)); + } + + RemoteConnector remoteConnector = ((SimidudeApplicationContext)ApplicationBase.getContext()).getRemoteConnector(); + List thisPeerConnectedClients = remoteConnector.getConnector().getConnectedClientList(); + List notYetReachedList = new ArrayList(); + for (ClientNode client : thisPeerConnectedClients) + { + if (!connectedClients.contains(client)) + { + notYetReachedList.add(client); + } + } + if (notYetReachedList.size() > 0) + { + mp.networkRemoveItem(notYetReachedList, sourceDataStub); + } + + return Boolean.TRUE; + } + +} diff --git a/src/java/com/agynamix/simidude/remote/RequestSourceDataContentCommand.java b/src/java/com/agynamix/simidude/remote/RequestSourceDataContentCommand.java new file mode 100644 index 0000000..128ad60 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RequestSourceDataContentCommand.java @@ -0,0 +1,46 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.File; + +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.source.impl.FileSourceData; + +public class RequestSourceDataContentCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + final FileSourceData sourceData; + + public RequestSourceDataContentCommand(FileSourceData sourceData) + { + this.sourceData = sourceData; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + File f = sourceData.getFile(); +// if (f.exists() && f.canRead()) +// { +// We catch any error directly when trying to load the file and then report the failed file back. + // FIXME: Diese Abfrage darf erst Daten liefern, nachdem die invoke-Funktion zurückgekehrt ist!!! + connectorServerHandler.executeParallel(new SourceDataContentsUploader(connectorServerHandler, sourceData)); + return Boolean.TRUE; +// } else { +// return Boolean.FALSE; +// } + } + +} diff --git a/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataCommand.java b/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataCommand.java new file mode 100644 index 0000000..b9150ed --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataCommand.java @@ -0,0 +1,53 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.util.ArrayList; +import java.util.List; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.ISourceData.TransportType; + +public class RetrieveExistingSourceDataCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + return retrieveExistingSourceData(); + } + + public List retrieveExistingSourceData() + { + List itemList = new ArrayList(); + + SourceDataManager tm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + List clipboardItems = tm.getClipboardItems(); + + for (IClipboardItem ci : clipboardItems) + { + ISourceData d = ci.getSourceData(); + d.setTransportType(TransportType.remote); + itemList.add(d); + } + + return itemList; + } + +} diff --git a/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataTask.java b/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataTask.java new file mode 100644 index 0000000..3f8d657 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/RetrieveExistingSourceDataTask.java @@ -0,0 +1,114 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.ConnectionUtils; +import com.agynamix.platform.net.IConnector; +import com.agynamix.platform.net.NetworkAuthException; +import com.agynamix.platform.net.NetworkProtocolException; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; + +/** + * Task is used to retrieve source data from other connected peers. + * Once a connection to other peers is established this task is started in a seperate thread + * to retrieve source data items from all other instances, merge them together and + * populate the source data table. + * @author tuhlmann + * + */ +public class RetrieveExistingSourceDataTask implements Callable { + + final IConnector connector; + + public RetrieveExistingSourceDataTask(IConnector connector) + { + this.connector = connector; + } + + public Boolean call() throws Exception + { +// System.out.println("RETRIEVE existing SourceData"); + try { + retrieveExistingSourceData(); + return Boolean.TRUE; + } catch (Exception e) + { + e.printStackTrace(); + return Boolean.FALSE; + } + } + + /** + * Doing: + * Nachdem eine Node eine Clientliste gesendet hat, diese Funktion für jeden Knoten + * (außer dem eigenen) aufrufen. + * @throws IOException + * @throws NetworkProtocolException + * @throws NetworkAuthException + */ + public void retrieveExistingSourceData() throws IOException, NetworkProtocolException, NetworkAuthException + { + List completeItemList = new ArrayList(); + List clients = connector.getConnectedClientList(); + for (ClientNode node : clients) + { + if ((!node.equals(connector.getMyOwnNode())) && (!node.isShutdown())) + { +// System.out.println("RETRIEVE: get SourecData from "+node); + ConnectionCtx connectionCtx = ConnectionUtils.connectTo(connector, node); + RetrieveExistingSourceDataCommand cmd = new RetrieveExistingSourceDataCommand(); + List nodeItems = (List) connectionCtx.invoke(cmd); + mergeNodeItems(completeItemList, nodeItems); + } + } + IQueueManager qm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); +// System.out.println("retrieveExistingSourceData"); + qm.putAllReverse(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, completeItemList); + } + + private void mergeNodeItems(List completeItemList, List nodeItems) + { + for (ISourceData data : nodeItems) + { + if (!listContains(completeItemList, data)) + { + completeItemList.add(data); + } + } + } + + private boolean listContains(List completeItemList, ISourceData sourceData) + { + for (ISourceData data : completeItemList) + { + if (data.getSourceId().equals(sourceData.getSourceId())) + { + return true; + } + } + return false; + } + + + +} diff --git a/src/java/com/agynamix/simidude/remote/SourceDataContentsCollector.java b/src/java/com/agynamix/simidude/remote/SourceDataContentsCollector.java new file mode 100644 index 0000000..f0ba7b6 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/SourceDataContentsCollector.java @@ -0,0 +1,157 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; + +import com.agynamix.platform.frontend.gui.ApplicationGUI; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.PlatformUtils; +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.NetworkProtocolException; +import com.agynamix.platform.net.protocol.Expt; +import com.agynamix.platform.net.protocol.ICommands; +import com.agynamix.platform.net.protocol.NodeCommand; +import com.agynamix.platform.net.protocol.Objt; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.infra.IContentsCacheInfo; +import com.agynamix.simidude.infra.IContentsCacheManager; +import com.agynamix.simidude.source.SourceDataContents; +import com.agynamix.simidude.source.impl.FileSourceData; + +public class SourceDataContentsCollector implements Runnable { + + final ConnectionCtx connectionCtx; + final FileSourceData fileSourceData; + final Runnable attachedCommand; + + public SourceDataContentsCollector(ConnectionCtx connectionCtx, FileSourceData fileSourceData, Runnable attachedCommand) + { + this.connectionCtx = connectionCtx; + this.fileSourceData = fileSourceData; + this.attachedCommand = attachedCommand; + } + + public void run() + { + ApplicationGUI gui = ApplicationBase.getContext().getApplicationGUI(); + IProgressMonitor pm = gui.getStatusLineManager().getProgressMonitor(); + requestContentsForProxyObject(pm, connectionCtx, fileSourceData); + if (attachedCommand != null) + { + try { + attachedCommand.run(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + } + + protected void requestContentsForProxyObject(final IProgressMonitor pm, final ConnectionCtx connectionCtx, FileSourceData sourceData) + { + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + pm.beginTask("Download from "+connectionCtx.getHostAddress(), IProgressMonitor.UNKNOWN); + } + }); + IContentsCacheManager cacheManager = CacheManagerFactory.newContentsCacheManager(); + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + sdm.setDownloadInProgress(sourceData, true); + List failedDownloads = new ArrayList(); + try { + SourceDataContents contents = null; + boolean isFinished = false; + cacheManager.begin(); + boolean isFollowUp = false; + while ((!isFinished) && ((contents = readSourceDataContentsPackage(connectionCtx)) != null)) + { + isFollowUp = true; + if (contents.isLastPackage()) + { + isFinished = true; + } else if (contents.isAborted()) { + failedDownloads.add(contents); + cacheManager.removeAbortedItem(contents); + } else { + cacheManager.write(contents); + } + } + IContentsCacheInfo cacheInfo = cacheManager.finish(); + if (cacheInfo != null) { + sourceData.setContentsCacheInfo(cacheInfo); + } + + // Change appearance of this IClipboardItem + sdm.contentsReceived(failedDownloads); + } catch (RemoteException e) + { + Throwable t = e.getCause(); + System.out.println("Exception occured on the client: "+t.getMessage()); + if (t instanceof ContentsLoaderException) + { + ContentsLoaderException clE = (ContentsLoaderException) t; + PlatformUtils.showErrorMessageWithException("Error while downloading contents", + "The connected client at "+connectionCtx.getHostAddress()+" experienced a problem\nreading the ressource "+ + clE.getFilename()+"\nThe client might not be able to read the ressource.", t); + } else { + PlatformUtils.showErrorMessageWithException("Error while downloading contents", + "The connected client at "+connectionCtx.getHostAddress()+" experienced a problem:\n"+t.getMessage(), t); + } + cacheManager.abort(); + } catch (IOException e) + { + e.printStackTrace(); + cacheManager.abort(); + } catch (NetworkProtocolException e) + { + e.printStackTrace(); + cacheManager.abort(); + } finally { + connectionCtx.disconnect(); + sdm.setDownloadInProgress(sourceData, false); + PlatformUtils.safeAsyncRunnable(new Runnable() { + public void run() + { + pm.done(); + } + }); + } + + } + + private SourceDataContents readSourceDataContentsPackage(ConnectionCtx connectionCtx) throws IOException, NetworkProtocolException, RemoteException + { + NodeCommand nodeCmd = connectionCtx.getNodeCommandUtils().receiveCommand(); + if (ICommands.OBJT.equals(nodeCmd.getCommand())) + { + Objt objt = (Objt) nodeCmd; + return (SourceDataContents) objt.getObject(); + } else if (ICommands.EXPT.equals(nodeCmd.getCommand())) + { + Expt expt = (Expt) nodeCmd; + throw new RemoteException(expt.getException()); + } else { + throw new NetworkProtocolException("Expected OBJT, but got "+nodeCmd.getCommand()); + } + } + + +} diff --git a/src/java/com/agynamix/simidude/remote/SourceDataContentsUploader.java b/src/java/com/agynamix/simidude/remote/SourceDataContentsUploader.java new file mode 100644 index 0000000..7f7cf15 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/SourceDataContentsUploader.java @@ -0,0 +1,70 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.IOException; + +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.clipboard.SourceDataContentsLoader; +import com.agynamix.simidude.source.SourceDataContents; +import com.agynamix.simidude.source.impl.FileSourceData; + +public class SourceDataContentsUploader implements Runnable { + + final FileSourceData sourceData; + final IConnectorServerHandler connectorServerHandler; + + public SourceDataContentsUploader(IConnectorServerHandler connectorServerHandler, FileSourceData sourceData) + { + this.connectorServerHandler = connectorServerHandler; + this.sourceData = sourceData; + } + + public void run() + { + try + { + try + { + Thread.sleep(200); + } catch (InterruptedException ignore){} // Wait until the instantiating method has returned. + + SourceDataContentsLoader loader = new SourceDataContentsLoader(sourceData); + SourceDataContents contents = null; + while ((contents = loader.loadContents()) != null) + { + connectorServerHandler.sendSourceDataContents(contents); + } +// } catch (ContentsLoaderException e) +// { +// System.out.println("Error while trying to send file: "+e.getFile()); +//// e.printStackTrace(); +// abortTransaction(e); + } catch (IOException e) + { + System.out.println("Connection error: "+e.getMessage()); + abortTransaction(e); + } + } + + private void abortTransaction(Exception exception) + { + try { + connectorServerHandler.sendException(exception); + } catch (IOException e2) + { + System.out.println("Error sending abort signal: "+e2.getMessage()); + } + } + +} diff --git a/src/java/com/agynamix/simidude/remote/SourceDataSynchronizer.java b/src/java/com/agynamix/simidude/remote/SourceDataSynchronizer.java new file mode 100644 index 0000000..670a9c9 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/SourceDataSynchronizer.java @@ -0,0 +1,220 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.agynamix.platform.concurrent.ThreadManagerAware; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.ClientNode; +import com.agynamix.platform.net.ConnectionCtx; +import com.agynamix.platform.net.ConnectionUtils; +import com.agynamix.platform.net.IConnector; +import com.agynamix.platform.net.NetworkAuthException; +import com.agynamix.platform.net.NetworkProtocolException; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataStub; +import com.agynamix.simidude.source.ISourceData.TransportType; + +/** + * SourceDataSynchronizer wird verwendet, um periodisch die ISourceData-Einträge der verbundenen + * Simidude-Clients miteinander abzugleichen. Wenn also ein Client eine Zeitlang mit + * anderen nicht verbunden war, so werden die fehlenden Einträge trotzdem periodisch angestoßen. + * @author tuhlmann + * + */ +public class SourceDataSynchronizer implements ThreadManagerAware { + + Logger log = ApplicationLog.getLogger(SourceDataSynchronizer.class); + + final RemoteConnector remoteConnector; + + public final static int CALL_COUNT_UNTIL_RUN = 6; // runs each minute + + List lastRunClientList = new ArrayList(); + int callCount = 0; + + boolean shouldStop = false; + + public SourceDataSynchronizer(RemoteConnector remoteConnector) + { + this.remoteConnector = remoteConnector; + } + + /** + * Der Executor wird alle 10s gestartet, soll aber nicht immer etwas unternehmen. + * Die Vorgehensweise ist wie folgt: + *
    + *
  • Wenn seit dem letzten Aufruf neue Nodes zu unserer Liste hinzugefügt wurden, dann wird synchronisiert
  • + *
  • Wenn keine neuen Nodes hinzugekommen sind, dann wird nur bei jedem X-ten Aufruf etwas unternommen.
  • + *
+ */ + public void run() + { + if (!shouldStop) + { + callCount++; + IConnector connector = remoteConnector.getConnector(); + List connectedClients = connector.getConnectedClientList(); + ClientNode myOwnNode = remoteConnector.getConnector().getMyOwnNode(); + if (callCount >= CALL_COUNT_UNTIL_RUN) + { + callCount = 0; + synchronizeSourceData(connector, myOwnNode, connectedClients); + } else { + if (isNewClientsConnected(lastRunClientList, connectedClients)) + { +// System.out.println("New clients connected"); + synchronizeSourceData(connector, myOwnNode, connectedClients); + } + } + lastRunClientList.clear(); + lastRunClientList.addAll(connectedClients); + } + } + + /** + * Go to our peers and get the SourceDataStub items. + * We only get those that are visible in the Clipboard table, not those that have been cleared out. + */ + private void synchronizeSourceData(IConnector connector, ClientNode myOwnNode, List connectedClients) + { + for (ClientNode node : connectedClients) + { + if ((!node.equals(myOwnNode)) && (!node.isShutdown())) + { +// System.out.println("SourceDataSynchronizer: Contact "+node); + try + { + synchronizeSourceData(connector, node); + } catch (IOException e) + { + log.log(Level.FINE, e.getMessage(), e); + } catch (NetworkAuthException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } catch (NetworkProtocolException e) + { + log.log(Level.WARNING, e.getMessage(), e); + } + } + } + + } + + /** + * Synchronize SourceData with a specific peer. Algorithm: + *
    + *
  • connect to the node
  • + *
  • send a list of our visible SourceDataStubs
  • + *
  • the peer sends back two lists: + *
      + *
    • The first List contains the items we do not yet have
    • + *
    • The second List contains the items the peer requests from us.
    • + *
    + *
+ * @param node the peer to contact. + * @throws NetworkAuthException + * @throws IOException + * @throws NetworkProtocolException + */ + @SuppressWarnings("unchecked") + private void synchronizeSourceData(IConnector connector, ClientNode node) throws IOException, NetworkAuthException, NetworkProtocolException + { + ConnectionCtx connectionCtx = ConnectionUtils.connectTo(connector, node); + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + List mySourceDataEntries = sdm.getSourceDataStubEntries(); + List myRemovedSourceDataEntries = sdm.getRemovedSourceDataStubEntries(); + CompareSourceDataStubListsResult result = (CompareSourceDataStubListsResult) connectionCtx.invoke(new CompareSourceDataStubListsCommand(mySourceDataEntries, myRemovedSourceDataEntries)); + List stubsForEntriesWeWant = getNeededSourceDataEntryList(sdm, result.getLocallyMissingEntries()); + List entriesRemoteWants = assembleRemotelyNeededEntries(sdm, result.getRemotelyMissingEntries()); + if ((stubsForEntriesWeWant.size() > 0) || (entriesRemoteWants.size() > 0)) + { + List entriesWeWant = (List) connectionCtx.invoke(new TransmitSourceDataStubListsCommand(stubsForEntriesWeWant, entriesRemoteWants)); + IQueueManager qm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + qm.putAllReverse(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, entriesWeWant); + } + connectionCtx.disconnect(); + } + + private List getNeededSourceDataEntryList(SourceDataManager sdm, List locallyMissingEntries) + { + List stubsForEntriesWeWant = new ArrayList(); + for (SourceDataStub stub : locallyMissingEntries) + { + if (sdm.getClipboardItem(stub) == null) + { + stubsForEntriesWeWant.add(stub); + } + } + return stubsForEntriesWeWant; + } + + private List assembleRemotelyNeededEntries(SourceDataManager sdm, List remotelyMissingEntries) + { + List entriesRemoteWants = new ArrayList(); + for (SourceDataStub stub : remotelyMissingEntries) + { + IClipboardItem item = sdm.getClipboardItem(stub); + if (item != null) + { + ISourceData sourceData = item.getSourceData().copy(); + sourceData.setTransportType(TransportType.remote); + entriesRemoteWants.add(sourceData); + } else { + System.out.println("WARN: No ClipboardItem found for remotely wanted item with stub "+stub); + } + } + return entriesRemoteWants; + } + + /** + * Checks if new clients have connected since our last run + * @param lastRunClientList list of clients connected the last time we ran. + * @param connectedClients connected clients + * @return true if new clients have connected, false otherwise. + */ + private boolean isNewClientsConnected(List lastRunClientList, List connectedClients) + { + for (ClientNode node : connectedClients) + { + if (!lastRunClientList.contains(node)) + { +// System.out.println("SourceDataSynchronizer: New Node detected: "+node); + return true; + } + } + return false; + } + + public String getId() + { + return "SourceDataSynchronizer"; + } + + public void shutdown() + { + shouldStop = true; + } + + +} diff --git a/src/java/com/agynamix/simidude/remote/TransmitSourceDataStubListsCommand.java b/src/java/com/agynamix/simidude/remote/TransmitSourceDataStubListsCommand.java new file mode 100644 index 0000000..9c26608 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/TransmitSourceDataStubListsCommand.java @@ -0,0 +1,72 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.clipboard.IClipboardItem; +import com.agynamix.simidude.clipboard.SourceDataManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataStub; +import com.agynamix.simidude.source.ISourceData.TransportType; + +public class TransmitSourceDataStubListsCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + final List stubsForEntriesWeWant; + final List entriesRemoteWants; + + public TransmitSourceDataStubListsCommand(List stubsForEntriesWeWant, List entriesRemoteWants) + { + this.stubsForEntriesWeWant = stubsForEntriesWeWant; + this.entriesRemoteWants = entriesRemoteWants; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + SourceDataManager sdm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getSourceDataManager(); + List entriesWeWant = new ArrayList(); + for (SourceDataStub stub : stubsForEntriesWeWant) + { + IClipboardItem item = sdm.getClipboardItem(stub); + if (item != null) + { + ISourceData sourceData = item.getSourceData().copy(); + sourceData.setTransportType(TransportType.remote); + entriesWeWant.add(sourceData); + } else { + getLogger().warning("WARN: No ClipboardItem found for stub "+stub); + } + } + if (entriesRemoteWants.size() > 0) + { + IQueueManager qm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + qm.putAllReverse(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, entriesRemoteWants); + } + return entriesWeWant; + } + + private Logger getLogger() + { + return ApplicationLog.getLogger(TransmitSourceDataStubListsCommand.class); + } +} diff --git a/src/java/com/agynamix/simidude/remote/TransportSourceDataCommand.java b/src/java/com/agynamix/simidude/remote/TransportSourceDataCommand.java new file mode 100644 index 0000000..47525b3 --- /dev/null +++ b/src/java/com/agynamix/simidude/remote/TransportSourceDataCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.remote; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.platform.net.AbstractRemoteCommand; +import com.agynamix.platform.net.IConnectorServerHandler; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISourceData; + +public class TransportSourceDataCommand extends AbstractRemoteCommand { + + private static final long serialVersionUID = 1L; + + final ISourceData sourceData; + + public TransportSourceDataCommand(ISourceData sourceData) + { + this.sourceData = sourceData; + } + + public Object invoke(IConnectorServerHandler connectorServerHandler) + { + IQueueManager qm = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + qm.put(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, sourceData); + return new Boolean(true); + } + +} diff --git a/src/java/com/agynamix/simidude/source/ISource.java b/src/java/com/agynamix/simidude/source/ISource.java new file mode 100644 index 0000000..98a0a74 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/ISource.java @@ -0,0 +1,35 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source; + + +public interface ISource { + + /** + * + * @return true if new data is available at the source, false otherwise + */ + boolean isDataAvailable(); + + /** + * + * @return retrieve the new data from the source. + */ + ISourceData[] getData(); + + /** + * Tells the Listener how long it should sleep between calls to "isDataAvailable()". + * @return sleep time in milliseconds + */ + int getSleepTime(); + +} diff --git a/src/java/com/agynamix/simidude/source/ISourceData.java b/src/java/com/agynamix/simidude/source/ISourceData.java new file mode 100644 index 0000000..0808c60 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/ISourceData.java @@ -0,0 +1,110 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source; + +import java.io.Serializable; +import java.util.Date; +import java.util.UUID; + +import com.agynamix.simidude.infra.IContentsCacheInfo; + +/** + * Abstract data transport container + * @author tuhlmann + * + */ +public interface ISourceData extends Serializable { + + /** + * The SourceType distinguishes the different types of data that enter the system. + * It does not matter if data comes though the clipboard or through a drop event. + */ + public enum SourceType { TEXT, FILE, IMAGE }; + public enum TransportType { local, remote }; + + SourceType getType(); + + String getText(); + + Object getData(); + + /** + * The unique ID of the instance this data originated at. This Id does not change through the + * lifecycle of the instance. + * @return the UUID of the sender. + */ + UUID getSenderId(); + + /** + * + * @return The unique ID of this specific packet. + */ + UUID getSourceId(); + + void setTransportType(TransportType transportType); + + TransportType getTransportType(); + + /** + * Large objects are not send over the wire, they are only sent after a request by the specific party. + * If there are 5 clients participating in the network and only one needs the file then it would produce + * to much overhead to send the file right away. + * Instead we send a proxy object to all members. If one member requests the content we download it specifically. + * @return true if this is a proxy object, false otherwise. + */ + boolean isProxy(); + + /** + * Indicates that the contents for this object is either local or has been written to the ContentsCache already. + * @return true if the contents for this object is either local or has been cached, false otherwise. + */ + boolean isCached(); + + /** + * Stores a ContentsCacheInfo object inside ISourceData which holds information about the cached contents. + * @param cacheInfo + */ + void setContentsCacheInfo(IContentsCacheInfo cacheInfo); + + public IContentsCacheInfo getContentsCacheInfo(); + + /** + * Clone das aktuelle ISourceData Objekt mit allen Eigenschaften. + * @return ein Clone des aktuellen Objektes. + */ + ISourceData copy(); + + /** + * Clone das aktuelle ISourceData Objekt mit nur den Eigenschaften, die für einen equals-Vergleich benötigt werden. + * @return ein Clone des aktuellen Objektes mit nur den Equals-Eigenschaften. + */ + ISourceData equalsCopy(); + + /** + * + * @return a SourceDataStub instance that identifies this entry. + */ + SourceDataStub getStub(); + + Date getCreationDate(); + + /** + * Strip the item off its contents. + * All items are remembered, even when they have been deleted from the list. To safe memory (images + * can take a lot of space) we can strip the item from its contents. + * @return a reference to this item. + */ + public void deleteContents(); + + + +} diff --git a/src/java/com/agynamix/simidude/source/ISourceDataListener.java b/src/java/com/agynamix/simidude/source/ISourceDataListener.java new file mode 100644 index 0000000..873452f --- /dev/null +++ b/src/java/com/agynamix/simidude/source/ISourceDataListener.java @@ -0,0 +1,19 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source; + + +public interface ISourceDataListener { + + void sourceDataChanged(ISourceData data); + +} diff --git a/src/java/com/agynamix/simidude/source/SourceDataContents.java b/src/java/com/agynamix/simidude/source/SourceDataContents.java new file mode 100644 index 0000000..e9fe4c0 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/SourceDataContents.java @@ -0,0 +1,114 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source; + +import java.io.Serializable; +import java.util.UUID; + +public class SourceDataContents implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * The UUID of the associated ISourceData instance. + */ + final UUID sourceDataId; + final String name; + final byte[] fileContents; + final boolean isDirectory; + + final boolean lastPackage; + boolean endOfFile = false; + boolean aborted = false; + Throwable exception = null; + + public SourceDataContents(UUID sourceDataId, String fileName, byte[] fileContents) + { + this.sourceDataId = sourceDataId; + this.name = fileName; + this.fileContents = fileContents; + this.isDirectory = false; + this.lastPackage = false; + } + + public SourceDataContents(UUID sourceDataId, String directoryName) + { + this.sourceDataId = sourceDataId; + this.name = directoryName; + this.isDirectory = true; + this.fileContents = null; + this.lastPackage = false; + } + + public SourceDataContents(UUID sourceDataId, boolean isLastPackage) + { + this.lastPackage = isLastPackage; + this.sourceDataId = sourceDataId; + this.name = null; + this.isDirectory = false; + this.fileContents = null; + } + + public String getName() + { + return name; + } + + public byte[] getFileContents() + { + return fileContents; + } + + public boolean isDirectory() + { + return this.isDirectory; + } + + public boolean isFile() + { + return fileContents != null; + } + + public boolean isLastPackage() + { + return lastPackage; + } + + public boolean isEndOfFile() + { + return endOfFile; + } + + public void setEndOfFile(boolean endOfFile) + { + this.endOfFile = endOfFile; + } + + public boolean isAborted() + { + return aborted; + } + + public void setAborted(Throwable exception) + { + this.aborted = true; + this.exception = exception; + } + + public Throwable getException() + { + return this.exception; + } + + +} diff --git a/src/java/com/agynamix/simidude/source/SourceDataFactory.java b/src/java/com/agynamix/simidude/source/SourceDataFactory.java new file mode 100644 index 0000000..46aacd1 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/SourceDataFactory.java @@ -0,0 +1,126 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source; + +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.graphics.ImageData; + +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.infra.ModelProvider; +import com.agynamix.simidude.source.impl.FileSourceData; +import com.agynamix.simidude.source.impl.ImageSourceData; +import com.agynamix.simidude.source.impl.TextSourceData; + +public class SourceDataFactory { + + protected static ModelProvider modelProvider; + + protected static Logger log = ApplicationLog.getLogger(SourceDataFactory.class); + + public static ISourceData[] createFromDropTarget(DropTargetEvent event) + { + ISourceData[] itemList = null; + + try { + if (ImageTransfer.getInstance().isSupportedType(event.currentDataType)) + { + log.fine("Image Data dropped"); + ImageData imageData = (ImageData) event.data; + itemList = new ISourceData[1]; + itemList[0] = new ImageSourceData(getSenderId(), imageData); + } else if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) + { + log.fine("File Data dropped"); + String files[] = (String[]) event.data; + if (files != null) + { + itemList = new ISourceData[files.length]; + for (int i = 0; i < files.length; i++) + { + log.fine("Dropped File: "+files[i]); + itemList[i] = new FileSourceData(getSenderId(), files[i]); + } + } + } else if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) + { + String text = (String) event.data; + log.fine("Text Data dropped: "+text); + itemList = new ISourceData[1]; + itemList[0] = new TextSourceData(getSenderId(), text); + } + } catch (Exception e) + { + log.log(Level.WARNING, "Could not create ISourceData from DropTarget: "+e.getMessage(), e); + } + + return itemList; + } + + public static ISourceData createFromText(String text) + { + try { + return new TextSourceData(getSenderId(), text); + } catch (Exception e) + { + log.log(Level.WARNING, "Could not create TextSourceData entry: "+e.getMessage(), e); + return null; + } + } + + public static ISourceData createFromFile(String filename) + { + try { + return new FileSourceData(getSenderId(), filename); + } catch (Exception e) + { + log.log(Level.WARNING, "Could not create FileSourceData entry: "+e.getMessage(), e); + return null; + } + } + + public static ISourceData createFromImage(ImageData imageData) + { + try { + return new ImageSourceData(getSenderId(), imageData); + } catch (Exception e) + { + log.log(Level.WARNING, "Could not create ImageSourceData entry: "+e.getMessage(), e); + return null; + } + + } + + protected static UUID getSenderId() + { + return getModelProvider().getSenderId(); + } + + protected static ModelProvider getModelProvider() + { + if (modelProvider == null) + { + modelProvider = ((SimidudeApplicationContext)ApplicationBase.getContext()).getModelProvider(); + } + return modelProvider; + } + +} diff --git a/src/java/com/agynamix/simidude/source/SourceDataStub.java b/src/java/com/agynamix/simidude/source/SourceDataStub.java new file mode 100644 index 0000000..b5f775a --- /dev/null +++ b/src/java/com/agynamix/simidude/source/SourceDataStub.java @@ -0,0 +1,79 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source; + +import java.io.Serializable; +import java.util.UUID; + +/** + * This class is created by a ISourceData item to represent the id of the data. + * It is potentially much smaller then a complete ISourceData item. + * It is used to transmit the id of a ISourceData item to peers and ask them if they already have this item. + * peers can then request the contents of the items they do not yet have. + * @author tuhlmann + * + */ +public class SourceDataStub implements Serializable { + + private static final long serialVersionUID = 1L; + + private volatile int hashCode; + + final UUID sourceId; + + public SourceDataStub(ISourceData sourceData) + { + this.sourceId = sourceData.getSourceId(); + } + + public SourceDataStub(UUID sourceId) + { + this.sourceId = sourceId; + } + + @Override + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (!(o instanceof SourceDataStub)) + { + return false; + } + SourceDataStub stub = (SourceDataStub) o; + return this.sourceId.equals(stub.sourceId); + } + + @Override + public int hashCode() + { + int result = hashCode; + if (result == 0) + { + result = 17; + result = 31 * result + sourceId.hashCode(); + hashCode = result; + } + return result; + } + + @Override + public String toString() + { + return sourceId.toString(); + } + + +} diff --git a/src/java/com/agynamix/simidude/source/SourceDataUtils.java b/src/java/com/agynamix/simidude/source/SourceDataUtils.java new file mode 100644 index 0000000..eb4ff5d --- /dev/null +++ b/src/java/com/agynamix/simidude/source/SourceDataUtils.java @@ -0,0 +1,38 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source; + +import java.net.URL; + +import com.agynamix.simidude.source.impl.TextSourceData.TextType; + +public class SourceDataUtils { + + public static TextType recognizeTextType(String text) + { + if ((text.contains("\n")) || (text.contains("\r"))) + { + return TextType.Text; + } + // Only one line + try { + URL uri = new URL(text); + if (uri != null) + { + return TextType.URI; + } + } catch (Exception e) {} + return TextType.Text; + } + +} diff --git a/src/java/com/agynamix/simidude/source/SourceQueueService.java b/src/java/com/agynamix/simidude/source/SourceQueueService.java new file mode 100644 index 0000000..7aeff63 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/SourceQueueService.java @@ -0,0 +1,72 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.agynamix.platform.concurrent.AbstractService; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; + + +public class SourceQueueService extends AbstractService { + + public static final String SERVICE_NAME = "SourceDispatcher"; + + IQueueManager queueManager; + + List listeners = new CopyOnWriteArrayList(); + + public SourceQueueService(String serviceId) + { + super(serviceId); + } + + public void addSourceDataListener(ISourceDataListener listener) + { + listeners.add(listener); + } + + public void removeSourceDataListener(ISourceDataListener listener) + { + listeners.remove(listener); + } + + @Override + protected void internalInitialize() + { + queueManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + ApplicationBase.getContext().registerService(SourceQueueService.SERVICE_NAME, this); + } + + @Override + protected void internalRun() throws InterruptedException + { + ISourceData data = (ISourceData) queueManager.take(IQueueManager.QUEUE_SOURCE_DATA_MONITOR); + // notify listeners + if (data != null) + { + for (ISourceDataListener listener : listeners) + { + listener.sourceDataChanged(data); + } + } + } + + @Override + protected void preRunLoop() + { + } + +} diff --git a/src/java/com/agynamix/simidude/source/impl/AbstractSourceData.java b/src/java/com/agynamix/simidude/source/impl/AbstractSourceData.java new file mode 100644 index 0000000..5b958ae --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/AbstractSourceData.java @@ -0,0 +1,130 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source.impl; + +import java.util.Date; +import java.util.UUID; +import java.util.logging.Logger; + +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.infra.IContentsCacheInfo; +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataStub; + +public abstract class AbstractSourceData implements ISourceData { + + private static final long serialVersionUID = 1L; + + protected final UUID senderId; + protected final UUID uuid; + protected final SourceType sourceType; + protected TransportType transportType; + + protected final Date creationDate; + + protected SourceDataStub sourceDataStub = null; + + protected boolean isProxy = false; + + protected transient IContentsCacheInfo contentsCacheInfo; + + public AbstractSourceData(UUID senderId, SourceType sourceType) + { + this.senderId = senderId; + this.sourceType = sourceType; + this.transportType = TransportType.local; + this.uuid = UUID.randomUUID(); + this.creationDate = new Date(); + } + + public AbstractSourceData(AbstractSourceData sourceData) + { + this.isProxy = sourceData.isProxy; + this.senderId = sourceData.senderId; + this.sourceType = sourceData.sourceType; + this.transportType = sourceData.transportType; + this.uuid = sourceData.uuid; + this.creationDate = sourceData.creationDate; + } + + public UUID getSenderId() + { + return this.senderId; + } + + public UUID getSourceId() + { + return this.uuid; + } + + public SourceType getType() + { + return this.sourceType; + } + + public void setTransportType(TransportType transportType) + { + this.transportType = transportType; + } + + public TransportType getTransportType() + { + return this.transportType; + } + + public boolean isProxy() + { + return isProxy; + } + + public void setProxy(boolean isProxy) + { + this.isProxy = isProxy; + } + + public boolean isCached() + { + return contentsCacheInfo != null; + } + + public void setContentsCacheInfo(IContentsCacheInfo cacheInfo) + { + this.contentsCacheInfo = cacheInfo; + } + + public IContentsCacheInfo getContentsCacheInfo() + { + return this.contentsCacheInfo; + } + + public Date getCreationDate() + { + return this.creationDate; + } + + public SourceDataStub getStub() + { + if (sourceDataStub == null) + { + sourceDataStub = new SourceDataStub(this); + } + return sourceDataStub; + } + + protected Logger getLogger() + { + return ApplicationLog.getLogger(AbstractSourceData.class); + } + + +} diff --git a/src/java/com/agynamix/simidude/source/impl/FileSourceData.java b/src/java/com/agynamix/simidude/source/impl/FileSourceData.java new file mode 100644 index 0000000..9b0ed83 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/FileSourceData.java @@ -0,0 +1,226 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source.impl; + +import java.io.File; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.swt.graphics.ImageData; + +import com.agynamix.platform.log.ApplicationLog; +import com.agynamix.simidude.infra.CacheManagerFactory; +import com.agynamix.simidude.source.ISourceData; + + +public class FileSourceData extends AbstractSourceData { + + private static final long serialVersionUID = 1L; + + private final static String[] imgExt = new String[] {".jpg", ".png", ".gif", ".bmp", ".tiff"}; + private final static long MAX_IMAGE_FOR_THUMBNAIL = 2000000; + + File file; + boolean isDirectory; + String filename; + boolean isImage; + + ImageDataWrapper thumbnail = null; + + int hashCode = 0; + + /** + * The contents of a file or directory + */ + Object contents; + + public FileSourceData(UUID senderId, String filename) + { + super(senderId, SourceType.FILE); + this.filename = filename; + this.file = new File(filename); + this.isDirectory = file.isDirectory(); + if (this.isDirectory) + { + this.isImage = false; + } else { + this.isImage = checkFileIsImage(file); + } + // FileSourceData instances always are proxies. + setProxy(true); + } + + public FileSourceData(FileSourceData sourceData) + { + this(sourceData, true); + } + + public FileSourceData(FileSourceData sourceData, boolean fullCopy) + { + super(sourceData); + this.filename = sourceData.filename; + if (fullCopy) + { + this.isImage = sourceData.isImage; + this.file = new File(filename); + this.isDirectory = file.isDirectory(); + this.thumbnail = sourceData.thumbnail; + } + } + + public ISourceData copy() + { + FileSourceData sd = new FileSourceData(this); + return sd; + } + + public ISourceData equalsCopy() + { + FileSourceData sd = new FileSourceData(this, false); + return sd; + } + + @Override + public String toString() + { + return filename; + } + + public Object getData() + { + return filename; + } + + public String getText() + { + return filename; + } + + public boolean isDirectory() + { + return isDirectory; + } + + public String getFilename() + { + return filename; + } + + public File getFile() + { + return this.file; + } + + + public String getLocalFilename() + { + if (isCached()) + { + return getContentsCacheInfo().getFilenameInCache(); + } + return filename; + } + + @Override + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (!(o instanceof FileSourceData)) + { + return false; + } + FileSourceData sd = (FileSourceData) o; + return this.filename.equals(sd.filename); + } + + @Override + public int hashCode() + { + int result = hashCode; + if (result == 0) + { + result = 17; + result = 31 * result + filename.hashCode(); + hashCode = result; + } + return result; + } + + private boolean checkFileIsImage(File file) + { + if (file.canRead()) + { + int pos = file.getAbsolutePath().lastIndexOf("."); + if (pos > -1) + { + String extension = file.getAbsolutePath().substring(pos).toLowerCase(); + for (String ext : imgExt) + { + if (ext.equals(extension)) + { + return true; + } + } + } + } + return false; + } + + public boolean isImage() + { + return isImage; + } + + /** + * If this FileSourceData holds an image under a predefined size, we read the file and create a thumbnail. + * @return a thumbnail of the image or null if the file is no image or the image is too large. + */ + public ImageData getThumbnail() + { + if (thumbnail == null) + { + try { + if ((isImage()) && (file.exists()) && (file.canRead()) && (file.length() < MAX_IMAGE_FOR_THUMBNAIL)) + { + ImageDataWrapper wrapper = new ImageDataWrapper(new ImageData(filename)); + thumbnail = new ImageDataWrapper(wrapper.getThumbnailImageData()); + } + } catch (Exception e) + { + getLogger().log(Level.WARNING, e.getMessage(), e); + } + } + if (thumbnail != null) + { + return thumbnail.getImageData(); + } else { + return null; + } + } + + public void deleteContents() + { + if (isCached()) + { + CacheManagerFactory.removeContentsFromCache(getContentsCacheInfo()); + setContentsCacheInfo(null); + } + this.filename = ""; + this.file = null; + this.thumbnail = null; + } + +} diff --git a/src/java/com/agynamix/simidude/source/impl/ImageDataWrapper.java b/src/java/com/agynamix/simidude/source/impl/ImageDataWrapper.java new file mode 100644 index 0000000..09d16c2 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/ImageDataWrapper.java @@ -0,0 +1,113 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source.impl; + +import java.io.Serializable; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +public class ImageDataWrapper implements Serializable { + + private static final long serialVersionUID = 1L; + + public final int width; + public final int height; + public final int depth; + + public final int red; + public final int green; + public final int blue; + + public final int scanlinePad; + + public byte[] data; + + private transient ImageData thumbnail = null; + + public ImageDataWrapper(ImageData imageData) + { + if (imageData == null) + { + throw new NullPointerException(); + } + this.width = imageData.width; + this.height = imageData.height; + this.depth = imageData.depth; + + this.red = imageData.palette.redMask; + this.green = imageData.palette.greenMask; + this.blue = imageData.palette.blueMask; + + this.scanlinePad = imageData.scanlinePad; + this.data = imageData.data; + } + + public ImageData getImageData() + { + return new ImageData(width, height, depth, new PaletteData(red, green, blue), scanlinePad, data); + } + + public ImageData getThumbnailImageData() + { + if (thumbnail == null) + { + ImageData imageData = getImageData(); + if (imageData != null) + { + int height = imageData.height; + int width = imageData.width; + double heightFactor = (double) 48 / (double) height; + double widthFactor = (double) 64 / (double) width; + + int scaledHeight; + int scaledWidth; + + int w = (int) (width * heightFactor); + if (w <= 64) + { + scaledHeight = (int) (height * heightFactor); + scaledWidth = w; + } else + { + scaledWidth = (int) (width * widthFactor); + scaledHeight = (int) (height * widthFactor); + } + Image thumb1 = new Image(Display.getDefault(), imageData.scaledTo(scaledWidth, scaledHeight)); + Image thumbnailImg = new Image(Display.getDefault(), new Rectangle(0, 0, 64, 48)); + GC gcThumb = new GC(thumbnailImg); + + int x = (64 - scaledWidth) / 2; + int y = (48 - scaledHeight) / 2; + + gcThumb.drawImage(thumb1, x, y); + + thumbnail = thumbnailImg.getImageData(); + thumb1.dispose(); + thumbnailImg.dispose(); + gcThumb.dispose(); + } + } + return thumbnail; + } + + public void removeImageData() + { + this.data = new byte[0]; + } + +} diff --git a/src/java/com/agynamix/simidude/source/impl/ImageSourceData.java b/src/java/com/agynamix/simidude/source/impl/ImageSourceData.java new file mode 100644 index 0000000..963464e --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/ImageSourceData.java @@ -0,0 +1,143 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package com.agynamix.simidude.source.impl; + +import java.util.UUID; + +import org.eclipse.swt.graphics.ImageData; + +import com.agynamix.simidude.source.ISourceData; + +public class ImageSourceData extends AbstractSourceData { + + public final static String CLIPBOARD_IMAGE_TEXT = "Clipboard Image"; + + private static final long serialVersionUID = 1L; + + ImageDataWrapper imageDataWrapper; + + String imageText = null; + + int hashCode = 0; + + public ImageSourceData(ImageSourceData sourceData) + { + this(sourceData, true); + } + + public ImageSourceData(ImageSourceData sourceData, boolean fullCopy) + { + super(sourceData); + this.imageDataWrapper = new ImageDataWrapper(sourceData.imageDataWrapper.getImageData()); + if (!fullCopy) + { + this.getThumbnail(); + this.imageDataWrapper.removeImageData(); + } + } + + public ImageSourceData(UUID senderId, ImageData imageData) + { + super(senderId, SourceType.IMAGE); + this.imageDataWrapper = new ImageDataWrapper(imageData); + setProxy(false); + } + + public ISourceData copy() + { + ImageSourceData isd = new ImageSourceData(this); + return isd; + } + + public ISourceData equalsCopy() + { + ImageSourceData isd = new ImageSourceData(this, false); + return isd; + } + + public Object getData() + { + return getImageData(); + } + + public ImageData getImageData() + { + return imageDataWrapper.getImageData(); + } + + public ImageData getThumbnail() + { + return imageDataWrapper.getThumbnailImageData(); + } + + public String getText() + { + if (imageText == null) + { + imageText = CLIPBOARD_IMAGE_TEXT + " ("+imageDataWrapper.width+"x"+imageDataWrapper.height+" Pixel)"; + } + return imageText; + } + + @Override + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (!(o instanceof ImageSourceData)) + { + return false; + } + ImageSourceData sd = (ImageSourceData) o; + return bytesEqual(this.getThumbnail().data, sd.getThumbnail().data); + } + + @Override + public int hashCode() + { + int result = hashCode; + if (result == 0) + { + result = 17; + result = 31 * result + getThumbnail().hashCode(); + hashCode = result; + } + return result; + } + + private boolean bytesEqual(byte[] myData, byte[] itsData) + { + if (myData.length != itsData.length) + { + return false; + } + for (int i = 0; i < myData.length; i++) + { + if (myData[i] != itsData[i]) + { + return false; + } + } + return true; + } + + public void deleteContents() + { + imageText = ""; + imageDataWrapper = null; + } + +} + diff --git a/src/java/com/agynamix/simidude/source/impl/SourceListener.java b/src/java/com/agynamix/simidude/source/impl/SourceListener.java new file mode 100644 index 0000000..1ce66f1 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/SourceListener.java @@ -0,0 +1,62 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source.impl; + +import com.agynamix.platform.concurrent.AbstractService; +import com.agynamix.platform.infra.ApplicationBase; +import com.agynamix.platform.infra.IQueueManager; +import com.agynamix.simidude.impl.SimidudeApplicationContext; +import com.agynamix.simidude.source.ISource; +import com.agynamix.simidude.source.ISourceData; + + + +public class SourceListener extends AbstractService { + + final ISource source; + IQueueManager queueManager; + + final int sleepTime; + + public SourceListener(String serviceId, ISource source) + { + super(serviceId); + this.source = source; + this.sleepTime = source.getSleepTime(); + } + + @Override + protected void internalInitialize() + { + queueManager = ((SimidudeApplicationContext)ApplicationBase.getContext()).getQueueManager(); + } + + @Override + protected void internalRun() throws InterruptedException + { +// System.out.println("Check SourceListener..."); + if (source.isDataAvailable()) + { + ISourceData[] sourceData = source.getData(); + ISourceData s = sourceData[0]; +// System.out.println("ITEM: "+s.getText()+"("+DateUtils.date2string("HH:mm:ss SSS", s.getCreationDate())+")"); + queueManager.putAll(IQueueManager.QUEUE_SOURCE_DATA_MONITOR, sourceData); + } + Thread.sleep(this.sleepTime); + } + + @Override + protected void preRunLoop() + { + } + +} diff --git a/src/java/com/agynamix/simidude/source/impl/TextSourceData.java b/src/java/com/agynamix/simidude/source/impl/TextSourceData.java new file mode 100644 index 0000000..98eadd8 --- /dev/null +++ b/src/java/com/agynamix/simidude/source/impl/TextSourceData.java @@ -0,0 +1,131 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.de + */ + +package com.agynamix.simidude.source.impl; + +import java.util.UUID; + +import com.agynamix.simidude.source.ISourceData; +import com.agynamix.simidude.source.SourceDataUtils; + + +public class TextSourceData extends AbstractSourceData { + + private static final long serialVersionUID = 1L; + + public enum TextType { Text, URI }; + + private String data; + private TextType textType = null; + + int hashCode = 0; + + public TextSourceData(UUID senderId, String text) + { + super(senderId, SourceType.TEXT); + this.data = text; + if (this.data == null) + { + this.data = ""; + } + // TextSourceData instances always hold its contents. + setProxy(false); + } + + public TextSourceData(TextSourceData sourceData) + { + super(sourceData); + this.data = sourceData.data; + if (this.data == null) + { + this.data = ""; + } + this.textType = sourceData.textType; + } + + public ISourceData copy() + { + TextSourceData sd = new TextSourceData(this); + return sd; + } + + public ISourceData equalsCopy() + { + return this.copy(); + } + + @Override + public String toString() + { + return data; + } + + public Object getData() + { + return data; + } + + public String getText() + { + return data; + } + + public TextType getTextType() + { + if (this.textType == null) + { + textType = SourceDataUtils.recognizeTextType(getText()); + } + return this.textType; + } + + @Override + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (!(o instanceof TextSourceData)) + { + return false; + } + TextSourceData sd = (TextSourceData) o; + if ((this.data == null) && (sd.data == null)) + { + return true; + } + if ((this.data == null) || (sd.data == null)) + { + return false; + } + return this.data.equals(sd.data); + } + + @Override + public int hashCode() + { + int result = hashCode; + if (result == 0) + { + result = 17; + result = 31 * result + data.hashCode(); + hashCode = result; + } + return result; + } + + public void deleteContents() + { + this.data = ""; + } + +} diff --git a/src/java/sb/CheckNetwork.java b/src/java/sb/CheckNetwork.java new file mode 100644 index 0000000..0eba748 --- /dev/null +++ b/src/java/sb/CheckNetwork.java @@ -0,0 +1,113 @@ +package sb; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +public class CheckNetwork { + + public static List getHostAddresses() + { + List ipAddresses = new ArrayList(); + + try + { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) + { + NetworkInterface ni = interfaces.nextElement(); + Enumeration addresses = ni.getInetAddresses(); + while (addresses.hasMoreElements()) + { + InetAddress addr = addresses.nextElement(); + if (!addr.isLoopbackAddress()) + { + if (addr instanceof Inet4Address) // Fixme: Only IP4 at this time. + { + // if (addr.isReachable(10000)) + // { + // System.out.println("Address "+addr+" is reachable"); + System.out.println("My address: " + addr.getHostAddress()); + ipAddresses.add(addr); + // } + } + } + } + } + // addCustomAddressFromPreferences(ipAddresses); + } catch (SocketException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } + if (ipAddresses.size() == 0) + { + try + { + ipAddresses.add(InetAddress.getLocalHost()); + } catch (UnknownHostException e) + { + e.printStackTrace(); + throw new IllegalStateException(e); + } + } + return ipAddresses; + } + + public static InetAddress getPrimaryHostAddress() + { + try + { + return getHostAddresses().get(0); + } catch (Exception e) + { + try + { + return Inet4Address.getByName("127.0.0.1"); + } catch (UnknownHostException e1) + { + return null; + } + } + } + + public static String getLocalHostAddress() + { + try + { + // InetAddress addr = InetAddress.getLocalHost(); + // System.out.println("Found local address: "+addr.getHostAddress()); + // return addr.getHostAddress(); + List addresses = getHostAddresses(); + // for (InetAddress a : addresses) + // { + // System.out.println("Address: "+a.getHostAddress()); + // } + InetAddress hostname = addresses.get(0); + return hostname.getHostAddress(); + } catch (Exception e) + { + e.printStackTrace(); + return "127.0.0.1"; + } + } + + + /** + * @param args + */ + public static void main(String[] args) + { + System.out.println("The main host address: "+getLocalHostAddress()); + + } + +} diff --git a/src/java/swt/snippets/AlternateColumnColorExample.java b/src/java/swt/snippets/AlternateColumnColorExample.java new file mode 100644 index 0000000..b780599 --- /dev/null +++ b/src/java/swt/snippets/AlternateColumnColorExample.java @@ -0,0 +1,247 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TableItem; + +public class AlternateColumnColorExample { + + private class MyContentProvider implements IStructuredContentProvider { + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) + */ + public Object[] getElements(Object inputElement) + { + return (MyModel[]) inputElement; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() + { + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, + * java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + } + + } + + public class MyModel { + public int counter; + + public MyModel(int counter) + { + this.counter = counter; + } + + public String toString() + { + return "Item " + this.counter; + } + } + + private class OptimizedIndexSearcher { + private int lastIndex = 0; + + public boolean isEven(TableItem item) + { + TableItem[] items = item.getParent().getItems(); + + // 1. Search the next ten items + for (int i = lastIndex; i < items.length && lastIndex + 10 > i; i++) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + // 2. Search the previous ten items + for (int i = lastIndex; i < items.length && lastIndex - 10 > i; i--) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + // 3. Start from the beginning + for (int i = 0; i < items.length; i++) + { + if (items[i] == item) + { + lastIndex = i; + return lastIndex % 2 == 0; + } + } + + return false; + } + } + + public AlternateColumnColorExample(Shell shell) + { + final TableViewer v = new TableViewer(shell, SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL); + v.setContentProvider(new MyContentProvider()); + + final OptimizedIndexSearcher searcher = new OptimizedIndexSearcher(); + + TableViewerColumn column = new TableViewerColumn(v, SWT.NONE); + column.getColumn().setWidth(200); + column.getColumn().setText("Column 1"); + column.setLabelProvider(new ColumnLabelProvider() { + boolean even = true; + + public Color getBackground(Object element) + { + if (even) + { + return null; + } else + { + return v.getTable().getDisplay().getSystemColor(SWT.COLOR_GRAY); + } + } + + public void update(ViewerCell cell) + { + even = searcher.isEven((TableItem) cell.getItem()); + super.update(cell); + } + }); + + column = new TableViewerColumn(v, SWT.NONE); + column.getColumn().setWidth(200); + column.getColumn().setText("Column 2"); + column.setLabelProvider(new ColumnLabelProvider() { + boolean even = true; + + public Color getBackground(Object element) + { + if (even) + { + return null; + } else + { + return v.getTable().getDisplay().getSystemColor(SWT.COLOR_GRAY); + } + } + + public void update(ViewerCell cell) + { + even = searcher.isEven((TableItem) cell.getItem()); + super.update(cell); + } + + }); + + MyModel[] model = createModel(); + v.setInput(model); + v.getTable().setLinesVisible(true); + v.getTable().setHeaderVisible(true); + + final ViewerFilter filter = new ViewerFilter() { + + public boolean select(Viewer viewer, Object parentElement, Object element) + { + return ((MyModel) element).counter % 2 == 0; + } + + }; + + Button b = new Button(shell, SWT.PUSH); + b.addSelectionListener(new SelectionAdapter() { + boolean b = true; + + public void widgetSelected(SelectionEvent e) + { + if (b) + { + v.setFilters(new ViewerFilter[] { filter }); + b = false; + } else + { + v.setFilters(new ViewerFilter[0]); + b = true; + } + } + + }); + } + + private MyModel[] createModel() + { + MyModel[] elements = new MyModel[100000]; + + for (int i = 0; i < 100000; i++) + { + elements[i] = new MyModel(i); + } + + return elements; + } + + /** + * @param args + */ + public static void main(String[] args) + { + Display display = new Display(); + + Shell shell = new Shell(display); + shell.setLayout(new FillLayout()); + new AlternateColumnColorExample(shell); + shell.open(); + + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + display.sleep(); + } + + display.dispose(); + + } + +} diff --git a/src/java/swt/snippets/ArrowButtonExample.java b/src/java/swt/snippets/ArrowButtonExample.java new file mode 100644 index 0000000..0043e40 --- /dev/null +++ b/src/java/swt/snippets/ArrowButtonExample.java @@ -0,0 +1,57 @@ +package swt.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class ArrowButtonExample { + Display d; + + Shell s; + + ArrowButtonExample() { + d = new Display(); + s = new Shell(d); + s.setSize(250, 250); + s.setText("A Button Example"); + final Button b1 = new Button(s, SWT.ARROW | SWT.UP); + b1.setBounds(100, 55, 20, 15); + final Button b2 = new Button(s, SWT.ARROW | SWT.DOWN); + b2.setBounds(100, 70, 20, 15); + final Text t1 = new Text(s, SWT.BORDER | SWT.SINGLE | SWT.CENTER); + t1.setBounds(80, 55, 20, 30); + t1.setText("1"); + t1.selectAll(); + b1.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + int n = new Integer(t1.getText()).intValue(); + n++; + t1.setText(new Integer(n).toString()); + t1.selectAll(); + } + }); + b2.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + int n = new Integer(t1.getText()).intValue(); + n--; + t1.setText(new Integer(n).toString()); + t1.selectAll(); + } + }); + s.open(); + while (!s.isDisposed()) { + if (!d.readAndDispatch()) + d.sleep(); + } + d.dispose(); + } + + public static void main(String[] argv) { + new ArrowButtonExample(); + } + +} \ No newline at end of file diff --git a/src/java/swt/snippets/BalloonTooltipExample.java b/src/java/swt/snippets/BalloonTooltipExample.java new file mode 100644 index 0000000..f5622e3 --- /dev/null +++ b/src/java/swt/snippets/BalloonTooltipExample.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package swt.snippets; + +/* + * Tooltip example snippet: create a balloon tooltip for a tray item + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + * + * @since 3.2 + */ +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.widgets.*; + +public class BalloonTooltipExample { + + public static void main(String[] args) + { + Display display = new Display(); + Shell shell = new Shell(display); + Image image = null; + final ToolTip tip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_INFORMATION); + tip.setMessage("Here is a message for the user. When the message is too long it wraps. I should say something cool but nothing comes to my mind."); + Tray tray = display.getSystemTray(); + if (tray != null) + { + TrayItem item = new TrayItem(tray, SWT.NONE); + image = display.getSystemImage(SWT.ICON_INFORMATION); + item.setImage(image); + tip.setText("Notification from a tray item"); + item.setToolTip(tip); + } else + { + tip.setText("Notification from anywhere"); + tip.setLocation(400, 400); + } + Button button = new Button(shell, SWT.PUSH); + button.setText("Press for balloon tip"); + button.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) + { + tip.setVisible(true); + } + }); + button.pack(); + shell.setBounds(50, 50, 300, 200); + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + display.sleep(); + } + if (image != null) + image.dispose(); + display.dispose(); + } +} diff --git a/src/java/swt/snippets/BroadcastExample.java b/src/java/swt/snippets/BroadcastExample.java new file mode 100644 index 0000000..5baf7db --- /dev/null +++ b/src/java/swt/snippets/BroadcastExample.java @@ -0,0 +1,113 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +public class BroadcastExample { + + public final static int port = 12555; + + /** + * @param args + */ + public static void main(String[] args) + { + if (args.length == 0) + { + System.out.println("Usage: BroadcastExample server|client"); + System.exit(1); + } + + BroadcastExample bc = new BroadcastExample(); + + if (args[0].equals("server")) + { + bc.runServer(); + } else { + bc.runClient(); + } + } + + private void runServer() + { + try + { + byte[] buffer = new byte[512]; + DatagramPacket dp = new DatagramPacket(buffer, buffer.length); + DatagramSocket s = new DatagramSocket(port); + System.out.println("Wait for package"); + s.receive(dp); + System.out.println("Returned"); + System.out.println("Received Package from "+dp.getAddress().getHostAddress()); + System.out.println("Length of data: "+dp.getLength()); + String msg = new String(dp.getData()); + System.out.println("Msg: "+msg); + + // now send that client back my own address + DatagramPacket dp2 = new DatagramPacket(buffer, buffer.length, dp.getAddress(), port); + s.send(dp2); + System.out.println("Sent answer"); + + } catch (SocketException e) + { + e.printStackTrace(); + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + + private void runClient() + { + try + { + byte[] buffer = new byte[512]; + String msg = "192.168.0.71"; + System.arraycopy(msg.getBytes(), 0, buffer, 0, msg.length()); + DatagramSocket s = new DatagramSocket(null); + DatagramPacket dp = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.0.255"), port); + s.send(dp); + + // wait for answer + byte[] buffer2 = new byte[512]; + DatagramSocket s2 = new DatagramSocket(port); + DatagramPacket dp2 = new DatagramPacket(buffer2, buffer2.length); + s2.receive(dp2); + System.out.println("Received Answer from "+dp2.getAddress().getHostAddress()); + + + } catch (SocketException e) + { + e.printStackTrace(); + } catch (UnknownHostException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + +} diff --git a/src/java/swt/snippets/ClipboardExample.java b/src/java/swt/snippets/ClipboardExample.java new file mode 100644 index 0000000..215d139 --- /dev/null +++ b/src/java/swt/snippets/ClipboardExample.java @@ -0,0 +1,628 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.HTMLTransfer; +import org.eclipse.swt.dnd.RTFTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class ClipboardExample { + + Clipboard clipboard; + + Shell shell; + + Text copyText; + + Text pasteText; + + Text copyRtfText; + + Text pasteRtfText; + + Text copyHtmlText; + + Text pasteHtmlText; + + Table copyFileTable; + + Table pasteFileTable; + + Text text; + + Combo combo; + + StyledText styledText; + + Label status; + + static final int SIZE = 60; + + public static void main(String[] args) { + Display display = new Display(); + new ClipboardExample().open(display); + display.dispose(); + } + + public void open(Display display) { + clipboard = new Clipboard(display); + shell = new Shell(display); + shell.setText("SWT Clipboard"); + shell.setLayout(new FillLayout()); + + ScrolledComposite sc = new ScrolledComposite(shell, SWT.H_SCROLL + | SWT.V_SCROLL); + Composite parent = new Composite(sc, SWT.NONE); + sc.setContent(parent); + parent.setLayout(new GridLayout(2, true)); + + Group copyGroup = new Group(parent, SWT.NONE); + copyGroup.setText("Copy From:"); + GridData data = new GridData(GridData.FILL_BOTH); + copyGroup.setLayoutData(data); + copyGroup.setLayout(new GridLayout(3, false)); + + Group pasteGroup = new Group(parent, SWT.NONE); + pasteGroup.setText("Paste To:"); + data = new GridData(GridData.FILL_BOTH); + pasteGroup.setLayoutData(data); + pasteGroup.setLayout(new GridLayout(3, false)); + + Group controlGroup = new Group(parent, SWT.NONE); + controlGroup.setText("Control API:"); + data = new GridData(GridData.FILL_BOTH); + data.horizontalSpan = 2; + controlGroup.setLayoutData(data); + controlGroup.setLayout(new GridLayout(5, false)); + + Group typesGroup = new Group(parent, SWT.NONE); + typesGroup.setText("Available Types"); + data = new GridData(GridData.FILL_BOTH); + data.horizontalSpan = 2; + typesGroup.setLayoutData(data); + typesGroup.setLayout(new GridLayout(2, false)); + + status = new Label(parent, SWT.BORDER); + data = new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan = 2; + data.heightHint = 60; + status.setLayoutData(data); + + createTextTransfer(copyGroup, pasteGroup); + createRTFTransfer(copyGroup, pasteGroup); + createHTMLTransfer(copyGroup, pasteGroup); + createFileTransfer(copyGroup, pasteGroup); + createMyTransfer(copyGroup, pasteGroup); + createControlTransfer(controlGroup); + createAvailableTypes(typesGroup); + + sc.setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Rectangle monitorArea = shell.getMonitor().getClientArea(); + shell.setSize(Math.min(size.x, monitorArea.width - 20), Math.min( + size.y, monitorArea.height - 20)); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + clipboard.dispose(); + } + + void createTextTransfer(Composite copyParent, Composite pasteParent) { + + // TextTransfer + Label l = new Label(copyParent, SWT.NONE); + l.setText("TextTransfer:"); //$NON-NLS-1$ + copyText = new Text(copyParent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL + | SWT.H_SCROLL); + copyText.setText("some\nplain\ntext"); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + copyText.setLayoutData(data); + Button b = new Button(copyParent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String data = copyText.getText(); + if (data.length() > 0) { + status.setText(""); + clipboard.setContents(new Object[] { data }, + new Transfer[] { TextTransfer.getInstance() }); + } else { + status.setText("nothing to copy"); + } + } + }); + + l = new Label(pasteParent, SWT.NONE); + l.setText("TextTransfer:"); //$NON-NLS-1$ + pasteText = new Text(pasteParent, SWT.READ_ONLY | SWT.MULTI + | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + pasteText.setLayoutData(data); + b = new Button(pasteParent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String data = (String) clipboard.getContents(TextTransfer + .getInstance()); + if (data != null && data.length() > 0) { + status.setText(""); + pasteText.setText("begin paste>" + data + " 0) { + status.setText(""); + data = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i " + + data + "}"; + clipboard.setContents(new Object[] { data }, + new Transfer[] { RTFTransfer.getInstance() }); + } else { + status.setText("nothing to copy"); + } + } + }); + + l = new Label(pasteParent, SWT.NONE); + l.setText("RTFTransfer:"); //$NON-NLS-1$ + pasteRtfText = new Text(pasteParent, SWT.READ_ONLY | SWT.MULTI + | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + pasteRtfText.setLayoutData(data); + b = new Button(pasteParent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String data = (String) clipboard.getContents(RTFTransfer + .getInstance()); + if (data != null && data.length() > 0) { + status.setText(""); + pasteRtfText.setText("start paste>" + data + "Hello World"); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + copyHtmlText.setLayoutData(data); + Button b = new Button(copyParent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String data = copyHtmlText.getText(); + if (data.length() > 0) { + status.setText(""); + clipboard.setContents(new Object[] { data }, + new Transfer[] { HTMLTransfer.getInstance() }); + } else { + status.setText("nothing to copy"); + } + } + }); + + l = new Label(pasteParent, SWT.NONE); + l.setText("HTMLTransfer:"); //$NON-NLS-1$ + pasteHtmlText = new Text(pasteParent, SWT.READ_ONLY | SWT.MULTI + | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + pasteHtmlText.setLayoutData(data); + b = new Button(pasteParent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String data = (String) clipboard.getContents(HTMLTransfer + .getInstance()); + if (data != null && data.length() > 0) { + status.setText(""); + pasteHtmlText.setText("start paste>" + data + " 0) { + // copyFileTable.removeAll(); + String separator = System.getProperty("file.separator"); + String path = dialog.getFilterPath(); + String[] names = dialog.getFileNames(); + for (int i = 0; i < names.length; i++) { + TableItem item = new TableItem(copyFileTable, SWT.NONE); + item.setText(path + separator + names[i]); + } + } + } + }); + b = new Button(c, SWT.PUSH); + b.setText("Select directory"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + DirectoryDialog dialog = new DirectoryDialog(shell, SWT.OPEN); + String result = dialog.open(); + if (result != null && result.length() > 0) { + // copyFileTable.removeAll(); + TableItem item = new TableItem(copyFileTable, SWT.NONE); + item.setText(result); + } + } + }); + + b = new Button(copyParent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + TableItem[] items = copyFileTable.getItems(); + if (items.length > 0) { + status.setText(""); + String[] data = new String[items.length]; + for (int i = 0; i < data.length; i++) { + data[i] = items[i].getText(); + } + clipboard.setContents(new Object[] { data }, + new Transfer[] { FileTransfer.getInstance() }); + } else { + status.setText("nothing to copy"); + } + } + }); + + l = new Label(pasteParent, SWT.NONE); + l.setText("FileTransfer:"); //$NON-NLS-1$ + pasteFileTable = new Table(pasteParent, SWT.MULTI | SWT.BORDER); + data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + pasteFileTable.setLayoutData(data); + b = new Button(pasteParent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String[] data = (String[]) clipboard.getContents(FileTransfer + .getInstance()); + if (data != null && data.length > 0) { + status.setText(""); + pasteFileTable.removeAll(); + for (int i = 0; i < data.length; i++) { + TableItem item = new TableItem(pasteFileTable, SWT.NONE); + item.setText(data[i]); + } + } else { + status.setText("nothing to paste"); + } + } + }); + } + + void createMyTransfer(Composite copyParent, Composite pasteParent) { + // MyType Transfer + // TODO + } + + void createControlTransfer(Composite parent) { + Label l = new Label(parent, SWT.NONE); + l.setText("Text:"); + Button b = new Button(parent, SWT.PUSH); + b.setText("Cut"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + text.cut(); + } + }); + b = new Button(parent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + text.copy(); + } + }); + b = new Button(parent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + text.paste(); + } + }); + text = new Text(parent, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL + | SWT.V_SCROLL); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + text.setLayoutData(data); + + l = new Label(parent, SWT.NONE); + l.setText("Combo:"); + b = new Button(parent, SWT.PUSH); + b.setText("Cut"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + combo.cut(); + } + }); + b = new Button(parent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + combo.copy(); + } + }); + b = new Button(parent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + combo.paste(); + } + }); + combo = new Combo(parent, SWT.NONE); + combo.setItems(new String[] { "Item 1", "Item 2", "Item 3", + "A longer Item" }); + + l = new Label(parent, SWT.NONE); + l.setText("StyledText:"); + l = new Label(parent, SWT.NONE); + l.setVisible(false); + b = new Button(parent, SWT.PUSH); + b.setText("Copy"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + styledText.copy(); + } + }); + b = new Button(parent, SWT.PUSH); + b.setText("Paste"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + styledText.paste(); + } + }); + styledText = new StyledText(parent, SWT.BORDER | SWT.MULTI + | SWT.H_SCROLL | SWT.V_SCROLL); + data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = data.widthHint = SIZE; + styledText.setLayoutData(data); + } + + void createAvailableTypes(Composite parent) { + final List list = new List(parent, SWT.BORDER | SWT.H_SCROLL + | SWT.V_SCROLL); + GridData data = new GridData(GridData.FILL_BOTH); + data.heightHint = 100; + list.setLayoutData(data); + Button b = new Button(parent, SWT.PUSH); + b.setText("Get Available Types"); + b.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + list.removeAll(); + String[] names = clipboard.getAvailableTypeNames(); + for (int i = 0; i < names.length; i++) { + list.add(names[i]); + } + } + }); + } +} + +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +class MyTypeTransfer extends ByteArrayTransfer { + + private static final String MYTYPENAME = "name_list"; //$NON-NLS-1$ + + private static final int MYTYPEID = registerType(MYTYPENAME); + + private static MyTypeTransfer _instance = new MyTypeTransfer(); + + public static MyTypeTransfer getInstance() { + return _instance; + } + + public void javaToNative(Object object, TransferData transferData) { + if (!checkMyType(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + MyType[] myTypes = (MyType[]) object; + try { + // write data to a byte array and then ask super to convert to + // pMedium + ByteArrayOutputStream out = new ByteArrayOutputStream(); + DataOutputStream writeOut = new DataOutputStream(out); + for (int i = 0, length = myTypes.length; i < length; i++) { + byte[] buffer = myTypes[i].firstName.getBytes(); + writeOut.writeInt(buffer.length); + writeOut.write(buffer); + buffer = myTypes[i].firstName.getBytes(); + writeOut.writeInt(buffer.length); + writeOut.write(buffer); + } + byte[] buffer = out.toByteArray(); + writeOut.close(); + super.javaToNative(buffer, transferData); + } catch (IOException e) { + } + } + + public Object nativeToJava(TransferData transferData) { + if (isSupportedType(transferData)) { + + byte[] buffer = (byte[]) super.nativeToJava(transferData); + if (buffer == null) + return null; + + MyType[] myData = new MyType[0]; + try { + ByteArrayInputStream in = new ByteArrayInputStream(buffer); + DataInputStream readIn = new DataInputStream(in); + while (readIn.available() > 20) { + MyType datum = new MyType(); + int size = readIn.readInt(); + byte[] name = new byte[size]; + readIn.read(name); + datum.firstName = new String(name); + size = readIn.readInt(); + name = new byte[size]; + readIn.read(name); + datum.lastName = new String(name); + MyType[] newMyData = new MyType[myData.length + 1]; + System.arraycopy(myData, 0, newMyData, 0, myData.length); + newMyData[myData.length] = datum; + myData = newMyData; + } + readIn.close(); + } catch (IOException ex) { + return null; + } + return myData; + } + + return null; + } + + protected String[] getTypeNames() { + return new String[] { MYTYPENAME }; + } + + protected int[] getTypeIds() { + return new int[] { MYTYPEID }; + } + + boolean checkMyType(Object object) { + if (object == null || !(object instanceof MyType[]) + || ((MyType[]) object).length == 0) + return false; + MyType[] myTypes = (MyType[]) object; + for (int i = 0; i < myTypes.length; i++) { + if (myTypes[i] == null || myTypes[i].firstName == null + || myTypes[i].firstName.length() == 0 + || myTypes[i].lastName == null + || myTypes[i].lastName.length() == 0) + return false; + } + return true; + } + + protected boolean validate(Object object) { + return checkMyType(object); + } +} + +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +class MyType { + String firstName; + + String lastName; +} \ No newline at end of file diff --git a/src/java/swt/snippets/ComplexToolbarExample.java b/src/java/swt/snippets/ComplexToolbarExample.java new file mode 100644 index 0000000..c4d800e --- /dev/null +++ b/src/java/swt/snippets/ComplexToolbarExample.java @@ -0,0 +1,125 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +public class ComplexToolbarExample { + Display display = new Display(); + Shell shell = new Shell(display); + + ToolBar toolBar; + + public ComplexToolbarExample() { + toolBar = new ToolBar(shell, SWT.FLAT | SWT.WRAP | SWT.RIGHT); + + ToolItem itemPush = new ToolItem(toolBar, SWT.PUSH); + itemPush.setText("PUSH item"); +// Image icon = PlatformIcons.get(PlatformIcons.EXIT); +// itemPush.setImage(icon); + + ToolItem itemCheck = new ToolItem(toolBar, SWT.CHECK); + itemCheck.setText("CHECK item"); + + ToolItem itemRadio1 = new ToolItem(toolBar, SWT.RADIO); + itemRadio1.setText("RADIO item 1"); + + ToolItem itemRadio2 = new ToolItem(toolBar, SWT.RADIO); + itemRadio2.setText("RADIO item 2"); + + ToolItem itemSeparator = new ToolItem(toolBar, SWT.SEPARATOR); + Text text = new Text(toolBar, SWT.BORDER | SWT.SINGLE); + text.pack(); + itemSeparator.setWidth(text.getBounds().width); + itemSeparator.setControl(text); + + final ToolItem itemDropDown = new ToolItem(toolBar, SWT.DROP_DOWN); + itemDropDown.setText("DROP_DOWN item"); + itemDropDown.setToolTipText("Click here to see a drop down menu ..."); + + final Menu menu = new Menu(shell, SWT.POP_UP); + new MenuItem(menu, SWT.PUSH).setText("Menu item 1"); + new MenuItem(menu, SWT.PUSH).setText("Menu item 2"); + new MenuItem(menu, SWT.SEPARATOR); + new MenuItem(menu, SWT.PUSH).setText("Menu item 3"); + + itemDropDown.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + if(event.detail == SWT.ARROW) { + Rectangle bounds = itemDropDown.getBounds(); + Point point = toolBar.toDisplay(bounds.x, bounds.y + bounds.height); + menu.setLocation(point); + menu.setVisible(true); + } + } + }); + + Listener selectionListener = new Listener() { + public void handleEvent(Event event) { + ToolItem item = (ToolItem)event.widget; + System.out.println(item.getText() + " is selected"); + if( (item.getStyle() & SWT.RADIO) != 0 || (item.getStyle() & SWT.CHECK) != 0 ) + System.out.println("Selection status: " + item.getSelection()); + } + }; + + itemPush.addListener(SWT.Selection, selectionListener); + itemCheck.addListener(SWT.Selection, selectionListener); + itemRadio1.addListener(SWT.Selection, selectionListener); + itemRadio2.addListener(SWT.Selection, selectionListener); + itemDropDown.addListener(SWT.Selection, selectionListener); + + toolBar.pack(); + + shell.addListener(SWT.Resize, new Listener() { + public void handleEvent(Event event) { + Rectangle clientArea = shell.getClientArea(); + toolBar.setSize(toolBar.computeSize(clientArea.width, SWT.DEFAULT)); + } + }); + + shell.setSize(500, 100); + shell.open(); + //textUser.forceFocus(); + + // Set up the event loop. + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + // If no more entries in event queue + display.sleep(); + } + } + + display.dispose(); + } + + private void init() { + + } + + public static void main(String[] args) { + new ComplexToolbarExample(); + } +} + diff --git a/src/java/swt/snippets/CustomGradientSelection.java b/src/java/swt/snippets/CustomGradientSelection.java new file mode 100644 index 0000000..f339096 --- /dev/null +++ b/src/java/swt/snippets/CustomGradientSelection.java @@ -0,0 +1,93 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.layout.*; +import org.eclipse.swt.widgets.*; + +public class CustomGradientSelection { + + public static void main(String [] args) { + final Display display = new Display(); + Shell shell = new Shell(display); + shell.setText("Custom gradient selection for Table"); + shell.setLayout(new FillLayout()); + final Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION); + table.setHeaderVisible(true); + table.setLinesVisible(true); + int columnCount = 3; + for (int i=0; i 0) { + Region region = new Region(); + gc.getClipping(region); + region.add(event.x, event.y, width, event.height); + gc.setClipping(region); + region.dispose(); + } + } + gc.setAdvanced(true); + if (gc.getAdvanced()) gc.setAlpha(127); + Rectangle rect = event.getBounds(); + Color foreground = gc.getForeground(); + Color background = gc.getBackground(); + gc.setForeground(display.getSystemColor(SWT.COLOR_RED)); + gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + gc.fillGradientRectangle(0, rect.y, 500, rect.height, false); + // restore colors for subsequent drawing + gc.setForeground(foreground); + gc.setBackground(background); + event.detail &= ~SWT.SELECTED; + } + } + }); + for (int i=0; i 0) + { + sb.append("MOD+"); + } + +// if ((e.stateMask & SWT.CTRL) > 0) +// { +// sb.append("CTRL+"); +// } + + if ((e.stateMask & SWT.SHIFT) > 0) + { + sb.append("SHIFT+"); + } + + if ((e.stateMask & SWT.ALT) > 0) + { + sb.append("ALT+"); + } + + String c = ""+(char)e.keyCode; + sb.append(c.toUpperCase()); + + return sb.toString(); + } else { + return null; + } + } + + + + +} diff --git a/src/java/swt/snippets/EnableMenuItemsDynamicallyExample.java b/src/java/swt/snippets/EnableMenuItemsDynamicallyExample.java new file mode 100644 index 0000000..a4a4568 --- /dev/null +++ b/src/java/swt/snippets/EnableMenuItemsDynamicallyExample.java @@ -0,0 +1,70 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import org.eclipse.swt.*; +import org.eclipse.swt.widgets.*; + +/* + * Menu example snippet: enable menu items dynamically (when menu shown) + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + */ +public class EnableMenuItemsDynamicallyExample { + + public static void main(String[] args) + { + Display display = new Display(); + Shell shell = new Shell(display); + final Tree tree = new Tree(shell, SWT.BORDER | SWT.MULTI); + final Menu menu = new Menu(shell, SWT.POP_UP); + tree.setMenu(menu); + for (int i = 0; i < 12; i++) + { + TreeItem treeItem = new TreeItem(tree, SWT.NONE); + treeItem.setText("Item " + i); + MenuItem menuItem = new MenuItem(menu, SWT.PUSH); + menuItem.setText(treeItem.getText()); + } + menu.addListener(SWT.Show, new Listener() { + public void handleEvent(Event event) + { + MenuItem[] menuItems = menu.getItems(); + TreeItem[] treeItems = tree.getSelection(); + for (int i = 0; i < menuItems.length; i++) + { + String text = menuItems[i].getText(); + int index = 0; + while (index < treeItems.length) + { + if (treeItems[index].getText().equals(text)) + break; + index++; + } + menuItems[i].setEnabled(index != treeItems.length); + } + } + }); + tree.setSize(200, 200); + shell.setSize(300, 300); + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + display.sleep(); + } + display.dispose(); + } + +} diff --git a/src/java/swt/snippets/ImageInTableCell.java b/src/java/swt/snippets/ImageInTableCell.java new file mode 100644 index 0000000..b8723de --- /dev/null +++ b/src/java/swt/snippets/ImageInTableCell.java @@ -0,0 +1,89 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.layout.*; +import org.eclipse.swt.widgets.*; + +public class ImageInTableCell { + + public static void main(String[] args) + { + Display display = new Display(); + final Image image = display.getSystemImage(SWT.ICON_INFORMATION); + Shell shell = new Shell(display); + shell.setText("Images on the right side of the TableItem"); + shell.setLayout(new FillLayout()); + Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION); + table.setHeaderVisible(false); + table.setLinesVisible(true); + int columnCount = 3; + for (int i = 0; i < columnCount; i++) + { + TableColumn column = new TableColumn(table, SWT.NONE); + column.setText("Column " + i); + } + int itemCount = 8; + for (int i = 0; i < itemCount; i++) + { + TableItem item = new TableItem(table, SWT.NONE); + item.setText(new String[] { "item " + i + " a", "item " + i + " b", "item " + i + " c" }); + } + /* + * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly. Therefore, it is critical for performance that + * these methods be as efficient as possible. + */ + Listener paintListener = new Listener() { + public void handleEvent(Event event) + { + switch (event.type) + { + case SWT.MeasureItem: { + Rectangle rect = image.getBounds(); + event.width += rect.width; + System.out.println("event.height="+event.height); + System.out.println("rect.height ="+rect.height); + event.height = Math.max(event.height, rect.height + 20); + break; + } + case SWT.PaintItem: { + int x = event.x + event.width; + Rectangle rect = image.getBounds(); + int offset = Math.max(0, (event.height - rect.height) / 2); + event.gc.drawImage(image, x, event.y + offset); + break; + } + } + } + }; + table.addListener(SWT.MeasureItem, paintListener); + table.addListener(SWT.PaintItem, paintListener); + + for (int i = 0; i < columnCount; i++) + { + table.getColumn(i).pack(); + } + shell.setSize(500, 200); + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + display.sleep(); + } + if (image != null) + image.dispose(); + display.dispose(); + } +} diff --git a/src/java/swt/snippets/InetAddrFinder.java b/src/java/swt/snippets/InetAddrFinder.java new file mode 100644 index 0000000..acf9bcc --- /dev/null +++ b/src/java/swt/snippets/InetAddrFinder.java @@ -0,0 +1,28 @@ +/* + * Copyright by AGYNAMIX(R). All rights reserved. + * This file is made available under the terms of the + * license this product is released under. + * + * For details please see the license file you should have + * received, or go to: + * + * http://www.agynamix.com + * + * Contributors: agynamix.com (http://www.agynamix.com) + */ +package swt.snippets; + +import java.net.InetAddress; + +public class InetAddrFinder { + + /** + * @param args + */ + public static void main(String[] args) throws Exception + { + InetAddress addr = InetAddress.getLocalHost(); + System.out.println("Host="+addr.getHostAddress()); + } + +} diff --git a/src/java/swt/snippets/JIntellitypeTester.java b/src/java/swt/snippets/JIntellitypeTester.java new file mode 100644 index 0000000..ea5f981 --- /dev/null +++ b/src/java/swt/snippets/JIntellitypeTester.java @@ -0,0 +1,304 @@ +/* + * JIntellitype ----------------- Copyright 2005-2006 Emil A. Lefkof III + * + * I always give it my best shot to make a program useful and solid, but remeber + * that there is absolutely no warranty for using this program as stated in the + * following terms: + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package swt.snippets; + +import java.awt.BorderLayout; +import java.awt.Event; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.border.EtchedBorder; + +import com.melloware.jintellitype.HotkeyListener; +import com.melloware.jintellitype.IntellitypeListener; +import com.melloware.jintellitype.JIntellitype; + +/** + * Swing based test application to test all the functions of the JIntellitype + * library. + *

+ * Copyright (c) 2006 Melloware, Inc. + * @author Emil A. Lefkof III + * @version 1.0 + */ +public class JIntellitypeTester extends JFrame implements HotkeyListener, IntellitypeListener { + + private static JIntellitypeTester mainFrame; + private static final int WINDOWS_A = 88; + private static final int ALT_SHIFT_B = 89; + private static final int CTRL_SHIFT_C = 90; + private static final int PRINT_SCREEN = 91; + private static final int F9 = 92; + private static final int F12 = 93; + private JButton btnRegisterHotKey = new JButton(); + private JButton btnUnregisterHotKey = new JButton(); + private JPanel bottomPanel = new JPanel(); + private JPanel mainPanel = new JPanel(); + private JPanel topPanel = new JPanel(); + private JScrollPane scrollPane = new JScrollPane(); + private JTextArea textArea = new JTextArea(); + + /** + * Creates new form. + */ + public JIntellitypeTester() { + initComponents(); + } + + /** + * Main method to launch this application. + *

+ * @param args any command line arguments + */ + public static void main(String[] args) { + // first check to see if an instance of this application is already + // running, use the name of the window title of this JFrame for checking + if (JIntellitype.checkInstanceAlreadyRunning("JIntellitype Test Application")) { + System.exit(1); + } + + // next check to make sure JIntellitype DLL can be found and we are on + // a Windows operating System + if (!JIntellitype.isJIntellitypeSupported()) { + System.exit(1); + } + + mainFrame = new JIntellitypeTester(); + mainFrame.setTitle("JIntellitype Test Application"); + center(mainFrame); + mainFrame.setVisible(true); + mainFrame.initJIntellitype(); + } + + /* + * (non-Javadoc) + * @see com.melloware.jintellitype.HotkeyListener#onHotKey(int) + */ + public void onHotKey(int aIdentifier) { + output("WM_HOTKEY message received " + Integer.toString(aIdentifier)); + } + + /* + * (non-Javadoc) + * @see com.melloware.jintellitype.IntellitypeListener#onIntellitype(int) + */ + public void onIntellitype(int aCommand) { + + switch (aCommand) { + case JIntellitype.APPCOMMAND_BROWSER_BACKWARD: + output("BROWSER_BACKWARD message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_FAVOURITES: + output("BROWSER_FAVOURITES message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_FORWARD: + output("BROWSER_FORWARD message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_HOME: + output("BROWSER_HOME message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_REFRESH: + output("BROWSER_REFRESH message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_SEARCH: + output("BROWSER_SEARCH message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_BROWSER_STOP: + output("BROWSER_STOP message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_LAUNCH_APP1: + output("LAUNCH_APP1 message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_LAUNCH_APP2: + output("LAUNCH_APP2 message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_LAUNCH_MAIL: + output("LAUNCH_MAIL message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_MEDIA_NEXTTRACK: + output("MEDIA_NEXTTRACK message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_MEDIA_PLAY_PAUSE: + output("MEDIA_PLAY_PAUSE message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_MEDIA_PREVIOUSTRACK: + output("MEDIA_PREVIOUSTRACK message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_MEDIA_STOP: + output("MEDIA_STOP message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_VOLUME_DOWN: + output("VOLUME_DOWN message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_VOLUME_UP: + output("VOLUME_UP message received " + Integer.toString(aCommand)); + break; + case JIntellitype.APPCOMMAND_VOLUME_MUTE: + output("VOLUME_MUTE message received " + Integer.toString(aCommand)); + break; + default: + output("Undefined INTELLITYPE message caught " + Integer.toString(aCommand)); + break; + } + } + + /** + * Centers window on desktop. + *

+ * @param aFrame the Frame to center + */ + private static void center(JFrame aFrame) { + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + final Point centerPoint = ge.getCenterPoint(); + final Rectangle bounds = ge.getMaximumWindowBounds(); + final int w = Math.min(aFrame.getWidth(), bounds.width); + final int h = Math.min(aFrame.getHeight(), bounds.height); + final int x = centerPoint.x - (w / 2); + final int y = centerPoint.y - (h / 2); + aFrame.setBounds(x, y, w, h); + if ((w == bounds.width) && (h == bounds.height)) { + aFrame.setExtendedState(Frame.MAXIMIZED_BOTH); + } + aFrame.validate(); + } + + /** + * Method to register a hotkey using the RegisterHotKey Windows API call. + *

+ * @param aEvent the ActionEvent fired. + */ + private void btnRegisterHotKey_actionPerformed(ActionEvent aEvent) { + // assign the WINDOWS+A key to the unique id 88 for identification + JIntellitype.getInstance().registerHotKey(WINDOWS_A, JIntellitype.MOD_WIN, (int) 'A'); + JIntellitype.getInstance().registerHotKey(ALT_SHIFT_B, JIntellitype.MOD_ALT + JIntellitype.MOD_SHIFT, (int) 'B'); + JIntellitype.getInstance().registerSwingHotKey(CTRL_SHIFT_C, Event.CTRL_MASK + Event.SHIFT_MASK, (int) 'C'); + + // use a 0 for the modifier if you just want a single keystroke to be a hotkey + JIntellitype.getInstance().registerHotKey(PRINT_SCREEN, 0, 44); + JIntellitype.getInstance().registerHotKey(F9, 0, 120); + JIntellitype.getInstance().registerHotKey(F12, JIntellitype.MOD_ALT, 123); + // clear the text area + textArea.setText(""); + output("RegisterHotKey WINDOWS+A was assigned uniqueID 88"); + output("RegisterHotKey ALT+SHIFT+B was assigned uniqueID 89"); + output("RegisterHotKey CTRL+SHIFT+C was assigned uniqueID 90"); + output("RegisterHotKey PRINT_SCREEN was assigned uniqueID 91"); + output("RegisterHotKey F9 was assigned uniqueID 92"); + output("RegisterHotKey F12 was assigned uniqueID 93"); + output("Press WINDOWS+A or ALT+SHIFT+B or CTRL+SHIFT+C in another application and you will see the debug output in the textarea."); + } + + /** + * Method to unregister a hotkey using the UnregisterHotKey Windows API call. + *

+ * @param aEvent the ActionEvent fired. + */ + private void btnUnregisterHotKey_actionPerformed(ActionEvent aEvent) { + JIntellitype.getInstance().unregisterHotKey(WINDOWS_A); + JIntellitype.getInstance().unregisterHotKey(ALT_SHIFT_B); + JIntellitype.getInstance().unregisterHotKey(CTRL_SHIFT_C); + JIntellitype.getInstance().unregisterHotKey(PRINT_SCREEN); + JIntellitype.getInstance().unregisterHotKey(F9); + JIntellitype.getInstance().unregisterHotKey(F12); + output("UnregisterHotKey WINDOWS+A"); + output("UnregisterHotKey ALT+SHIFT+B"); + output("UnregisterHotKey CTRL+SHIFT+C"); + output("UnregisterHotKey PRINT_SCREEN"); + output("UnregisterHotKey F9"); + output("Press WINDOWS+A or ALT+SHIFT+B in another application and you will NOT see the debug output in the textarea."); + } + + /** + * This method is called from within the constructor to initialize the form. + */ + private void initComponents() { + mainPanel.setLayout(new BorderLayout()); + topPanel.setBorder(new EtchedBorder(1)); + bottomPanel.setLayout(new BorderLayout()); + bottomPanel.setBorder(new EtchedBorder(1)); + btnRegisterHotKey.setText("RegisterHotKey"); + btnRegisterHotKey.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + btnRegisterHotKey_actionPerformed(e); + } + }); + btnUnregisterHotKey.setText("UnregisterHotKey"); + btnUnregisterHotKey.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + btnUnregisterHotKey_actionPerformed(e); + } + }); + topPanel.add(btnRegisterHotKey); + topPanel.add(btnUnregisterHotKey); + scrollPane.getViewport().add(textArea); + bottomPanel.add(scrollPane, BorderLayout.CENTER); + mainPanel.add(topPanel, BorderLayout.NORTH); + mainPanel.add(bottomPanel, BorderLayout.CENTER); + + this.addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + // don't forget to clean up any resources before close + JIntellitype.getInstance().cleanUp(); + System.exit(0); + } + }); + + this.getContentPane().add(mainPanel); + this.pack(); + this.setSize(800, 600); + } + + /** + * Initialize the JInitellitype library making sure the DLL is located. + * + */ + public void initJIntellitype() { + try { + + // initialize JIntellitype with the frame so all windows commands can + // be attached to this window + JIntellitype.getInstance().addHotKeyListener(this); + JIntellitype.getInstance().addIntellitypeListener(this); + output("JIntellitype initialized"); + } catch (RuntimeException ex) { + output("Either you are not on Windows, or there is a problem with the JIntellitype library!"); + } + } + + /** + * Send the output to the log and the text area. + *

+ * @param text the text to output + */ + private void output(String text) { + textArea.append(text); + textArea.append("\n"); + } + +} \ No newline at end of file diff --git a/src/java/swt/snippets/ListSystemInfo.java b/src/java/swt/snippets/ListSystemInfo.java new file mode 100644 index 0000000..da3f303 --- /dev/null +++ b/src/java/swt/snippets/ListSystemInfo.java @@ -0,0 +1,44 @@ +package swt.snippets; + +import java.util.Properties; + +public class ListSystemInfo { + + /** + * @param args + */ + public static void main(String[] args) + { + Properties p = System.getProperties(); + for (Object key : p.keySet()) + { + System.out.println(key+" = "+p.getProperty(key.toString())); + } + + +/* +java.runtime.name = Java(TM) 2 Runtime Environment, Standard Edition +java.vm.version = 1.5.0_16-134 +java.vm.vendor = Apple Inc. +java.vendor.url = http://www.apple.com/ +java.vm.name = Java HotSpot(TM) Client VM +user.country = DE +java.runtime.version = 1.5.0_16-b06-290 +os.arch = i386 +os.name = Mac OS X +sun.jnu.encoding = MacRoman +java.class.version = 49.0 +sun.management.compiler = HotSpot Client Compiler +os.version = 10.5.7 +http.nonProxyHosts = local|*.local|169.254/16|*.169.254/16 +file.encoding = UTF-8 +java.home = /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home +sun.arch.data.model = 32 +user.language = de +java.version = 1.5.0_16 +java.vendor = Apple Inc. + */ + + } + +} diff --git a/src/java/swt/snippets/PreferenceTest.java b/src/java/swt/snippets/PreferenceTest.java new file mode 100644 index 0000000..04f7956 --- /dev/null +++ b/src/java/swt/snippets/PreferenceTest.java @@ -0,0 +1,21 @@ +package swt.snippets; + +import java.util.prefs.Preferences; + +public class PreferenceTest { + + /** + * @param args + */ + public static void main(String[] args) + { + Preferences prefs = Preferences.userNodeForPackage(PreferenceTest.class); + prefs.put("my_pref_key", "This is a sample pref value"); + + String retrieved = prefs.get("my_pref_key", "no value"); + + System.out.println("Returned: "+retrieved); + + } + +} diff --git a/src/java/swt/snippets/ProgressBarDialog.java b/src/java/swt/snippets/ProgressBarDialog.java new file mode 100644 index 0000000..150cfa4 --- /dev/null +++ b/src/java/swt/snippets/ProgressBarDialog.java @@ -0,0 +1,363 @@ +package swt.snippets; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.Shell; + +/** + * progress bar dialog. + * the first, you must know your app execute times, + * you need implement two method: + * + * process(int times); + * initGuage(); + * + * you can implements method: + * + * cleanUp() + * doBefore() + * doAfter() + * @author yin_zhiguo + * yin_zhiguo@hotmail.com + * + */ +public abstract class ProgressBarDialog extends Dialog { + + private Label processMessageLabel; //info of process finish + private Button cancelButton; //cancel button + private Composite cancelComposite; + private Label lineLabel;// + private Composite progressBarComposite;// + private CLabel message;// + private ProgressBar progressBar = null; // + + private Object result; // + private Shell shell; // + private Display display = null; + + protected volatile boolean isClosed = false;//closed state + + protected int executeTime = 50;//process times + protected String processMessage = "process......";//procress info + protected String shellTitle = "Progress..."; // + protected Image processImage = SWTUtil.getImageOfMessage();//image + protected boolean mayCancel = true; //cancel + protected int processBarStyle = SWT.SMOOTH; //process bar style + + public void setMayCancel(boolean mayCancel) { + this.mayCancel = mayCancel; + } + + public void setExecuteTime(int executeTime) { + this.executeTime = executeTime; + } + + public void setProcessImage(Image processImage) { + this.processImage = processImage; + } + + public void setProcessMessage(String processInfo) { + this.processMessage = processInfo; + } + + public ProgressBarDialog(Shell parent) { + super(parent); + } + + + public abstract void initGuage(); + + public Object open() { + createContents(); //create window + shell.open(); + shell.layout(); + + //start work + new ProcessThread(executeTime).start(); + + Display display = getParent().getDisplay(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + return result; + } + + protected void createContents() { + shell = new Shell(getParent(), SWT.TITLE | SWT.PRIMARY_MODAL); + display = shell.getDisplay(); + final GridLayout gridLayout = new GridLayout(); + gridLayout.verticalSpacing = 10; + + shell.setLayout(gridLayout); + shell.setSize(483, 181); + shell.setText(shellTitle); + + final Composite composite = new Composite(shell, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + composite.setLayout(new GridLayout()); + + message = new CLabel(composite, SWT.NONE); + message.setImage(processImage); + message.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + message.setText(processMessage); + + progressBarComposite = new Composite(shell, SWT.NONE); + progressBarComposite.setLayoutData(new GridData(GridData.FILL, + GridData.CENTER, false, false)); + progressBarComposite.setLayout(new FillLayout()); + + progressBar = new ProgressBar(progressBarComposite, processBarStyle); + progressBar.setMaximum(executeTime); + + processMessageLabel = new Label(shell, SWT.NONE); + processMessageLabel.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false)); + lineLabel = new Label(shell, SWT.HORIZONTAL | SWT.SEPARATOR); + lineLabel.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false)); + + cancelComposite = new Composite(shell, SWT.NONE); + cancelComposite.setLayoutData(new GridData(GridData.END, + GridData.CENTER, false, false)); + final GridLayout gridLayout_1 = new GridLayout(); + gridLayout_1.numColumns = 2; + cancelComposite.setLayout(gridLayout_1); + + cancelButton = new Button(cancelComposite, SWT.NONE); + cancelButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + isClosed = true; + //System.out.println(isClosed); + } + }); + cancelButton.setLayoutData(new GridData(78, SWT.DEFAULT)); + cancelButton.setText("ȡ��"); + cancelButton.setEnabled(this.mayCancel); + + } + + protected abstract String process(int times); + + + protected void cleanUp() + { + + } + + + protected void doBefore() + { + + } + + protected void doAfter() + { + + } + + class ProcessThread extends Thread { + private int max = 0; + private volatile boolean shouldStop = false; + + ProcessThread(int max) { + this.max = max; + } + + public void run() { + doBefore(); + for (final int[] i = new int[] {1}; i[0] <= max; i[0]++) + { + // + final String info = process(i[0]); + if (display.isDisposed()) { + return; + } + display.syncExec(new Runnable() { + public void run() { + if (progressBar.isDisposed()) { + return; + } + // + processMessageLabel.setText(info); + // + progressBar.setSelection(i[0]); + // + if (i[0] == max || isClosed) { + if (isClosed) { + shouldStop = true;// + cleanUp();// + } + shell.close();// + } + } + }); + + if (shouldStop) { + break; + } + } + doAfter(); + } + } + + public void setShellTitle(String shellTitle) { + this.shellTitle = shellTitle; + } + + public void setProcessBarStyle(boolean pStyle) { + if(pStyle) + this.processBarStyle = SWT.SMOOTH; + else + this.processBarStyle = SWT.NONE; + + } +} + + +class DemoProgressBar extends ProgressBarDialog { + + private String[] info = null; + + public DemoProgressBar(Shell parent) { + super(parent); + } + + + @Override + public void initGuage() { + info = new String[100]; + for (int i = 0; i < info.length; i++) { + info[i] = "process task " + i + "."; + } + this.setExecuteTime(100); + this.setMayCancel(true); + this.setProcessMessage("please waiting...."); + this.setShellTitle("Demo"); + + } + + @Override + protected String process(int arg0) { + try{ + Thread.sleep((long)(Math.random() * 300)); + }catch(Exception e){e.printStackTrace();} + + return info[arg0 - 1]; + } + +} + + +class SWTUtil { + + + private static ImageRegistry imageRegistry = new ImageRegistry(); + + private static Clipboard clipboard = new Clipboard(Display.getCurrent()); + + private static final String ___IMAGE_Of_MESSAGE = ""; + + static{ + imageRegistry.put(___IMAGE_Of_MESSAGE, ImageDescriptor.createFromURL(newURL("file:icons/info2.gif"))); + } + + + private SWTUtil(){} + + + public static URL newURL(String url_name) { + try { + return new URL(url_name); + } catch (MalformedURLException e) { + throw new RuntimeException("Malformed URL " + url_name, e); + } + } + + + public static void registryImage(String id, String urlName) + { + imageRegistry.put(id, ImageDescriptor.createFromURL(newURL(urlName))); + } + + + public static Image getImage(String id) + { + return imageRegistry.get(id); + } + + + public static Clipboard getClipboard() { + return clipboard; + } + + + public static Image getImageOfMessage() + { + return imageRegistry.get(___IMAGE_Of_MESSAGE); + } +} + + + + +class PBDialogDemo extends Shell { + + public static void main(String args[]) { + try { + Display display = Display.getDefault(); + PBDialogDemo shell = new PBDialogDemo(display, SWT.SHELL_TRIM); + shell.open(); + shell.layout(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public PBDialogDemo(Display display, int style) { + super(display, style); + createContents(); + } + + protected void createContents() { + setText("ProgressBar Dialog"); + setSize(218, 98); + setLayout(new FillLayout()); + + final Button openProgressbarDialogButton = new Button(this, SWT.NONE); + openProgressbarDialogButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + DemoProgressBar dpb = new DemoProgressBar(PBDialogDemo.this); + dpb.initGuage(); + dpb.open(); + } + }); + openProgressbarDialogButton.setText("Open ProgressBar Dialog"); + + } + + protected void checkSubclass() { + } + +} \ No newline at end of file diff --git a/src/java/swt/snippets/SearchFieldExample.java b/src/java/swt/snippets/SearchFieldExample.java new file mode 100644 index 0000000..a9b8a04 --- /dev/null +++ b/src/java/swt/snippets/SearchFieldExample.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package swt.snippets; + +/* + * Create a search text control + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + * + * @since 3.3 + */ +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.widgets.*; +import org.eclipse.swt.layout.*; +import org.eclipse.swt.events.*; + +public class SearchFieldExample { + public static void main(String[] args) + { + Display display = new Display(); + Shell shell = new Shell(display); + shell.setLayout(new GridLayout(2, false)); + + final Text text = new Text(shell, SWT.SEARCH | SWT.CANCEL); + Image image = null; + if ((text.getStyle() & SWT.CANCEL) == 0) + { + image = display.getSystemImage(SWT.ICON_ERROR); + ToolBar toolBar = new ToolBar(shell, SWT.FLAT); + ToolItem item = new ToolItem(toolBar, SWT.PUSH); + item.setImage(image); + item.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) + { + text.setText(""); + System.out.println("Search cancelled"); + } + }); + } + text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + text.setText("Search text"); + text.addSelectionListener(new SelectionAdapter() { + public void widgetDefaultSelected(SelectionEvent e) + { + if (e.detail == SWT.CANCEL) + { + System.out.println("Search cancelled"); + } else + { + System.out.println("Searching for: " + text.getText() + "..."); + } + } + }); + + shell.pack(); + shell.open(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + display.sleep(); + } + if (image != null) + image.dispose(); + display.dispose(); + } +} diff --git a/src/java/swt/snippets/SimpleHttp2.java b/src/java/swt/snippets/SimpleHttp2.java new file mode 100644 index 0000000..99f114c --- /dev/null +++ b/src/java/swt/snippets/SimpleHttp2.java @@ -0,0 +1,261 @@ +package swt.snippets; + +/*------------------------------------------------------------------------ + SimpleHttpd2 ist ein Java-Server-Programm das einen sehr + kleinen Teil des http-Protokolls implementiert. + + Der Server implementiert die GET Methode ohne Auswertung von weiteren http- + Header-Informationen. Er implementiert also einen "http-Fileserver" + + Der Quellcode zu diesem Programm ist bis auf unwesentliche Modifikationen + dem Buch "JAVA Server und Servlets" von Peter Roßbach und + Hendrik Schreiber, Addison-Wesley 1999, Seite 24, ISBN: 3-8273-1408-9 entnommen. + + Aufruf des Programms + + java SimpleHttpd2 doc-root port-number + + ------------------------------------------------------------------------*/ + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Properties; +import java.util.StringTokenizer; + +public class SimpleHttp2 extends Thread { + + protected Socket s = null; + protected static File docRoot; + protected static String canonicalDocRoot; + protected static int port; + + public final static String CRLF = "\r\n"; + public final static String PROTOCOL = "HTTP/1.0 "; + + public final static String SC_OK = "200 OK"; + public final static String SC_BAD_REQUEST = "400 Bad Request"; + public final static String SC_FORBIDDEN = "403 Forbidden"; + public final static String SC_NOT_FOUND = "404 Not Found"; + + protected static Properties typeMap = new Properties(); + protected String statusCode = SC_OK; + protected Hashtable myHeaders = new Hashtable(); + + public static void main(String args[]) + { + + try + { + if (args.length != 2) + { + throw new IllegalArgumentException("usage: java SimpleHttp2 "); + } + + // typeMap.load(new FileInputStream("Mime.types")); + docRoot = new File(args[0]); + port = Integer.parseInt(args[1]); + canonicalDocRoot = docRoot.getCanonicalPath(); + ServerSocket listen = new ServerSocket(port); + + System.out.println("http server started on: " + (InetAddress.getLocalHost()).getHostAddress()); + System.out.println("listening on port: " + listen.getLocalPort()); + System.out.println("document root is: " + canonicalDocRoot); + + while (true) + { + SimpleHttp2 aRequest = new SimpleHttp2(listen.accept()); + } + } catch (Exception e) + { + System.err.println("Exception: " + e.toString()); + } + } + + public SimpleHttp2(Socket s) + { + this.s = s; + start(); + } + + public void run() + { + + try + { + setHeader("Server", "Simidude"); + BufferedReader is = new BufferedReader(new InputStreamReader(s.getInputStream())); + DataOutputStream os = new DataOutputStream(s.getOutputStream()); + String request = is.readLine(); + + System.out.println(s.getInetAddress().getHostAddress() + " " + request); + + StringTokenizer st = new StringTokenizer(request); + + if ((st.countTokens() == 3) && st.nextToken().equals("GET")) + { + + String filename = docRoot.getPath() + st.nextToken(); + + // if ( filename.endsWith("/") || filename.equals("") ) { + // filename += "index.html"; + // } + + File file = new File(filename); + if (file.getCanonicalPath().startsWith(canonicalDocRoot)) + { + if (file.isDirectory()) + { + sendListing(os, file); + } else { + sendDocument(os, file); + } + } else + { + sendError(SC_FORBIDDEN, os); + } + } else + { + sendError(SC_BAD_REQUEST, os); + } + + is.close(); + os.close(); + s.close(); + } catch (IOException e) + { + System.err.println("Exception: " + e.toString()); + } + } + + protected void sendDocument(DataOutputStream os, File file) throws IOException + { + try + { + BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); + sendStatusLine(os); + setHeader("Content-Length", (new Long(file.length())).toString()); + setHeader("Content-Type", guessType(file.getPath())); + sendHeader(os); + os.writeBytes(CRLF); + + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf, 0, 1024)) != -1) + { + os.write(buf, 0, len); + } + in.close(); + } catch (FileNotFoundException e) + { + sendError(SC_NOT_FOUND, os); + } + } + + protected void sendListing(DataOutputStream os, File file) throws IOException + { + try + { + sendStatusLine(os); + setHeader("Content-Type", "text/html"); + sendHeader(os); + os.writeBytes(CRLF); + + String s = "Simidude Entries

Simidude Entries

"; + + os.write(s.getBytes()); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + protected void setStatusCode(String statusCode) + { + this.statusCode = statusCode; + } + + protected String getStatusCode() + { + return statusCode; + } + + /** + * die Methode sendet eine Statuszeile an den Client. + */ + protected void sendStatusLine(DataOutputStream out) throws IOException + { + out.writeBytes(PROTOCOL + getStatusCode() + CRLF); + } + + /** + * die Methode fügt der Header-Hashtable ein Name-Value-Paar hinzu. + */ + protected void setHeader(String key, String value) + { + myHeaders.put(key, value); + } + + /** + * die Methode sendet die http-Header-Informationen zum Client. Die + * Header-Informationen sind in einer Hashtable abgelegt. + */ + protected void sendHeader(DataOutputStream out) throws IOException + { + String line; + String key; + Enumeration e = myHeaders.keys(); + while (e.hasMoreElements()) + { + key = (String) e.nextElement(); + out.writeBytes(key + ": " + myHeaders.get(key) + CRLF); + } + } + + /** + * die Methode sendet eine Fehlerseite mit Status-Code an den Client. Die + * Fehlerseite besteht aus einer Statuszeile und einer HTML-Seite die durch + * CRLF von der Statuszeile getrennt ist. + */ + protected void sendError(String statusCode, DataOutputStream out) throws IOException + { + setStatusCode(statusCode); + sendStatusLine(out); + out.writeBytes(CRLF + "" + "" + getStatusCode() + "" + "" + + getStatusCode() + "" + ""); + System.err.println(getStatusCode()); + } + + /** + * die Methode bestimmt aus der Dateiendung den mimetype einer Datei. + * + * Dazu vergleicht sie die Dateiendung mit den beim Programmstart in eine + * Hashtable (Properties) geladenen Name-Value-Paare aus Dateiendung und + * mimetype. Im Erfolgsfall gibt sie den mimetype der Datei als String zurück. + * Sonst wird der String "unknown/unknown" als Rückgabewert verwendet. + */ + public String guessType(String filename) + { + String type = null; + int i = filename.lastIndexOf("."); + if (i > 0) + { + type = typeMap.getProperty(filename.substring(i)); + } + if (type == null) + { + type = "unknown/unknown"; + } + return type; + } +} diff --git a/src/java/swt/snippets/Snippet67.java b/src/java/swt/snippets/Snippet67.java new file mode 100644 index 0000000..22517bf --- /dev/null +++ b/src/java/swt/snippets/Snippet67.java @@ -0,0 +1,54 @@ +package swt.snippets; + +/* + * ToolBar example snippet: Place a drop down menu in a tool bar + * + * For a list of all SWT example snippets see + * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets + */ +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +public class Snippet67 { + + public static void main(String[] args) { + final Display display = new Display(); + final Shell shell = new Shell(display); + final ToolBar toolBar = new ToolBar(shell, SWT.NONE); + final Menu menu = new Menu(shell, SWT.POP_UP); + for (int i = 0; i < 8; i++) { + MenuItem item = new MenuItem(menu, SWT.PUSH); + item.setText("Item " + i); + } + final ToolItem item = new ToolItem(toolBar, SWT.DROP_DOWN); + item.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + if (event.detail == SWT.ARROW) { + Rectangle rect = item.getBounds(); + Point pt = new Point(rect.x, rect.y + rect.height); + pt = toolBar.toDisplay(pt); + menu.setLocation(pt.x, pt.y); + menu.setVisible(true); + } + } + }); + toolBar.pack(); + shell.pack(); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + menu.dispose(); + display.dispose(); + } +}