├── .gitignore ├── src ├── test │ ├── testData │ │ └── rename │ │ │ ├── foo.xml │ │ │ └── foo_after.xml │ └── kotlin │ │ └── com │ │ └── github │ │ └── gitofleonardo │ │ └── simplesqlitebrowser │ │ └── MyPluginTest.kt └── main │ ├── resources │ ├── messages │ │ └── MyBundle.properties │ └── META-INF │ │ ├── pluginIcon.svg │ │ └── plugin.xml │ └── kotlin │ └── com │ └── github │ └── gitofleonardo │ └── simplesqlitebrowser │ ├── mvvm │ ├── ViewModel.kt │ └── LiveData.kt │ ├── data │ ├── DbTable.kt │ ├── DbColumn.kt │ ├── SqliteMetadata.kt │ ├── DbTableInstance.kt │ └── DbRow.kt │ ├── Constants.kt │ ├── ui │ ├── TabbedChildView.kt │ ├── view │ │ └── BeeplessFormattedTextView.kt │ ├── window │ │ ├── SqliteBrowserMainWindow.kt │ │ └── SqliteMetaDataWindow.kt │ └── viewmodel │ │ ├── MetadataViewModel.kt │ │ └── TableViewModel.kt │ ├── sqlite │ ├── SqliteLanguage.kt │ └── SqliteFileType.kt │ ├── model │ ├── ConnectionManager.kt │ └── SqliteModel.kt │ ├── tools │ ├── DatabaseTableModel.kt │ ├── DatabaseTableCellRenderer.kt │ ├── DatabaseTreeModel.kt │ └── DatabaseTreeCellRenderer.kt │ ├── provider │ ├── SqliteEditorProvider.kt │ └── SqliteEditor.kt │ └── Extensions.kt ├── raw ├── sample-tables.png └── sample-metadata.png ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── settings.gradle.kts ├── tablefilter ├── src │ └── main │ │ ├── resources │ │ └── net │ │ │ └── coderazzi │ │ │ └── filters │ │ │ └── resources │ │ │ ├── matchEmptyIcon.png │ │ │ └── tableFilterHeader.png │ │ └── java │ │ └── net │ │ └── coderazzi │ │ └── filters │ │ ├── IFilterObserver.java │ │ ├── gui │ │ ├── AutoChoices.java │ │ ├── TableFilterHeaderBeanInfo.java │ │ ├── ChoiceRenderer.java │ │ ├── editor │ │ │ ├── IChoicesParser.java │ │ │ ├── ChoiceMatch.java │ │ │ ├── FilterArrowButton.java │ │ │ └── HistoryListModel.java │ │ ├── HtmlChoiceRenderer.java │ │ ├── LooseParserModel.java │ │ ├── IFilterHeaderObserver.java │ │ ├── IParserModel.java │ │ ├── CustomChoiceDecorator.java │ │ ├── Look.java │ │ ├── ChoicesHandler.java │ │ ├── IFilterEditor.java │ │ ├── NonAdaptiveChoicesHandler.java │ │ ├── PositionHelper.java │ │ └── FilterSettings.java │ │ ├── NotFilter.java │ │ ├── AndFilter.java │ │ ├── IFilter.java │ │ ├── OrFilter.java │ │ ├── Filter.java │ │ ├── IParser.java │ │ ├── parser │ │ ├── HtmlHandler.java │ │ ├── DateComparator.java │ │ └── HtmlEntities.java │ │ └── ComposedFilter.java ├── build.gradle.kts ├── .gitignore └── LICENSE.txt ├── qodana.yml ├── CHANGELOG.md ├── .github ├── dependabot.yml └── workflows │ ├── run-ui-tests.yml │ ├── release.yml │ └── build.yml ├── .idea └── gradle.xml ├── .run ├── Run Plugin.run.xml ├── Run Tests.run.xml ├── Run IDE for UI Tests.run.xml ├── Run Qodana.run.xml └── Run Verifications.run.xml ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | .qodana 4 | build 5 | -------------------------------------------------------------------------------- /src/test/testData/rename/foo.xml: -------------------------------------------------------------------------------- 1 | 2 | 1>Foo 3 | 4 | -------------------------------------------------------------------------------- /src/test/testData/rename/foo_after.xml: -------------------------------------------------------------------------------- 1 | 2 | Foo 3 | 4 | -------------------------------------------------------------------------------- /raw/sample-tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitofleonardo/SimpleSqliteBrowser/HEAD/raw/sample-tables.png -------------------------------------------------------------------------------- /raw/sample-metadata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitofleonardo/SimpleSqliteBrowser/HEAD/raw/sample-metadata.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitofleonardo/SimpleSqliteBrowser/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/messages/MyBundle.properties: -------------------------------------------------------------------------------- 1 | name=My Plugin 2 | applicationService=Application service 3 | projectService=Project service: {0} 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/mvvm/ViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.mvvm 2 | 3 | interface ViewModel { 4 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0" 3 | } 4 | 5 | rootProject.name = "SimpleSqliteBrowser" 6 | 7 | include("tablefilter") 8 | -------------------------------------------------------------------------------- /tablefilter/src/main/resources/net/coderazzi/filters/resources/matchEmptyIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitofleonardo/SimpleSqliteBrowser/HEAD/tablefilter/src/main/resources/net/coderazzi/filters/resources/matchEmptyIcon.png -------------------------------------------------------------------------------- /tablefilter/src/main/resources/net/coderazzi/filters/resources/tableFilterHeader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitofleonardo/SimpleSqliteBrowser/HEAD/tablefilter/src/main/resources/net/coderazzi/filters/resources/tableFilterHeader.png -------------------------------------------------------------------------------- /qodana.yml: -------------------------------------------------------------------------------- 1 | # Qodana configuration: 2 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html 3 | 4 | version: 1.0 5 | profile: 6 | name: qodana.recommended 7 | exclude: 8 | - name: All 9 | paths: 10 | - .qodana 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/data/DbTable.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.data 2 | 3 | class DbTable { 4 | var tableName: String = "" 5 | val columns = ArrayList() 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/data/DbColumn.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.data 2 | 3 | data class DbColumn( 4 | val name: String, 5 | val type: Int, 6 | val typeName: String, 7 | val schema: String 8 | ) 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser 2 | 3 | const val SQLITE_LANGUAGE = "sqlite" 4 | const val MINE_TYPE = "db" 5 | 6 | const val NAME = "Sqlite Database File" 7 | const val DESC = "Sqlite Database File" 8 | const val EXTENSION = "db" 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/data/SqliteMetadata.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.data 2 | 3 | class SqliteMetadata { 4 | var isValidSqliteDatabase: Boolean = false 5 | var version: Int = -1 6 | var driverVersion: String? = null 7 | val tables = ArrayList() 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/TabbedChildView.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui 2 | 3 | import com.intellij.ui.components.JBPanel 4 | import javax.swing.Icon 5 | import javax.swing.JPanel 6 | 7 | abstract class TabbedChildView : JBPanel() { 8 | abstract val title: String 9 | abstract val icon: Icon? 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/view/BeeplessFormattedTextView.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui.view 2 | 3 | import javax.swing.JFormattedTextField 4 | 5 | class BeeplessFormattedTextView(formatter: AbstractFormatter?) : JFormattedTextField(formatter) { 6 | 7 | override fun invalidEdit() { 8 | // No beep feedback 9 | } 10 | } -------------------------------------------------------------------------------- /tablefilter/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | group = "com.github.gitofleonardo" 6 | version = "1.0.0" 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | testImplementation(platform("org.junit:junit-bom:5.9.1")) 14 | testImplementation("org.junit.jupiter:junit-jupiter") 15 | } 16 | 17 | tasks.test { 18 | useJUnitPlatform() 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/sqlite/SqliteLanguage.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.sqlite 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.MINE_TYPE 4 | import com.github.gitofleonardo.simplesqlitebrowser.SQLITE_LANGUAGE 5 | import com.intellij.lang.Language 6 | 7 | object SqliteLanguage : Language( 8 | SQLITE_LANGUAGE, 9 | MINE_TYPE 10 | ) 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # SimpleSqliteBrowser Changelog 4 | 5 | ## [Unreleased] 6 | 7 | ## [1.0.0] 8 | ### Added 9 | - View structures of all tables 10 | - View columns and rows data of table 11 | - Blob icon can be previewed as image 12 | 13 | ## [1.0.1] 14 | ### Added 15 | - Change coroutine dispatcher from `MainScope()` to a custom dispatch with `Swing` context -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/data/DbTableInstance.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.data 2 | 3 | /** 4 | * Represents a page of table. 5 | */ 6 | class DbTableInstance( 7 | val columns: List = emptyList(), 8 | val rows: List = emptyList(), 9 | val pageCount: Int = 0, 10 | val page: Int = 0, 11 | val totalCount: Int = 0 12 | ) 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration: 2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | # Maintain dependencies for Gradle dependencies 7 | - package-ecosystem: "gradle" 8 | directory: "/" 9 | target-branch: "next" 10 | schedule: 11 | interval: "daily" 12 | # Maintain dependencies for GitHub Actions 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | target-branch: "next" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | 8 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | -------------------------------------------------------------------------------- /tablefilter/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # libraries 3 | annotations = "24.0.1" 4 | 5 | # plugins 6 | kotlin = "1.9.0" 7 | changelog = "2.1.2" 8 | gradleIntelliJPlugin = "1.15.0" 9 | qodana = "0.1.13" 10 | kover = "0.7.3" 11 | 12 | [libraries] 13 | annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } 14 | 15 | [plugins] 16 | changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } 17 | gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" } 18 | kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 19 | kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } 20 | qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/window/SqliteBrowserMainWindow.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui.window 2 | 3 | import com.intellij.openapi.vfs.VirtualFile 4 | import com.intellij.ui.components.JBTabbedPane 5 | import java.awt.BorderLayout 6 | import javax.swing.JPanel 7 | 8 | class SqliteBrowserMainWindow(dbFile: VirtualFile) : JPanel(BorderLayout()) { 9 | private val tabbedChildViews = arrayListOf( 10 | SqliteTablesWindow(dbFile), 11 | SqliteMetaDataWindow(dbFile) 12 | ) 13 | private val tabbedPane: JBTabbedPane = JBTabbedPane() 14 | 15 | init { 16 | for (child in tabbedChildViews) { 17 | tabbedPane.addTab(child.title, child.icon, child) 18 | } 19 | 20 | add(tabbedPane) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/model/ConnectionManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.model 2 | 3 | import com.intellij.openapi.vfs.VirtualFile 4 | import java.sql.Connection 5 | import java.sql.DriverManager 6 | 7 | object ConnectionManager { 8 | // Ensure driver is loaded 9 | private val clazz = Class.forName("org.sqlite.JDBC") 10 | 11 | fun createConnection(file: VirtualFile): Connection? { 12 | return try { 13 | val connection = DriverManager.getConnection("jdbc:sqlite:${file.canonicalPath}") 14 | connection 15 | } catch (e : Exception) { 16 | e.printStackTrace() 17 | null 18 | } 19 | } 20 | 21 | fun disposeConnection(connection: Connection?) { 22 | connection?.close() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/sqlite/SqliteFileType.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.sqlite 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.DESC 4 | import com.github.gitofleonardo.simplesqlitebrowser.EXTENSION 5 | import com.github.gitofleonardo.simplesqlitebrowser.NAME 6 | import com.intellij.openapi.fileTypes.LanguageFileType 7 | import javax.swing.Icon 8 | 9 | class SqliteFileType : LanguageFileType(SqliteLanguage) { 10 | companion object { 11 | @JvmStatic 12 | val INSTANCE = SqliteFileType() 13 | } 14 | 15 | override fun getName(): String = NAME 16 | 17 | override fun getDescription(): String = DESC 18 | 19 | override fun getDefaultExtension(): String = EXTENSION 20 | 21 | override fun getIcon(): Icon? { 22 | return null 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/data/DbRow.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.data 2 | 3 | class DbRow( 4 | val rowData: List 5 | ) { 6 | data class RowData(val type: Int, val typeName: String, val data:Any?): Comparable { 7 | override fun compareTo(other: RowData): Int { 8 | if (this == other) { 9 | return 0 10 | } 11 | if (data == null && other.data == null) { 12 | return 0 13 | } 14 | if (data == null) { 15 | return 1 16 | } 17 | if (other.data == null) { 18 | return -1 19 | } 20 | if (data is Number && other.data is Number) { 21 | return data.toFloat().compareTo(other.data.toFloat()) 22 | } 23 | return data.toString().compareTo(other.data.toString()) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.github.gitofleonardo.simplesqlitebrowser 4 | SimpleSqliteBrowser 5 | gitofleonardo 6 | Browsing Sqlite database file, designed for directly opening `.db` file in IDE. 7 | 8 | com.intellij.modules.platform 9 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/mvvm/LiveData.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.mvvm 2 | 3 | class LiveData { 4 | private val observers: MutableList> = ArrayList() 5 | private var data: T? = null 6 | 7 | var value: T? 8 | get() = data 9 | set(value) { 10 | data = value 11 | data?.let { notifyChange(it) } 12 | } 13 | 14 | private fun notifyChange(data: T) { 15 | for (observer in observers) { 16 | observer.onChanged(data) 17 | } 18 | } 19 | 20 | fun observe(observer: LiveDataObserver) { 21 | observers.add(observer) 22 | } 23 | 24 | fun observe(observer: (T) -> Unit) { 25 | observers.add(object : LiveDataObserver { 26 | override fun onChanged(newData: T) { 27 | observer.invoke(newData) 28 | } 29 | }) 30 | } 31 | 32 | @FunctionalInterface 33 | interface LiveDataObserver { 34 | fun onChanged(newData: T) 35 | } 36 | } -------------------------------------------------------------------------------- /.run/Run Plugin.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/Run Tests.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.run/Run IDE for UI Tests.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | false 23 | 24 | 25 | -------------------------------------------------------------------------------- /tablefilter/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Luis M. Pena All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/gitofleonardo/simplesqlitebrowser/MyPluginTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser 2 | 3 | import com.intellij.ide.highlighter.XmlFileType 4 | import com.intellij.psi.xml.XmlFile 5 | import com.intellij.testFramework.TestDataPath 6 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 7 | import com.intellij.util.PsiErrorElementUtil 8 | 9 | @TestDataPath("\$CONTENT_ROOT/src/test/testData") 10 | class MyPluginTest : BasePlatformTestCase() { 11 | 12 | fun testXMLFile() { 13 | val psiFile = myFixture.configureByText(XmlFileType.INSTANCE, "bar") 14 | val xmlFile = assertInstanceOf(psiFile, XmlFile::class.java) 15 | 16 | assertFalse(PsiErrorElementUtil.hasErrors(project, xmlFile.virtualFile)) 17 | 18 | assertNotNull(xmlFile.rootTag) 19 | 20 | xmlFile.rootTag?.let { 21 | assertEquals("foo", it.name) 22 | assertEquals("bar", it.value.text) 23 | } 24 | } 25 | 26 | override fun getTestDataPath() = "src/test/testData/rename" 27 | 28 | fun testRename() { 29 | myFixture.testRename("foo.xml", "foo_after.xml", "a2") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/viewmodel/MetadataViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui.viewmodel 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.SqliteMetadata 4 | import com.github.gitofleonardo.simplesqlitebrowser.model.SqliteModel 5 | import com.github.gitofleonardo.simplesqlitebrowser.mvvm.LiveData 6 | import com.github.gitofleonardo.simplesqlitebrowser.mvvm.ViewModel 7 | import com.intellij.openapi.vfs.VirtualFile 8 | import io.reactivex.rxjava3.core.Observable 9 | import io.reactivex.rxjava3.schedulers.Schedulers 10 | import javax.swing.SwingUtilities 11 | 12 | class MetadataViewModel : ViewModel { 13 | private val model = SqliteModel 14 | 15 | val metadata: LiveData = LiveData() 16 | 17 | fun loadMetaData(file: VirtualFile) { 18 | Observable 19 | .create { emitter -> 20 | emitter.onNext(model.loadMetaData(file)) 21 | } 22 | .subscribeOn(Schedulers.io()) 23 | .subscribe { 24 | SwingUtilities.invokeLater { 25 | metadata.value = it 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.run/Run Qodana.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 16 | 22 | 24 | true 25 | true 26 | false 27 | false 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/tools/DatabaseTableModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.tools 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbRow 4 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbTableInstance 5 | import javax.swing.table.AbstractTableModel 6 | 7 | class DatabaseTableModel( 8 | private val dbTableData: DbTableInstance, 9 | ) : AbstractTableModel() { 10 | 11 | override fun getRowCount(): Int = dbTableData.rows.size 12 | 13 | override fun getColumnCount(): Int = dbTableData.columns.size 14 | 15 | override fun getColumnName(columnIndex: Int): String { 16 | return dbTableData.columns[columnIndex].name 17 | } 18 | 19 | override fun getColumnClass(columnIndex: Int): Class<*> = DbRow.RowData::class.java 20 | 21 | override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean = false 22 | 23 | override fun getValueAt(rowIndex: Int, columnIndex: Int): Any { 24 | return dbTableData.rows[rowIndex].rowData[columnIndex] 25 | } 26 | 27 | fun checkIndexRange(rowIndex: Int, columnIndex: Int): Boolean { 28 | return rowIndex in IntRange(0, rowCount - 1) && columnIndex in IntRange(0, columnCount - 1) 29 | } 30 | } -------------------------------------------------------------------------------- /.run/Run Verifications.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/provider/SqliteEditorProvider.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.provider 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.EXTENSION 4 | import com.github.gitofleonardo.simplesqlitebrowser.SQLITE_LANGUAGE 5 | import com.intellij.openapi.fileEditor.FileEditor 6 | import com.intellij.openapi.fileEditor.FileEditorPolicy 7 | import com.intellij.openapi.fileEditor.FileEditorProvider 8 | import com.intellij.openapi.project.DumbAware 9 | import com.intellij.openapi.project.Project 10 | import com.intellij.openapi.util.Disposer 11 | import com.intellij.openapi.vfs.VirtualFile 12 | 13 | class SqliteEditorProvider : FileEditorProvider, DumbAware { 14 | override fun accept(project: Project, file: VirtualFile): Boolean { 15 | return file.extension == EXTENSION 16 | } 17 | 18 | override fun createEditor(project: Project, file: VirtualFile): FileEditor { 19 | return SqliteEditor(project, file) 20 | } 21 | 22 | override fun getEditorTypeId(): String = SQLITE_LANGUAGE 23 | 24 | override fun getPolicy(): FileEditorPolicy = FileEditorPolicy.HIDE_DEFAULT_EDITOR 25 | 26 | override fun disposeEditor(editor: FileEditor) { 27 | super.disposeEditor(editor) 28 | Disposer.dispose(editor) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/tools/DatabaseTableCellRenderer.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.tools 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbRow 4 | import com.github.gitofleonardo.simplesqlitebrowser.model.SqliteModel 5 | import com.github.gitofleonardo.simplesqlitebrowser.toStringOr 6 | import java.awt.Component 7 | import java.sql.Types 8 | import javax.swing.JTable 9 | import javax.swing.table.DefaultTableCellRenderer 10 | 11 | class DatabaseTableCellRenderer : DefaultTableCellRenderer() { 12 | override fun getTableCellRendererComponent( 13 | table: JTable, 14 | value: Any?, 15 | isSelected: Boolean, 16 | hasFocus: Boolean, 17 | row: Int, 18 | column: Int 19 | ): Component { 20 | val newValue: String = when (value) { 21 | null -> { 22 | SqliteModel.NULL 23 | } 24 | is DbRow.RowData -> { 25 | when (value.type) { 26 | Types.BLOB -> { 27 | if (value.data == null) { 28 | SqliteModel.NULL 29 | } else { 30 | SqliteModel.BLOB 31 | } 32 | } 33 | else -> value.data.toStringOr(SqliteModel.NULL) 34 | } 35 | } 36 | else -> { 37 | value.toString() 38 | } 39 | } 40 | return super.getTableCellRendererComponent(table, newValue, isSelected, hasFocus, row, column) 41 | } 42 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html 2 | 3 | pluginGroup = com.github.gitofleonardo 4 | pluginName = SimpleSqliteBrowser 5 | # SemVer format -> https://semver.org 6 | pluginVersion = 1.0.8 7 | 8 | # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html 9 | pluginSinceBuild = 201 10 | pluginUntilBuild = 11 | 12 | # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension 13 | platformType = AI 14 | platformVersion = 2023.2.1.1 15 | 16 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 17 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 18 | platformPlugins = 19 | 20 | # Gradle Releases -> https://github.com/gradle/gradle/releases 21 | gradleVersion = 8.3 22 | 23 | # Opt-out flag for bundling Kotlin standard library -> https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library 24 | # suppress inspection "UnusedProperty" 25 | kotlin.stdlib.default.dependency = false 26 | 27 | # Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html 28 | org.gradle.configuration-cache = true 29 | 30 | # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html 31 | org.gradle.caching = true 32 | 33 | # Enable Gradle Kotlin DSL Lazy Property Assignment -> https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:assignment 34 | systemProp.org.gradle.unsafe.kotlin.assignment = true -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/provider/SqliteEditor.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.provider 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.ui.window.SqliteBrowserMainWindow 4 | import com.intellij.openapi.fileEditor.FileEditor 5 | import com.intellij.openapi.fileEditor.FileEditorLocation 6 | import com.intellij.openapi.fileEditor.FileEditorState 7 | import com.intellij.openapi.project.Project 8 | import com.intellij.openapi.util.UserDataHolderBase 9 | import com.intellij.openapi.vfs.VirtualFile 10 | import java.beans.PropertyChangeListener 11 | import javax.swing.JComponent 12 | 13 | private const val NAME = "SqliteEditor" 14 | 15 | class SqliteEditor(private val proj: Project, private val dbFile: VirtualFile) : UserDataHolderBase(), FileEditor { 16 | private val mainWindow by lazy { SqliteBrowserMainWindow(dbFile) } 17 | 18 | override fun dispose() { 19 | } 20 | 21 | override fun getComponent(): JComponent { 22 | return mainWindow 23 | } 24 | 25 | override fun getPreferredFocusedComponent(): JComponent? { 26 | return null 27 | } 28 | 29 | override fun getName(): String = NAME 30 | 31 | override fun setState(state: FileEditorState) { 32 | } 33 | 34 | override fun isModified(): Boolean { 35 | return false 36 | } 37 | 38 | override fun isValid(): Boolean { 39 | return true 40 | } 41 | 42 | override fun addPropertyChangeListener(listener: PropertyChangeListener) { 43 | } 44 | 45 | override fun removePropertyChangeListener(listener: PropertyChangeListener) { 46 | } 47 | 48 | override fun getCurrentLocation(): FileEditorLocation? { 49 | return null 50 | } 51 | 52 | override fun getFile(): VirtualFile { 53 | return dbFile 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/IFilterObserver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | 29 | /** 30 | *

A IFilterObserver instance receives notifications when the associated 31 | * {@link IFilter} instance updates the held filter.

32 | * 33 | * @author Luis M Pena - lu@coderazzi.net 34 | */ 35 | public interface IFilterObserver { 36 | 37 | /** 38 | *

Notification made by the observer when the associated {@link 39 | * IFilter} instance updates the held filter.

40 | */ 41 | void filterUpdated(IFilter obs); 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/run-ui-tests.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow for launching UI tests on Linux, Windows, and Mac in the following steps: 2 | # - prepare and launch IDE with your plugin and robot-server plugin, which is needed to interact with UI 3 | # - wait for IDE to start 4 | # - run UI tests with separate Gradle task 5 | # 6 | # Please check https://github.com/JetBrains/intellij-ui-test-robot for information about UI tests with IntelliJ Platform 7 | # 8 | # Workflow is triggered manually. 9 | 10 | name: Run UI Tests 11 | on: 12 | workflow_dispatch 13 | 14 | jobs: 15 | 16 | testUI: 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - os: ubuntu-latest 23 | runIde: | 24 | export DISPLAY=:99.0 25 | Xvfb -ac :99 -screen 0 1920x1080x16 & 26 | gradle runIdeForUiTests & 27 | - os: windows-latest 28 | runIde: start gradlew.bat runIdeForUiTests 29 | - os: macos-latest 30 | runIde: ./gradlew runIdeForUiTests & 31 | 32 | steps: 33 | 34 | # Check out current repository 35 | - name: Fetch Sources 36 | uses: actions/checkout@v3 37 | 38 | # Setup Java 11 environment for the next steps 39 | - name: Setup Java 40 | uses: actions/setup-java@v3 41 | with: 42 | distribution: zulu 43 | java-version: 11 44 | 45 | # Run IDEA prepared for UI testing 46 | - name: Run IDE 47 | run: ${{ matrix.runIde }} 48 | 49 | # Wait for IDEA to be started 50 | - name: Health Check 51 | uses: jtalk/url-health-check-action@v2 52 | with: 53 | url: http://127.0.0.1:8082 54 | max-attempts: 15 55 | retry-delay: 30s 56 | 57 | # Run tests 58 | - name: Tests 59 | run: ./gradlew test 60 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/AutoChoices.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | /** 29 | * Enumeration to define the available auto choices modes on a table filter or 30 | * on each separated filter editor. 31 | */ 32 | public enum AutoChoices { 33 | 34 | /** No auto choices, any choices must be explicitly inserted. */ 35 | DISABLED, 36 | 37 | /** Enumerations and booleans automatically handled. */ 38 | ENUMS, 39 | 40 | /** 41 | * Choices extracted from the model, it is guaranteed that the choices 42 | * include all the model's values, and only those. 43 | */ 44 | ENABLED 45 | } 46 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/TableFilterHeaderBeanInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.beans.BeanDescriptor; 29 | import java.beans.SimpleBeanInfo; 30 | 31 | 32 | public class TableFilterHeaderBeanInfo extends SimpleBeanInfo { 33 | 34 | @Override public BeanDescriptor getBeanDescriptor() { 35 | BeanDescriptor desc = new BeanDescriptor(TableFilterHeader.class); 36 | desc.setValue("isContainer", Boolean.FALSE); 37 | 38 | return desc; 39 | } 40 | 41 | @Override public java.awt.Image getIcon(int iconKind) { 42 | return loadImage( 43 | "/net/coderazzi/filters/resources/tableFilterHeader.png"); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/ChoiceRenderer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.Component; 29 | 30 | 31 | /** 32 | * Interface to customize the rendering of choices in the {@link IFilterEditor}. 33 | */ 34 | public interface ChoiceRenderer { 35 | 36 | /** 37 | * Returns the component used to represent the choice (normally, an element 38 | * from the associated table).
39 | * The value can be as well {@link CustomChoice} instances; to use the 40 | * default rendering in this case, the method should return null. 41 | */ 42 | Component getRendererComponent(IFilterEditor editor, 43 | Object value, 44 | boolean isSelected); 45 | } 46 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/editor/IChoicesParser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui.editor; 27 | 28 | /** 29 | * Interface to escape properly choices, so that the IParser handles them 30 | * properly. In special, HTML content must be always removed from the choices. 31 | *
32 | * Starting on version 4.3, the parser is also able to handle html content; 33 | * in this case, the parser accepts simple text, but the created filter can 34 | * be applied to Html content 35 | * 36 | * @author Luis M Pena - lu@coderazzi.net 37 | */ 38 | interface IChoicesParser { 39 | 40 | /** 41 | * Escapes a given expression, such that, when parsed, the parser will make 42 | * no character/operator substitutions. 43 | */ 44 | String escapeChoice(String s); 45 | } 46 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/HtmlChoiceRenderer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.Component; 29 | 30 | import javax.swing.JLabel; 31 | 32 | /** 33 | * Class to render properly columns having html content. 34 | */ 35 | public class HtmlChoiceRenderer extends JLabel implements ChoiceRenderer { 36 | 37 | private static final long serialVersionUID = -825539410560961416L; 38 | 39 | public HtmlChoiceRenderer() { 40 | setOpaque(true); 41 | } 42 | 43 | @Override 44 | public Component getRendererComponent(IFilterEditor editor, Object value, 45 | boolean isSelected) { 46 | setText(value==null? "" : value.toString()); 47 | editor.getLook().setupComponent(this, isSelected, 48 | editor.getFilter().isEnabled()); 49 | return this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/NotFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import javax.swing.RowFilter; 29 | 30 | 31 | /** 32 | * Composed set of filters, added via logical AND, and then NOT-ed the result. 33 | * 34 | * @author Luis M Pena - lu@coderazzi.net 35 | */ 36 | public class NotFilter extends AndFilter { 37 | 38 | /** Default constructor. */ 39 | public NotFilter() { 40 | super(); 41 | } 42 | 43 | /** 44 | * Constructor built up out of one or more {@link 45 | * IFilter} instances. 46 | */ 47 | public NotFilter(IFilter... observables) { 48 | super(observables); 49 | } 50 | 51 | /** @see IFilter#include(Entry) */ 52 | @Override public boolean include(Entry rowEntry) { 53 | return !isEnabled() || !super.include(rowEntry); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleSqliteBrowser 2 | 3 | ![Build](https://github.com/gitofleonardo/SimpleSqliteBrowser/workflows/Build/badge.svg) 4 | [![Version](https://img.shields.io/jetbrains/plugin/v/19797-simplesqlitebrowser.svg)](https://plugins.jetbrains.com/plugin/19797-simplesqlitebrowser) 5 | [![Downloads](https://img.shields.io/jetbrains/plugin/d/19797-simplesqlitebrowser.svg)](https://plugins.jetbrains.com/plugin/19797-simplesqlitebrowser) 6 | 7 | 8 | A simple plugin that helps you to view your sqlite databases in `Intellij Platform`. It's also good to directly double-click 9 | the database file to open it in your `Android Studio`-`Device File Explorer` without any extra actions. 10 | 11 | 12 | --- 13 | 14 | ## Installation 15 | 16 | - Using IDE built-in plugin system: 17 | 18 | Settings/Preferences > Plugins > Marketplace > Search for "SimpleSqliteBrowser" > 19 | Install Plugin 20 | 21 | - Manually: 22 | 23 | Download the [latest release](https://github.com/gitofleonardo/SimpleSqliteBrowser/releases/latest) and install it manually using 24 | Settings/Preferences > Plugins > ⚙️ > Install plugin from disk... 25 | 26 | 27 | --- 28 | 29 | ## Examples 30 | 31 | | ![sample-tables](raw/sample-tables.png) | ![sample-metadata](raw/sample-metadata.png) | 32 | |--|--| 33 | 34 | --- 35 | 36 | ## Credits 37 | 38 | + [tablefilter-swing](https://github.com/coderazzi/tablefilter-swing) of [coderazzi](https://github.com/coderazzi), for filtering table column results. 39 | 40 | ## License 41 | 42 | ``` 43 | Licensed under the Apache License, Version 2.0 (the "License"); 44 | you may not use this file except in compliance with the License. 45 | You may obtain a copy of the License at 46 | 47 | http://www.apache.org/licenses/LICENSE-2.0 48 | 49 | Unless required by applicable law or agreed to in writing, software 50 | distributed under the License is distributed on an "AS IS" BASIS, 51 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | See the License for the specific language governing permissions and 53 | limitations under the License. 54 | ``` 55 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/AndFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import javax.swing.RowFilter; 29 | 30 | 31 | /** 32 | * Composed set of filters, added via logical AND. 33 | * 34 | * @author Luis M Pena - lu@coderazzi.net 35 | */ 36 | public class AndFilter extends ComposedFilter { 37 | 38 | /** Default constructor. */ 39 | public AndFilter() { 40 | super(); 41 | } 42 | 43 | /** 44 | * Constructor built up out of one or more {@link 45 | * IFilter} instances. 46 | */ 47 | public AndFilter(IFilter... observables) { 48 | super(observables); 49 | } 50 | 51 | /** @see IFilter#include(Entry) */ 52 | @Override public boolean include(Entry rowEntry) { 53 | for (IFilter filter : filters) { 54 | if (filter.isEnabled() && !filter.include(rowEntry)) { 55 | return false; 56 | } 57 | } 58 | 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/IFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import javax.swing.RowFilter; 29 | 30 | 31 | /** 32 | *

Interface to be implemented by any instance holding a filter than can be 33 | * updated dynamically.

34 | * 35 | *

Any change on the filter is propagated to the observers, in no given 36 | * order.

37 | * 38 | * @author Luis M Pena - lu@coderazzi.net 39 | */ 40 | public interface IFilter { 41 | 42 | /** {@link RowFilter} interface. */ 43 | boolean include(RowFilter.Entry rowEntry); 44 | 45 | /** Returns true if the filter is enabled. */ 46 | boolean isEnabled(); 47 | 48 | /** Enables/Disables the filter. */ 49 | void setEnabled(boolean enable); 50 | 51 | /** Adds an observer to receive filter change notifications. */ 52 | void addFilterObserver(IFilterObserver observer); 53 | 54 | /** 55 | * Unregisters an observer, that will not receive any further filter update 56 | * notifications. 57 | */ 58 | void removeFilterObserver(IFilterObserver observer); 59 | } 60 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/OrFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import javax.swing.RowFilter; 29 | 30 | 31 | /** 32 | * Composed set of filters, added via logical OR. 33 | * 34 | * @author Luis M Pena - lu@coderazzi.net 35 | */ 36 | public class OrFilter extends ComposedFilter { 37 | 38 | /** Default constructor. */ 39 | public OrFilter() { 40 | super(); 41 | } 42 | 43 | /** 44 | * Constructor built up out of one or more {@link 45 | * IFilter} instances. 46 | */ 47 | public OrFilter(IFilter... observables) { 48 | super(observables); 49 | } 50 | 51 | /** @see IFilter#include(Entry) */ 52 | @Override public boolean include(Entry rowEntry) { 53 | boolean ret = true; 54 | for (IFilter filter : filters) { 55 | if (filter.isEnabled()) { 56 | if (filter.include(rowEntry)) { 57 | return true; 58 | } 59 | 60 | ret = false; 61 | } 62 | } 63 | 64 | return ret; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/Extensions.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser 2 | 3 | import com.intellij.openapi.ui.ComboBox 4 | import java.awt.event.* 5 | import javax.swing.JComponent 6 | import javax.swing.text.JTextComponent 7 | 8 | inline fun ComboBox.addOnItemChangeListener(crossinline listener: (T) -> Unit) { 9 | addItemListener { 10 | if (it.stateChange == ItemEvent.SELECTED) { 11 | val item = it.item 12 | if (item is T) { 13 | listener.invoke(item) 14 | } 15 | } 16 | } 17 | } 18 | 19 | fun JTextComponent.addOnKeyEventListener(listener: (KeyEvent) -> Unit) { 20 | addKeyListener(object : KeyListener { 21 | override fun keyTyped(e: KeyEvent?) { 22 | e?.let(listener) 23 | } 24 | 25 | override fun keyPressed(e: KeyEvent?) { 26 | } 27 | 28 | override fun keyReleased(e: KeyEvent?) { 29 | } 30 | }) 31 | } 32 | 33 | fun JComponent.addOnClickListener(listener:(MouseEvent) -> Unit) { 34 | addMouseListener(object : MouseListener { 35 | override fun mouseClicked(e: MouseEvent?) { 36 | e?.let(listener) 37 | } 38 | 39 | override fun mousePressed(e: MouseEvent?) {} 40 | 41 | override fun mouseReleased(e: MouseEvent?) {} 42 | 43 | override fun mouseEntered(e: MouseEvent?) {} 44 | 45 | override fun mouseExited(e: MouseEvent?) {} 46 | }) 47 | } 48 | 49 | fun JComponent.addOnTouchListener(listener: (MouseEvent) -> Unit) { 50 | addMouseListener(object : MouseListener { 51 | override fun mouseClicked(e: MouseEvent?) {} 52 | 53 | override fun mousePressed(e: MouseEvent?) { 54 | e?.let(listener) 55 | } 56 | 57 | override fun mouseReleased(e: MouseEvent?) {} 58 | 59 | override fun mouseEntered(e: MouseEvent?) {} 60 | 61 | override fun mouseExited(e: MouseEvent?) {} 62 | }) 63 | } 64 | 65 | fun Any?.toStringOr(placeHolder: String = ""): String { 66 | return this?.toString() ?: placeHolder 67 | } 68 | 69 | private const val BYTE_SIZE = 1024 70 | private const val K_BYTE_SIZE = 1024 * 1024 71 | 72 | fun ByteArray.toSizeString(): String { 73 | val siz = size 74 | return if (siz <= BYTE_SIZE) { 75 | "$siz Bytes" 76 | } else if (siz <= K_BYTE_SIZE) { 77 | String.format("%.2f KB", siz / BYTE_SIZE.toFloat()) 78 | } else{ 79 | String.format("%.2f MB", siz / K_BYTE_SIZE.toFloat()) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/window/SqliteMetaDataWindow.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui.window 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.SqliteMetadata 4 | import com.github.gitofleonardo.simplesqlitebrowser.tools.DatabaseTreeCellRenderer 5 | import com.github.gitofleonardo.simplesqlitebrowser.tools.DatabaseTreeModel 6 | import com.github.gitofleonardo.simplesqlitebrowser.ui.TabbedChildView 7 | import com.github.gitofleonardo.simplesqlitebrowser.ui.viewmodel.MetadataViewModel 8 | import com.intellij.openapi.vfs.VirtualFile 9 | import com.intellij.ui.components.JBScrollPane 10 | import com.intellij.ui.components.JBTreeTable 11 | import com.intellij.ui.treeStructure.Tree 12 | import java.awt.BorderLayout 13 | import javax.swing.Icon 14 | import javax.swing.JPanel 15 | import javax.swing.JTree 16 | import javax.swing.ScrollPaneConstants 17 | 18 | private const val TITLE = "Database Metadata" 19 | 20 | class SqliteMetaDataWindow(private val file: VirtualFile) : TabbedChildView() { 21 | override val title: String = TITLE 22 | override val icon: Icon? = null 23 | 24 | private val viewModel = MetadataViewModel() 25 | private val emptyMetadata = SqliteMetadata() 26 | private var treeModel: DatabaseTreeModel = DatabaseTreeModel(emptyMetadata) 27 | 28 | // Auto-generated components {@ 29 | private lateinit var rootTree: Tree 30 | private lateinit var rootContainer: JPanel 31 | private lateinit var treeScrollContainer: JBScrollPane 32 | // @} 33 | 34 | init { 35 | setupUI() 36 | initObserve() 37 | viewModel.loadMetaData(file) 38 | } 39 | 40 | private fun initObserve() { 41 | viewModel.metadata.observe { 42 | if (!it.isValidSqliteDatabase) { 43 | return@observe 44 | } 45 | treeModel = DatabaseTreeModel(it) 46 | rootTree.model = treeModel 47 | } 48 | } 49 | 50 | // UI Setup {@ 51 | private fun setupUI() { 52 | rootContainer = JPanel() 53 | rootContainer.layout = BorderLayout(0, 0) 54 | rootTree = Tree() 55 | rootTree.cellRenderer = DatabaseTreeCellRenderer() 56 | treeScrollContainer = JBScrollPane() 57 | treeScrollContainer.horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED 58 | treeScrollContainer.setViewportView(rootTree) 59 | rootContainer.add(treeScrollContainer, BorderLayout.CENTER) 60 | 61 | layout = BorderLayout() 62 | add(rootContainer) 63 | } 64 | // @} 65 | } 66 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/editor/ChoiceMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui.editor; 27 | 28 | import java.util.Comparator; 29 | 30 | 31 | /** Class to find matches in the lists (history / choices). */ 32 | class ChoiceMatch { 33 | // exact is true if the given index corresponds to an string that fully 34 | // matches the passed string 35 | boolean exact; 36 | // the matched content 37 | Object content; 38 | // index in the list. Will be -1 if the content is empty or a fullMatch 39 | // is required and cannot be found 40 | int index = -1; 41 | // length of the string that is matched, if exact is false. 42 | int len; 43 | 44 | /** Returns the number of matching characters between two strings. */ 45 | public static int getMatchingLength(String a, 46 | String b, 47 | Comparator stringComparator) { 48 | int max = Math.min(a.length(), b.length()); 49 | for (int i = 0; i < max; i++) { 50 | char f = a.charAt(i); 51 | char s = b.charAt(i); 52 | if ((f != s) 53 | && (stringComparator.compare(String.valueOf(f), 54 | String.valueOf(s)) != 0)) { 55 | return i; 56 | } 57 | } 58 | 59 | return max; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/tools/DatabaseTreeModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.tools 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbColumn 4 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbTable 5 | import com.github.gitofleonardo.simplesqlitebrowser.data.SqliteMetadata 6 | import javax.swing.event.TreeModelListener 7 | import javax.swing.tree.DefaultMutableTreeNode 8 | import javax.swing.tree.MutableTreeNode 9 | import javax.swing.tree.TreeModel 10 | import javax.swing.tree.TreeNode 11 | import javax.swing.tree.TreePath 12 | 13 | class DatabaseTreeModel(private val metadata: SqliteMetadata) : TreeModel { 14 | private val root = DefaultMutableTreeNode("Tables") 15 | 16 | init { 17 | for (table in metadata.tables) { 18 | root.add(buildTableNode(table)) 19 | } 20 | } 21 | 22 | private fun buildTableNode(table: DbTable): MutableTreeNode { 23 | val tableNode = DefaultMutableTreeNode(table, true) 24 | for (col in table.columns) { 25 | tableNode.add(buildColumnNode(col)) 26 | } 27 | return tableNode 28 | } 29 | 30 | private fun buildColumnNode(col: DbColumn): MutableTreeNode { 31 | return DefaultMutableTreeNode(col, false) 32 | } 33 | 34 | override fun getRoot(): Any { 35 | return root 36 | } 37 | 38 | override fun getChild(parent: Any?, index: Int): Any? { 39 | if (parent == null) { 40 | return null 41 | } 42 | if (parent !is MutableTreeNode) { 43 | return null 44 | } 45 | if (index >= parent.childCount) { 46 | return null 47 | } 48 | return parent.getChildAt(index) 49 | } 50 | 51 | override fun getChildCount(parent: Any?): Int { 52 | if (parent == null) { 53 | return 0 54 | } 55 | if (parent !is MutableTreeNode) { 56 | return 0 57 | } 58 | return parent.childCount 59 | } 60 | 61 | override fun isLeaf(node: Any?): Boolean { 62 | if (node == null || node !is DefaultMutableTreeNode) { 63 | return false 64 | } 65 | return node.isLeaf 66 | } 67 | 68 | override fun valueForPathChanged(path: TreePath?, newValue: Any?) { 69 | } 70 | 71 | override fun getIndexOfChild(parent: Any?, child: Any?): Int { 72 | if (parent == null || child == null) { 73 | return -1 74 | } 75 | if (parent !is TreeNode || child !is TreeNode) { 76 | return -1 77 | } 78 | return parent.getIndex(child) 79 | } 80 | 81 | override fun addTreeModelListener(l: TreeModelListener?) { 82 | } 83 | 84 | override fun removeTreeModelListener(l: TreeModelListener?) { 85 | } 86 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/LooseParserModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import net.coderazzi.filters.IParser; 29 | import net.coderazzi.filters.parser.DateComparator; 30 | import net.coderazzi.filters.parser.Parser; 31 | 32 | import java.beans.PropertyChangeListener; 33 | import java.beans.PropertyChangeSupport; 34 | import java.text.DateFormat; 35 | import java.text.FieldPosition; 36 | import java.text.Format; 37 | import java.text.ParseException; 38 | import java.text.ParsePosition; 39 | import java.text.SimpleDateFormat; 40 | import java.util.Comparator; 41 | import java.util.Date; 42 | import java.util.HashMap; 43 | import java.util.Map; 44 | 45 | 46 | /** 47 | * Default {@link Format} instances, supporting all the basic java types
48 | * It also includes support for {@link Comparator} of {@link Date} instances. 49 | *
50 | * The default {@link IParser} is automatically configured to use these {@link 51 | * Format} instances, when created by the {@link TableFilterHeader}.
52 | * Users can add any {@link Format} or {@link Comparator} definitions, as the 53 | * class is used as a singleton. 54 | * 55 | * @author Luis M Pena - lu@coderazzi.net 56 | */ 57 | public class LooseParserModel extends ParserModel { 58 | 59 | /** Creates the parser as required with the given parameters */ 60 | protected IParser createParser(Format fmt, Comparator cmp, 61 | Comparator stringCmp, boolean ignoreCase, 62 | int modelIndex) { 63 | return new Parser(fmt, cmp, stringCmp, ignoreCase, modelIndex){ 64 | @Override 65 | protected String getInstantAppliedExpression(String expression) { 66 | return expression; 67 | } 68 | 69 | @Override 70 | public IOperand getDefaultOperator(boolean instantMode) { 71 | return super.getDefaultOperator(true); 72 | } 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/IFilterHeaderObserver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import javax.swing.table.TableColumn; 29 | 30 | 31 | /** 32 | *

A ITableFilterHeaderObserver instance receives notifications when the 33 | * associated {@link IFilterEditor} instances are 34 | * created, destroyed, or update the held filter.

35 | * 36 | * @author Luis M Pena - lu@coderazzi.net 37 | */ 38 | public interface IFilterHeaderObserver { 39 | 40 | /** 41 | *

Informs the observer than a new filter editor is created

42 | * 43 | * @param header the associated table filter header 44 | * @param editor 45 | * @param tableColumn the associated {@link TableColumn} 46 | */ 47 | void tableFilterEditorCreated(TableFilterHeader header, 48 | IFilterEditor editor, 49 | TableColumn tableColumn); 50 | 51 | /** 52 | *

Informs the observer than an existing filter editor has been excluded 53 | * from the filter header

54 | * 55 | * @param header the associated table filter header 56 | * @param editor 57 | * @param tableColumn the associated {@link TableColumn} 58 | */ 59 | void tableFilterEditorExcluded(TableFilterHeader header, 60 | IFilterEditor editor, 61 | TableColumn tableColumn); 62 | 63 | /** 64 | *

Notification made by the {@link 65 | * IFilterEditor} when the filter's content is 66 | * updated

67 | * 68 | * @param header the associated table filter header 69 | * @param editor the observable instance 70 | * @param tableColumn the associated {@link TableColumn} 71 | */ 72 | void tableFilterUpdated(TableFilterHeader header, 73 | IFilterEditor editor, 74 | TableColumn tableColumn); 75 | } 76 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/tools/DatabaseTreeCellRenderer.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.tools 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbColumn 4 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbTable 5 | import com.intellij.uiDesigner.core.GridConstraints 6 | import com.intellij.uiDesigner.core.GridLayoutManager 7 | import java.awt.Component 8 | import java.awt.Dimension 9 | import java.awt.Insets 10 | import javax.swing.JLabel 11 | import javax.swing.JPanel 12 | import javax.swing.JTree 13 | import javax.swing.tree.DefaultMutableTreeNode 14 | import javax.swing.tree.TreeCellRenderer 15 | 16 | class DatabaseTreeCellRenderer : TreeCellRenderer { 17 | override fun getTreeCellRendererComponent( 18 | tree: JTree, 19 | value: Any?, 20 | selected: Boolean, 21 | expanded: Boolean, 22 | leaf: Boolean, 23 | row: Int, 24 | hasFocus: Boolean 25 | ): Component { 26 | if (value == null || value !is DefaultMutableTreeNode) { 27 | return JPanel() 28 | } 29 | return when (val data = value.userObject) { 30 | null -> { 31 | JPanel() 32 | } 33 | is DbTable -> { 34 | buildTreeNodeComponent( data.tableName, "", "") 35 | } 36 | is DbColumn -> { 37 | buildTreeNodeComponent(data.name, data.typeName, "\"${data.name}\" ${data.typeName} ${data.schema}") 38 | } 39 | else -> { 40 | buildTreeNodeComponent(data.toString(), "", "") 41 | } 42 | } 43 | } 44 | 45 | // Auto-generated code {@ 46 | private fun buildTreeNodeComponent(name: String, type: String, schema: String): Component { 47 | val rootPanel = JPanel() 48 | rootPanel.layout = GridLayoutManager(1, 3, Insets(0, 0, 0, 0), -1, -1, true, false) 49 | rootPanel.minimumSize = Dimension(28, 26) 50 | rootPanel.preferredSize = Dimension(28, 26) 51 | val nameLabel = JLabel() 52 | nameLabel.text = name 53 | rootPanel.add(nameLabel, GridConstraints(0, 0, 1, 1, 54 | GridConstraints.ANCHOR_WEST, GridConstraints.FILL_VERTICAL, 55 | GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_CAN_GROW, 56 | GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_CAN_GROW, 57 | null, null, null, 0, false)) 58 | val typeLabel = JLabel() 59 | typeLabel.text = type 60 | rootPanel.add(typeLabel, GridConstraints(0, 1, 1, 1, 61 | GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, 62 | GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_WANT_GROW, 63 | GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_CAN_GROW, 64 | null, null, null, 0, false)) 65 | val schemaLabel = JLabel() 66 | schemaLabel.text = schema 67 | rootPanel.add(schemaLabel, GridConstraints(0, 2, 1, 1, 68 | GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, 69 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)) 70 | return rootPanel 71 | } 72 | // @} 73 | } 74 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/Filter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import java.util.ArrayList; 29 | import java.util.HashSet; 30 | import java.util.Set; 31 | 32 | import javax.swing.RowFilter; 33 | 34 | 35 | /** 36 | * Commodity class implementing the interface {@link 37 | * IFilter} on a {@link RowFilter}. 38 | * 39 | * @author Luis M Pena - lu@coderazzi.net 40 | */ 41 | abstract public class Filter extends RowFilter implements IFilter { 42 | 43 | /** The set of currently subscribed observers. */ 44 | private Set observers = new HashSet(); 45 | 46 | /** The enabled state. */ 47 | private boolean enabled = true; 48 | 49 | /** @see IFilter#isEnabled() */ 50 | @Override public boolean isEnabled() { 51 | return enabled; 52 | } 53 | 54 | /** @see IFilter#setEnabled(boolean) */ 55 | @Override public void setEnabled(boolean enable) { 56 | if (enable != this.enabled) { 57 | this.enabled = enable; 58 | reportFilterUpdatedToObservers(); 59 | } 60 | } 61 | 62 | /** @see IFilter#addFilterObserver(IFilterObserver) */ 63 | @Override public void addFilterObserver(IFilterObserver observer) { 64 | observers.add(observer); 65 | } 66 | 67 | /** @see IFilter#removeFilterObserver(IFilterObserver) */ 68 | @Override public void removeFilterObserver(IFilterObserver observer) { 69 | observers.remove(observer); 70 | } 71 | 72 | /** Returns all the registered {@link IFilterObserver} instances. */ 73 | public Set getFilterObservers() { 74 | return new HashSet(observers); 75 | } 76 | 77 | /** 78 | * Method to be called by subclasses to report to the observers that the 79 | * filter has changed. 80 | */ 81 | public void reportFilterUpdatedToObservers() { 82 | for (IFilterObserver obs : new ArrayList(observers)) { 83 | obs.filterUpdated(this); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for handling the release process based on the draft release prepared 2 | # with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. 3 | 4 | name: Release 5 | on: 6 | release: 7 | types: [prereleased, released] 8 | 9 | jobs: 10 | 11 | # Prepare and publish the plugin to the Marketplace repository 12 | release: 13 | name: Publish Plugin 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | pull-requests: write 18 | steps: 19 | 20 | # Check out current repository 21 | - name: Fetch Sources 22 | uses: actions/checkout@v3 23 | with: 24 | ref: ${{ github.event.release.tag_name }} 25 | 26 | # Setup Java 11 environment for the next steps 27 | - name: Setup Java 28 | uses: actions/setup-java@v3 29 | with: 30 | distribution: zulu 31 | java-version: 11 32 | 33 | # Set environment variables 34 | - name: Export Properties 35 | id: properties 36 | shell: bash 37 | run: | 38 | CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d' 39 | ${{ github.event.release.body }} 40 | EOM 41 | )" 42 | 43 | CHANGELOG="${CHANGELOG//'%'/'%25'}" 44 | CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" 45 | CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" 46 | 47 | echo "::set-output name=changelog::$CHANGELOG" 48 | 49 | # Update Unreleased section with the current release note 50 | - name: Patch Changelog 51 | if: ${{ steps.properties.outputs.changelog != '' }} 52 | env: 53 | CHANGELOG: ${{ steps.properties.outputs.changelog }} 54 | run: | 55 | ./gradlew patchChangelog --release-note="$CHANGELOG" 56 | 57 | # Publish the plugin to the Marketplace 58 | - name: Publish Plugin 59 | env: 60 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 61 | CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} 62 | PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} 63 | PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} 64 | run: ./gradlew publishPlugin 65 | 66 | # Upload artifact as a release asset 67 | - name: Upload Release Asset 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* 71 | 72 | # Create pull request 73 | - name: Create Pull Request 74 | if: ${{ steps.properties.outputs.changelog != '' }} 75 | env: 76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | run: | 78 | VERSION="${{ github.event.release.tag_name }}" 79 | BRANCH="changelog-update-$VERSION" 80 | 81 | git config user.email "action@github.com" 82 | git config user.name "GitHub Action" 83 | 84 | git checkout -b $BRANCH 85 | git commit -am "Changelog update - $VERSION" 86 | git push --set-upstream origin $BRANCH 87 | 88 | gh pr create \ 89 | --title "Changelog update - \`$VERSION\`" \ 90 | --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ 91 | --base main \ 92 | --head $BRANCH 93 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/ui/viewmodel/TableViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.ui.viewmodel 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.DbTableInstance 4 | import com.github.gitofleonardo.simplesqlitebrowser.model.SqliteModel 5 | import com.github.gitofleonardo.simplesqlitebrowser.mvvm.LiveData 6 | import com.github.gitofleonardo.simplesqlitebrowser.mvvm.ViewModel 7 | import com.intellij.openapi.vfs.VirtualFile 8 | import io.reactivex.rxjava3.core.Observable 9 | import io.reactivex.rxjava3.schedulers.Schedulers 10 | import javax.swing.SwingUtilities 11 | import kotlin.math.ceil 12 | 13 | private const val DEFAULT_PGE_COUNT = 50 14 | 15 | class TableViewModel(private val dbFile: VirtualFile) : ViewModel { 16 | private val model = SqliteModel 17 | var currentPage: Int = 1 18 | var pageCount: Int = DEFAULT_PGE_COUNT 19 | var currentTableName: String? = null 20 | var totalPages: Int = 1 21 | var totalCount: Int = 0 22 | 23 | val tables = LiveData>() 24 | val tableData = LiveData() 25 | 26 | fun resetTableData() { 27 | currentTableName?.let { resetTableData(it) } 28 | } 29 | 30 | fun resetTableData(tableName: String) { 31 | currentPage = 1 32 | currentTableName = tableName 33 | loadTableData(dbFile, tableName, pageCount, currentPage) 34 | } 35 | 36 | fun loadNextPage() { 37 | currentTableName?.let { 38 | if (currentPage < totalPages) { 39 | ++currentPage 40 | loadTableData(dbFile, it, pageCount, currentPage) 41 | } 42 | } 43 | } 44 | 45 | fun loadPreviousPage() { 46 | currentTableName?.let { 47 | if (currentPage > 1) { 48 | --currentPage 49 | loadTableData(dbFile, it, pageCount, currentPage) 50 | } 51 | } 52 | } 53 | 54 | fun loadPage(page: Int) { 55 | if (page < 1 || page > totalPages) { 56 | return 57 | } 58 | currentTableName?.let { 59 | currentPage = page 60 | loadTableData(dbFile, it, pageCount, currentPage) 61 | } 62 | } 63 | 64 | fun loadFirstPage() { 65 | loadPage(1) 66 | } 67 | 68 | fun loadLastPage() { 69 | loadPage(totalPages) 70 | } 71 | 72 | private fun loadTableData(file: VirtualFile, tableName: String, pageCount: Int, page: Int) { 73 | Observable 74 | .create { emitter -> 75 | emitter.onNext(model.loadTableData(file, tableName, pageCount, page)) 76 | } 77 | .subscribeOn(Schedulers.io()) 78 | .subscribe { result -> 79 | SwingUtilities.invokeLater { 80 | totalCount = result.totalCount 81 | totalPages = ceil(totalCount.toFloat() / pageCount).toInt() 82 | tableData.value = result 83 | } 84 | } 85 | 86 | } 87 | 88 | fun loadTables() { 89 | Observable 90 | .create { emitter-> 91 | emitter.onNext(model.loadTables(dbFile)) 92 | } 93 | .subscribeOn(Schedulers.io()) 94 | .subscribe { tbls -> 95 | SwingUtilities.invokeLater { 96 | tables.value = tbls 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/IParserModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.beans.PropertyChangeListener; 29 | 30 | import java.text.Format; 31 | 32 | import java.util.Comparator; 33 | 34 | import net.coderazzi.filters.IParser; 35 | 36 | 37 | /** 38 | * Interface defining the model required to use and create {@link IParser} 39 | * instances. 40 | * 41 | * @author Luis M Pena - lu@coderazzi.net 42 | */ 43 | public interface IParserModel { 44 | 45 | /** Property fired when the ignore case value changes. */ 46 | String IGNORE_CASE_PROPERTY = "ignoreCase"; 47 | 48 | /** Property fired when any class' comparator changes. */ 49 | String COMPARATOR_PROPERTY = "comparator"; 50 | 51 | /** Property fired when any class' format changes. */ 52 | String FORMAT_PROPERTY = "format"; 53 | 54 | /** Creates a text parser for the given editor. */ 55 | IParser createParser(IFilterEditor editor); 56 | 57 | /** Returns the {@link Format} for the given class. */ 58 | Format getFormat(Class c); 59 | 60 | /** Defines the {@link Format} for the given class. */ 61 | void setFormat(Class c, Format format); 62 | 63 | /** 64 | * Returns the {@link Comparator} for the given class.
65 | * It never returns null. 66 | */ 67 | Comparator getComparator(Class c); 68 | 69 | /** Defines the {@link Comparator} for the given class. */ 70 | void setComparator(Class c, Comparator format); 71 | 72 | /** Returns the {@link Comparator} used for String comparisons. */ 73 | Comparator getStringComparator(boolean ignoreCase); 74 | 75 | /** Sets a String comparator that is case sensitive/insensitive. */ 76 | void setIgnoreCase(boolean set); 77 | 78 | /** 79 | * Returns true if the String comparator ignores case
80 | * Note that this is redundant information, which can be retrieved from the 81 | * {@link #getComparator(Class)} method with a String.class parameter. 82 | */ 83 | boolean isIgnoreCase(); 84 | 85 | /** 86 | * Adds a {@link PropertyChangeListener}.
87 | * Any property change will be transmitted as an event 88 | */ 89 | void addPropertyChangeListener(PropertyChangeListener listener); 90 | 91 | /** Removes an existing {@link PropertyChangeListener}. */ 92 | void removePropertyChangeListener(PropertyChangeListener listener); 93 | 94 | } 95 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/IParser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import java.text.ParseException; 29 | 30 | import javax.swing.RowFilter; 31 | 32 | import net.coderazzi.filters.gui.IFilterEditor; 33 | 34 | 35 | /** 36 | * Interface defining the requirements on text parsing for filter expressions. 37 | *
38 | * Starting on version 4.3, the parser is also able to handle html content; 39 | * in this case, the parser accepts simple text, but the created filter can 40 | * be applied to Html content 41 | * 42 | * @author Luis M Pena - lu@coderazzi.net 43 | */ 44 | public interface IParser { 45 | 46 | /** 47 | * Parses the text, returning a filter that can be applied to the table. 48 | * 49 | * @param expression the text to parse 50 | */ 51 | RowFilter parseText(String expression) throws ParseException; 52 | 53 | /** 54 | * Parses the text, considered to be a part of the whole text to enter.
55 | * 56 | *

The behaviour of this method is implementation specific; the default 57 | * implementation considers the expression to be the beginning of the 58 | * expected final string

59 | * 60 | *

This method is invoked when the user inputs text on a filter editor, 61 | * if instant parsing is enabled, and if the text entered so far does not 62 | * match any table's row value for the associated column.

63 | * 64 | *

Alternative implementations that would consider matching the provided 65 | * expression to any substring ('contain' meaning), should set the 66 | * autoCompletion flag in the {@link IFilterEditor}to false

67 | * 68 | * @param expression the text to parse 69 | * 70 | * @return the filter plus the real expression used to create the filter 71 | */ 72 | InstantFilter parseInstantText(String expression) throws ParseException; 73 | 74 | /** 75 | * Escapes a given expression, such that, when parsed, the parser will make 76 | * no character/operator substitutions. 77 | */ 78 | String escape(String s); 79 | 80 | /** 81 | * Removes any Html content from the passed string, converting special 82 | * Html characters to Java characters. 83 | */ 84 | String stripHtml(String s); 85 | 86 | /** Helper class used on {@link IParser#parseInstantText(String)}. */ 87 | public class InstantFilter { 88 | public RowFilter filter; 89 | public String expression; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/editor/FilterArrowButton.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui.editor; 27 | 28 | import java.awt.Dimension; 29 | import java.awt.Graphics; 30 | import java.awt.Graphics2D; 31 | import java.awt.RenderingHints; 32 | 33 | import javax.swing.JButton; 34 | 35 | import net.coderazzi.filters.gui.Look; 36 | 37 | 38 | /** Custom implementation of the arrow used to display the popup menu. */ 39 | final class FilterArrowButton extends JButton { 40 | private static final long serialVersionUID = -777416843479142582L; 41 | private final static int MIN_X = 6; 42 | private final static int MIN_Y = 6; 43 | private final static int FILL_X[] = { 0, 3, 6 }; 44 | private final static int FILL_Y[] = { 0, 5, 0 }; 45 | 46 | private boolean focus; 47 | private Look look; 48 | 49 | public void setLook(Look look) { 50 | this.look = look; 51 | repaint(); 52 | } 53 | 54 | public Look getLook() { 55 | return look; 56 | } 57 | 58 | public void setFocused(boolean focus) { 59 | this.focus = focus; 60 | repaint(); 61 | } 62 | 63 | 64 | @Override public void paint(Graphics g) { 65 | ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, 66 | RenderingHints.VALUE_ANTIALIAS_ON); 67 | 68 | int height = getHeight(); 69 | int width = getWidth(); 70 | 71 | if (isEnabled()) { 72 | g.setColor(focus ? look.getSelectionBackground() 73 | : look.getBackground()); 74 | } else { 75 | g.setColor(look.getDisabledBackground()); 76 | } 77 | 78 | g.fillRect(0, 0, width, height); 79 | 80 | width = (width - MIN_X) / 2; 81 | height = Math.min(height / 2, height - MIN_Y); 82 | g.translate(width, height); 83 | 84 | if (isEnabled()) { 85 | g.setColor(focus ? look.getSelectionForeground() 86 | : look.getForeground()); 87 | } else { 88 | g.setColor(look.getDisabledForeground()); 89 | } 90 | 91 | g.fillPolygon(FILL_X, FILL_Y, FILL_X.length); 92 | } 93 | 94 | @Override protected void paintBorder(Graphics g) { 95 | super.paintBorder(g); 96 | } 97 | 98 | @Override public boolean isFocusable() { 99 | return false; 100 | } 101 | 102 | @Override public Dimension getPreferredSize() { 103 | return new Dimension(12, 12); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/parser/HtmlHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.parser; 27 | 28 | /** 29 | * Class to handle HTML content, required to remove HTML tags and to convert 30 | * HTML special characters (like &) to Java characters 31 | */ 32 | class HtmlHandler { 33 | 34 | private StringBuffer buffer = new StringBuffer(); 35 | 36 | /** 37 | * Converts an String to the corresponding string without HTML 38 | * information. 39 | */ 40 | public String stripHtml(String s) { 41 | String inner = getSubstringUnderHtmlTag(s); 42 | return (inner == null ? s : removeHtmlInfo(inner)).trim(); 43 | } 44 | 45 | /** 46 | * Removes any tag and converts special HTML characters to Java chars. 47 | */ 48 | private String removeHtmlInfo(String inner) { 49 | boolean inTag = false, inQuoteInTag = false; 50 | char quoteChar = '"'; 51 | int entityPos = -1; 52 | 53 | buffer.delete(0, buffer.length()); 54 | for (char c : inner.toCharArray()) { 55 | if (c == '<') { 56 | inTag = true; 57 | entityPos = -1; 58 | } else if (c == '>') { 59 | // not anymore tag, unless is inside a quote 60 | inTag = inTag && inQuoteInTag; 61 | } else if (inTag) { 62 | // special attention to "' characters 63 | if (c == '"' || c == '\'') { 64 | if (inQuoteInTag) { 65 | inQuoteInTag = (quoteChar != c); 66 | } else { 67 | inQuoteInTag = true; 68 | quoteChar = c; 69 | } 70 | } 71 | } else { 72 | if (c == '&') { 73 | entityPos = buffer.length(); 74 | } else if (c == ';' && entityPos != -1) { 75 | int len = buffer.length(); 76 | if (len > entityPos + 2) { 77 | int entityValue = getEntityValue(entityPos + 1); 78 | if (entityValue > 0 && entityValue < 65536) { 79 | buffer.delete(entityPos, len); 80 | c = (char) entityValue; 81 | } 82 | } 83 | } 84 | buffer.append(c); 85 | } 86 | } 87 | return buffer.toString(); 88 | } 89 | 90 | /** 91 | * Returns the integer associated to the entity stored in the StringBuffer, 92 | * starting at the passed position (until the end of the buffer). 93 | * @return -1 if it is not a valid html entity 94 | */ 95 | private int getEntityValue(int start) { 96 | if (buffer.charAt(start) == '#') { 97 | char hex = buffer.charAt(start); 98 | try { 99 | if (hex == 'x' || hex == 'X') { 100 | return Integer.valueOf(buffer.substring(start + 2), 16); 101 | } 102 | return Integer.valueOf(buffer.substring(start + 1)); 103 | } catch (NumberFormatException nfe) { 104 | return -1; 105 | } 106 | } 107 | return HtmlEntities.getEntityValue(buffer.substring(start)); 108 | } 109 | 110 | /** 111 | * Removes the external tags, if existing. 112 | * It returns the string contained inside the tags, or null if the tags 113 | * are not present 114 | */ 115 | private String getSubstringUnderHtmlTag(String s) { 116 | int l = s.length(); 117 | if (l >= 6 && (s.charAt(0) == '<') && (s.charAt(5) == '>') 118 | && (s.charAt(1) == 'h' || s.charAt(1) == 'H') 119 | && (s.charAt(2) == 't' || s.charAt(2) == 'T') 120 | && (s.charAt(3) == 'm' || s.charAt(3) == 'M') 121 | && (s.charAt(4) == 'l' || s.charAt(4) == 'L') 122 | && (s.charAt(0) == '<')) { 123 | // it is enough if the string starts with , ending not 124 | // important 125 | if (l >= 13 && (s.charAt(l - 1) == '>') && (s.charAt(l - 7) == '<') 126 | && (s.charAt(l - 6) == '/') 127 | && (s.charAt(l - 5) == 'h' || s.charAt(l - 5) == 'H') 128 | && (s.charAt(l - 4) == 't' || s.charAt(l - 4) == 'T') 129 | && (s.charAt(l - 3) == 'm' || s.charAt(l - 3) == 'M') 130 | && (s.charAt(l - 2) == 'l' || s.charAt(l - 2) == 'L')) { 131 | l -= 7; 132 | } 133 | return s.substring(6, l); 134 | } 135 | return null; 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/CustomChoiceDecorator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.Color; 29 | import java.awt.Font; 30 | import java.awt.Graphics; 31 | 32 | import javax.swing.JComponent; 33 | 34 | 35 | /** 36 | * Interface that allows customizing the appearance of CustomChoices in those 37 | * {@link IFilterEditor}s without associated {@link ChoiceRenderer}. 38 | */ 39 | public interface CustomChoiceDecorator { 40 | 41 | /** Returns the background color. */ 42 | Color getBackground(CustomChoice choice, 43 | IFilterEditor editor, 44 | boolean isSelected); 45 | 46 | /** Returns the foreground color. */ 47 | Color getForeground(CustomChoice choice, 48 | IFilterEditor editor, 49 | boolean isSelected); 50 | 51 | /** Returns the font. */ 52 | Font getFont(CustomChoice choice, IFilterEditor editor, boolean isSelected); 53 | 54 | /** Decorates the choice on the given editor. */ 55 | void decorateComponent(CustomChoice choice, 56 | IFilterEditor editor, 57 | boolean isSelected, 58 | JComponent c, 59 | Graphics g); 60 | 61 | /** 62 | * Default decorator, delegating always to the associated methods on the 63 | * {@link CustomChoice} instances. The font, by default, will be cursive 64 | */ 65 | public class DefaultDecorator implements CustomChoiceDecorator { 66 | 67 | private Font baseFont; 68 | private Font italicFont; 69 | 70 | @Override public void decorateComponent(CustomChoice choice, 71 | IFilterEditor editor, 72 | boolean isSelected, 73 | JComponent c, 74 | Graphics g) { 75 | choice.decorateComponent(editor, isSelected, c, g); 76 | } 77 | 78 | @Override public Font getFont(CustomChoice choice, 79 | IFilterEditor editor, 80 | boolean isSelected) { 81 | Font ret = choice.getFont(editor, isSelected); 82 | if (ret == null) { 83 | ret = editor.getLook().getFont(); 84 | if (ret != baseFont) { 85 | baseFont = ret; 86 | italicFont = baseFont.deriveFont(Font.ITALIC); 87 | } 88 | 89 | ret = italicFont; 90 | } 91 | 92 | return ret; 93 | } 94 | 95 | @Override public Color getBackground(CustomChoice choice, 96 | IFilterEditor editor, 97 | boolean isSelected) { 98 | Color color = choice.getBackground(editor, isSelected); 99 | if (color == null) { 100 | Look look = editor.getLook(); 101 | color = isSelected ? look.getSelectionBackground() 102 | : look.getBackground(); 103 | } 104 | return color; 105 | } 106 | 107 | @Override public Color getForeground(CustomChoice choice, 108 | IFilterEditor editor, 109 | boolean isSelected) { 110 | Color color = choice.getForeground(editor, isSelected); 111 | if (color == null) { 112 | Look look = editor.getLook(); 113 | color = isSelected ? look.getSelectionForeground() 114 | : look.getForeground(); 115 | } 116 | return color; 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/ComposedFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters; 27 | 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | 32 | /** 33 | *

Abstract parent class to support the composition of multiple filters.

34 | * 35 | *

The exact composition semantics (and / or / not) are not defined.

36 | * 37 | * @author Luis M Pena - lu@coderazzi.net 38 | */ 39 | abstract public class ComposedFilter extends Filter implements IFilterObserver { 40 | 41 | /** Set of associated IFilters. */ 42 | protected Set filters; 43 | 44 | /** disabled filters. */ 45 | private Set disabledFilters = new HashSet(); 46 | 47 | /** Default constructor. */ 48 | protected ComposedFilter() { 49 | filters = new HashSet(); 50 | } 51 | 52 | /** 53 | * Constructor built up out of one or more {@link 54 | * IFilter} instances. 55 | */ 56 | protected ComposedFilter(IFilter... observables) { 57 | this(); 58 | addFilter(observables); 59 | } 60 | 61 | /** 62 | * Subscribes one or more {@link IFilter} instances to 63 | * receive filter events from this composition filter. 64 | */ 65 | public void addFilter(IFilter... filtersToAdd) { 66 | for (IFilter filter : filtersToAdd) { 67 | if (filters.add(filter)) { 68 | filter.addFilterObserver(this); 69 | if (filter.isEnabled()) { 70 | super.setEnabled(true); 71 | } else { 72 | disabledFilters.add(filter); 73 | } 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Unsubscribes one or more {@link IFilter}s that were 80 | * previously subscribed to receive filter events. 81 | */ 82 | public void removeFilter(IFilter... filtersToRemove) { 83 | boolean report = false; 84 | for (IFilter filter : filtersToRemove) { 85 | if (filters.remove(filter)) { 86 | filter.removeFilterObserver(this); 87 | disabledFilters.remove(filter); 88 | report = true; 89 | } 90 | } 91 | 92 | if (report) { 93 | if (isEnabled() && !filters.isEmpty() 94 | && (disabledFilters.size() == filters.size())) { 95 | super.setEnabled(false); 96 | } else { 97 | reportFilterUpdatedToObservers(); 98 | } 99 | } 100 | } 101 | 102 | /** 103 | * Returns all {@link IFilter} instances previously 104 | * added. 105 | */ 106 | public Set getFilters() { 107 | return new HashSet(filters); 108 | } 109 | 110 | /** @see IFilterObserver#filterUpdated(IFilter) */ 111 | @Override public void filterUpdated(IFilter filter) { 112 | boolean enabled = isEnabled(); 113 | boolean changeState = false; 114 | if (filter.isEnabled()) { 115 | changeState = disabledFilters.remove(filter) && !enabled; 116 | } else { 117 | changeState = disabledFilters.add(filter) 118 | && (disabledFilters.size() == filters.size()); 119 | } 120 | 121 | if (changeState) { 122 | super.setEnabled(!enabled); 123 | } else { 124 | reportFilterUpdatedToObservers(); 125 | } 126 | } 127 | 128 | /** @see IFilter#setEnabled(boolean) */ 129 | @Override public void setEnabled(boolean enable) { 130 | if (filters.isEmpty()) { 131 | super.setEnabled(enable); 132 | } else { 133 | // perhaps some filter will not honor the request 134 | // super.setEnabled is now only call when the filters report 135 | // its update 136 | for (IFilter filter : filters) { 137 | filter.setEnabled(enable); 138 | } 139 | } 140 | } 141 | 142 | /** Returns true if there is information of this filter as disabled. */ 143 | protected boolean isDisabled(IFilter filter) { 144 | return disabledFilters.contains(filter); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/Look.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.Color; 29 | import java.awt.Component; 30 | import java.awt.Font; 31 | 32 | 33 | /** Class representing the current {@link TableFilterHeader} appearance. */ 34 | public class Look { 35 | Color background; 36 | Color disabledBackground; 37 | Color disabledForeground; 38 | Color errorForeground; 39 | Color foreground; 40 | Color gridColor; 41 | Color selectionBackground; 42 | Color selectionForeground; 43 | Color textSelection; 44 | Color warningForeground; 45 | Font font; 46 | int maxVisiblePopupRows = FilterSettings.maxVisiblePopupRows; 47 | CustomChoiceDecorator customChoiceDecorator = FilterSettings 48 | .newCustomChoiceDecorator(); 49 | 50 | /** Returns the background color used by the editors. */ 51 | public Color getBackground() { 52 | return background; 53 | } 54 | 55 | /** Returns the registered {@link CustomChoiceDecorator}. */ 56 | public CustomChoiceDecorator getCustomChoiceDecorator() { 57 | return customChoiceDecorator; 58 | } 59 | 60 | /** Returns the background color used for disabled editors. */ 61 | public Color getDisabledBackground() { 62 | return disabledBackground; 63 | } 64 | 65 | /** Returns the foreground color used for disabled editors. */ 66 | public Color getDisabledForeground() { 67 | return disabledForeground; 68 | } 69 | 70 | /** 71 | * Returns the color set by default as foreground on each text editor 72 | * when the user commits any error on the filter expression. 73 | */ 74 | public Color getErrorForeground() { 75 | return errorForeground; 76 | } 77 | 78 | /** Returns the font used on editors. */ 79 | public Font getFont() { 80 | return font; 81 | } 82 | 83 | /** Returns the foreground color used by the editors. */ 84 | public Color getForeground() { 85 | return foreground; 86 | } 87 | 88 | /** Returns the color set by default for the header's grid. */ 89 | public Color getGridColor() { 90 | return gridColor; 91 | } 92 | 93 | /** Returns the maximum number of visible rows in the popup menu. */ 94 | public int getMaxVisiblePopupRows() { 95 | return maxVisiblePopupRows; 96 | } 97 | 98 | /** Returns the background color on focused editors. */ 99 | public Color getSelectionBackground() { 100 | return selectionBackground; 101 | } 102 | 103 | /** Returns the foreground color on focused editors. */ 104 | public Color getSelectionForeground() { 105 | return selectionForeground; 106 | } 107 | 108 | /** Returns the color set by default as text selection on filters. */ 109 | public Color getTextSelection() { 110 | return textSelection; 111 | } 112 | 113 | /** 114 | *

Returns the color set by default as foreground on each text editor 115 | * when the filter would produce no visible rows

116 | */ 117 | public Color getWarningForeground() { 118 | return warningForeground; 119 | } 120 | 121 | /** 122 | * Prepares the provided component to have the expected appearance
123 | * Only the background, foreground and font are updated. 124 | */ 125 | public void setupComponent(Component c, 126 | boolean isSelected, 127 | boolean isEnabled) { 128 | Color bg; 129 | Color fg; 130 | if (isEnabled) { 131 | if (isSelected) { 132 | bg = getSelectionBackground(); 133 | fg = getSelectionForeground(); 134 | } else { 135 | bg = getBackground(); 136 | fg = getForeground(); 137 | } 138 | } else { 139 | bg = getDisabledBackground(); 140 | fg = getDisabledForeground(); 141 | } 142 | 143 | if (bg != c.getBackground()) { 144 | c.setBackground(bg); 145 | } 146 | 147 | if (fg != c.getForeground()) { 148 | c.setForeground(fg); 149 | } 150 | 151 | if (c.getFont() != getFont()) { 152 | c.setFont(getFont()); 153 | } 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/gitofleonardo/simplesqlitebrowser/model/SqliteModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.gitofleonardo.simplesqlitebrowser.model 2 | 3 | import com.github.gitofleonardo.simplesqlitebrowser.data.* 4 | import com.intellij.openapi.vfs.VirtualFile 5 | import java.sql.ResultSet 6 | import java.sql.Types 7 | 8 | object SqliteModel { 9 | const val NULL = "null" 10 | const val BLOB = "BLOB" 11 | 12 | fun loadMetaData(file: VirtualFile) : SqliteMetadata { 13 | val connection = ConnectionManager.createConnection(file) 14 | val metadata = SqliteMetadata() 15 | connection?.let { 16 | val md = it.metaData 17 | metadata.isValidSqliteDatabase = true 18 | metadata.version = md.databaseMajorVersion 19 | metadata.driverVersion = md.driverVersion 20 | 21 | val tables = ArrayList() 22 | val tableResult = md.getTables(null, null, "%", null) 23 | while (tableResult.next()) { 24 | val tb = DbTable() 25 | tb.tableName = tableResult.getString("TABLE_NAME") 26 | val tableType = tableResult.getString("TABLE_TYPE") 27 | if ("TABLE" != tableType) { 28 | continue 29 | } 30 | val columnResult = md.getColumns(null, null, tb.tableName, null) 31 | while (columnResult.next()) { 32 | val columnName = columnResult.getString("COLUMN_NAME") 33 | val type = columnResult.getInt("DATA_TYPE") 34 | val typeName = columnResult.getString("TYPE_NAME") 35 | val schema = getAllSchema(columnResult) 36 | tb.columns.add(DbColumn(columnName, type, typeName, schema)) 37 | } 38 | tables.add(tb) 39 | } 40 | metadata.tables.addAll(tables) 41 | } 42 | ConnectionManager.disposeConnection(connection) 43 | return metadata 44 | } 45 | 46 | fun loadTables(file: VirtualFile) : List { 47 | val connection = ConnectionManager.createConnection(file) 48 | val result = mutableListOf() 49 | connection?.let { 50 | val resultSet = it.metaData.getTables(null, null, "%", null) 51 | while (resultSet.next()) { 52 | val table = resultSet.getString("TABLE_NAME") 53 | val type = resultSet.getString("TABLE_TYPE") 54 | if ("TABLE" == type) { 55 | result.add(table) 56 | } 57 | } 58 | } 59 | ConnectionManager.disposeConnection(connection) 60 | return result 61 | } 62 | 63 | fun loadTableData(file: VirtualFile, tableName: String, pageCount: Int, page: Int) : DbTableInstance { 64 | val columns = mutableListOf() 65 | val rows = mutableListOf() 66 | var totalCount = 0 67 | val connection = ConnectionManager.createConnection(file) 68 | connection?.let { 69 | val columnResult = it.metaData.getColumns(null, null, tableName, null) 70 | while (columnResult.next()) { 71 | val columnName = columnResult.getString("COLUMN_NAME") 72 | val type = columnResult.getInt("DATA_TYPE") 73 | val typeName = columnResult.getString("TYPE_NAME") 74 | val schema = getAllSchema(columnResult) 75 | columns.add(DbColumn(columnName, type, typeName, schema)) 76 | } 77 | 78 | val statement = it.createStatement() 79 | val rowResult = statement.executeQuery("SELECT * FROM \"$tableName\" LIMIT $pageCount OFFSET ${pageCount * (page - 1)}") 80 | val rowMeta = rowResult.metaData 81 | while (rowResult.next()) { 82 | val dbRows = mutableListOf() 83 | val dbRow = DbRow(dbRows) 84 | for (columnIndex in columns.indices) { 85 | val type = rowMeta.getColumnType(columnIndex + 1) 86 | val typeName = rowMeta.getColumnTypeName(columnIndex + 1) 87 | val rowData = when (type) { 88 | Types.BLOB -> { 89 | DbRow.RowData(type, typeName, rowResult.getBytes(columnIndex + 1)) 90 | } 91 | else -> { 92 | DbRow.RowData(type, typeName, rowResult.getObject(columnIndex + 1)) 93 | } 94 | } 95 | dbRows.add(rowData) 96 | } 97 | rows.add(dbRow) 98 | } 99 | 100 | val countResult = statement.executeQuery("SELECT COUNT(*) FROM \"$tableName\"") 101 | countResult.next() 102 | totalCount = countResult.getInt(1) 103 | } 104 | ConnectionManager.disposeConnection(connection) 105 | return DbTableInstance(columns, rows, rows.size, page, totalCount) 106 | } 107 | 108 | private fun getAllSchema(resultSet: ResultSet): String { 109 | val nullable = resultSet.getBoolean("NULLABLE") 110 | val nullableString = if (nullable) "" else "NOT NULL" 111 | var def = resultSet.getString("COLUMN_DEF") 112 | def = if (def == null || def.isEmpty()) { 113 | "" 114 | } else { 115 | "DEFAULT $def" 116 | } 117 | val autoIncrement = resultSet.getBoolean("IS_AUTOINCREMENT") 118 | val autoIncString = if (autoIncrement) "AUTO INCREMENT" else "" 119 | return "$nullableString $def $autoIncString" 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for testing and preparing the plugin release in following steps: 2 | # - validate Gradle Wrapper, 3 | # - run 'test' and 'verifyPlugin' tasks, 4 | # - run Qodana inspections, 5 | # - run 'buildPlugin' task and prepare artifact for the further tests, 6 | # - run 'runPluginVerifier' task, 7 | # - create a draft release. 8 | # 9 | # Workflow is triggered on push and pull_request events. 10 | # 11 | # GitHub Actions reference: https://help.github.com/en/actions 12 | # 13 | ## JBIJPPTPL 14 | 15 | name: Build 16 | on: 17 | # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) 18 | push: 19 | branches: [main] 20 | # Trigger the workflow on any pull request 21 | pull_request: 22 | 23 | jobs: 24 | 25 | # Run Gradle Wrapper Validation Action to verify the wrapper's checksum 26 | # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks 27 | # Build plugin and provide the artifact for the next workflow jobs 28 | build: 29 | name: Build 30 | runs-on: ubuntu-latest 31 | outputs: 32 | version: ${{ steps.properties.outputs.version }} 33 | changelog: ${{ steps.properties.outputs.changelog }} 34 | steps: 35 | 36 | # Free GitHub Actions Environment Disk Space 37 | - name: Maximize Build Space 38 | run: | 39 | sudo rm -rf /usr/share/dotnet 40 | sudo rm -rf /usr/local/lib/android 41 | sudo rm -rf /opt/ghc 42 | 43 | # Check out current repository 44 | - name: Fetch Sources 45 | uses: actions/checkout@v3 46 | 47 | # Validate wrapper 48 | - name: Gradle Wrapper Validation 49 | uses: gradle/wrapper-validation-action@v1.0.4 50 | 51 | # Setup Java 11 environment for the next steps 52 | - name: Setup Java 53 | uses: actions/setup-java@v3 54 | with: 55 | distribution: zulu 56 | java-version: 11 57 | 58 | # Set environment variables 59 | - name: Export Properties 60 | id: properties 61 | shell: bash 62 | run: | 63 | PROPERTIES="$(./gradlew properties --console=plain -q)" 64 | VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" 65 | NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" 66 | CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" 67 | CHANGELOG="${CHANGELOG//'%'/'%25'}" 68 | CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" 69 | CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" 70 | 71 | echo "::set-output name=version::$VERSION" 72 | echo "::set-output name=name::$NAME" 73 | echo "::set-output name=changelog::$CHANGELOG" 74 | echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" 75 | 76 | ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier 77 | 78 | # Run tests 79 | - name: Run Tests 80 | run: ./gradlew test 81 | 82 | # Collect Tests Result of failed tests 83 | - name: Collect Tests Result 84 | if: ${{ failure() }} 85 | uses: actions/upload-artifact@v3 86 | with: 87 | name: tests-result 88 | path: ${{ github.workspace }}/build/reports/tests 89 | 90 | # Cache Plugin Verifier IDEs 91 | - name: Setup Plugin Verifier IDEs Cache 92 | uses: actions/cache@v3 93 | with: 94 | path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides 95 | key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} 96 | 97 | # Run Verify Plugin task and IntelliJ Plugin Verifier tool 98 | - name: Run Plugin Verification tasks 99 | run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} 100 | 101 | # Collect Plugin Verifier Result 102 | - name: Collect Plugin Verifier Result 103 | if: ${{ always() }} 104 | uses: actions/upload-artifact@v3 105 | with: 106 | name: pluginVerifier-result 107 | path: ${{ github.workspace }}/build/reports/pluginVerifier 108 | 109 | # Run Qodana inspections 110 | - name: Qodana - Code Inspection 111 | uses: JetBrains/qodana-action@v2022.2.1 112 | 113 | # Prepare plugin archive content for creating artifact 114 | - name: Prepare Plugin Artifact 115 | id: artifact 116 | shell: bash 117 | run: | 118 | cd ${{ github.workspace }}/build/distributions 119 | FILENAME=`ls *.zip` 120 | unzip "$FILENAME" -d content 121 | 122 | echo "::set-output name=filename::${FILENAME:0:-4}" 123 | 124 | # Store already-built plugin as an artifact for downloading 125 | - name: Upload artifact 126 | uses: actions/upload-artifact@v3 127 | with: 128 | name: ${{ steps.artifact.outputs.filename }} 129 | path: ./build/distributions/content/*/* 130 | 131 | # Prepare a draft release for GitHub Releases page for the manual verification 132 | # If accepted and published, release workflow would be triggered 133 | releaseDraft: 134 | name: Release Draft 135 | if: github.event_name != 'pull_request' 136 | needs: build 137 | runs-on: ubuntu-latest 138 | permissions: 139 | contents: write 140 | steps: 141 | 142 | # Check out current repository 143 | - name: Fetch Sources 144 | uses: actions/checkout@v3 145 | 146 | # Remove old release drafts by using the curl request for the available releases with draft flag 147 | - name: Remove Old Release Drafts 148 | env: 149 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 150 | run: | 151 | gh api repos/{owner}/{repo}/releases \ 152 | --jq '.[] | select(.draft == true) | .id' \ 153 | | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} 154 | 155 | # Create new release draft - which is not publicly visible and requires manual acceptance 156 | - name: Create Release Draft 157 | env: 158 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 159 | run: | 160 | gh release create v${{ needs.build.outputs.version }} \ 161 | --draft \ 162 | --title "v${{ needs.build.outputs.version }}" \ 163 | --notes "$(cat << 'EOM' 164 | ${{ needs.build.outputs.changelog }} 165 | EOM 166 | )" 167 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/parser/DateComparator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.parser; 27 | 28 | import java.text.Format; 29 | 30 | import java.util.Calendar; 31 | import java.util.Comparator; 32 | import java.util.Date; 33 | 34 | 35 | /** 36 | * Class to deduce a sensible {@link Comparator} for {@link Date} instances.
37 | */ 38 | abstract public class DateComparator implements Comparator { 39 | 40 | /** 41 | * Factory constructor, returning an instance suitable for the given format. 42 | */ 43 | public static DateComparator getDateComparator(Format dateFormat) { 44 | // the idea is to build a date instance, change then each field 45 | // (milliseconds / seconds / etc) and check the change on the 46 | // parsed instance. If changing, for example, the seconds, does 47 | // not produce a different formatted string, the comparator will 48 | // not pay attention to the seconds, and so on 49 | Calendar calendar = Calendar.getInstance(); 50 | calendar.setTimeInMillis(new Date().getTime()); 51 | if (change(calendar, dateFormat, Calendar.MILLISECOND)) { 52 | // Milliseconds affect the output, full comparison 53 | return new DateComparator() { 54 | @Override public long diff(Date o1, Date o2) { 55 | return o1.compareTo(o2); 56 | } 57 | }; 58 | } 59 | 60 | int divisor = 0; 61 | if (change(calendar, dateFormat, Calendar.SECOND)) { 62 | divisor = 1000; 63 | } else if (change(calendar, dateFormat, Calendar.MINUTE)) { 64 | divisor = 1000 * 60; 65 | } else if (change(calendar, dateFormat, Calendar.HOUR)) { 66 | divisor = 1000 * 60 * 60; 67 | } else if (change(calendar, dateFormat, Calendar.DAY_OF_YEAR)) { 68 | return new DayMonthYearComparator(calendar); 69 | } else if (change(calendar, dateFormat, Calendar.MONTH)) { 70 | return new MonthYearComparator(calendar); 71 | } else if (change(calendar, dateFormat, Calendar.YEAR)) { 72 | return new YearComparator(calendar); 73 | } else { 74 | // nothing affects the output, great formatter! 75 | return new DateComparator() { 76 | @Override public long diff(Date o1, Date o2) { 77 | return 0; 78 | } 79 | }; 80 | } 81 | 82 | return new TimeComparator(divisor); 83 | } 84 | 85 | static private boolean change(Calendar c, Format f, int field) { 86 | c.set(field, 10); 87 | 88 | String sf = f.format(c.getTime()); 89 | c.set(field, 11); 90 | 91 | return !sf.equals(f.format(c.getTime())); 92 | } 93 | 94 | @Override public int compare(Date o1, Date o2) { 95 | if (o1 == null) { 96 | return (o2 == null) ? 0 : -1; 97 | } 98 | 99 | if (o2 == null) { 100 | return 1; 101 | } 102 | 103 | long diff = diff(o1, o2); 104 | 105 | return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1); 106 | } 107 | 108 | public abstract long diff(Date o1, Date o2); 109 | 110 | /** 111 | * DateComparator when the difference relies on time fields (seconds, 112 | * minutes, hours).
113 | * We divide the time to set out the unneeded information, before comparing 114 | */ 115 | static class TimeComparator extends DateComparator { 116 | int divisor; 117 | 118 | public TimeComparator(int divisor) { 119 | this.divisor = divisor; 120 | } 121 | 122 | @Override public long diff(Date o1, Date o2) { 123 | return (o1.getTime() / divisor) - (o2.getTime() / divisor); 124 | } 125 | } 126 | 127 | /** DateComparator that simply compares the year's fields. */ 128 | static class YearComparator extends DateComparator { 129 | Calendar calendar; 130 | 131 | public YearComparator(Calendar calendar) { 132 | this.calendar = calendar; 133 | } 134 | 135 | @Override public long diff(Date o1, Date o2) { 136 | calendar.setTime(o1); 137 | 138 | long base = time(); 139 | calendar.setTime(o2); 140 | 141 | return base - time(); 142 | } 143 | 144 | long time() { 145 | return calendar.get(Calendar.YEAR); 146 | } 147 | } 148 | 149 | /** DateComparator that simply compares the year and month's fields. */ 150 | static class MonthYearComparator extends YearComparator { 151 | public MonthYearComparator(Calendar calendar) { 152 | super(calendar); 153 | } 154 | 155 | @Override long time() { 156 | return (calendar.get(Calendar.YEAR) * 12) 157 | + calendar.get(Calendar.MONTH); 158 | } 159 | } 160 | 161 | /** DateComparator that simply compares the year/month/day's fields. */ 162 | static class DayMonthYearComparator extends YearComparator { 163 | public DayMonthYearComparator(Calendar calendar) { 164 | super(calendar); 165 | } 166 | 167 | @Override long time() { 168 | return (calendar.get(Calendar.YEAR) * 400) 169 | + calendar.get(Calendar.DAY_OF_YEAR); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/ChoicesHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.text.Format; 29 | 30 | import javax.swing.JTable; 31 | import javax.swing.RowFilter; 32 | import javax.swing.SwingUtilities; 33 | import javax.swing.event.TableModelEvent; 34 | import javax.swing.event.TableModelListener; 35 | import javax.swing.table.TableModel; 36 | 37 | import net.coderazzi.filters.IFilter; 38 | import net.coderazzi.filters.gui.editor.FilterEditor; 39 | 40 | 41 | /** 42 | * Interface implemented by the classes that handle the choices on each {@link 43 | * FilterEditor}. 44 | */ 45 | abstract class ChoicesHandler implements TableModelListener, Runnable { 46 | 47 | protected FiltersHandler handler; 48 | 49 | /** The model being listened to handle model changes. */ 50 | private TableModel listenedModel; 51 | 52 | /** this variable is true to signal an update to the FiltersHandler. */ 53 | private boolean runScheduled; 54 | 55 | protected ChoicesHandler(FiltersHandler handler) { 56 | this.handler = handler; 57 | } 58 | 59 | /** Returns the {@link RowFilter} associated to this handler. */ 60 | public abstract RowFilter getRowFilter(); 61 | 62 | /** 63 | * Sets/unsets the handler on interrupt mode
64 | * On interrupt mode, the associated {@link FiltersHandler} is likely to 65 | * send many update events, which shouldn't be treated (if possible). 66 | */ 67 | public abstract boolean setInterrupted(boolean interrupted); 68 | 69 | /** Reports a {@link FilterEditor} update. */ 70 | public abstract void editorUpdated(FilterEditor editor); 71 | 72 | /** 73 | * Reports a {@link IFilter} update. 74 | * 75 | * @param retInfoRequired set to true if the return value is required 76 | * 77 | * @return true if the filter let pass any row 78 | */ 79 | public abstract boolean filterUpdated(IFilter filter, 80 | boolean retInfoRequired); 81 | 82 | /** 83 | * Reports the beginning or end of {@link IFilter} add/remove operations. 84 | */ 85 | public abstract void filterOperation(boolean start); 86 | 87 | /** Call triggered after a filter becomes enabled. */ 88 | public abstract void filterEnabled(IFilter filter); 89 | 90 | /** Call triggered after all filters become disabled. */ 91 | public abstract void allFiltersDisabled(); 92 | 93 | /** Ensures that instant changes are propagated. */ 94 | public abstract void consolidateFilterChanges(int modelIndex); 95 | 96 | /** Reports a table update. */ 97 | protected abstract void tableUpdated(TableModel model, 98 | int eventType, 99 | int firstRow, 100 | int lastRow, 101 | int column); 102 | 103 | @Override public void tableChanged(TableModelEvent e) { 104 | int firstRow = e.getFirstRow(); 105 | if (firstRow != TableModelEvent.HEADER_ROW) { 106 | int type = e.getType(); 107 | TableModel model = (TableModel) e.getSource(); 108 | tableUpdated(model, type, firstRow, e.getLastRow(), e.getColumn()); 109 | if (!runScheduled) { 110 | runScheduled = true; 111 | // invoke later filtersHandler.tableUpdated, as perhaps the 112 | // row sorter hasn't been updated its status 113 | SwingUtilities.invokeLater(this); 114 | } 115 | } 116 | } 117 | 118 | /** {@link Runnable} interface. */ 119 | @Override public void run() { 120 | runScheduled = false; 121 | handler.tableUpdated(); 122 | } 123 | 124 | /** 125 | * Sets whether to send table model events to the {@link ChoicesHandler}. 126 | */ 127 | protected void setEnableTableModelEvents(boolean set) { 128 | if (set) { 129 | JTable table = handler.getTable(); 130 | if (table != null) { 131 | if (listenedModel != null) { 132 | if (listenedModel == table.getModel()) { 133 | return; 134 | } 135 | 136 | setEnableTableModelEvents(false); 137 | } 138 | 139 | listenedModel = table.getModel(); 140 | listenedModel.addTableModelListener(this); 141 | } 142 | } else if (listenedModel != null) { 143 | listenedModel.removeTableModelListener(this); 144 | listenedModel = null; 145 | } 146 | } 147 | 148 | /** 149 | * Basic RowFilter.Entry instance, used internally to handle the RowFilter 150 | * default filtering. 151 | */ 152 | static protected class RowEntry extends RowFilter.Entry { 153 | private TableModel model; 154 | private int count; 155 | private Format formatters[]; 156 | public int row; 157 | 158 | public RowEntry(TableModel model, FilterEditor editors[]) { 159 | this.model = model; 160 | this.count = model.getColumnCount(); 161 | 162 | int len = editors.length; 163 | formatters = new Format[len]; 164 | while (len-- > 0) { 165 | formatters[len] = editors[len].getFormat(); 166 | } 167 | } 168 | 169 | public int getModelRowCount() { 170 | return model.getRowCount(); 171 | } 172 | 173 | public Format[] getFormatters() { 174 | return formatters; 175 | } 176 | 177 | @Override public Object getIdentifier() { 178 | return row; 179 | } 180 | 181 | @Override public TableModel getModel() { 182 | return model; 183 | } 184 | 185 | @Override public Object getValue(int index) { 186 | return model.getValueAt(row, index); 187 | } 188 | 189 | @Override public int getValueCount() { 190 | return count; 191 | } 192 | 193 | @Override public String getStringValue(int index) { 194 | Format f = formatters[index]; 195 | return f == null ? "" : f.format(getValue(index)); 196 | } 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/IFilterEditor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.text.Format; 29 | 30 | import java.util.Comparator; 31 | import java.util.List; 32 | import java.util.Set; 33 | 34 | import javax.swing.table.TableModel; 35 | 36 | import net.coderazzi.filters.IFilter; 37 | 38 | 39 | /** Public interface of the editors associated to each table's column. */ 40 | public interface IFilterEditor { 41 | 42 | /** Returns the model position associated to this editor. */ 43 | int getModelIndex(); 44 | 45 | /** Returns the class associated to the editor on the model. */ 46 | Class getModelClass(); 47 | 48 | /** 49 | * Returns the {@link IFilter} associated to the editor's content
50 | * The returned instance can then be used to enable or disable the filter 51 | * and its GUI component. 52 | */ 53 | IFilter getFilter(); 54 | 55 | /** 56 | * Resets the filter, which implies set its content to empty and reset its 57 | * history choices. 58 | */ 59 | void resetFilter(); 60 | 61 | /** Sets the content, adapted to the editors' type. */ 62 | void setContent(Object content); 63 | 64 | /** Returns the current editor's content. */ 65 | Object getContent(); 66 | 67 | /** 68 | * Using autoChoices, the choices displayed on the popup menu are 69 | * automatically extracted from the associated {@link TableModel}.
70 | * For editors associated to boolean or short enumerations, if 71 | * AutoCompletion is not set, setting the AutoChoices automatically changes 72 | * the editable flag to true, unless AutoChoices has the DISABLED value 73 | */ 74 | void setAutoChoices(AutoChoices mode); 75 | 76 | /** Returns the autoChoices mode. */ 77 | AutoChoices getAutoChoices(); 78 | 79 | /** Sets the available choices, shown on the popup menu. */ 80 | void setCustomChoices(Set choices); 81 | 82 | /** Returns the current choices. */ 83 | Set getCustomChoices(); 84 | 85 | /** 86 | * Enables or disables the user's interaction; if disabled, the control 87 | * is disabled but the associated filter remains in place. 88 | */ 89 | void setUserInteractionEnabled(boolean enable); 90 | 91 | /** Returns the user interaction mode. */ 92 | boolean isUserInteractionEnabled(); 93 | 94 | /** 95 | * Defines the editor, if text based -i.e., without associated {@link 96 | * ChoiceRenderer}, as editable: this flag means that the user can enter any 97 | * text, not being limited to the existing choices 98 | */ 99 | void setEditable(boolean enable); 100 | 101 | /** Returns the editable flag. */ 102 | boolean isEditable(); 103 | 104 | /** Sets the ignore case flag. */ 105 | void setIgnoreCase(boolean set); 106 | 107 | /** Returns the ignore case flag. */ 108 | boolean isIgnoreCase(); 109 | 110 | /** 111 | * Sets the {@link Format} required by the editor to handle the user's input 112 | * when the associated class is not a String
113 | * It is initially retrieved from the {@link IParserModel}. 114 | */ 115 | void setFormat(Format format); 116 | 117 | /** Returns the associated {@link Format}. */ 118 | Format getFormat(); 119 | 120 | /** 121 | * Sets the {@link Comparator} required to compare (and sort) instances of 122 | * the associated class in the table model.
123 | * This operation sets also this operator as the choices comparator 124 | * (see {@link #setChoicesComparator(Comparator)}) 125 | * @param comparator cannot be null 126 | */ 127 | void setComparator(Comparator comparator); 128 | 129 | /** Returns the associated {@link Comparator}, which is never null. */ 130 | Comparator getComparator(); 131 | 132 | /** 133 | * Sets the {@link Comparator} used to sort out the choices. By default. 134 | * this is the same operator associated to the editor. Note that editors 135 | * associated to enumeration types are sorted by default alphabetically.
136 | * @param comparator can be set to null to use alphabetic sorting 137 | * @see IFilterEditor#setComparator(Comparator) 138 | */ 139 | void setChoicesComparator(Comparator comparator); 140 | 141 | /** Returns the associated {@link Comparator} choices comparator. */ 142 | Comparator getChoicesComparator(); 143 | 144 | /** Sets the auto completion flag. */ 145 | void setAutoCompletion(boolean enable); 146 | 147 | /** Returns the auto completion flag. */ 148 | boolean isAutoCompletion(); 149 | 150 | /** Sets the auto hide-popup flag*/ 151 | void setHidePopupOnTableUpdates(boolean set); 152 | 153 | /** Returns the auto hide-popup flag */ 154 | boolean isHidePopupOnTableUpdates(); 155 | 156 | /** Sets the instant filtering flag. */ 157 | void setInstantFiltering(boolean enable); 158 | 159 | /** Returns the instant filtering flag. */ 160 | boolean isInstantFiltering(); 161 | 162 | /** Sets the allow instant vanishing flag. */ 163 | void setAllowedInstantVanishing(boolean enable); 164 | 165 | /** Returns the instant filtering flag. */ 166 | boolean isAllowedInstantVanishing(); 167 | 168 | /** 169 | * Limits the history size.
170 | * This limit is only used when the popup contains also choices. Otherwise, 171 | * the maximum history size is to the maximum number of visible rows
172 | * The max history cannot be greater than the max visible rows 173 | */ 174 | void setMaxHistory(int size); 175 | 176 | /** 177 | * Returns the maximum history size, as defined by the user.
178 | * This is not the real maximum history size, as it depends on the max 179 | * number of visible rows and whether the popup contains only history or 180 | * also choices 181 | */ 182 | int getMaxHistory(); 183 | 184 | /** 185 | * Sets the history contents. 186 | * @since 4.3.1.0 187 | */ 188 | void setHistory(List history); 189 | 190 | /** 191 | * Returns the current history contents 192 | * @since 4.3.1.0 193 | */ 194 | List getHistory(); 195 | 196 | /** 197 | * Sets the {@link ChoiceRenderer} for the choices / history. 198 | * 199 | *

It also affects to how the content is rendered
200 | * If not null, the content cannot be text-edited anymore

201 | * 202 | * @param renderer 203 | */ 204 | void setRenderer(ChoiceRenderer renderer); 205 | 206 | /** Returns the associated {@link ChoiceRenderer}. */ 207 | ChoiceRenderer getRenderer(); 208 | 209 | /** Returns the current editor's look. */ 210 | Look getLook(); 211 | 212 | void setChoicesEnable(boolean enable); 213 | } 214 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/editor/HistoryListModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui.editor; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Comparator; 30 | import java.util.List; 31 | 32 | import javax.swing.AbstractListModel; 33 | 34 | import net.coderazzi.filters.gui.CustomChoice; 35 | 36 | 37 | /** 38 | * List model to handle the history in the popup menu.
39 | * When the user specifies a Renderer, history elements are considered non-text; 40 | * this affects to the search algorithm to find the best matches {@link 41 | * PopupComponent#selectBestMatch(Object)}
42 | * Otherwise, content is always pure strings (@link {@link CustomChoice} are not 43 | * inserted into the history) 44 | */ 45 | class HistoryListModel extends AbstractListModel { 46 | private static final long serialVersionUID = -374115548677017807L; 47 | private List history = new ArrayList(); 48 | private List shownHistory = history; 49 | private Object lastAdded; 50 | private Comparator stringComparator; 51 | private int maxHistory; 52 | 53 | /** Initializes the model to a specific history content */ 54 | public void initialize(List history){ 55 | this.lastAdded = null; 56 | this.shownHistory = history; 57 | this.history.clear(); 58 | if (!history.isEmpty()){ 59 | this.history.addAll(history.subList 60 | (0, Math.min(maxHistory, history.size()))); 61 | } 62 | } 63 | 64 | /** Returns the items currently visible */ 65 | public List getShownHistory(){ 66 | return new ArrayList(shownHistory); 67 | } 68 | 69 | /** 70 | * Specifies how to handle the content. If there is a string comparator, 71 | * content is handled as strings and it is possible to look for best 72 | * matches; otherwise, it is treated as abstract objects, matching is done 73 | * by identity. 74 | */ 75 | public void setStringContent(Comparator stringComparator) { 76 | if (this.stringComparator != stringComparator) { 77 | this.stringComparator = stringComparator; 78 | clear(); 79 | } 80 | } 81 | 82 | /** Clears any restrictions. {@link #restrict(Object)} */ 83 | public int clearRestrictions() { 84 | shownHistory = history; 85 | 86 | return shownHistory.size(); 87 | } 88 | 89 | /** Restricts the elements from the history -without removing it. */ 90 | public boolean restrict(Object exclude) { 91 | int index = shownHistory.indexOf(exclude); 92 | if (index != -1) { 93 | if (shownHistory == history) { 94 | shownHistory = new ArrayList(history); 95 | } 96 | 97 | shownHistory.remove(index); 98 | fireIntervalAdded(this, index, index); 99 | return true; 100 | } 101 | 102 | return false; 103 | } 104 | 105 | @Override public Object getElementAt(int index) { 106 | return shownHistory.get(index); 107 | } 108 | 109 | /** Adds an element, Returning true if the number of elements changes. */ 110 | public boolean add(Object st) { 111 | // never add the passed element (which is now selected on the 112 | // editor). We will add it when the next element is passed 113 | boolean ret = false; 114 | boolean removed = history.remove(st); 115 | if ((maxHistory > 0) && (lastAdded != null) 116 | && (lastAdded.toString().length() > 0) 117 | && !lastAdded.equals(st)) { 118 | history.add(0, lastAdded); 119 | 120 | int size = history.size(); 121 | if (size > maxHistory) { 122 | history.remove(--size); 123 | removed = true; 124 | } else { 125 | ret = true; 126 | if (!removed) { 127 | fireIntervalAdded(this, 0, 0); 128 | } 129 | } 130 | } 131 | 132 | if (removed) { 133 | fireContentsChanged(this, 0, history.size()); 134 | ret = true; 135 | } 136 | 137 | lastAdded = st; 138 | shownHistory = history; 139 | 140 | return ret; 141 | } 142 | 143 | public boolean isEmpty() { 144 | return shownHistory.isEmpty(); 145 | } 146 | 147 | public void clear() { 148 | int size = history.size(); 149 | if (size > 0) { 150 | history.clear(); 151 | shownHistory = history; 152 | fireIntervalRemoved(this, 0, size); 153 | } 154 | 155 | lastAdded = null; 156 | } 157 | 158 | @Override public int getSize() { 159 | return shownHistory.size(); 160 | } 161 | 162 | /** Sets the max history size. */ 163 | public void setMaxHistory(int size) { 164 | maxHistory = size; 165 | 166 | int current = history.size(); 167 | if (current > size) { 168 | for (int i = current - 1; i >= size; i--) { 169 | history.remove(i); 170 | } 171 | 172 | shownHistory = history; 173 | fireContentsChanged(this, maxHistory, current); 174 | } 175 | } 176 | 177 | /** Returns the max history. */ 178 | public int getMaxHistory() { 179 | return maxHistory; 180 | } 181 | 182 | /** Returns the history as a list. */ 183 | public List getList() { 184 | return history; 185 | } 186 | 187 | /** @see PopupComponent#selectBestMatch(Object) */ 188 | public ChoiceMatch getClosestMatch(Object hint) { 189 | ChoiceMatch ret = new ChoiceMatch(); 190 | if ((stringComparator != null) && (hint instanceof String)) { 191 | String strStart = (String) hint; 192 | int strLen = strStart.length(); 193 | int historyLen = shownHistory.size(); 194 | while (historyLen-- > 0) { 195 | Object content = shownHistory.get(historyLen); 196 | String str = content.toString(); 197 | int len = ChoiceMatch.getMatchingLength(strStart, str, 198 | stringComparator); 199 | if (((len > 0) && (len >= ret.len)) || (ret.len == 0)) { 200 | ret.content = content; 201 | ret.index = historyLen; 202 | ret.len = len; 203 | if ((len == strLen) && (str.length() == strLen)) { 204 | ret.exact = true; 205 | return ret; 206 | } 207 | } 208 | } 209 | } else { 210 | ret.index = shownHistory.indexOf(hint); 211 | if (ret.index != -1) { 212 | ret.exact = true; 213 | ret.content = hint; 214 | } 215 | } 216 | return ret; 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/parser/HtmlEntities.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.parser; 27 | 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * Class to encode all the possible HTML entities 33 | */ 34 | class HtmlEntities { 35 | 36 | /** 37 | * Returns the integer value associated to the given entity, or -1 if 38 | * it is not a proper HTML entity 39 | */ 40 | public static int getEntityValue(String entity){ 41 | Integer value = ents.get(entity); 42 | return value==null? -1 : value; 43 | } 44 | 45 | private static Map ents = new HashMap(); 46 | 47 | static { 48 | ents.put("Aacute", 193); 49 | ents.put("aacute", 225); 50 | ents.put("Acirc", 194); 51 | ents.put("acirc", 226); 52 | ents.put("acute", 180); 53 | ents.put("AElig", 198); 54 | ents.put("aelig", 230); 55 | ents.put("Agrave", 192); 56 | ents.put("agrave", 224); 57 | ents.put("alefsym", 8501); 58 | ents.put("Alpha", 913); 59 | ents.put("alpha", 945); 60 | ents.put("amp", 38); 61 | ents.put("and", 8743); 62 | ents.put("ang", 8736); 63 | ents.put("Aring", 197); 64 | ents.put("aring", 229); 65 | ents.put("asymp", 8776); 66 | ents.put("Atilde", 195); 67 | ents.put("atilde", 227); 68 | ents.put("Auml", 196); 69 | ents.put("auml", 228); 70 | ents.put("bdquo", 8222); 71 | ents.put("Beta", 914); 72 | ents.put("beta", 946); 73 | ents.put("brvbar", 166); 74 | ents.put("bull", 8226); 75 | ents.put("cap", 8745); 76 | ents.put("Ccedil", 199); 77 | ents.put("ccedil", 231); 78 | ents.put("cedil", 184); 79 | ents.put("cent", 162); 80 | ents.put("Chi", 935); 81 | ents.put("chi", 967); 82 | ents.put("circ", 710); 83 | ents.put("clubs", 9827); 84 | ents.put("cong", 8773); 85 | ents.put("copy", 169); 86 | ents.put("crarr", 8629); 87 | ents.put("cup", 8746); 88 | ents.put("curren", 164); 89 | ents.put("Dagger", 8225); 90 | ents.put("dagger", 8224); 91 | ents.put("dArr", 8659); 92 | ents.put("darr", 8595); 93 | ents.put("deg", 176); 94 | ents.put("Delta", 916); 95 | ents.put("delta", 948); 96 | ents.put("diams", 9830); 97 | ents.put("divide", 247); 98 | ents.put("Eacute", 201); 99 | ents.put("eacute", 233); 100 | ents.put("Ecirc", 202); 101 | ents.put("ecirc", 234); 102 | ents.put("Egrave", 200); 103 | ents.put("egrave", 232); 104 | ents.put("empty", 8709); 105 | ents.put("emsp", 8195); 106 | ents.put("ensp", 8194); 107 | ents.put("Epsilon", 917); 108 | ents.put("epsilon", 949); 109 | ents.put("equiv", 8801); 110 | ents.put("Eta", 919); 111 | ents.put("eta", 951); 112 | ents.put("ETH", 208); 113 | ents.put("eth", 240); 114 | ents.put("Euml", 203); 115 | ents.put("euml", 235); 116 | ents.put("euro", 8364); 117 | ents.put("exist", 8707); 118 | ents.put("fnof", 402); 119 | ents.put("forall", 8704); 120 | ents.put("frac12", 189); 121 | ents.put("frac14", 188); 122 | ents.put("frac34", 190); 123 | ents.put("frasl", 8260); 124 | ents.put("Gamma", 915); 125 | ents.put("gamma", 947); 126 | ents.put("ge", 8805); 127 | ents.put("gt", 62); 128 | ents.put("hArr", 8660); 129 | ents.put("harr", 8596); 130 | ents.put("hearts", 9829); 131 | ents.put("hellip", 8230); 132 | ents.put("Iacute", 205); 133 | ents.put("iacute", 237); 134 | ents.put("Icirc", 206); 135 | ents.put("icirc", 238); 136 | ents.put("iexcl", 161); 137 | ents.put("Igrave", 204); 138 | ents.put("igrave", 236); 139 | ents.put("image", 8465); 140 | ents.put("infin", 8734); 141 | ents.put("int", 8747); 142 | ents.put("Iota", 921); 143 | ents.put("iota", 953); 144 | ents.put("iquest", 191); 145 | ents.put("isin", 8712); 146 | ents.put("Iuml", 207); 147 | ents.put("iuml", 239); 148 | ents.put("Kappa", 922); 149 | ents.put("kappa", 954); 150 | ents.put("Lambda", 923); 151 | ents.put("lambda", 955); 152 | ents.put("lang", 9001); 153 | ents.put("laquo", 171); 154 | ents.put("lArr", 8656); 155 | ents.put("larr", 8592); 156 | ents.put("lceil", 8968); 157 | ents.put("ldquo", 8220); 158 | ents.put("le", 8804); 159 | ents.put("lfloor", 8970); 160 | ents.put("lowast", 8727); 161 | ents.put("loz", 9674); 162 | ents.put("lrm", 8206); 163 | ents.put("lsaquo", 8249); 164 | ents.put("lsquo", 8216); 165 | ents.put("lt", 60); 166 | ents.put("macr", 175); 167 | ents.put("mdash", 8212); 168 | ents.put("micro", 181); 169 | ents.put("middot", 183); 170 | ents.put("minus", 8722); 171 | ents.put("Mu", 924); 172 | ents.put("mu", 956); 173 | ents.put("nabla", 8711); 174 | ents.put("nbsp", 160); 175 | ents.put("ndash", 8211); 176 | ents.put("ne", 8800); 177 | ents.put("ni", 8715); 178 | ents.put("not", 172); 179 | ents.put("notin", 8713); 180 | ents.put("Ntilde", 209); 181 | ents.put("ntilde", 241); 182 | ents.put("Nu", 925); 183 | ents.put("nu", 957); 184 | ents.put("Oacute", 211); 185 | ents.put("oacute", 243); 186 | ents.put("Ocirc", 212); 187 | ents.put("ocirc", 244); 188 | ents.put("OElig", 338); 189 | ents.put("oelig", 339); 190 | ents.put("Ograve", 210); 191 | ents.put("ograve", 242); 192 | ents.put("oline", 8254); 193 | ents.put("Omega", 937); 194 | ents.put("omega", 969); 195 | ents.put("Omicron", 927); 196 | ents.put("omicron", 959); 197 | ents.put("oplus", 8853); 198 | ents.put("or", 8744); 199 | ents.put("ordf", 170); 200 | ents.put("ordm", 186); 201 | ents.put("Oslash", 216); 202 | ents.put("oslash", 248); 203 | ents.put("Otilde", 213); 204 | ents.put("otilde", 245); 205 | ents.put("otimes", 8855); 206 | ents.put("Ouml", 214); 207 | ents.put("ouml", 246); 208 | ents.put("para", 182); 209 | ents.put("part", 8706); 210 | ents.put("permil", 8240); 211 | ents.put("perp", 8869); 212 | ents.put("Phi", 934); 213 | ents.put("phi", 966); 214 | ents.put("Pi", 928); 215 | ents.put("pi", 960); 216 | ents.put("piv", 982); 217 | ents.put("plusmn", 177); 218 | ents.put("pound", 163); 219 | ents.put("Prime", 8243); 220 | ents.put("prime", 8242); 221 | ents.put("prod", 8719); 222 | ents.put("prop", 8733); 223 | ents.put("Psi", 936); 224 | ents.put("psi", 968); 225 | ents.put("quot", 34); 226 | ents.put("radic", 8730); 227 | ents.put("rang", 9002); 228 | ents.put("raquo", 187); 229 | ents.put("rArr", 8658); 230 | ents.put("rarr", 8594); 231 | ents.put("rceil", 8969); 232 | ents.put("rdquo", 8221); 233 | ents.put("real", 8476); 234 | ents.put("reg", 174); 235 | ents.put("rfloor", 8971); 236 | ents.put("Rho", 929); 237 | ents.put("rho", 961); 238 | ents.put("rlm", 8207); 239 | ents.put("rsaquo", 8250); 240 | ents.put("rsquo", 8217); 241 | ents.put("sbquo", 8218); 242 | ents.put("Scaron", 352); 243 | ents.put("scaron", 353); 244 | ents.put("sdot", 8901); 245 | ents.put("sect", 167); 246 | ents.put("shy", 173); 247 | ents.put("Sigma", 931); 248 | ents.put("sigma", 963); 249 | ents.put("sigmaf", 962); 250 | ents.put("sim", 8764); 251 | ents.put("spades", 9824); 252 | ents.put("sub", 8834); 253 | ents.put("sube", 8838); 254 | ents.put("sum", 8721); 255 | ents.put("sup", 8835); 256 | ents.put("sup1", 185); 257 | ents.put("sup2", 178); 258 | ents.put("sup3", 179); 259 | ents.put("supe", 8839); 260 | ents.put("szlig", 223); 261 | ents.put("Tau", 932); 262 | ents.put("tau", 964); 263 | ents.put("there4", 8756); 264 | ents.put("Theta", 920); 265 | ents.put("theta", 952); 266 | ents.put("thetasym", 977); 267 | ents.put("thinsp", 8201); 268 | ents.put("THORN", 222); 269 | ents.put("thorn", 254); 270 | ents.put("tilde", 732); 271 | ents.put("times", 215); 272 | ents.put("trade", 8482); 273 | ents.put("Uacute", 218); 274 | ents.put("uacute", 250); 275 | ents.put("uArr", 8657); 276 | ents.put("uarr", 8593); 277 | ents.put("Ucirc", 219); 278 | ents.put("ucirc", 251); 279 | ents.put("Ugrave", 217); 280 | ents.put("ugrave", 249); 281 | ents.put("uml", 168); 282 | ents.put("upsih", 978); 283 | ents.put("Upsilon", 933); 284 | ents.put("upsilon", 965); 285 | ents.put("Uuml", 220); 286 | ents.put("uuml", 252); 287 | ents.put("weierp", 8472); 288 | ents.put("Xi", 926); 289 | ents.put("xi", 958); 290 | ents.put("Yacute", 221); 291 | ents.put("yacute", 253); 292 | ents.put("yen", 165); 293 | ents.put("Yuml", 376); 294 | ents.put("yuml", 255); 295 | ents.put("Zeta", 918); 296 | ents.put("zeta", 950); 297 | ents.put("zwj", 8205); 298 | ents.put("zwnj", 8204); 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command; 206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 207 | # shell script including quotes and variable substitutions, so put them in 208 | # double quotes to make sure that they get re-expanded; and 209 | # * put everything else in single quotes, so that it's not re-expanded. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/NonAdaptiveChoicesHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.util.Collection; 29 | import java.util.HashMap; 30 | import java.util.HashSet; 31 | import java.util.Map; 32 | import java.util.Set; 33 | 34 | import javax.swing.RowFilter; 35 | import javax.swing.event.TableModelEvent; 36 | import javax.swing.table.TableModel; 37 | 38 | import net.coderazzi.filters.IFilter; 39 | import net.coderazzi.filters.gui.editor.FilterEditor; 40 | 41 | 42 | /** 43 | * Internal class to handle choices without adaptive behaviour
44 | * Choices are automatically updated as the table model changes. 45 | */ 46 | class NonAdaptiveChoicesHandler extends ChoicesHandler { 47 | 48 | private boolean interrupted = true; 49 | // it is needed to map the filters to its editors 50 | private Map filtersMap = 51 | new HashMap(); 52 | // entry used to filter rows 53 | private RowEntry rowEntry; 54 | 55 | public NonAdaptiveChoicesHandler(FiltersHandler handler) { 56 | super(handler); 57 | } 58 | 59 | @Override public RowFilter getRowFilter() { 60 | return handler; 61 | } 62 | 63 | @Override public boolean setInterrupted(boolean interrupted) { 64 | if (this.interrupted != interrupted) { 65 | this.interrupted = interrupted; 66 | setEnableTableModelEvents(!interrupted); 67 | if (!interrupted) { 68 | for (FilterEditor editor : handler.getEditors()) { 69 | editorUpdated(editor); 70 | } 71 | 72 | initialiseFiltersInfo(); 73 | } 74 | } 75 | 76 | return !interrupted; // filter should be updated 77 | } 78 | 79 | @Override public void editorUpdated(FilterEditor editor) { 80 | if (editor.isEnabled()) { 81 | initEditorChoices(editor); 82 | } 83 | } 84 | 85 | @Override public boolean filterUpdated(IFilter iFilter, 86 | boolean retInfoRequired) { 87 | // if return value is not required, do not bother checking for it, as 88 | // there is nothing to do with filter updates normally 89 | if (retInfoRequired) { 90 | if (!iFilter.isEnabled()) { 91 | return false; 92 | } 93 | 94 | rowEntry.row = handler.getTable().getModel().getRowCount(); 95 | if (rowEntry.row > 0) { 96 | while (rowEntry.row-- > 0) { 97 | if (iFilter.include(rowEntry)) { 98 | return true; 99 | } 100 | } 101 | 102 | return false; 103 | } 104 | } 105 | 106 | return true; 107 | } 108 | 109 | @Override public void filterOperation(boolean start) { 110 | handler.enableNotifications(!start); 111 | if (!start && !interrupted) { 112 | initialiseFiltersInfo(); 113 | } 114 | } 115 | 116 | @Override public void filterEnabled(IFilter filter) { 117 | for (FilterEditor editor : handler.getEditors()) { 118 | if (editor.getFilter() == filter) { 119 | initEditorChoices(editor); 120 | 121 | break; 122 | } 123 | } 124 | 125 | if (!interrupted) { 126 | setEnableTableModelEvents(true); 127 | } 128 | } 129 | 130 | @Override public void allFiltersDisabled() { 131 | setEnableTableModelEvents(false); 132 | } 133 | 134 | @Override public void consolidateFilterChanges(int modelIndex) { 135 | // nothing to do 136 | } 137 | 138 | @Override public void tableUpdated(TableModel model, 139 | int eventType, 140 | int firstRow, 141 | int lastRow, 142 | int column) { 143 | if (column != TableModelEvent.ALL_COLUMNS) { 144 | // a change in ONE column is always handled as an update 145 | // (every update is handled by re-extracting the choices 146 | FilterEditor editor = handler.getEditor(column); 147 | if ((editor != null) && editor.isEnabled()) { 148 | setChoicesFromModel(editor, model); 149 | } 150 | } else { 151 | lastRow = Math.min(model.getRowCount() - 1, lastRow); 152 | for (FilterEditor editor : handler.getEditors()) { 153 | if (editor.isEnabled() 154 | && (AutoChoices.ENABLED == editor.getAutoChoices())) { 155 | // insert events can be handled by adding the 156 | // new model's values. 157 | // updates/deletes require reparsing the whole 158 | // table to obtain again the available choices 159 | if (eventType == TableModelEvent.INSERT) { 160 | editor.addChoices(modelExtract(editor, model, firstRow, 161 | lastRow, new HashSet())); 162 | } else { 163 | setChoicesFromModel(editor, model); 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * Initializes the choices in the given editor.
172 | * It can update the mode of the editor, from ENABLED to ENUMS (in case of 173 | * enumerations), and from ENUMS to DISABLED (for no enumerations) 174 | */ 175 | private void initEditorChoices(FilterEditor editor) { 176 | AutoChoices autoChoices = editor.getAutoChoices(); 177 | if (autoChoices == AutoChoices.DISABLED) { 178 | editor.setChoices(editor.getCustomChoices()); 179 | } else { 180 | TableModel model = handler.getTable().getModel(); 181 | Class c = model.getColumnClass(editor.getModelIndex()); 182 | boolean asEnum = c.equals(Boolean.class) || c.isEnum(); 183 | if (asEnum && (autoChoices != AutoChoices.ENUMS)) { 184 | editor.setAutoChoices(AutoChoices.ENUMS); 185 | } else if (!asEnum && (autoChoices == AutoChoices.ENUMS)) { 186 | editor.setAutoChoices(AutoChoices.DISABLED); 187 | } else if (asEnum) { 188 | Set choices = editor.getCustomChoices(); 189 | if (c.equals(Boolean.class)) { 190 | choices.add(true); 191 | choices.add(false); 192 | } else { 193 | for (Object each : c.getEnumConstants()) { 194 | choices.add(each); 195 | } 196 | } 197 | 198 | editor.setChoices(choices); 199 | } else { 200 | setChoicesFromModel(editor, model); 201 | } 202 | } 203 | } 204 | 205 | /** Sets the content for the given editor from the model's values. */ 206 | private void setChoicesFromModel(FilterEditor editor, TableModel model) { 207 | editor.setChoices(modelExtract(editor, model, 0, 208 | model.getRowCount() - 1, editor.getCustomChoices())); 209 | } 210 | 211 | /** 212 | * Extract content from the given range of rows in the model, adding the 213 | * results to the provided Set, which is then returned. 214 | */ 215 | private Set modelExtract(FilterEditor editor, 216 | TableModel model, 217 | int firstRow, 218 | int lastRow, 219 | Set fill) { 220 | int column = editor.getModelIndex(); 221 | for (; lastRow >= firstRow; firstRow++) { 222 | fill.add(model.getValueAt(firstRow, column)); 223 | } 224 | 225 | return fill; 226 | } 227 | 228 | /** Initialise structures related to the filters and editors. */ 229 | private void initialiseFiltersInfo() { 230 | // recreate the filtersMap 231 | filtersMap.clear(); 232 | 233 | if (handler.getTable() != null) { 234 | for (FilterEditor fe : handler.getEditors()) { 235 | filtersMap.put(fe.getFilter(), fe); 236 | } 237 | 238 | // and the RowEntry 239 | Collection eds = handler.getEditors(); 240 | rowEntry = new RowEntry(handler.getTable().getModel(), 241 | eds.toArray(new FilterEditor[eds.size()])); 242 | } 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/PositionHelper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.BorderLayout; 29 | import java.awt.Component; 30 | import java.awt.Container; 31 | 32 | import java.beans.PropertyChangeEvent; 33 | import java.beans.PropertyChangeListener; 34 | 35 | import javax.swing.JScrollPane; 36 | import javax.swing.JTable; 37 | import javax.swing.JViewport; 38 | import javax.swing.table.JTableHeader; 39 | 40 | import net.coderazzi.filters.gui.TableFilterHeader.Position; 41 | 42 | 43 | /** 44 | *

Helper class to locate the filter header on the expected place by the 45 | * table header

46 | * 47 | * @author Luis M Pena - lu@coderazzi.net 48 | */ 49 | class PositionHelper implements PropertyChangeListener { 50 | 51 | /** This variable defines how to handle the position of the header. */ 52 | Position location; 53 | 54 | /** 55 | * The viewport associated to this header. It is null if the location is not 56 | * automatically managed 57 | */ 58 | JViewport headerViewport; 59 | 60 | /** The previous viewport of the associated table. */ 61 | Component previousTableViewport; 62 | 63 | /** The handled filter header. */ 64 | TableFilterHeader filterHeader; 65 | 66 | public PositionHelper(TableFilterHeader filterHeader) { 67 | this.filterHeader = filterHeader; 68 | } 69 | 70 | 71 | /** Sets the position of the header related to the table. */ 72 | public void setPosition(Position location) { 73 | this.location = location; 74 | 75 | JTable table = filterHeader.getTable(); 76 | changeTable(table, table); 77 | } 78 | 79 | 80 | /** Returns the mode currently associated to the TableHeader. */ 81 | public Position getPosition() { 82 | return location; 83 | } 84 | 85 | /** The associated TableFilterHeader reports a change on its visibility. */ 86 | public void headerVisibilityChanged(boolean visible) { 87 | JTable table = filterHeader.getTable(); 88 | changeTable(table, null); 89 | if (visible && (table != null)) { 90 | changeTable(null, table); 91 | } 92 | } 93 | 94 | 95 | /** 96 | * The filter header reports that the table being handled is going to 97 | * change. 98 | */ 99 | public void changeTable(JTable oldTable, JTable newTable) { 100 | if (oldTable != null) { 101 | oldTable.removePropertyChangeListener("ancestor", this); 102 | } 103 | 104 | cleanUp(); 105 | if (newTable != null) { 106 | newTable.addPropertyChangeListener("ancestor", this); 107 | trySetUp(newTable); 108 | } 109 | } 110 | 111 | /** Method automatically invoked when the class ancestor changes. */ 112 | public void filterHeaderContainmentUpdate() { 113 | if (!canHeaderLocationBeManaged()) { 114 | cleanUp(); 115 | } 116 | } 117 | 118 | /** PropertyChangeListener interface. */ 119 | @Override public void propertyChange(PropertyChangeEvent evt) { 120 | 121 | // the table has changed containment. clean up status and prepare again, 122 | // if possible; however, do nothing if the current setup is fine 123 | if ((previousTableViewport != evt.getNewValue()) 124 | || (evt.getSource() != filterHeader.getTable())) { 125 | previousTableViewport = null; 126 | cleanUp(); 127 | trySetUp(filterHeader.getTable()); 128 | } 129 | } 130 | 131 | /** 132 | * Returns true if the header location can be automatically controlled. 133 | * 134 | * @return false if the component has been explicitly included in a 135 | * container 136 | */ 137 | private boolean canHeaderLocationBeManaged() { 138 | if (location == Position.NONE) { 139 | return false; 140 | } 141 | 142 | Container parent = filterHeader.getParent(); 143 | 144 | return (parent == null) || (parent == headerViewport); 145 | } 146 | 147 | 148 | /** Tries to setup the filter header automatically for the given table. */ 149 | private void trySetUp(JTable table) { 150 | if ((table != null) && table.isVisible() && canHeaderLocationBeManaged() 151 | && filterHeader.isVisible()) { 152 | Container p = table.getParent(); 153 | if (p instanceof JViewport) { 154 | Container gp = p.getParent(); 155 | if (gp instanceof JScrollPane) { 156 | JScrollPane scrollPane = (JScrollPane) gp; 157 | JViewport viewport = scrollPane.getViewport(); 158 | if ((viewport != null) && (viewport.getView() == table)) { 159 | setUp(scrollPane); 160 | previousTableViewport = p; 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | /** 168 | * Sets up the header, placing it on a new viewport for the given 169 | * Scrollpane. 170 | */ 171 | private void setUp(JScrollPane scrollPane) { 172 | headerViewport = new JViewport() { 173 | 174 | private static final long serialVersionUID = 7109623726722227105L; 175 | 176 | @Override public void setView(Component view) { 177 | // if the view is not a table header, somebody is doing 178 | // funny stuff. not much to do! 179 | if (view instanceof JTableHeader) { 180 | removeTableHeader(); 181 | // the view is always added, even if set non visible 182 | // this way, it can be recovered if the position changes 183 | view.setVisible(location != Position.REPLACE); 184 | filterHeader.add(view, location == Position.INLINE ? 185 | BorderLayout.NORTH : BorderLayout.SOUTH); 186 | filterHeader.revalidate(); 187 | super.setView(filterHeader); 188 | } 189 | } 190 | 191 | /** 192 | * Removes the current JTableHeader in the filterHeader, returning 193 | * it. it does nothing if there is no such JTableHeader 194 | */ 195 | private Component removeTableHeader() { 196 | Component tableHeader = getTableHeader(); 197 | if (tableHeader != null) { 198 | filterHeader.remove(tableHeader); 199 | } 200 | 201 | return tableHeader; 202 | } 203 | 204 | }; 205 | 206 | JViewport currentColumnHeader = scrollPane.getColumnHeader(); 207 | if (currentColumnHeader != null) { 208 | // this happens if the table has not been yet added to the 209 | // scrollPane 210 | Component view = currentColumnHeader.getView(); 211 | if (view != null) { 212 | headerViewport.setView(view); 213 | } 214 | } 215 | 216 | scrollPane.setColumnHeader(headerViewport); 217 | } 218 | 219 | /** Removes the current viewport, setting it up to clean status. */ 220 | private void cleanUp() { 221 | JViewport currentViewport = headerViewport; 222 | headerViewport = null; 223 | if (currentViewport != null) { 224 | currentViewport.remove(filterHeader); 225 | 226 | Container parent = currentViewport.getParent(); 227 | if (parent instanceof JScrollPane) { 228 | JScrollPane scrollPane = (JScrollPane) parent; 229 | if (scrollPane.getColumnHeader() == currentViewport) { 230 | Component tableHeader = getTableHeader(); 231 | JViewport newView = (tableHeader == null) 232 | ? null : createCleanViewport(tableHeader); 233 | scrollPane.setColumnHeader(newView); 234 | } 235 | } 236 | } 237 | } 238 | 239 | /** Creates a simple JViewport with the given component as view. */ 240 | private JViewport createCleanViewport(Component tableHeader) { 241 | JViewport ret = new JViewport(); 242 | ret.setView(tableHeader); 243 | 244 | return ret; 245 | } 246 | 247 | /** Returns the JTableHeader in the filterHeader, if any. */ 248 | Component getTableHeader() { 249 | for (Component component : filterHeader.getComponents()) { 250 | // there should be just one (the header's controller) 251 | // or two components (with the table header) 252 | if (component instanceof JTableHeader) { 253 | return component; 254 | } 255 | } 256 | 257 | return null; 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /tablefilter/src/main/java/net/coderazzi/filters/gui/FilterSettings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Luis M Pena ( lu@coderazzi.net ) 3 | * License: MIT License 4 | * 5 | * Copyright (c) 2007 Luis M. Pena - lu@coderazzi.net 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | package net.coderazzi.filters.gui; 27 | 28 | import java.awt.Color; 29 | import java.awt.Font; 30 | 31 | import javax.swing.Icon; 32 | import javax.swing.ImageIcon; 33 | 34 | import net.coderazzi.filters.IParser; 35 | import net.coderazzi.filters.gui.TableFilterHeader.Position; 36 | 37 | 38 | /** 39 | * Class to define some common settings to the TableFilter library.
40 | * It is just a sugar replacement to using directly system properties (which 41 | * could be not available, anyway) 42 | */ 43 | public class FilterSettings { 44 | 45 | /** Properties must be defined with this prefix. */ 46 | public final static String PROPERTIES_PREFIX = "net.coderazzi.filters."; 47 | 48 | /** Whether to enable adaptive choices, true by default. */ 49 | public static boolean adaptiveChoices = Boolean.parseBoolean(getString( 50 | "AdaptiveChoices", "true")); 51 | 52 | /** If and how to provide content to the editor field's choices. */ 53 | public static AutoChoices autoChoices; 54 | 55 | /** Whether to enable auto completion, true by default. */ 56 | public static boolean autoCompletion = Boolean.parseBoolean(getString( 57 | "AutoCompletion", "true")); 58 | 59 | /** 60 | * Set to true to perform automatically the selection of a row that is 61 | * uniquely identified by the existing filter. It is true by default. 62 | */ 63 | public static boolean autoSelection = Boolean.parseBoolean(getString( 64 | "AutoSelection", "true")); 65 | 66 | /** Header's background color. */ 67 | public static Color backgroundColor = getColor("BackgroundColor", null); 68 | 69 | /** 70 | * The class defining the generic {@link CustomChoiceDecorator}
71 | * It must have a default constructor.
72 | */ 73 | public static Class customChoiceDecoratorClass; 74 | 75 | /** The default date format, used on the default filter model. */ 76 | public static String dateFormat = getString("DateFormat", null); 77 | 78 | /** Header's disabled color. */ 79 | public static Color disabledBackgroundColor = getColor( 80 | "DisabledBackgroundColor", null); 81 | 82 | /** Header's disabled color. */ 83 | public static Color disabledColor = getColor("DisabledColor", null); 84 | 85 | /** Header's error color. */ 86 | public static Color errorColor = getColor("ErrorColor", null); 87 | 88 | /** If true, table updates trigger filter and sort updates. */ 89 | public static boolean filterOnUpdates = Boolean.parseBoolean(getString( 90 | "FilterOnUpdates", "true")); 91 | 92 | /** 93 | * Setting to add / decrease height to the filter row.
94 | * This setting could be specifically required on specific Look And Feels 95 | * -Substance seems to require additional height.
96 | */ 97 | public static int filterRowHeightDelta = getInteger("FilterRowHeightDelta", 98 | 0); 99 | 100 | /** Header's font. */ 101 | public static Font font; 102 | 103 | /** Header's foreground color. */ 104 | public static Color foregroundColor = getColor("ForegroundColor", null); 105 | 106 | /** Header's grid color. */ 107 | public static Color gridColor = getColor("GridColor", null); 108 | 109 | /** The header position, {@link Position#INLINE} by default. */ 110 | public static Position headerPosition = Position.valueOf(getString( 111 | "Header.Position", "INLINE")); 112 | 113 | /** 114 | * Set to true to automatically hide any filter popups during table updates. 115 | * It is false by default. 116 | */ 117 | public static boolean hidePopupsOnTableUpdates = Boolean.parseBoolean( 118 | getString("HidePopupsOnTableUpdates", "false")); 119 | 120 | /** Whether to ignore case or not, false by default (case sensitive). */ 121 | public static boolean ignoreCase = Boolean.parseBoolean(getString( 122 | "IgnoreCase", "true")); 123 | 124 | /** Whether to enable instant filtering, true by default. */ 125 | public static boolean instantFiltering = Boolean.parseBoolean(getString( 126 | "InstantFiltering", "true")); 127 | 128 | /** Whether to allow vanishing during instant filtering, false by default. */ 129 | public static boolean allowInstantVanishing = Boolean.parseBoolean(getString( 130 | "AllowInstantVanishing", "false")); 131 | 132 | /** The default icon used to represent null/empty values. */ 133 | public static Icon matchEmptyFilterIcon = new ImageIcon(IParser.class 134 | .getResource("resources/matchEmptyIcon.png")); 135 | 136 | /** 137 | * The default string associated to a nop operation. 138 | * 139 | *

It is chosen as = because that is the expression that the default text 140 | * parser can use to find null/empty values. If any other parse is chosen, 141 | * it could be meaningful to update this string.

142 | */ 143 | public static String matchEmptyFilterString = "="; 144 | 145 | /** The maximum size of the history when no choices are present. */ 146 | public static int maxPopupHistory = getInteger("Popup.MaxHistory", 2); 147 | 148 | /** The maximum number of visible tows on the popup menus. */ 149 | public static int maxVisiblePopupRows = getInteger("Popup.MaxVisibleRows", 150 | 8); 151 | 152 | /** 153 | * The class defining the generic {@link IParserModel}
154 | * It must have a default constructor.
155 | * It corresponds to the property ParserModel.class 156 | */ 157 | public static Class parserModelClass; 158 | 159 | /** Header's selection background color. */ 160 | public static Color selectionBackgroundColor = getColor( 161 | "SelectionBackgroundColor", null); 162 | 163 | /** Header's selection color. */ 164 | public static Color selectionColor = getColor("SelectionColor", null); 165 | 166 | /** Header's selection foreground color. */ 167 | public static Color selectionForegroundColor = getColor( 168 | "SelectionForegroundColor", null); 169 | 170 | /** Header's warning color. */ 171 | public static Color warningColor = getColor("WarningColor", null); 172 | 173 | /** Creates a TextParser as defined by default. */ 174 | public static IParserModel newParserModel() { 175 | try { 176 | return parserModelClass.newInstance(); 177 | } catch (Exception ex) { 178 | throw new RuntimeException("Error creating parser model of type " 179 | + parserModelClass, ex); 180 | } 181 | } 182 | 183 | /** Creates a CustomChoiceDecorator as defined by default. */ 184 | public static CustomChoiceDecorator newCustomChoiceDecorator() { 185 | try { 186 | return customChoiceDecoratorClass.newInstance(); 187 | } catch (Exception ex) { 188 | throw new RuntimeException("Error creating decorator of type " 189 | + customChoiceDecoratorClass, ex); 190 | } 191 | } 192 | 193 | static { 194 | try { 195 | font = Font.decode(getString("Font")); 196 | } catch (Exception ex) { 197 | // font remains null 198 | } 199 | 200 | try { 201 | autoChoices = AutoChoices.valueOf(getString("AutoChoices", 202 | "ENUMS")); 203 | } catch (Exception ex) { 204 | autoChoices = AutoChoices.ENUMS; 205 | } 206 | 207 | parserModelClass = ParserModel.class; 208 | 209 | String cl = getString("ParserModel.Class", null); 210 | if (cl != null) { 211 | try { 212 | parserModelClass = (Class) Class 213 | .forName(cl); 214 | } catch (ClassNotFoundException cne) { 215 | throw new RuntimeException( 216 | "Error finding filter model of class " + cl, cne); 217 | } catch (ClassCastException cce) { 218 | throw new RuntimeException("Filter model of class " + cl 219 | + " is not a valid IParserModel class"); 220 | } 221 | } 222 | 223 | customChoiceDecoratorClass = 224 | CustomChoiceDecorator.DefaultDecorator.class; 225 | cl = getString("CustomChoiceDecorator.Class", null); 226 | if (cl != null) { 227 | try { 228 | customChoiceDecoratorClass = 229 | (Class) Class.forName(cl); 230 | } catch (ClassNotFoundException cne) { 231 | throw new RuntimeException( 232 | "Error finding choice decorator of class " + cl, cne); 233 | } catch (ClassCastException cce) { 234 | throw new RuntimeException( 235 | "CustomChoiceDecorator model of class " + cl 236 | + " is not a valid CustomChoiceDecorator class"); 237 | } 238 | } 239 | } 240 | 241 | private static String getString(String name, String defaultValue) { 242 | String ret = getString(name); 243 | 244 | return (ret == null) ? defaultValue : ret; 245 | } 246 | 247 | private static String getString(String name) { 248 | try { 249 | return System.getProperty(PROPERTIES_PREFIX + name); 250 | } catch (Exception ex) { 251 | return null; 252 | } 253 | } 254 | 255 | private static int getInteger(String name, int defaultValue) { 256 | String ret = getString(name); 257 | if (ret != null) { 258 | try { 259 | return Integer.valueOf(ret); 260 | } catch (Exception ex) { 261 | // return defaultValue 262 | } 263 | } 264 | 265 | return defaultValue; 266 | } 267 | 268 | private static Color getColor(String name, Color defaultValue) { 269 | String prop = getString(name); 270 | if (prop != null) { 271 | try { 272 | return Color.decode(prop); 273 | } catch (Exception ex) { 274 | // return defaultValue 275 | } 276 | } 277 | 278 | return defaultValue; 279 | } 280 | 281 | } 282 | --------------------------------------------------------------------------------