1 package jp.sourceforge.gokigen.memoma.extension;
3 import static jp.sourceforge.gokigen.memoma.Main.APP_NAMESPACE;
6 import java.text.SimpleDateFormat;
7 import java.util.ArrayList;
8 import java.util.Calendar;
9 import java.util.Enumeration;
10 import java.util.List;
11 import java.util.Locale;
13 import android.app.Activity;
14 import android.content.Intent;
15 import android.content.SharedPreferences;
16 import android.net.Uri;
17 import android.os.Build;
18 import android.os.Environment;
19 import android.preference.PreferenceManager;
20 import android.provider.DocumentsContract;
21 import android.util.Log;
22 import android.view.Menu;
23 import android.view.MenuItem;
24 import android.view.View;
25 import android.view.View.OnClickListener;
26 import android.widget.ImageButton;
27 import android.widget.ListAdapter;
28 import android.widget.ListView;
29 import android.widget.Toast;
31 import androidx.appcompat.app.ActionBar;
32 import androidx.appcompat.app.AlertDialog;
33 import androidx.appcompat.app.AppCompatActivity;
35 import jp.sourceforge.gokigen.memoma.holders.PositionObject;
36 import jp.sourceforge.gokigen.memoma.dialogs.FileSelectionDialog;
37 import jp.sourceforge.gokigen.memoma.io.MeMoMaFileExportCsvProcess;
38 import jp.sourceforge.gokigen.memoma.io.MeMoMaFileImportCsvProcess;
39 import jp.sourceforge.gokigen.memoma.io.MeMoMaFileLoadingProcess;
40 import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder;
41 import jp.sourceforge.gokigen.memoma.R;
42 import jp.sourceforge.gokigen.memoma.io.MeMoMaFileSavingEngine;
43 import jp.sourceforge.gokigen.memoma.io.SharedIntentInvoker;
44 import jp.sourceforge.gokigen.memoma.listitem.SymbolListArrayAdapter;
45 import jp.sourceforge.gokigen.memoma.listitem.SymbolListArrayItem;
50 public class ExtensionActivityListener implements OnClickListener, MeMoMaFileLoadingProcess.IResultReceiver, MeMoMaFileExportCsvProcess.IResultReceiver, FileSelectionDialog.IResultReceiver, MeMoMaFileImportCsvProcess.IResultReceiver
52 private final String TAG = toString();
53 private static final int PICK_CSV_FILE = 2020;
54 private static final int PICK_XML_FILE = 2030;
56 private final int MENU_ID_EXPORT= (Menu.FIRST + 1);
57 private final int MENU_ID_EXPORT_XML = (Menu.FIRST + 2);
58 private final int MENU_ID_SHARE = (Menu.FIRST + 3);
59 private final int MENU_ID_IMPORT = (Menu.FIRST + 4);
60 private final int MENU_ID_IMPORT_XML = (Menu.FIRST + 5);
61 private final int MENU_ID_DELETE = (Menu.FIRST + 6);
63 private final MeMoMaObjectHolder objectHolder;
64 //private FileSelectionDialog fileSelectionDialog = null;
65 private boolean isShareExportedData = false;
66 private List<SymbolListArrayItem> listItems = null;
67 private final AppCompatActivity parent; // 親分
72 ExtensionActivityListener(AppCompatActivity argument)
75 objectHolder = new MeMoMaObjectHolder(parent);
80 public void prepareExtraDatas(Intent myIntent)
84 String dataTitle = myIntent.getStringExtra(ExtensionActivity.MEMOMA_EXTENSION_DATA_TITLE);
86 SharedPreferences preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(parent);
87 String prefTitleString = preferences.getString("content_data_title", "");
88 if (prefTitleString.length() > 0)
90 // Preferenceに タイトル名が記録されていたら、上書きする
91 dataTitle = prefTitleString;
93 // Intentで拾ったデータを読み出す (初期化データ)
94 objectHolder.setDataTitle(dataTitle);
98 Log.v(TAG, "Exception :" + ex.getMessage());
102 private void setPreferenceString(String title)
106 SharedPreferences preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(parent);
107 SharedPreferences.Editor editor = preferences.edit();
108 editor.putString("content_data_title", title);
119 * がっつりこのクラスにイベントリスナを接続する
121 public void prepareListener()
124 final ImageButton filterButton = parent.findViewById(R.id.SetFilterButton);
125 filterButton.setOnClickListener(this);
131 public void finishListener()
133 //setPreferenceString("");
139 public void prepareToStart()
143 Log.v(TAG, "ExtensionActivityListener::prepareToStart() : " + objectHolder.getDataTitle());
146 ActionBar bar = parent.getSupportActionBar();
149 bar.setIcon(R.drawable.icon1);
150 bar.setTitle(objectHolder.getDataTitle());
155 // (AsyncTaskを使ってデータを読み込む)
156 MeMoMaFileLoadingProcess asyncTask = new MeMoMaFileLoadingProcess(parent, this);
157 asyncTask.execute(objectHolder);
168 private void showDetailData(String first, String second, String third)
170 Log.v(TAG, "SELECTED: " + first + " " + second + " " + third);
176 public void shutdown()
178 //setPreferenceString("");
181 private void imporObjectFromCsv(final Uri uri)
185 // Perform operations on the document using its URI.
186 Thread thread = new Thread(() -> {
187 ExtensionCsvImport importer = new ExtensionCsvImport(parent, objectHolder, uri);
188 importer.importFromCsvFile();
190 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
191 String backgroundUri = preferences.getString("backgroundUri","");
192 String userCheckboxString = preferences.getString("userCheckboxString","");
195 MeMoMaFileSavingEngine savingEngine = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
196 String result = savingEngine.saveObjects(objectHolder);
197 parent.runOnUiThread(() -> {
200 onImportedResult(result);
216 private void importDataFromXml(final Uri uri)
220 // Perform operations on the document using its URI.
221 Thread thread = new Thread(() -> {
222 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
223 String backgroundUri = preferences.getString("backgroundUri","");
224 String userCheckboxString = preferences.getString("userCheckboxString","");
227 MeMoMaFileSavingEngine savingEngine = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
228 String result0 = savingEngine.saveObjects(objectHolder);
229 Log.v(TAG, "Saved : " + result0);
232 ExtensionXmlImport importer = new ExtensionXmlImport(parent, objectHolder, uri);
233 String result1 = importer.importFromXmlFile();
236 MeMoMaFileSavingEngine savingEngine2 = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
237 String result = savingEngine2.saveObjects(objectHolder) + " " + result1;
238 Log.v(TAG, "=== Data Saved : " + objectHolder.getDataTitle() + " " + result + " " + result1);
239 parent.runOnUiThread(() -> {
242 // 読み込んだファイル名をタイトルに設定する
243 parent.setTitle(objectHolder.getDataTitle());
246 ActionBar bar = parent.getSupportActionBar();
249 bar.setIcon(R.drawable.icon1);
250 bar.setTitle(objectHolder.getDataTitle());
253 onImportedResultXml(result);
272 public void onActivityResult(int requestCode, int resultCode, Intent resultData)
276 if (resultCode == Activity.RESULT_OK)
278 if (resultData != null)
280 Uri uri = resultData.getData();
281 if (requestCode == PICK_CSV_FILE)
283 imporObjectFromCsv(uri);
285 else if (requestCode == PICK_XML_FILE)
287 importDataFromXml(uri);
291 Log.v(TAG, "========== rc: " + requestCode + " rs: " + resultCode + " uri: " + uri.toString());
300 // Log.v(TAG, "rc: " + requestCode + " rs: " + resultCode + " it: " + resultData.getDataString());
306 public void onClick(View v)
309 if (id == R.id.SetFilterButton)
312 Log.v(TAG, "Selected Filter");
320 public Menu onCreateOptionsMenu(Menu menu)
324 MenuItem menuItem = menu.add(Menu.NONE, MENU_ID_SHARE, Menu.NONE, parent.getString(R.string.export_csv));
325 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
326 menuItem.setIcon(android.R.drawable.ic_menu_share);
328 menuItem = menu.add(Menu.NONE, MENU_ID_EXPORT, Menu.NONE, parent.getString(R.string.shareContent));
329 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
330 menuItem.setIcon(android.R.drawable.ic_menu_save);
332 menuItem = menu.add(Menu.NONE, MENU_ID_IMPORT, Menu.NONE, parent.getString(R.string.import_csv));
333 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
334 menuItem.setIcon(android.R.drawable.ic_menu_edit);
336 menuItem = menu.add(Menu.NONE, MENU_ID_EXPORT_XML, Menu.NONE, parent.getString(R.string.export_xml));
337 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
338 menuItem.setIcon(android.R.drawable.ic_menu_send);
340 menuItem = menu.add(Menu.NONE, MENU_ID_IMPORT_XML, Menu.NONE, parent.getString(R.string.import_xml));
341 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
342 menuItem.setIcon(android.R.drawable.ic_menu_add);
344 menuItem = menu.add(Menu.NONE, MENU_ID_DELETE, Menu.NONE, parent.getString(R.string.delete_content));
345 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
346 menuItem.setIcon(android.R.drawable.ic_menu_delete);
360 public void onPrepareOptionsMenu(Menu menu)
364 menu.findItem(MENU_ID_SHARE).setVisible(true);
365 menu.findItem(MENU_ID_EXPORT).setVisible(true);
366 menu.findItem(MENU_ID_EXPORT_XML).setVisible(true);
367 menu.findItem(MENU_ID_IMPORT).setVisible(true);
368 menu.findItem(MENU_ID_IMPORT_XML).setVisible(true);
369 menu.findItem(MENU_ID_DELETE).setVisible(true);
378 * メニューのアイテムが選択されたときの処理
381 public boolean onOptionsItemSelected(MenuItem item)
384 switch (item.getItemId())
386 case MENU_ID_EXPORT -> {
388 export_as_csv(false);
391 case MENU_ID_EXPORT_XML -> {
396 case MENU_ID_SHARE -> {
400 case MENU_ID_IMPORT -> {
402 importObjectFromCsv();
405 case MENU_ID_IMPORT_XML -> {
407 importObjectFromXml();
410 case MENU_ID_DELETE -> {
415 default -> result = false;
423 private void importObjectFromXml()
428 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
430 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
431 intent.addCategory(Intent.CATEGORY_OPENABLE);
432 intent.setType("text/*");
433 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
434 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
436 String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() + "/" + APP_NAMESPACE + "/";
437 intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
439 parent.startActivityForResult(intent, PICK_XML_FILE);
443 // 旧バージョンの Android での処理... (File Picker ってあったっけ?)
457 private void deleteContent()
462 FileSelectionDialog dialog = new FileSelectionDialog(parent, parent.getString(R.string.delete_content), ".xml", fileName -> {
463 // fileNameのファイルを削除する...
464 Thread thread = new Thread(() -> {
466 String targetFile = parent.getFilesDir() + "/" + fileName;
467 if (!(new File(targetFile).delete()))
469 Log.v(TAG, "Content Delete Failure : " + fileName);
476 parent.runOnUiThread(() -> {
477 String outputMessage = parent.getString(R.string.delete_content) + " " + fileName;
479 Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
488 dialog.getDialog().show();
500 private void importObjectFromCsv()
503 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
505 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
506 intent.addCategory(Intent.CATEGORY_OPENABLE);
507 intent.setType("text/*");
508 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
509 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
511 String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() + "/" + APP_NAMESPACE + "/";
512 intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
514 parent.startActivityForResult(intent, PICK_CSV_FILE);
518 // 旧バージョンの Android での処理... (File Picker ってあったっけ?)
527 private void export_as_csv(boolean isShare)
529 isShareExportedData = isShare;
531 // AsyncTaskを使ってデータをエクスポートする
532 MeMoMaFileExportCsvProcess asyncTask = new MeMoMaFileExportCsvProcess(parent, this);
533 asyncTask.execute(objectHolder);
539 private void export_as_xml()
543 Thread thread = new Thread(() -> {
546 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
547 String backgroundUri = preferences.getString("backgroundUri", "");
548 String userCheckboxString = preferences.getString("userCheckboxString", "");
549 ExtensionXmlExport exporter = new ExtensionXmlExport(parent, objectHolder, backgroundUri, userCheckboxString);
550 final String result = exporter.exportToXmlFile();
551 parent.runOnUiThread(() -> {
554 onExportedResultXml(result);
564 ee.printStackTrace();
576 * ファイルをロードする途中のバックグラウンド処理...
579 public void onLoadingProcess()
585 listItems = new ArrayList<>();
587 // TODO: 何らかの法則に従って並べ替えをする。
589 Enumeration<Integer> keys = objectHolder.getObjectKeys();
590 while (keys.hasMoreElements())
592 Integer key = keys.nextElement();
593 PositionObject pos = objectHolder.getPosition(key);
596 int objectStyleIcon = MeMoMaObjectHolder .getObjectDrawStyleIcon(pos.getDrawStyle());
599 int userCheckedIcon = (pos.getUserChecked()) ? R.drawable.btn_checked : R.drawable.btn_notchecked;
601 // TODO: アイテム選択時の情報エリアは(ArrayItem側には)用意しているが未使用。
602 SymbolListArrayItem listItem = new SymbolListArrayItem(userCheckedIcon, pos.getLabel(), pos.getDetail(), "", objectStyleIcon);
604 listItems.add(listItem);
610 Log.v(TAG, "ExtensionActivityListener::onLoadingProcess() : " + ex.getMessage());
611 ex.printStackTrace();
619 public void onLoadedResult(boolean isError, String detail)
621 Log.v(TAG, "ExtensionActivityListener::onLoadedResult() '" + objectHolder.getDataTitle() +"' : " + detail);
623 // 読み込んだファイル名をタイトルに設定する
624 parent.setTitle(objectHolder.getDataTitle());
630 //String outputMessage = parent.getString(R.string.load_data) + " " + objectHolder.getDataTitle() + " " + detail;
631 //Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
638 public void onExportedResult(Uri documentUri, String detail)
640 Log.v(TAG, "ExtensionActivityListener::onExportedResult() '" + objectHolder.getDataTitle() +"' : " + detail);
643 String outputMessage = parent.getString(R.string.export_csv) + " " + objectHolder.getDataTitle() + " " + detail;
644 if ((documentUri == null)&&(isShareExportedData))
647 isShareExportedData = false;
648 outputMessage = parent.getString(R.string.exported_data_not_shared) + " : " + objectHolder.getDataTitle() + " " + detail;
650 Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
652 if (isShareExportedData)
655 shareContent(documentUri);
657 isShareExportedData = false;
663 private void updateObjectList()
668 ListView listView = parent.findViewById(R.id.ExtensionView);
669 ListAdapter adapter = new SymbolListArrayAdapter(parent, R.layout.listarrayitems, listItems);
670 listView.setAdapter(adapter);
673 listView.setOnItemClickListener((parentView, view, position, id) -> {
674 ListView listView1 = (ListView) parentView;
675 SymbolListArrayItem item = (SymbolListArrayItem) listView1.getItemAtPosition(position);
677 /// リストが選択されたときの処理...データを開く
678 showDetailData(item.getTextResource1st(), item.getTextResource2nd(), item.getTextResource3rd());
680 System.gc(); // いらない(参照が切れた)クラスを消したい
691 private void shareContent(Uri documentUri)
697 Calendar calendar = Calendar.getInstance();
698 SimpleDateFormat outFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
699 String date = outFormat.format(calendar.getTime());
702 String title = parent.getString(R.string.app_name) + " | "+ objectHolder.getDataTitle() + " | " + date;
705 message = message + "Name : " + objectHolder.getDataTitle() + "\n";
706 message = message + "exported : " + date + "\n";
707 message = message + "number of objects : " + objectHolder.getCount() + "\n";
709 // Share Intentを発行する。
710 SharedIntentInvoker.shareContent(parent, MENU_ID_SHARE, title, message, documentUri, "text/plain");
714 Log.v(TAG, "shareContent (fileName : " + objectHolder.getDataTitle() + ")");
715 ex.printStackTrace();
723 public void selectedFileName(String fileName)
725 // CSVファイルからオブジェクトをロードするクラスを呼び出す。
726 Log.v(TAG, "ExtensionActivityListener::selectedFileName() : " + fileName);
727 MeMoMaFileImportCsvProcess asyncTask = new MeMoMaFileImportCsvProcess(parent, this, fileName);
728 asyncTask.execute(objectHolder);
735 public void onImportedResult(String detail)
737 Log.v(TAG, "ExtensionActivityListener::onImportedResult() '" + objectHolder.getDataTitle() +"' : " + detail);
740 String outputMessage = parent.getString(R.string.import_csv) + " " + objectHolder.getDataTitle() + " " + detail;
741 Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
748 private void onImportedResultXml(String detail)
750 String title = objectHolder.getDataTitle();
751 Log.v(TAG, "ExtensionActivityListener::onImportedResultXml() '" + title + "' : " + detail);
753 // インポート時の注意事項ダイアログを表示する
754 parent.runOnUiThread(() -> {
756 new AlertDialog.Builder(parent)
757 .setIcon(android.R.drawable.ic_dialog_alert)
758 .setTitle(parent.getString(R.string.import_xml) + " (" + objectHolder.getDataTitle() + ")")
759 .setMessage(parent.getString(R.string.import_xml_information))
760 .setPositiveButton(parent.getString(R.string.confirmYes), null)
764 String outputMessage = parent.getString(R.string.import_xml) + " " + objectHolder.getDataTitle() + " " + detail;
765 Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
769 setPreferenceString(title);
775 private void onExportedResultXml(String detail)
777 Log.v(TAG, "ExtensionActivityListener::onExportedResultXml() '" + objectHolder.getDataTitle() +"' : " + detail);
780 String outputMessage = parent.getString(R.string.export_xml) + " " + objectHolder.getDataTitle() + " " + detail;
781 Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();