Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,13 @@ data class FileExtensionFilter(val description: String, val extensions: List<Str
/**
* Options for displaying file chooser fields in a property pane.
*/
data class FileDisplayOptions(val extensionFilters: MutableList<FileExtensionFilter> = mutableListOf<FileExtensionFilter>()) :
PropertyDisplayOptions<File>()
data class FileDisplayOptions(
var isSaveNotOpen: Boolean = false,
var allowMultipleSelection: Boolean = false,
var browseButtonText: String = "Browse...",
var chooserTitle: String = "Choose a file",
val extensionFilters: MutableList<FileExtensionFilter> = mutableListOf())
: PropertyDisplayOptions<File>()

/**
* Options for displaying integer fields in a property pane.
Expand Down
3 changes: 3 additions & 0 deletions ganttproject/src/main/java/biz/ganttproject/app/Dialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ along with GanttProject. If not, see <http://www.gnu.org/licenses/>.
package biz.ganttproject.app

import biz.ganttproject.FXUtil
import biz.ganttproject.app.DialogPlacement.applicationWindow
import biz.ganttproject.centerOnOwner
import biz.ganttproject.colorFromUiManager
import biz.ganttproject.lib.fx.VBoxBuilder
Expand Down Expand Up @@ -169,6 +170,8 @@ class DialogPaneExt : DialogPane() {
}

private val dialogStack = mutableListOf<Dialog<*>>()
fun topWindow(): Window? = dialogStack.lastOrNull()?.dialogPane?.scene?.window ?: applicationWindow

fun dialog(title: String? = null, id: String? = null, contentBuilder: (DialogController) -> Unit) {
Platform.runLater {
try {
Expand Down
49 changes: 3 additions & 46 deletions ganttproject/src/main/java/biz/ganttproject/app/PropertySheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class PropertyPaneBuilderImpl(private val localizer: Localizer, private val grid

fun file(property: ObservableFile, optionValues: (FileDisplayOptions.()->Unit)? = null) {
rowBuilders.add(run {
val options = optionValues?.let { FileDisplayOptions().apply(it) }
val options = optionValues?.let { FileDisplayOptions().apply(it) } ?: FileDisplayOptions()
createOptionItem(property, createFileOptionEditor(property, options))
})
}
Expand Down Expand Up @@ -272,52 +272,9 @@ class PropertyPaneBuilderImpl(private val localizer: Localizer, private val grid
return textField
}

private fun createFileOptionEditor(option: ObservableFile, displayOptions: FileDisplayOptions? = null): Node {
val textField = CustomTextField()
val onBrowse = {
val fileChooser = FileChooser();
var initialFile: File? = File(textField.text)
while (initialFile?.exists() == false) {
initialFile = initialFile.parentFile
}
initialFile?.let {
if (it.isDirectory) {
fileChooser.initialDirectory = it
} else {
fileChooser.initialDirectory = it.parentFile
}
}
fileChooser.title = "Choose a file"
displayOptions?.let {
it.extensionFilters.forEach {filter ->
fileChooser.extensionFilters.add(FileChooser.ExtensionFilter(filter.description, filter.extensions))
}
}

val resultFile = fileChooser.showOpenDialog(null)
option.value = resultFile
resultFile?.let {
textField.text = it.absolutePath
}
}
textField.right = buildFontAwesomeButton(
iconName = FontAwesomeIcon.SEARCH.name,
label = "Browse...",
onClick = { onBrowse() },
styleClass = "btn"
)
textField.id = option.id
displayOptions?.editorStyles?.let(textField.styleClass::addAll)
return textField
// return HBox().apply {
// HBox.setHgrow(textField, Priority.ALWAYS)
// children.add(textField)
// children.add(Region().also {
// it.padding = Insets(0.0, 5.0, 0.0, 0.0)
// })
// children.add(btn)
// }

private fun createFileOptionEditor(option: ObservableFile, displayOptions: FileDisplayOptions = FileDisplayOptions()): Node {
return FileOptionEditor(option, displayOptions).node
}

fun createDateOptionEditor(option: ObservableDate, displayOptions: DateDisplayOptions = DateDisplayOptions(createDateConverter())): DatePicker {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@ along with GanttProject. If not, see <http://www.gnu.org/licenses/>.
*/
package biz.ganttproject.app

import biz.ganttproject.core.option.DropdownDisplayOptions
import biz.ganttproject.core.option.ObservableChoice
import biz.ganttproject.core.option.ObservableProperty
import biz.ganttproject.core.option.*
import biz.ganttproject.lib.fx.buildFontAwesomeButton
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
import javafx.collections.FXCollections
import javafx.event.EventHandler
import javafx.scene.Node
import javafx.scene.control.ComboBox
import javafx.scene.control.ListCell
import javafx.scene.layout.HBox
import javafx.stage.FileChooser
import javafx.util.Callback
import javafx.util.StringConverter
import org.controlsfx.control.textfield.CustomTextField
import java.io.File
import java.util.*

/**
* Creates a dropdown editor for the given choice option.
Expand Down Expand Up @@ -72,3 +76,74 @@ fun <E> createDropdownEditor(option: ObservableProperty<E>, key2i18n: List<Pair<
comboBox.value = key2i18n.find { it.first == option.value }
})
}

private val ourTimer = Timer()

class FileOptionEditor(private val option: ObservableFile, private val displayOptions: FileDisplayOptions = FileDisplayOptions()) {
private val textField = CustomTextField()
private var myTimerTask: TimerTask? = null

val node: Node = textField
init {
textField.right = buildFontAwesomeButton(
iconName = FontAwesomeIcon.SEARCH.name,
label = displayOptions.browseButtonText,
onClick = { onBrowse() },
styleClass = "btn"
)
textField.text = option.value?.absolutePath ?: ""
textField.id = option.id
textField.textProperty().addListener {
onTextChange()
}
displayOptions.editorStyles.let(textField.styleClass::addAll)
option.addWatcher {
if (it.trigger != textField) {
textField.text = option.value?.absolutePath ?: ""
}
}
}

private fun onBrowse() {
val fileChooser = FileChooser()
var initialFile: File? = File(textField.text)
while (initialFile?.exists() == false) {
initialFile = initialFile.parentFile
}
initialFile?.let {
if (it.isDirectory) {
fileChooser.initialDirectory = it
} else {
fileChooser.initialDirectory = it.parentFile
}
}
fileChooser.title = displayOptions.chooserTitle.ifBlank { "Choose a file" }
displayOptions.let {
it.extensionFilters.forEach {filter ->
fileChooser.extensionFilters.add(FileChooser.ExtensionFilter(filter.description, filter.extensions))
}
}

val ownerWindow = topWindow()
val resultFile =
if (displayOptions.isSaveNotOpen) fileChooser.showSaveDialog(ownerWindow)
else fileChooser.showOpenDialog(ownerWindow)
resultFile?.let {
option.set(resultFile, textField)
textField.text = it.absolutePath
}
}

private fun onTextChange() {
if (myTimerTask == null) {
myTimerTask = object : TimerTask() {
override fun run() {
val file = File(textField.text)
option.set(file, textField)
myTimerTask = null
}
}
ourTimer.schedule(myTimerTask, 1000)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,51 @@
package net.sourceforge.ganttproject.export

import biz.ganttproject.app.RootLocalizer
import biz.ganttproject.core.option.FileExtensionFilter
import biz.ganttproject.core.option.GPOptionGroup
import biz.ganttproject.storage.asLocalDocument
import biz.ganttproject.storage.getDefaultLocalFolder
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import net.sourceforge.ganttproject.IGanttProject
import net.sourceforge.ganttproject.filter.ExtensionBasedFileFilter
import net.sourceforge.ganttproject.gui.FileChooserPageBase
import net.sourceforge.ganttproject.gui.UIFacade
import net.sourceforge.ganttproject.gui.UIUtil
import net.sourceforge.ganttproject.util.FileUtil.replaceExtension
import org.osgi.service.prefs.Preferences
import java.awt.Component
import java.io.File
import javax.swing.JFileChooser
import javax.swing.filechooser.FileFilter

/**
* A wizard page for choosing a file to export to.
*/
internal class ExportFileChooserPage(
private val myState: ExportFileWizardImpl.State,
private val myState: ExportWizardModel,
private val myProject: IGanttProject,
override val preferences: Preferences,
uiFacade: UIFacade?
override val preferences: Preferences
) : FileChooserPageBase(
myProject.document, uiFacade,
myProject.document,
fileChooserTitle = i18n.formatText("selectFileToExport"),
fileChooserSelectionMode = JFileChooser.FILES_AND_DIRECTORIES,
pageTitle = i18n.formatText("selectFileToExport")
pageTitle = i18n.formatText("selectFileToExport"),
errorMessage = myState.errorMessage
) {
private val myWebPublishingGroup: GPOptionGroup = GPOptionGroup(
"exporter.webPublishing", myState.publishInWebOption
).also { it.isTitled = false }

init {
updateChosenFile = { replaceExtension(it, myState.exporter.proposeFileExtension()) }
updateChosenFile = { file ->
myState.exporter?.let {
replaceExtension(file, it.proposeFileExtension())
} ?: file
}
proposeChosenFile = {
proposeOutputFile(myProject, myState.exporter) ?: File(defaultFileName)
myState.exporter?.let {proposeOutputFile(myProject, it) } ?: File(defaultFileName)
}
overwriteOption.addChangeValueListener { tryChosenFile(chooser.file) }
selectedFileProperty.addListener { _, _, newValue ->
myState.file = newValue
fxFile.addWatcher {
myState.file = it.newValue
}
}

Expand All @@ -71,7 +72,7 @@ internal class ExportFileChooserPage(
return Err("File cannot be null")
}

overwriteOption.getIsWritableProperty().set(false, this)
fxOverwrite.isWritable.value = false
if (!file.exists()) {
val parent = file.getParentFile()
if (!parent.exists()) {
Expand Down Expand Up @@ -101,22 +102,21 @@ internal class ExportFileChooserPage(
)
}
} else {
overwriteOption.getIsWritableProperty().set(true, this)
if (!overwriteOption.isChecked()) {
fxOverwrite.isWritable.value = true
if (!fxOverwrite.value) {
return Err(i18n.formatText("fileChooser.warning.fileExists"))
}
}
return Ok(file)
}

override fun createSecondaryOptionsPanel(): Component {
return myState.exporter.getCustomOptionsUI() ?: super.createSecondaryOptionsPanel()
return myState.exporter?.getCustomOptionsUI() ?: super.createSecondaryOptionsPanel()
}

override fun createFileFilter(): FileFilter =
ExtensionBasedFileFilter(
myState.exporter.getFileNamePattern(), myState.exporter.getFileTypeDescription()
)
override fun createFileFilter(): FileExtensionFilter? = myState.exporter?.let {
FileExtensionFilter(it.getFileTypeDescription(), listOf(it.getFileNamePattern()))
}

override val optionGroups: List<GPOptionGroup>
get() = listOf(myWebPublishingGroup) + (myState.exporter?.secondaryOptions ?: emptyList())
Expand Down
Loading
Loading