33
44package software.aws.toolkits.jetbrains.services.amazonq.toolwindow
55
6- import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
76import com.intellij.idea.AppMode
87import com.intellij.openapi.Disposable
98import com.intellij.openapi.components.service
@@ -21,8 +20,6 @@ import kotlinx.coroutines.CoroutineScope
2120import kotlinx.coroutines.flow.first
2221import kotlinx.coroutines.launch
2322import kotlinx.coroutines.withContext
24- import software.aws.toolkits.core.utils.error
25- import software.aws.toolkits.core.utils.getLogger
2623import software.aws.toolkits.jetbrains.core.coroutines.EDT
2724import software.aws.toolkits.jetbrains.isDeveloperMode
2825import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
@@ -47,12 +44,7 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable
4744import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable
4845import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable
4946import software.aws.toolkits.resources.message
50- import java.awt.datatransfer.DataFlavor
51- import java.awt.dnd.DropTarget
52- import java.awt.dnd.DropTargetDropEvent
53- import java.io.File
5447import java.util.concurrent.CompletableFuture
55- import javax.imageio.ImageIO.read
5648import javax.swing.JButton
5749
5850class AmazonQPanel (val project : Project , private val scope : CoroutineScope ) : Disposable {
@@ -130,76 +122,12 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
130122
131123 withContext(EDT ) {
132124 browser.complete(
133- Browser (this @AmazonQPanel, webUri, project).also { browserInstance ->
134- wrapper.setContent(browserInstance.component())
135-
136- // Add DropTarget to the browser component
137- // JCEF does not propagate OS-level dragenter, dragOver and drop into DOM.
138- // As an alternative, enabling the native drag in JCEF,
139- // and let the native handling the drop event, and update the UI through JS bridge.
140- val dropTarget = object : DropTarget () {
141- override fun drop (dtde : DropTargetDropEvent ) {
142- try {
143- dtde.acceptDrop(dtde.dropAction)
144- val transferable = dtde.transferable
145- if (transferable.isDataFlavorSupported(DataFlavor .javaFileListFlavor)) {
146- val fileList = transferable.getTransferData(DataFlavor .javaFileListFlavor) as List <* >
147-
148- val errorMessages = mutableListOf<String >()
149- val validImages = mutableListOf<File >()
150- val allowedTypes = setOf (" jpg" , " jpeg" , " png" , " gif" , " webp" )
151- val maxFileSize = 3.75 * 1024 * 1024 // 3.75MB in bytes
152- val maxDimension = 8000
153-
154- for (file in fileList as List <File >) {
155- val validationResult = validateImageFile(file, allowedTypes, maxFileSize, maxDimension)
156- if (validationResult != null ) {
157- errorMessages.add(validationResult)
158- } else {
159- validImages.add(file)
160- }
161- }
162-
163- // File count restriction
164- if (validImages.size > 20 ) {
165- errorMessages.add(" A maximum of 20 images can be added to a single message." )
166- validImages.subList(20 , validImages.size).clear()
167- }
168-
169- val json = OBJECT_MAPPER .writeValueAsString(validImages)
170- browserInstance.jcefBrowser.cefBrowser.executeJavaScript(
171- " window.handleNativeDrop('$json ')" ,
172- browserInstance.jcefBrowser.cefBrowser.url,
173- 0
174- )
175-
176- val errorJson = OBJECT_MAPPER .writeValueAsString(errorMessages)
177- browserInstance.jcefBrowser.cefBrowser.executeJavaScript(
178- " window.handleNativeNotify('$errorJson ')" ,
179- browserInstance.jcefBrowser.cefBrowser.url,
180- 0
181- )
182- dtde.dropComplete(true )
183- } else {
184- dtde.dropComplete(false )
185- }
186- } catch (e: Exception ) {
187- LOG .error { " Failed to handle file drop operation: ${e.message} " }
188- dtde.dropComplete(false )
189- }
190- }
191- }
192-
193- // Set DropTarget on the browser component and its children
194- browserInstance.component()?.let { component ->
195- component.dropTarget = dropTarget
196- // Also try setting on parent if needed
197- component.parent?.dropTarget = dropTarget
198- }
125+ Browser (this @AmazonQPanel, webUri, project).also {
126+ wrapper.setContent(it.component())
199127
200128 initConnections()
201- connectUi(browserInstance )
202- connectApps(browserInstance )
129+ connectUi(it )
130+ connectApps(it )
203131
204132 loadingPanel.stopLoading()
205133 }
@@ -283,36 +211,6 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
283211 }
284212 }
285213
286- private fun validateImageFile (file : File , allowedTypes : Set <String >, maxFileSize : Double , maxDimension : Int ): String? {
287- val fileName = file.name
288- val ext = fileName.substringAfterLast(' .' , " " ).lowercase()
289-
290- if (ext !in allowedTypes) {
291- return " $fileName : File must be an image in JPEG, PNG, GIF, or WebP format."
292- }
293-
294- if (file.length() > maxFileSize) {
295- return " $fileName : Image must be no more than 3.75MB in size."
296- }
297-
298- return try {
299- val img = read(file)
300- when {
301- img == null -> " $fileName : File could not be read as an image."
302- img.width > maxDimension -> " $fileName : Image must be no more than 8,000px in width."
303- img.height > maxDimension -> " $fileName : Image must be no more than 8,000px in height."
304- else -> null
305- }
306- } catch (e: Exception ) {
307- " $fileName : File could not be read as an image."
308- }
309- }
310-
311- companion object {
312- private val LOG = getLogger<AmazonQPanel >()
313- private val OBJECT_MAPPER = jacksonObjectMapper()
314- }
315-
316214 override fun dispose () {
317215 }
318216}
0 commit comments