Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert Graphic wizard and image Drag and Drop #1729

Merged
merged 11 commits into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,21 @@
<!-- MPS doesn't have the EditSmartGroup group, so we register directly in the Edit menu. -->
<add-to-group group-id="EditMenu" anchor="last"/>

<!-- Table Creation Wizard-->
<action class="nl.hannahsten.texifyidea.action.tablewizard.LatexTableWizardAction" id="texify.TableCreationWizzard" text="_Table Creation Wizard"
description="Shows popup to create and insert a table."/>

<!-- Toggle Star -->
<action class="nl.hannahsten.texifyidea.action.LatexToggleStarAction" id="texify.ToggleStar" text="Toggle _Star"
description="Adds/removes a star from a LaTeX command.">
<keyboard-shortcut first-keystroke="alt shift 8" keymap="$default" />
</action>

<separator></separator>

<!-- Table Creation Wizard-->
<action class="nl.hannahsten.texifyidea.action.wizard.table.LatexTableWizardAction" id="texify.TableCreationWizard" text="Insert _Table..."
description="Shows a popup to create and insert a table."/>

<!-- Graphic Wizard-->
<action class="nl.hannahsten.texifyidea.action.wizard.graphic.InsertGraphicWizardAction" id="texify.GraphicInsertWizard" text="Insert _Graphic..."
description="Shows a popup to insert a graphic."/>
</group>

<!-- LaTeX Analyze commands -->
Expand Down Expand Up @@ -467,6 +473,7 @@
<backspaceHandlerDelegate implementation="nl.hannahsten.texifyidea.editor.InlineMathBackspaceHandler" />
<extendWordSelectionHandler implementation="nl.hannahsten.texifyidea.editor.LatexCommandSelectioner"/>
<basicWordSelectionFilter implementation="nl.hannahsten.texifyidea.editor.CommandSelectionFilter"/>
<customFileDropHandler implementation="nl.hannahsten.texifyidea.editor.GraphicsDragAndDropHandler"/>

<!-- References and refactoring -->
<lang.findUsagesProvider language="Latex" implementationClass="nl.hannahsten.texifyidea.reference.LatexUsagesProvider"/>
Expand Down
5 changes: 2 additions & 3 deletions src/nl/hannahsten/texifyidea/action/EditorAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import nl.hannahsten.texifyidea.file.LatexFile

import javax.swing.*
import java.util.Arrays
import java.util.*
import javax.swing.Icon

