From 9290fe9cff46c328b27a7a763d93cb3411e390d5 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Sat, 20 Dec 2025 18:14:41 +0100 Subject: [PATCH 01/11] Refactor splash screen launch logic in Start.kt (#1357) Simplifies the splash screen logic by removing coroutine delays and instead using a LaunchedEffect to trigger Base.main after the splash animation completes. The splash window now closes automatically when a new window is opened, improving startup flow and reliability. --- app/src/processing/app/ui/Start.kt | 45 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/app/src/processing/app/ui/Start.kt b/app/src/processing/app/ui/Start.kt index d7ed635ec..592b73399 100644 --- a/app/src/processing/app/ui/Start.kt +++ b/app/src/processing/app/ui/Start.kt @@ -14,10 +14,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.* -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState import processing.app.Base +import java.awt.AWTEvent +import java.awt.event.WindowEvent + /** * Show a splash screen window. A rewrite of Splash.java @@ -27,8 +31,6 @@ class Start { @JvmStatic fun main(args: Array) { val duration = 200 - val timeMargin = 50 - application { var starting by remember { mutableStateOf(true) } Window( @@ -44,24 +46,10 @@ class Start { ) ) { var visible by remember { mutableStateOf(false) } - val composition = rememberCoroutineScope() + var launched by remember { mutableStateOf(false) } LaunchedEffect(Unit) { Toolkit.setIcon(window) - visible = true - composition.launch { - delay(duration.toLong() + timeMargin) - try { - Base.main(args) - } catch (e: Exception) { - throw InternalError("Failed to invoke main method", e) - } - composition.launch { - visible = false - delay(duration.toLong() + timeMargin) - starting = false - } - } } AnimatedVisibility( visible = visible, @@ -76,8 +64,23 @@ class Start { durationMillis = duration, easing = LinearEasing ) - ) + ), ) { + LaunchedEffect(visible, transition.currentState) { + if (launched) return@LaunchedEffect + if (!visible) return@LaunchedEffect + // Wait until the view is no longer transitioning + if (transition.targetState != transition.currentState) return@LaunchedEffect + launched = true + Base.main(args) + // List for any new windows opening, and close the splash when one does + java.awt.Toolkit.getDefaultToolkit() + .addAWTEventListener({ event -> + if (event.id != WindowEvent.WINDOW_OPENED) return@addAWTEventListener + + visible = false + }, AWTEvent.WINDOW_EVENT_MASK); + } Image( painter = painterResource("about-processing.svg"), contentDescription = "About", From edaf153ba4452b7f7991c182ba868f65dde8854e Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Tue, 23 Dec 2025 17:34:56 +0100 Subject: [PATCH 02/11] Fix tabbing issue with textfields (#1367) --- app/src/processing/app/ui/preferences/General.kt | 1 + app/src/processing/app/ui/preferences/Other.kt | 1 + app/src/processing/app/ui/preferences/Sketches.kt | 1 + 3 files changed, 3 insertions(+) diff --git a/app/src/processing/app/ui/preferences/General.kt b/app/src/processing/app/ui/preferences/General.kt index a8bd55903..14b7e6578 100644 --- a/app/src/processing/app/ui/preferences/General.kt +++ b/app/src/processing/app/ui/preferences/General.kt @@ -46,6 +46,7 @@ class General { modifier = Modifier.fillMaxWidth(), label = { Text(locale["preferences.sketchbook_location"]) }, value = preference ?: "", + singleLine = true, onValueChange = { updatePreference(it) }, diff --git a/app/src/processing/app/ui/preferences/Other.kt b/app/src/processing/app/ui/preferences/Other.kt index 8544f7694..526449c77 100644 --- a/app/src/processing/app/ui/preferences/Other.kt +++ b/app/src/processing/app/ui/preferences/Other.kt @@ -74,6 +74,7 @@ class Other { OutlinedTextField( modifier = Modifier.widthIn(max = 300.dp), value = preference ?: "", + singleLine = true, onValueChange = { updatePreference(it) } diff --git a/app/src/processing/app/ui/preferences/Sketches.kt b/app/src/processing/app/ui/preferences/Sketches.kt index b3fef23cd..f6754705d 100644 --- a/app/src/processing/app/ui/preferences/Sketches.kt +++ b/app/src/processing/app/ui/preferences/Sketches.kt @@ -118,6 +118,7 @@ class Sketches { enabled = LocalPreferences.current["run.options.memory"]?.toBoolean() ?: false, modifier = Modifier.widthIn(max = 300.dp), value = preference ?: "", + singleLine = true, trailingIcon = { Text("MB") }, onValueChange = { setPreference(it) From 76b9bae9238c085656b0ddb2b8e42d70fc76660b Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Thu, 8 Jan 2026 19:31:18 +0100 Subject: [PATCH 03/11] Refactor locale resource loading logic (#1364) Read the locale strings as UTF-8 --- app/src/processing/app/ui/theme/Locale.kt | 26 ++++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt index 74a410afc..c264d24d8 100644 --- a/app/src/processing/app/ui/theme/Locale.kt +++ b/app/src/processing/app/ui/theme/Locale.kt @@ -7,7 +7,6 @@ import processing.app.Messages import processing.app.watchFile import processing.utils.Settings import java.io.File -import java.io.InputStream import java.util.* /** @@ -26,21 +25,18 @@ import java.util.* class Locale(language: String = "", val setLocale: ((java.util.Locale) -> Unit)? = null) : Properties() { var locale: java.util.Locale = java.util.Locale.getDefault() + fun loadResource(resourcePath: String) { + val stream = ClassLoader.getSystemResourceAsStream(resourcePath) ?: return + load(stream.reader(Charsets.UTF_8)) + } + init { - val locale = java.util.Locale.getDefault() - load(ClassLoader.getSystemResourceAsStream("languages/PDE.properties")) - load( - ClassLoader.getSystemResourceAsStream("languages/PDE_${locale.language}.properties") - ?: InputStream.nullInputStream() - ) - load( - ClassLoader.getSystemResourceAsStream("languages/PDE_${locale.toLanguageTag()}.properties") - ?: InputStream.nullInputStream() - ) - load( - ClassLoader.getSystemResourceAsStream("languages/PDE_${language}.properties") - ?: InputStream.nullInputStream() - ) + loadResource("languages/PDE.properties") + loadResource("languages/PDE_${locale.language}.properties") + loadResource("languages/PDE_${locale.toLanguageTag()}.properties") + if (language.isNotEmpty()) { + loadResource("languages/PDE_${language}.properties") + } } @Deprecated("Use get instead", ReplaceWith("get(key)")) From 621d9900b58a418fd9f9c70f3d850c7ddfe6d845 Mon Sep 17 00:00:00 2001 From: Madhav Majumdar <161720210+madhav2348@users.noreply.github.com> Date: Thu, 15 Jan 2026 03:24:27 +0530 Subject: [PATCH 04/11] Migration of the `svg` library to Gradle (#1289) * Update svg build.gradle.kts * update variable legacyLibraries and libraries --- java/build.gradle.kts | 4 +-- java/libraries/svg/build.gradle.kts | 41 ++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/java/build.gradle.kts b/java/build.gradle.kts index fc7151189..47fa76e46 100644 --- a/java/build.gradle.kts +++ b/java/build.gradle.kts @@ -68,7 +68,7 @@ tasks.register("copyCore"){ into(coreProject.layout.projectDirectory.dir("library")) } -val legacyLibraries = arrayOf("io","net","svg") +val legacyLibraries = arrayOf("io","net") legacyLibraries.forEach { library -> tasks.register("library-$library-extraResources"){ val build = project(":java:libraries:$library").tasks.named("build") @@ -87,7 +87,7 @@ legacyLibraries.forEach { library -> } } -val libraries = arrayOf("dxf", "pdf", "serial") +val libraries = arrayOf("dxf", "pdf", "serial", "svg") libraries.forEach { library -> val name = "create-$library-library" diff --git a/java/libraries/svg/build.gradle.kts b/java/libraries/svg/build.gradle.kts index a176f03df..ddc439784 100644 --- a/java/libraries/svg/build.gradle.kts +++ b/java/libraries/svg/build.gradle.kts @@ -1 +1,40 @@ -ant.importBuild("build.xml") \ No newline at end of file +plugins { + java +} + +sourceSets { + main { + java { + srcDirs("src") + } + } +} +repositories { + mavenCentral() +} + +dependencies { + compileOnly(project(":core")) + + implementation("org.apache.xmlgraphics:batik-all:1.19") +} + +tasks.register("createLibrary") { + dependsOn("jar") + into(layout.buildDirectory.dir("library")) + + from(layout.projectDirectory) { + include("library.properties") + include("examples/**") + } + + from(configurations.runtimeClasspath) { + into("library") + } + + from(tasks.jar) { + into("library") + rename { "svg.jar" } + } +} + From ac09bfe79e5052f59c987957aac530b04bfdb242 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Wed, 14 Jan 2026 22:56:03 +0100 Subject: [PATCH 05/11] Fixed an issue where the stream was left open (#1380) --- app/src/processing/app/Preferences.kt | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/processing/app/Preferences.kt b/app/src/processing/app/Preferences.kt index bd75896af..e742de189 100644 --- a/app/src/processing/app/Preferences.kt +++ b/app/src/processing/app/Preferences.kt @@ -103,15 +103,17 @@ fun PreferencesProvider(content: @Composable () -> Unit) { ReactiveProperties().apply { val defaultsStream = ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME) ?: InputStream.nullInputStream() - load( - defaultsStream - .reader(Charsets.UTF_8) - ) - load( - preferencesFile - .inputStream() - .reader(Charsets.UTF_8) - ) + defaultsStream + .reader(Charsets.UTF_8) + .use { reader -> + load(reader) + } + preferencesFile + .inputStream() + .reader(Charsets.UTF_8) + .use { reader -> + load(reader) + } } } @@ -135,6 +137,7 @@ fun PreferencesProvider(content: @Composable () -> Unit) { // Reload legacy Preferences Preferences.init() + output.close() } } } From 4edb29ad10355f7a472bbc7431916b13d598970a Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Wed, 14 Jan 2026 22:57:39 +0100 Subject: [PATCH 06/11] Refactor Other preferences registration logic (#1379) Made sure the logic for displaying experimental settings runs regardless of the visibility of the toggle --- app/src/processing/app/ui/PDEPreferences.kt | 4 +- .../processing/app/ui/preferences/Other.kt | 91 ++++++++++--------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/app/src/processing/app/ui/PDEPreferences.kt b/app/src/processing/app/ui/PDEPreferences.kt index ac5bf2609..9e3a92e60 100644 --- a/app/src/processing/app/ui/PDEPreferences.kt +++ b/app/src/processing/app/ui/PDEPreferences.kt @@ -99,7 +99,7 @@ class PDEPreferences { Interface.register() Coding.register() Sketches.register() - Other.register(panes) + Other.register() } /** @@ -111,6 +111,8 @@ class PDEPreferences { val locale = LocalLocale.current var preferencesQuery by remember { mutableStateOf("") } + Other.handleOtherPreferences(panes) + /** * Filter panes based on the search query. */ diff --git a/app/src/processing/app/ui/preferences/Other.kt b/app/src/processing/app/ui/preferences/Other.kt index 526449c77..c06058d72 100644 --- a/app/src/processing/app/ui/preferences/Other.kt +++ b/app/src/processing/app/ui/preferences/Other.kt @@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Lightbulb import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch +import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -27,7 +28,7 @@ class Other { after = sketches ) - fun register(panes: PDEPreferencePanes) { + fun register() { PDEPreferences.register( PDEPreference( key = "preferences.show_other", @@ -41,57 +42,61 @@ class Other { setPreference(it.toString()) } ) - if (!showOther) { - return@PDEPreference - } - val prefs = LocalPreferences.current - val locale = LocalLocale.current - DisposableEffect(Unit) { - // add all the other options to the same group as the current one - val group = - panes[other]?.find { group -> group.any { preference -> preference.key == "preferences.show_other" } } as? MutableList + } + ) + ) + } - val existing = panes.values.flatten().flatten().map { preference -> preference.key } - val keys = prefs.keys.mapNotNull { it as? String }.filter { it !in existing }.sorted() + @Composable + fun handleOtherPreferences(panes: PDEPreferencePanes) { + // This function can be used to handle any specific logic related to other preferences if needed + val prefs = LocalPreferences.current + val locale = LocalLocale.current + if (prefs["preferences.show_other"]?.toBoolean() != true) { + return + } + DisposableEffect(panes) { + // add all the other options to the same group as the current one + val group = + panes[other]?.find { group -> group.any { preference -> preference.key == "preferences.show_other" } } as? MutableList - for (prefKey in keys) { - val descriptionKey = "preferences.$prefKey" - val preference = PDEPreference( - key = prefKey, - descriptionKey = if (locale.containsKey(descriptionKey)) descriptionKey else prefKey, - pane = other, - control = { preference, updatePreference -> - if (preference?.toBooleanStrictOrNull() != null) { - Switch( - checked = preference.toBoolean(), - onCheckedChange = { - updatePreference(it.toString()) - } - ) - return@PDEPreference - } + val existing = panes.values.flatten().flatten().map { preference -> preference.key } + val keys = prefs.keys.mapNotNull { it as? String }.filter { it !in existing }.sorted() - OutlinedTextField( - modifier = Modifier.widthIn(max = 300.dp), - value = preference ?: "", - singleLine = true, - onValueChange = { - updatePreference(it) - } - ) + for (prefKey in keys) { + val descriptionKey = "preferences.$prefKey" + val preference = PDEPreference( + key = prefKey, + descriptionKey = if (locale.containsKey(descriptionKey)) descriptionKey else prefKey, + pane = other, + control = { preference, updatePreference -> + if (preference?.toBooleanStrictOrNull() != null) { + Switch( + checked = preference.toBoolean(), + onCheckedChange = { + updatePreference(it.toString()) } ) - group?.add(preference) + return@PDEPreference } - onDispose { - group?.apply { - removeIf { it.key != "preferences.show_other" } + + OutlinedTextField( + modifier = Modifier.widthIn(max = 300.dp), + value = preference ?: "", + onValueChange = { + updatePreference(it) } - } + ) } + ) + group?.add(preference) + } + onDispose { + group?.apply { + removeIf { it.key != "preferences.show_other" } } - ) - ) + } + } } } } \ No newline at end of file From 8466ee1ee05c34c99b8a184a32702b80f7b406f1 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Fri, 16 Jan 2026 15:51:52 +0100 Subject: [PATCH 07/11] Instant Locale Updatee (#1384) Keep track of locale updates within the Process so that when the user changes the locale, that is immediately reflected within the app and later within other instances of Processing when the watch file kicks off the reload --- app/src/processing/app/ui/theme/Locale.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt index c264d24d8..90de50a71 100644 --- a/app/src/processing/app/ui/theme/Locale.kt +++ b/app/src/processing/app/ui/theme/Locale.kt @@ -62,6 +62,7 @@ class Locale(language: String = "", val setLocale: ((java.util.Locale) -> Unit)? * ``` */ val LocalLocale = compositionLocalOf { error("No Locale Set") } +var LastLocaleUpdate by mutableStateOf(0L) /** * This composable function sets up a locale provider that manages application localization. @@ -101,7 +102,11 @@ fun LocaleProvider(content: @Composable () -> Unit) { } val update = watchFile(languageFile) - var code by remember(languageFile, update) { mutableStateOf(languageFile.readText().substring(0, 2)) } + var code by remember(languageFile, update, LastLocaleUpdate) { + mutableStateOf( + languageFile.readText().substring(0, 2) + ) + } remember(code) { val locale = java.util.Locale(code) java.util.Locale.setDefault(locale) @@ -111,6 +116,7 @@ fun LocaleProvider(content: @Composable () -> Unit) { Messages.log("Setting locale to ${locale.language}") languageFile.writeText(locale.language) code = locale.language + LastLocaleUpdate = System.currentTimeMillis() } From aaa3f75362bc9fa52e4b58c75f1608cc1c2df952 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Fri, 16 Jan 2026 15:52:40 +0100 Subject: [PATCH 08/11] Create PreferencesEvents to glue into base and other deps (#1386) To avoid creating dependencies within Preferences.kt, create an event structure that will listen to changes triggered by saving the Preferences. --- app/src/processing/app/Base.java | 2 ++ app/src/processing/app/Preferences.kt | 25 ++++++++++++++++++------- app/src/processing/app/ui/Editor.java | 1 + 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a083d139a..85a7ef015 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -198,6 +198,8 @@ static private void createAndShowGUI(String[] args) { // run static initialization that grabs all the prefs Preferences.init(); + PreferencesEvents.onUpdated(Preferences::init); + // boolean flag indicating whether to create new server instance or not boolean createNewInstance = DEBUG || !SingleInstance.alreadyRunning(args); diff --git a/app/src/processing/app/Preferences.kt b/app/src/processing/app/Preferences.kt index e742de189..1b344a5e1 100644 --- a/app/src/processing/app/Preferences.kt +++ b/app/src/processing/app/Preferences.kt @@ -1,12 +1,9 @@ package processing.app import androidx.compose.runtime.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.delay +import kotlinx.coroutines.* import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.dropWhile -import kotlinx.coroutines.launch import processing.utils.Settings import java.io.File import java.io.InputStream @@ -134,10 +131,9 @@ fun PreferencesProvider(content: @Composable () -> Unit) { .joinToString("\n") { (key, value) -> "$key=$value" } .toByteArray() ) - - // Reload legacy Preferences - Preferences.init() output.close() + + PreferencesEvents.updated() } } } @@ -205,4 +201,19 @@ fun watchFile(file: File): Any? { } } return event +} + +class PreferencesEvents { + companion object { + val updatedListeners = mutableListOf() + + @JvmStatic + fun onUpdated(callback: Runnable) { + updatedListeners.add(callback) + } + + fun updated() { + updatedListeners.forEach { it.run() } + } + } } \ No newline at end of file diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index 0437240b3..3ef108a27 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -371,6 +371,7 @@ public void actionPerformed(ActionEvent e) { }); } + PreferencesEvents.onUpdated(this::updateTheme); } From 1af2eb7348d33231e216e74e911227d10a21473b Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Fri, 16 Jan 2026 15:53:16 +0100 Subject: [PATCH 09/11] Make `CapturePreferences` only keep track of changes (#1383) Before `CapturePreferences` would override `LocalPreferences` and halt any changes upstream until `apply` was called, now it will let those changes slip through so we get immediate feedback on changes made in the preferences screen. --- app/src/processing/app/ui/PDEPreferences.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/ui/PDEPreferences.kt b/app/src/processing/app/ui/PDEPreferences.kt index 9e3a92e60..020856b8d 100644 --- a/app/src/processing/app/ui/PDEPreferences.kt +++ b/app/src/processing/app/ui/PDEPreferences.kt @@ -443,7 +443,7 @@ private val LocalModifiablePreferences = compositionLocalOf { ModifiablePreference(null, false, { }, {}) } /** - * Composable function that provides a modifiable copy of the current preferences. + * Composable function that captures an initial copy of the current preferences. * This allows for temporary changes to preferences that can be reset or applied later. * * @param content The composable content that will have access to the modifiable preferences. @@ -500,13 +500,13 @@ private fun CapturePreferences(content: @Composable () -> Unit) { } val apply = { - modified.entries.forEach { (key, value) -> - prefs.setProperty(key as String, (value ?: "") as String) + prefs.entries.forEach { (key, value) -> + modified.setProperty(key as String, (value ?: "") as String) } } val reset = { modified.entries.forEach { (key, value) -> - modified.setProperty(key as String, prefs[key] ?: "") + prefs.setProperty(key as String, modified[key] ?: "") } } val state = ModifiablePreference( @@ -517,7 +517,6 @@ private fun CapturePreferences(content: @Composable () -> Unit) { ) CompositionLocalProvider( - LocalPreferences provides modified, LocalModifiablePreferences provides state ) { content() From 02f8b39c1ce83c1e098531690aba81ff426d1461 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Fri, 16 Jan 2026 15:53:44 +0100 Subject: [PATCH 10/11] use starting to fully remove the window (#1382) --- app/src/processing/app/ui/Start.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/ui/Start.kt b/app/src/processing/app/ui/Start.kt index 592b73399..a5edc845e 100644 --- a/app/src/processing/app/ui/Start.kt +++ b/app/src/processing/app/ui/Start.kt @@ -78,7 +78,7 @@ class Start { .addAWTEventListener({ event -> if (event.id != WindowEvent.WINDOW_OPENED) return@addAWTEventListener - visible = false + starting = false }, AWTEvent.WINDOW_EVENT_MASK); } Image( From df585defc6e7633aba99ca86400e4d9c2edaaa36 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Fri, 16 Jan 2026 15:55:14 +0100 Subject: [PATCH 11/11] Added `rebuildToolList()` to fix nullpointer in contributions check (#1381) --- app/src/processing/app/Base.java | 1 + .../app/contrib/ContributionListing.java | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 85a7ef015..49a8625e5 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -487,6 +487,7 @@ public Base(String[] args) throws Exception { buildCoreModes(); rebuildContribModes(); rebuildContribExamples(); + rebuildToolList(); // Needs to happen after the sketchbook folder has been located. // Also relies on the modes to be loaded, so it knows what can be diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index 08b8d307c..b5937993c 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -21,14 +21,6 @@ */ package processing.app.contrib; -import java.awt.EventQueue; -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.net.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; - import processing.app.Base; import processing.app.Messages; import processing.app.UpdateCheck; @@ -37,6 +29,16 @@ import processing.data.StringDict; import processing.data.StringList; +import java.awt.*; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + public class ContributionListing { static volatile ContributionListing singleInstance; @@ -275,6 +277,8 @@ public void downloadAvailableList(final Base base, } catch (MalformedURLException e) { progress.setException(e); progress.finished(); + } catch (Exception e) { + Messages.log(e.getMessage()); } finally { downloadingLock.unlock(); }