Progress Bar Update Issues in My Plugin

Answered

I am trying to integrate a progress bar into my code. The intention is for it to display the current status, making it easier to debug in the event of an issue or any future bugs. 

When I initiate my plugin and the action begins, the progress bar displays with the initial status "Starting translation...".

 However, after that, the process continues without updating the progress bar, and it only displays the final result as a notification, as I intended. 

I want the progress bar to reflect each status change according to my code. 

Could you please assist me with this issue?

private val totalWeight = 100.0
private val weightLoadFiles = 10.0
private val weightIdentifyKeys = 30.0
private val weightTranslateKeys = 50.0
private val weightSaveKeys = 10.0

private fun performTranslation(event: AnActionEvent, indicator: ProgressIndicator) {
   LOG.info("TranslationAction triggered!")

   indicator.isIndeterminate = false
   indicator.fraction = 0.1
   indicator.text = "Starting translation..."
   Thread.sleep(500)
   indicator.checkCanceled()

   val selectedFiles = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return

   ApplicationManager.getApplication().invokeAndWait {
       // ... Code for selecting translator and files

 // Load Files
indicator.text = "Loading English properties..."
Thread.sleep(500)
indicator.checkCanceled()...
       
       indicator.fraction += weightLoadFiles / totalWeight
       
       // ... Code for identifying keys

// Identify Missing Keys
indicator.text = "Identifying missing keys in ${InputType.file.name}..."
Thread.sleep(500)
indicator.checkCanceled() ...

       indicator.fraction += weightIdentifyKeys / totalWeight

       // ... Code for translating keys

// Translate Missing Keys
indicator.text = "Translating missing keys..."
Thread.sleep(1000) ...

       indicator.fraction += weightTranslateKeys / totalWeight

// Save Translated Keys

       indicator.text = "Saving translated keys..."
       indicator.fraction += weightSaveKeys / totalWeight
       Thread.sleep(500)
       indicator.checkCanceled()
       
       // ... Code for saving keys ...

       indicator.text = "Translation action completed!"
       indicator.fraction = 1.0
   }
}

override fun actionPerformed(event: AnActionEvent) {
   val project = event.project ?: return
   ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Translating Properties", true) {
       override fun run(indicator: ProgressIndicator) {
           performTranslation(event, indicator)
       }
   })
}

0
2 comments

Hi Saeed,

Why do you wrap it in ApplicationManager.getApplication().invokeAndWait{ … }

I removed this code part and val selectedFiles = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return and everything works fine.

0

Hi Karol,

Thank you for your comment.

regarding this report , the code is attempting to access UI-related components or perform UI-related operations from a non-EDT thread.

Access is allowed from event dispatch thread only

com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments: EventQueue.isDispatchThread()=false
Current thread: Thread[ApplicationImpl pooled thread 1,4,main] 708266495
SystemEventQueueThread: Thread[AWT-EventQueue-0,6,main] 98897613
    at com.intellij.openapi.application.impl.ApplicationImpl.throwThreadAccessException(ApplicationImpl.java:1067)
    at com.intellij.openapi.application.impl.ApplicationImpl.assertIsDispatchThread(ApplicationImpl.java:1050)
    at com.intellij.ide.impl.DataManagerImpl.getDataContext(DataManagerImpl.java:261)
    at com.intellij.ide.impl.DataManagerImpl.getDataContext(DataManagerImpl.java:297)
    at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl.<init>(DialogWrapperPeerImpl.java:94)
    at com.intellij.openapi.ui.impl.DialogWrapperPeerFactoryImpl.createPeer(DialogWrapperPeerFactoryImpl.java:21)
    at com.jetbrains.rdserver.ui.dialogs.BackendDialogWrapperPeerFactory.createPeer(BackendDialogWrapperPeerFactory.kt:31)
    at com.intellij.openapi.ui.DialogWrapper.createPeer(DialogWrapper.java:851)
    at com.intellij.openapi.ui.DialogWrapper.<init>(DialogWrapper.java:226)
    at com.intellij.openapi.ui.DialogWrapper.<init>(DialogWrapper.java:218)
    at com.intellij.openapi.ui.messages.MessageDialog.<init>(MessageDialog.java:63)
    at com.intellij.openapi.ui.messages.MessageDialog.<init>(MessageDialog.java:49)
    at com.intellij.openapi.ui.messages.MessageDialog.<init>(MessageDialog.java:72)
    at com.intellij.ui.messages.ChooseDialog.<init>(ChooseDialog.java:58)
    at com.intellij.ui.messages.MessagesServiceImpl.showEditableChooseDialog(MessagesServiceImpl.java:205)
    at com.intellij.openapi.ui.Messages.showEditableChooseDialog(Messages.java:898)
     com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:429)
    at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:114)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$6(CoreProgressManager.java:480)
    at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$3(ProgressRunner.java:252)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:186)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$13(CoreProgressManager.java:604)
    at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:679)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:635)
    at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:603)
    at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:60)
    at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:173)
    at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:252)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:702)
    at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:699)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:699)
    at java.base/java.lang.Thread.run(Thread.java:833)

 