/**
* Action that fetches the required information beforehand.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package nl.hannahsten.texifyidea.action.wizard.graphic

import nl.hannahsten.texifyidea.lang.graphic.CaptionLocation
import nl.hannahsten.texifyidea.lang.graphic.FigureLocation

/**
* @author Hannah Schellekens
*/
data class InsertGraphicData(
val filePath: String,
val relativePath: Boolean,
val options: String,
val center: Boolean,
val placeInFigure: Boolean,
/** `null` when [placeInFigure] is `false`, not `null` otherwise */
val captionLocation: CaptionLocation? = null,
/** `null` when [placeInFigure] is `false`, not `null` otherwise */
val caption: String? = null,
/** `null` when [placeInFigure] is `false`, not `null` otherwise */
val shortCaption: String? = null,
/** `null` when [placeInFigure] is `false`, not `null` otherwise */
val label: String? = null,
/** `null` when [placeInFigure] is `false`, not `null` otherwise */
val positions: List<FigureLocation>? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package nl.hannahsten.texifyidea.action.wizard.graphic

import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import nl.hannahsten.texifyidea.lang.LatexPackage
import nl.hannahsten.texifyidea.lang.graphic.CaptionLocation
import nl.hannahsten.texifyidea.util.*
import nl.hannahsten.texifyidea.util.files.*
import java.io.File
import java.util.*

/**
* Action that shows a dialog with a graphic insertion wizard, and inserts the graphic as latex at the location of the
* cursor.
*
* @author Hannah Schellekens
*/
class InsertGraphicWizardAction(val initialFile: File? = null) : AnAction() {

/**
* Opens and handles the graphic insertion wizard.
*/
fun executeAction(file: VirtualFile, project: Project) {
val editor = project.currentTextEditor() ?: return
val document = editor.editor.document

// Get the indentation from the current line.
val indent = document.lineIndentationByOffset(editor.editor.caretOffset())

// Create the dialog.
val dialogWrapper = InsertGraphicWizardDialogWrapper(initialFilePath = initialFile?.absolutePath ?: "")

// If the user pressed OK, do stuff.
if (!dialogWrapper.showAndGet()) return

// Handle result.
val graphicData = dialogWrapper.extractData()
file.psiFile(project)?.let { graphicData.importPackages(it) }
editor.editor.insertGraphic(project, graphicData, indent)
}

override fun actionPerformed(e: AnActionEvent) {
val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return
val project = e.getData(PlatformDataKeys.PROJECT) ?: return
executeAction(file, project)
}

private fun Editor.insertGraphic(project: Project, data: InsertGraphicData, indent: String, tab: String = " ") {
// Only the graphics (non-centered).
val toInsert = if (data.center.not() && data.placeInFigure.not()) {
data.includeCommand(project)
}
// Centered graphics, but not in a figure.
else if (data.center && data.placeInFigure.not()) {
buildString {
append("\\begin{center}\n")
append(indent).append(tab).append(data.includeCommand(project)).newline()
append(indent).append("\\end{center}")
}
}
// Insert figure.
else data.figure(project, indent, tab)

insertAtCaretAndMove(toInsert)
}

private fun InsertGraphicData.figure(project: Project, indent: String, tab: String) = buildString {
append("\\begin{figure}")
if (positions?.isNotEmpty() == true) {
append(positionOptions())
}
newline()

if (center) {
append(indent).append(tab).append("\\centering").newline()
}

if (captionLocation == CaptionLocation.ABOVE_GRAPHIC) {
addCaptionAndLabel(this@figure, indent, tab)
}

append(indent).append(tab).append(includeCommand(project)).newline()

if (captionLocation == CaptionLocation.BELOW_GRAPHIC) {
addCaptionAndLabel(this@figure, indent, tab)
}

append(indent).append("\\end{figure}")
}

private fun StringBuilder.addCaptionAndLabel(data: InsertGraphicData, indent: String, tab: String) {
append(indent).append(tab).append(data.captionCommand()).newline()
append(indent).append(tab).append("\\label{").append(data.label ?: "").append("}").newline()
}

private fun InsertGraphicData.includeCommand(project: Project) = buildString {
append("\\includegraphics")
if (options.isNotBlank()) {
append("[").append(options).append("]")
}
append("{").append(convertFilePath(project, filePath)).append("}")
}

private fun InsertGraphicData.convertFilePath(project: Project, absoluteFilePath: String): String {
val rootManager = ProjectRootManager.getInstance(project)

val filePath = if (relativePath) {
rootManager.relativizePath(absoluteFilePath) ?: absoluteFilePath
}
else absoluteFilePath

return filePath.removeFileExtension()
}

private fun InsertGraphicData.captionCommand() = buildString {
append("\\caption")
if (shortCaption?.isNotBlank() == true) {
append("[").append(shortCaption).append("]")
}
append("{").append(caption ?: "").append("}")
}

private fun InsertGraphicData.importPackages(file: PsiFile) {
WriteCommandAction.runWriteCommandAction(file.project) {
file.insertUsepackage(LatexPackage.GRAPHICX)
positions?.forEach { location ->
location.requiredPackage?.let {
file.insertUsepackage(it)
}
}
}
}

private fun InsertGraphicData.positionOptions() = buildString {
append("[")
append(positions?.joinToString("") { it.symbol })
append("]")
}
}
Loading