diff --git a/src/main/kotlin/app/termora/NewHostTree.kt b/src/main/kotlin/app/termora/NewHostTree.kt index 243a5d5..ebcaebb 100644 --- a/src/main/kotlin/app/termora/NewHostTree.kt +++ b/src/main/kotlin/app/termora/NewHostTree.kt @@ -16,6 +16,7 @@ import org.apache.commons.csv.CSVParser import org.apache.commons.csv.CSVPrinter import org.apache.commons.io.FileUtils import org.apache.commons.io.FilenameUtils +import org.apache.commons.io.filefilter.FileFilterUtils import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.exception.ExceptionUtils import org.ini4j.Ini @@ -365,6 +366,7 @@ class NewHostTree : JXTree() { val importMenu = JMenu(I18n.getString("termora.welcome.contextmenu.import")) val csvMenu = importMenu.add("CSV") val xShellMenu = importMenu.add("Xshell") + val finalShellMenu = importMenu.add("FinalShell") val windTermMenu = importMenu.add("WindTerm") val secureCRTMenu = importMenu.add("SecureCRT") val mobaXtermMenu = importMenu.add("MobaXterm") @@ -398,6 +400,7 @@ class NewHostTree : JXTree() { xShellMenu.addActionListener { importHosts(lastNode, ImportType.Xshell) } secureCRTMenu.addActionListener { importHosts(lastNode, ImportType.SecureCRT) } mobaXtermMenu.addActionListener { importHosts(lastNode, ImportType.MobaXterm) } + finalShellMenu.addActionListener { importHosts(lastNode, ImportType.FinalShell) } csvMenu.addActionListener { importHosts(lastNode, ImportType.CSV) } windTermMenu.addActionListener { importHosts(lastNode, ImportType.WindTerm) } open.addActionListener { openHosts(it, false) } @@ -656,6 +659,11 @@ class NewHostTree : JXTree() { chooser.dialogTitle = "Xshell Sessions" chooser.isAcceptAllFileFilterUsed = true } + + ImportType.FinalShell -> { + chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY + chooser.isAcceptAllFileFilterUsed = true + } } val dir = properties.getString("NewHostTree.ImportHosts.defaultDir", StringUtils.EMPTY) @@ -706,20 +714,22 @@ class NewHostTree : JXTree() { // 选择文件 val code = chooser.showOpenDialog(owner) - // 记住目录 - properties.putString("NewHostTree.ImportHosts.defaultDir", chooser.currentDirectory.absolutePath) - if (code != JFileChooser.APPROVE_OPTION) { return } val file = chooser.selectedFile + properties.putString( + "NewHostTree.ImportHosts.defaultDir", + (if (FileUtils.isDirectory(file)) file else file.parentFile).absolutePath + ) val nodes = when (type) { ImportType.WindTerm -> parseFromWindTerm(folder, file) ImportType.SecureCRT -> parseFromSecureCRT(folder, file) ImportType.MobaXterm -> parseFromMobaXterm(folder, file) ImportType.Xshell -> parseFromXshell(folder, file) + ImportType.FinalShell -> parseFromFinalShell(folder, file) ImportType.CSV -> file.bufferedReader().use { parseFromCSV(folder, it) } } @@ -874,6 +884,45 @@ class NewHostTree : JXTree() { return parseFromCSV(folder, StringReader(sw.toString())) } + private fun parseFromFinalShell(folder: HostTreeNode, dir: File): List { + val files = FileUtils.listFiles( + dir, + FileFilterUtils.suffixFileFilter("_connect_config.json"), + FileFilterUtils.trueFileFilter() + ) + + if (files.isEmpty()) { + OptionPane.showMessageDialog( + owner, + I18n.getString("termora.welcome.contextmenu.import.finalshell-folder-empty") + ) + return emptyList() + } + + val sw = StringWriter() + CSVPrinter(sw, CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).get()).use { printer -> + for (file in files) { + try { + val json = ohMyJson.runCatching { ohMyJson.parseToJsonElement(file.readText()) } + .getOrNull()?.jsonObject ?: continue + val username = json["user_name"]?.jsonPrimitive?.content ?: StringUtils.EMPTY + val label = json["name"]?.jsonPrimitive?.content ?: StringUtils.EMPTY + val host = json["host"]?.jsonPrimitive?.content ?: StringUtils.EMPTY + val port = json["port"]?.jsonPrimitive?.intOrNull ?: 22 + if (StringUtils.isAllBlank(host, label)) continue + val folders = FilenameUtils.separatorsToUnix(file.parentFile.relativeTo(dir).toString()) + printer.printRecord(folders, StringUtils.defaultIfBlank(label, host), host, port, username, "SSH") + } catch (e: Exception) { + if (log.isErrorEnabled) { + log.error(file.absolutePath, e) + } + } + } + } + + return parseFromCSV(folder, StringReader(sw.toString())) + } + private fun parseFromCSV(folderNode: HostTreeNode, sr: Reader): List { val records = CSVParser.builder() .setFormat(CSVFormat.EXCEL.builder().setHeader(*CSV_HEADERS).setSkipHeaderRecord(true).get()) @@ -954,7 +1003,8 @@ class NewHostTree : JXTree() { CSV, Xshell, SecureCRT, - MobaXterm + MobaXterm, + FinalShell, } private class MoveHostTransferable(val nodes: List) : Transferable { diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index b9e469b..6ea323d 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -149,6 +149,7 @@ termora.welcome.contextmenu.import.csv.download-template=Do you want to import o termora.welcome.contextmenu.import.csv.download-template-done=Download the template successfully termora.welcome.contextmenu.import.csv.download-template-done-open-folder=Download the template successfully, Do you want to open the folder? termora.welcome.contextmenu.import.xshell-folder-empty=The folder does not contain any *.xsh files, Please select the correct Xshell Sessions directory +termora.welcome.contextmenu.import.finalshell-folder-empty=The folder does not contain any *_connect_config.json files, Please select the correct FinalShell directory # New Host termora.new-host.title=Create a new host diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index 073a908..bdffacc 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -137,6 +137,7 @@ termora.welcome.contextmenu.import.csv.download-template=您要导入还是下 termora.welcome.contextmenu.import.csv.download-template-done=下载成功 termora.welcome.contextmenu.import.csv.download-template-done-open-folder=下载成功, 是否需要打开所在文件夹? termora.welcome.contextmenu.import.xshell-folder-empty=该文件夹不包含 *.xsh 文件,请选择正确的 Xshell 会话目录 +termora.welcome.contextmenu.import.finalshell-folder-empty=该文件夹不包含 *_connect_config.json 文件,请选择正确的 FinalShell 配置目录 # New Host termora.new-host.title=新建主机 diff --git a/src/main/resources/i18n/messages_zh_TW.properties b/src/main/resources/i18n/messages_zh_TW.properties index e188c70..7ae761f 100644 --- a/src/main/resources/i18n/messages_zh_TW.properties +++ b/src/main/resources/i18n/messages_zh_TW.properties @@ -135,6 +135,7 @@ termora.welcome.contextmenu.import.csv.download-template=您要匯入還是下 termora.welcome.contextmenu.import.csv.download-template-done=下載成功 termora.welcome.contextmenu.import.csv.download-template-done-open-folder=下載成功, 是否需要開啟所在資料夾? termora.welcome.contextmenu.import.xshell-folder-empty=該資料夾不包含 *.xsh 文件,請選擇正確的 Xshell 會話目錄 +termora.welcome.contextmenu.import.finalshell-folder-empty=該資料夾不包含 *_connect_config.json 文件,請選擇正確的 FinalShell 設定目錄 # New Host termora.new-host.title=新主機