# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1620612088 0 # Node ID d3f09b3f3703e3ac48862d7379e48ed63fb13d07 # Parent 9fd26efff9dade12ed80485d3b55625ecf80d973 Android: Initial dw_file_browse() implementation, still needs some work. Fix minor issues with the Calendar control. diff -r 9fd26efff9da -r d3f09b3f3703 android/DWindows.kt --- a/android/DWindows.kt Sun May 09 22:39:13 2021 +0000 +++ b/android/DWindows.kt Mon May 10 02:01:28 2021 +0000 @@ -1,6 +1,8 @@ package org.dbsoft.dwindows -import android.R.attr +import android.R +import android.app.Activity +import android.app.Dialog import android.app.NotificationChannel import android.app.NotificationManager import android.content.ClipData @@ -45,6 +47,7 @@ import com.google.android.material.tabs.TabLayout.OnTabSelectedListener import com.google.android.material.tabs.TabLayoutMediator import java.io.File +import java.io.FileFilter import java.io.FileInputStream import java.io.FileNotFoundException import java.util.* @@ -236,6 +239,137 @@ ) } +class DWFileChooser(private val activity: Activity) { + private val list: ListView = ListView(activity) + private val dialog: Dialog = Dialog(activity) + private var currentPath: File? = null + + // filter on file extension + private var extension: String? = null + fun setExtension(extension: String?) { + this.extension = extension?.toLowerCase(Locale.ROOT) + } + + // file selection event handling + interface FileSelectedListener { + fun fileSelected(file: File?) + } + + fun setFileListener(fileListener: FileSelectedListener?): DWFileChooser { + this.fileListener = fileListener + return this + } + + private var fileListener: FileSelectedListener? = null + fun showDialog() { + dialog.show() + } + + /** + * Sort, filter and display the files for the given path. + */ + private fun refresh(path: File?) { + currentPath = path + if (path != null) { + if (path.exists()) { + val dirs = path.listFiles { file -> file.isDirectory && file.canRead() } + val files = path.listFiles { file -> + if (!file.isDirectory) { + if (!file.canRead()) { + false + } else if (extension == null) { + true + } else { + file.name.toLowerCase(Locale.ROOT).endsWith(extension!!) + } + } else { + false + } + } + + // convert to an array + var i = 0 + val fileList: Array + var filecount = 0 + var dircount = 0 + if(files != null) { + filecount = files.size + } + if(dirs != null) { + dircount = dirs.size + } + if (path.parentFile == null) { + fileList = arrayOfNulls(dircount + filecount) + } else { + fileList = arrayOfNulls(dircount + filecount + 1) + fileList[i++] = PARENT_DIR + } + if(dirs != null) { + Arrays.sort(dirs) + for (dir in dirs) { + fileList[i++] = dir.name + } + } + if(files != null) { + Arrays.sort(files) + for (file in files) { + fileList[i++] = file.name + } + } + + // refresh the user interface + dialog.setTitle(currentPath!!.path) + list.adapter = object : ArrayAdapter( + activity, + R.layout.simple_list_item_1, fileList + ) { + override fun getView(pos: Int, view: View?, parent: ViewGroup): View { + val thisview = super.getView(pos, view, parent) + (thisview as TextView).isSingleLine = true + return thisview + } + } + } + } + } + + /** + * Convert a relative filename into an actual File object. + */ + private fun getChosenFile(fileChosen: String): File? { + return if (fileChosen == PARENT_DIR) { + currentPath!!.parentFile + } else { + File(currentPath, fileChosen) + } + } + + companion object { + private const val PARENT_DIR = ".." + } + + init { + list.onItemClickListener = + OnItemClickListener { parent, view, which, id -> + val fileChosen = list.getItemAtPosition(which) as String + val chosenFile: File? = getChosenFile(fileChosen) + if (chosenFile != null) { + if (chosenFile.isDirectory) { + refresh(chosenFile) + } else { + if (fileListener != null) { + fileListener!!.fileSelected(chosenFile) + } + dialog.dismiss() + } + } + } + dialog.setContentView(list) + dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + refresh(Environment.getExternalStorageDirectory()) + } +} + class DWindows : AppCompatActivity() { var firstWindow: Boolean = true var windowLayout: LinearLayout? = null @@ -1557,6 +1691,34 @@ Log.d(null, text) } + fun fileBrowse(title: String, defpath: String?, ext: String?, flags: Int): String? + { + var retval: String? = null + + waitOnUiThread { + val fc = DWFileChooser(this) + fc.setFileListener(object: DWFileChooser.FileSelectedListener { + override fun fileSelected(file: File?) { + // do something with the file + retval = file!!.absolutePath + throw java.lang.RuntimeException() + } + }) + if(ext != null) { + fc.setExtension(ext) + } + fc.showDialog() + } + + // loop till a runtime exception is triggered. + try { + Looper.loop() + } catch (e2: RuntimeException) { + } + + return retval + } + fun messageBox(title: String, body: String, flags: Int): Int { var retval: Int = 0 diff -r 9fd26efff9da -r d3f09b3f3703 android/dw.cpp --- a/android/dw.cpp Sun May 09 22:39:13 2021 +0000 +++ b/android/dw.cpp Mon May 10 02:01:28 2021 +0000 @@ -760,6 +760,29 @@ */ char * API dw_file_browse(const char *title, const char *defpath, const char *ext, int flags) { + JNIEnv *env; + + if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) + { + // Use a long parameter + jstring jstr = env->NewStringUTF(title); + jstring path = NULL; + jstring jext = NULL; + if(defpath) + path = env->NewStringUTF(defpath); + if(ext) + jext = env->NewStringUTF(defpath); + // First get the class that contains the method you need to call + //jclass clazz = _dw_find_class(env, DW_CLASS_NAME); + jclass clazz = env->FindClass(DW_CLASS_NAME); + // Get the method that you want to call + jmethodID fileBrowse = env->GetMethodID(clazz, "fileBrowse", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;"); + // Call the method on the object + jstring jresult = (jstring)env->CallObjectMethod(_dw_obj, fileBrowse, jstr, path, jext, flags); + if(jresult) + return strdup(env->GetStringUTFChars(jresult, 0)); + } return NULL; } @@ -3283,7 +3306,7 @@ // Convert to Unix time ts.tm_year = year - 1900; - ts.tm_mon = month; + ts.tm_mon = month - 1; ts.tm_mday = day; date = mktime(&ts); @@ -3325,7 +3348,7 @@ if(year) *year = ts.tm_year + 1900; if(month) - *month = ts.tm_mon; + *month = ts.tm_mon + 1; if(day) *day = ts.tm_mday; }