This is a part of the code i am trying to implement
 


private val totalWeight = 100.0

// weights for each major step
private val weightLoadFiles = 10.0
private val weightIdentifyKeys = 30.0
private val weightTranslateKeys = 50.0
private val weightSaveKeys = 10.0

private fun simulateDelay(indicator: ProgressIndicator, millis: Long) {
Thread.sleep(millis)
indicator.checkCanceled()
}

private fun updateIndicator(indicator: ProgressIndicator, text: String, weight: Double) {
SwingUtilities.invokeLater {
indicator.text = text
indicator.fraction += weight / totalWeight
}
}

private fun performTranslation(event: AnActionEvent, indicator: ProgressIndicator) {
LOG.info("TranslationAction triggered!")
indicator.isIndeterminate = false
indicator.fraction = 0.0

updateIndicator(indicator, "Starting translation...", 0.0)
simulateDelay(indicator, 500)

val selectedFiles = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return

val translatorType = Messages.showEditableChooseDialog(
"Select a translator:",
"Choose Translator",
Messages.getInformationIcon(),
availableTranslators.toTypedArray(),
availableTranslators[0],
null
)

if (translatorType != null) {
val translator = translatorFactory.getTranslator(translatorType)

if (selectedFiles.size >= 2) {
updateIndicator(indicator, "Loading English properties...", weightLoadFiles)
simulateDelay(indicator, 500)

val englishPropertiesFile = findEnglishPropertiesFile(selectedFiles)
if (englishPropertiesFile == null) {
showErrorNotification("The English properties file could not be found or does not meet the expected format.")
return
}
val englishProperties = englishPropertiesFile?.let { loadProperties(it) }

// Identify Missing Keys
updateIndicator(indicator, "Identifying missing keys...", weightIdentifyKeys)
simulateDelay(indicator, 500)

val targetLanguages = mutableSetOf<String>()
val missingKeysPerFile = mutableMapOf<VirtualFile, Set<String>>()
selectedFiles
.filter { file -> file != englishPropertiesFile && file.name.matches(Regex(".+_[a-z]{2}\\.properties$")) }
.forEach { file ->
val properties = loadProperties(file)
val fileMissingKeys = englishProperties?.let { getMissingKeys(it, properties, indicator) }
if (fileMissingKeys != null) {
missingKeysPerFile[file] = fileMissingKeys
}

targetLanguages.add(getLanguageCodeFromFileName(file.name))
}

// Translate Missing Keys
updateIndicator(indicator, "Translating missing keys...", weightTranslateKeys)
simulateDelay(indicator, 500)

val processedFiles = mutableSetOf<String>()
try {
if (englishProperties != null) {
translateMissingKeys(
indicator,
englishProperties,
missingKeysPerFile,
targetLanguages,
selectedFiles,
translator,
processedFiles
)
}
} catch (e: Exception) {
val errorMessage = buildString {
append("An unexpected error occurred during translation:\n\n")
append("Last successful step: Translating missing keys.\n\n")
append("Error message: ${e.message}\n")
append("Exception: ${e.javaClass.simpleName}\n")
}
showErrorNotification(errorMessage)
}

// Save Translated Keys
updateIndicator(indicator, "Saving translated keys...", weightSaveKeys)
simulateDelay(indicator, 500)

if (englishProperties != null) {
checkAndRemoveExtraKeys(indicator, englishProperties, missingKeysPerFile, selectedFiles)
}
}

indicator.text = "Translation action completed!"
indicator.fraction = 1.0
}
}
 

override fun actionPerformed(event: AnActionEvent) {
val project = event.project ?: return
FileSaveListener.runActivity()
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Translating Properties", true) {
override fun run(indicator: ProgressIndicator) {
performTranslation(event, indicator)
}
})
}

0

Please sign in to leave a comment.