package jp.sourceforge.gokigen.memoma.extension;
-import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
import jp.sourceforge.gokigen.memoma.R;
/**
- *
- * @author MRSa
*
*/
-public class ExtensionActivity extends Activity
+public class ExtensionActivity extends AppCompatActivity
{
- /** 起動コード **/
+ // 起動コード
public static final String MEMOMA_EXTENSION_LAUNCH_ACTIVITY = "jp.sfjp.gokigen.memoma.extension.activity";
- /** データ識別子(表示中データの保存ファイルへのフルパス) **/
+ // データ識別子(表示中データの保存ファイルへのフルパス)
public static final String MEMOMA_EXTENSION_DATA_FULLPATH = "jp.sfjp.gokigen.memoma.extension.data.fullpath";
public static final String MEMOMA_EXTENSION_DATA_TITLE = "jp.sfjp.gokigen.memoma.extension.data.title";
{
super.onCreate(savedInstanceState);
- // リスナクラスを生成する
- listener = new ExtensionActivityListener(this);
-
- // レイアウトを設定する
- setContentView(R.layout.extensionview);
-
- // リスナクラスの準備
- listener.prepareExtraDatas(getIntent());
- listener.prepareListener();
+ try
+ {
+ // リスナクラスを生成する
+ listener = new ExtensionActivityListener(this);
+
+ // レイアウトを設定する
+ setContentView(R.layout.extensionview);
+
+ // リスナクラスの準備
+ listener.prepareExtraDatas(getIntent());
+ listener.prepareListener();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
/**
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
- menu = listener.onCreateOptionsMenu(menu);
+ try
+ {
+ menu = listener.onCreateOptionsMenu(menu);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
return (super.onCreateOptionsMenu(menu));
}
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
- listener.onPrepareOptionsMenu(menu);
+ try
+ {
+ listener.onPrepareOptionsMenu(menu);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
return (super.onPrepareOptionsMenu(menu));
}
catch (Exception ex)
{
// なにもしない
+ ex.printStackTrace();
}
}
@Override
protected void onDestroy()
{
- listener.finishListener();
- super.onDestroy();
+ try
+ {
+ listener.finishListener();
+ super.onDestroy();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
/**
*
*/
@Override
- protected void onSaveInstanceState(Bundle outState)
+ protected void onSaveInstanceState(@NonNull Bundle outState)
{
- super.onSaveInstanceState(outState);
+ super.onSaveInstanceState(outState);
}
/**
@Override
protected void onPrepareDialog(int id, Dialog dialog)
{
- listener.onPrepareDialog(id, dialog);
+ try
+ {
+ listener.onPrepareDialog(id, dialog);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
/**
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
+ super.onActivityResult(requestCode, resultCode, data);
try
{
// 子画面からもらった情報の応答処理をイベント処理クラスに依頼する
- listener.onActivityResult(requestCode, resultCode, data);
+ listener.onActivityResult(requestCode, resultCode, data);
}
catch (Exception ex)
{
// 例外が発生したときには、何もしない。
+ ex.printStackTrace();
}
}
}
package jp.sourceforge.gokigen.memoma.extension;
+import static jp.sourceforge.gokigen.memoma.Main.APP_NAMESPACE;
+
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
-import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.preference.PreferenceManager;
+import android.provider.DocumentsContract;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+
import jp.sourceforge.gokigen.memoma.holders.PositionObject;
import jp.sourceforge.gokigen.memoma.dialogs.FileSelectionDialog;
import jp.sourceforge.gokigen.memoma.io.MeMoMaFileExportCsvProcess;
import jp.sourceforge.gokigen.memoma.io.MeMoMaFileLoadingProcess;
import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder;
import jp.sourceforge.gokigen.memoma.R;
+import jp.sourceforge.gokigen.memoma.io.MeMoMaFileSavingEngine;
import jp.sourceforge.gokigen.memoma.io.SharedIntentInvoker;
import jp.sourceforge.gokigen.memoma.listitem.SymbolListArrayAdapter;
import jp.sourceforge.gokigen.memoma.listitem.SymbolListArrayItem;
/**
* リスト形式で表示・エクスポート
- *
- * @author MRSa
- *
*/
public class ExtensionActivityListener implements OnClickListener, MeMoMaFileLoadingProcess.IResultReceiver, MeMoMaFileExportCsvProcess.IResultReceiver, FileSelectionDialog.IResultReceiver, MeMoMaFileImportCsvProcess.IResultReceiver
{
private final String TAG = toString();
+ private static final int PICK_CSV_FILE = 2020;
private final int MENU_ID_EXPORT= (Menu.FIRST + 1);
private final int MENU_ID_SHARE = (Menu.FIRST + 2);
private final int MENU_ID_IMPORT = (Menu.FIRST + 3);
- private static final String EXTENSION_DIRECTORY = "/exported";
-
- //private ExternalStorageFileUtility fileUtility;
private final MeMoMaObjectHolder objectHolder;
private FileSelectionDialog fileSelectionDialog = null;
private List<SymbolListArrayItem> listItems = null;
- private final Activity parent; // 親分
-
+ private final AppCompatActivity parent; // 親分
+
/**
* コンストラクタ
- * @param argument parent activity
*/
- ExtensionActivityListener(Activity argument)
+ ExtensionActivityListener(AppCompatActivity argument)
{
parent = argument;
- //fileUtility = new ExternalStorageFileUtility(Main.APP_BASEDIR);
objectHolder = new MeMoMaObjectHolder(parent);
}
/**
* 起動時にデータを準備する
- *
- * @param myIntent intent information
*/
public void prepareExtraDatas(Intent myIntent)
{
try
{
// Intentで拾ったデータを読み出す (初期化データ)
- //fullPath = myIntent.getStringExtra(ExtensionActivity.MEMOMA_EXTENSION_DATA_FULLPATH);
objectHolder.setDataTitle(myIntent.getStringExtra(ExtensionActivity.MEMOMA_EXTENSION_DATA_TITLE));
-
- // Preferenceに記憶されたデータがあればそれを取得する
- // SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
}
catch (Exception ex)
{
// フィルタ設定ボタン
final ImageButton filterButton = parent.findViewById(R.id.SetFilterButton);
filterButton.setOnClickListener(this);
-
}
/**
*/
public void prepareToStart()
{
- Log.v(TAG, "ExtensionActivityListener::prepareToStart() : " + objectHolder.getDataTitle());
-
- // アクションバーを表示する
- ActionBar bar = parent.getActionBar();
- if (bar != null)
+ try
{
- bar.show();
- bar.setTitle(objectHolder.getDataTitle());
+ Log.v(TAG, "ExtensionActivityListener::prepareToStart() : " + objectHolder.getDataTitle());
+
+ // アクションバーを表示する
+ ActionBar bar = parent.getSupportActionBar();
+ if (bar != null)
+ {
+ bar.setIcon(R.drawable.icon1);
+ bar.setTitle(objectHolder.getDataTitle());
+ bar.show();
+ }
+
+ // ファイルをロードする!
+ // (AsyncTaskを使ってデータを読み込む)
+ MeMoMaFileLoadingProcess asyncTask = new MeMoMaFileLoadingProcess(parent, this);
+ asyncTask.execute(objectHolder);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
}
-
- // ファイルをロードする!
- // (AsyncTaskを使ってデータを読み込む)
- MeMoMaFileLoadingProcess asyncTask = new MeMoMaFileLoadingProcess(parent, this);
- asyncTask.execute(objectHolder);
}
/**
* 詳細データを表示する。
- *
*/
private void showDetailData(String first, String second, String third)
{
/**
* 他画面から戻ってきたとき...
- *
- *
*/
- public void onActivityResult(int requestCode, int resultCode, Intent data)
+ public void onActivityResult(int requestCode, int resultCode, Intent resultData)
{
- // なにもしない...
- Log.v(TAG, "rc: " + requestCode + " rs: " + resultCode + " it: " + data.getDataString());
+ try
+ {
+ if ((requestCode == PICK_CSV_FILE)&&(resultCode == Activity.RESULT_OK))
+ {
+ if (resultData != null)
+ {
+ Uri uri = resultData.getData();
+ Log.v(TAG, "========== rc: " + requestCode + " rs: " + resultCode + " uri: " + uri.toString());
+
+ // Perform operations on the document using its URI.
+ Thread thread = new Thread(() -> {
+ ExtensionCsvImport importer = new ExtensionCsvImport(parent, objectHolder, uri);
+ importer.importFromCsvFile();
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
+ String backgroundUri = preferences.getString("backgroundUri","");
+ String userCheckboxString = preferences.getString("userCheckboxString","");
+
+ // データの保管メイン
+ MeMoMaFileSavingEngine savingEngine = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
+ String result = savingEngine.saveObjects(objectHolder);
+
+ parent.runOnUiThread(() -> {
+ try
+ {
+ onImportedResult(result);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ });
+ });
+ try
+ {
+ thread.start();
+ }
+ catch (Exception ee)
+ {
+ ee.printStackTrace();
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ // Log.v(TAG, "rc: " + requestCode + " rs: " + resultCode + " it: " + resultData.getDataString());
}
/**
Log.v(TAG, "Selected Filter");
}
}
-
-/*
- **
- * 触られたときの処理
- *
- *
- public boolean onTouch(View v, MotionEvent event)
- {
- Log.v(Main.APP_IDENTIFIER, " " + v.toString() + " " + event.toString());
- // int id = v.getId();
- // int action = event.getAction();
-
- return (false);
- }
-*/
/**
* メニューへのアイテム追加
*/
public Menu onCreateOptionsMenu(Menu menu)
{
- MenuItem menuItem = menu.add(Menu.NONE, MENU_ID_SHARE, Menu.NONE, parent.getString(R.string.export_csv));
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); /* for Android 3.1 */
- menuItem.setIcon(android.R.drawable.ic_menu_share);
-
- menuItem = menu.add(Menu.NONE, MENU_ID_EXPORT, Menu.NONE, parent.getString(R.string.shareContent));
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); /* for Android 3.1 */
- menuItem.setIcon(android.R.drawable.ic_menu_save);
+ try
+ {
+ MenuItem menuItem = menu.add(Menu.NONE, MENU_ID_SHARE, Menu.NONE, parent.getString(R.string.export_csv));
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menuItem.setIcon(android.R.drawable.ic_menu_share);
- menuItem = menu.add(Menu.NONE, MENU_ID_IMPORT, Menu.NONE, parent.getString(R.string.import_csv));
- menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); /* for Android 3.1 */
- menuItem.setIcon(android.R.drawable.ic_menu_edit);
+ menuItem = menu.add(Menu.NONE, MENU_ID_EXPORT, Menu.NONE, parent.getString(R.string.shareContent));
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menuItem.setIcon(android.R.drawable.ic_menu_save);
- return (menu);
+ menuItem = menu.add(Menu.NONE, MENU_ID_IMPORT, Menu.NONE, parent.getString(R.string.import_csv));
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menuItem.setIcon(android.R.drawable.ic_menu_edit);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (menu);
}
/**
*/
public void onPrepareOptionsMenu(Menu menu)
{
- menu.findItem(MENU_ID_SHARE).setVisible(true);
- menu.findItem(MENU_ID_EXPORT).setVisible(true);
- menu.findItem(MENU_ID_IMPORT).setVisible(true);
+ try
+ {
+ menu.findItem(MENU_ID_SHARE).setVisible(true);
+ menu.findItem(MENU_ID_EXPORT).setVisible(true);
+ menu.findItem(MENU_ID_IMPORT).setVisible(true);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
/**
public boolean onOptionsItemSelected(MenuItem item)
{
boolean result;
- switch (item.getItemId())
- {
- case MENU_ID_EXPORT:
- // 表示中データのエクスポート
- export_as_csv(false);
- result = true;
- break;
-
- case MENU_ID_SHARE:
- export_as_csv(true);
- result = true;
- break;
-
- case MENU_ID_IMPORT:
- // データのインポート
- importObjectFromCsv();
- result = true;
- break;
-
- default:
- result = false;
- break;
- }
+ switch (item.getItemId())
+ {
+ case MENU_ID_EXPORT -> {
+ // 表示中データのエクスポート
+ export_as_csv(false);
+ result = true;
+ }
+ case MENU_ID_SHARE -> {
+ export_as_csv(true);
+ result = true;
+ }
+ case MENU_ID_IMPORT -> {
+ // データのインポート
+ importObjectFromCsv();
+ result = true;
+ }
+ default -> result = false;
+ }
return (result);
}
/**
* CSV形式でデータをインポートする
- *
*/
private void importObjectFromCsv()
{
- // データのインポート
- parent.showDialog(R.id.listdialog);
+ // ファイル選択のダイアログを取得する
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
+ {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("text/*");
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ {
+ String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() + "/" + APP_NAMESPACE + "/";
+ intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
+ }
+ parent.startActivityForResult(intent, PICK_CSV_FILE);
+ }
+ else
+ {
+ // 旧バージョンの Android での処理... (File Picker ってあったっけ?)
+
+
+ }
}
/**
* データをCSV形式で出力する
- *
*/
private void export_as_csv(boolean isShare)
{
/**
* ダイアログの生成
- *
*/
public Dialog onCreateDialog(int id)
{
fileSelectionDialog = new FileSelectionDialog(parent, parent.getString(R.string.dialogtitle_selectcsv), ".csv", this);
return (fileSelectionDialog.getDialog());
}
-
- /*
- if (id == R.id.info_about_gokigen)
- {
- CreditDialog dialog = new CreditDialog(parent);
- return (dialog.getDialog());
- }
- */
return (null);
}
--- /dev/null
+package jp.sourceforge.gokigen.memoma.extension
+
+import android.content.Context
+import android.net.Uri
+import android.util.Log
+import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder
+import java.io.BufferedReader
+import java.io.InputStream
+import java.io.InputStreamReader
+
+
+class ExtensionCsvImport(private val context: Context, private val objectHolder: MeMoMaObjectHolder, private val importUri: Uri)
+{
+ fun importFromCsvFile()
+ {
+ try
+ {
+ val inputStream: InputStream? = context.contentResolver.openInputStream(importUri)
+ val reader = BufferedReader(InputStreamReader(inputStream))
+
+ var dataLine: String? = readRecord(reader)
+ while (dataLine != null)
+ {
+ if (dataLine.startsWith(";") != true)
+ {
+ // データ行だった。ログに出力する!
+ parseRecord(dataLine, objectHolder)
+ }
+ // 次のデータ行を読み出す
+ dataLine = readRecord(reader)
+ }
+ inputStream?.close()
+ }
+ catch (e: Exception)
+ {
+ e.printStackTrace()
+ }
+ }
+
+ private fun readRecord(buf: BufferedReader): String?
+ {
+ var oneRecord: String? = null
+ try
+ {
+ var oneLine = buf.readLine()
+ while (oneLine != null)
+ {
+ oneRecord = if (oneRecord == null) oneLine else oneRecord + oneLine
+ if (oneRecord.indexOf(",;!<_$") > 0)
+ {
+ // レコード末尾が見つかったので break する。
+ break
+ }
+ // 次の行を読みだす。
+ oneLine = buf.readLine()
+ }
+ }
+ catch (ex: java.lang.Exception)
+ {
+ //
+ Log.v(TAG, "CSV:readRecord() ex : $ex")
+ oneRecord = null
+ }
+ return (oneRecord)
+ }
+ private fun parseRecord(dataLine: String, objectHolder: MeMoMaObjectHolder)
+ {
+ val detailIndex: Int
+ val userCheckIndexTrue: Int
+ val userCheckIndexFalse: Int
+ val nextIndex: Int
+ val label: String
+ val detail: String
+ val userChecked: Boolean
+ try
+ {
+ detailIndex = dataLine.indexOf("\",\"")
+ if (detailIndex < 0)
+ {
+ Log.v(TAG, "parseRecord() : label wrong : $dataLine")
+ return
+ }
+ label = dataLine.substring(1, detailIndex)
+ userCheckIndexTrue = dataLine.indexOf("\",True,", detailIndex)
+ userCheckIndexFalse = dataLine.indexOf("\",False,", detailIndex)
+ if (userCheckIndexFalse > detailIndex)
+ {
+ detail = dataLine.substring(detailIndex + 3, userCheckIndexFalse)
+ userChecked = false
+ nextIndex = userCheckIndexFalse + 8 // 8は、 ",False, を足した数
+ }
+ else if (userCheckIndexTrue > detailIndex)
+ {
+ detail = dataLine.substring(detailIndex + 3, userCheckIndexTrue)
+ userChecked = true
+ nextIndex = userCheckIndexTrue + 7 // 7は、 ",True, を足した数
+ }
+ else // if ((userCheckIndexTrue <= detailIndex)&&(userCheckIndexFalse <= detailIndex))
+ {
+ Log.v(TAG, "parseRecord() : detail wrong : $dataLine")
+ return
+ }
+
+ // 残りのデータを切り出す。
+ val datas =
+ dataLine.substring(nextIndex).split(",".toRegex()).dropLastWhile { it.isEmpty() }
+ .toTypedArray()
+ if (datas.size < 6)
+ {
+ Log.v(TAG, "parseRecord() : data size wrong : " + datas.size)
+ return
+ }
+ val drawStyle = datas[0].toInt()
+ val paintStyle = datas[1]
+ val centerX = datas[2].toFloat()
+ val centerY = datas[3].toFloat()
+ val width = datas[4].toFloat()
+ val height = datas[5].toFloat()
+ val left = centerX - width / 2.0f
+ val top = centerY - height / 2.0f
+
+ // オブジェクトのデータを作成する
+ val pos = objectHolder.createPosition(left, top, drawStyle)
+ if (pos == null)
+ {
+ Log.v(TAG, "parseRecord() : object create failure.")
+ return
+ }
+ pos.setRectRight(left + width)
+ pos.setRectBottom(top + height)
+ pos.label = label
+ pos.detail = detail
+ pos.paintStyle = paintStyle
+ pos.userChecked = userChecked
+ Log.v(TAG, "OBJECT CREATED: $label($left,$top) [$drawStyle]")
+ }
+ catch (ex: Exception)
+ {
+ Log.v(TAG, "parseRecord() $ex")
+ ex.printStackTrace()
+ }
+ }
+
+ companion object {
+ private val TAG = ExtensionCsvImport::class.java.simpleName
+ }
+
+}
\ No newline at end of file