OSDN Git Service

xml形式のデータインポートとエクスポート機能を搭載している途中。
authorMRSa <mrsa@myad.jp>
Tue, 2 May 2023 15:25:06 +0000 (00:25 +0900)
committerMRSa <mrsa@myad.jp>
Tue, 2 May 2023 15:25:06 +0000 (00:25 +0900)
13 files changed:
app/src/main/AndroidManifest.xml
app/src/main/java/jp/sourceforge/gokigen/memoma/Main.kt
app/src/main/java/jp/sourceforge/gokigen/memoma/MeMoMaListener.java
app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionActivity.java
app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionActivityListener.java
app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionCsvImport.kt
app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlExport.kt [new file with mode: 0644]
app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlImport.kt [new file with mode: 0644]
app/src/main/java/jp/sourceforge/gokigen/memoma/io/MeMoMaDataInOutManager.java
app/src/main/java/jp/sourceforge/gokigen/memoma/io/MeMoMaFileImportCsvProcess.java
app/src/main/java/jp/sourceforge/gokigen/memoma/io/MeMoMaFileSavingEngine.java
app/src/main/res/values-ja/strings.xml
app/src/main/res/values/strings.xml

index 71559e1..1ac74b2 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/Theme.AppCompat">
         <activity android:name=".Main"
             android:exported="true">
index 5b6e2b2..3ef5fac 100644 (file)
@@ -1,13 +1,18 @@
 package jp.sourceforge.gokigen.memoma
 
+import android.Manifest
 import android.app.Dialog
 import android.content.Intent
+import android.content.pm.PackageManager
 import android.os.Bundle
 import android.util.Log
 import android.view.Menu
 import android.view.MenuItem
 import android.view.Window
+import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
 import jp.sourceforge.gokigen.memoma.io.MeMoMaDataInOutManager
 
 /**
@@ -42,6 +47,19 @@ class Main : AppCompatActivity()
         {
             e.printStackTrace()
         }
+
+        try
+        {
+            if (!allPermissionsGranted())
+            {
+                ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
+            }
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+
         Log.v(TAG, " START MEMOMA...");
     }
 
@@ -94,7 +112,9 @@ class Main : AppCompatActivity()
         }
         return false
     }
-
+    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
+        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
+    }
     /**
      * 画面が裏に回ったときの処理
      */
@@ -227,8 +247,24 @@ class Main : AppCompatActivity()
         }
     }
 
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray)
+    {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        if (requestCode == REQUEST_CODE_PERMISSIONS)
+        {
+            if (!allPermissionsGranted())
+            {
+                Toast.makeText(this, getString(R.string.permission_not_granted), Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+
     companion object {
         const val APP_NAMESPACE = "gokigen"
         private val TAG = Main::class.java.simpleName
+        private const val REQUEST_CODE_PERMISSIONS = 10
+        private val REQUIRED_PERMISSIONS = arrayOf(
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+        )
     }
 }
index 0209424..f5772d2 100644 (file)
@@ -620,6 +620,7 @@ public class MeMoMaListener implements OnClickListener, OnTouchListener, OnKeyLi
 
         // データ表示用Activityを起動する
         parent.startActivityForResult(intent, MENU_ID_EXTEND);
+        //parent.startActivity(intent);
     }
 
     /**
index 5393d8c..19f5c8a 100644 (file)
@@ -1,6 +1,5 @@
 package jp.sourceforge.gokigen.memoma.extension;
 
-import android.app.Dialog;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.Menu;
@@ -63,9 +62,9 @@ public class ExtensionActivity extends AppCompatActivity
         {
             e.printStackTrace();
         }
-       return (super.onCreateOptionsMenu(menu));
+        return (super.onCreateOptionsMenu(menu));
     }
-    
+
     /**
      *  メニューアイテムの選択
      */
@@ -89,7 +88,7 @@ public class ExtensionActivity extends AppCompatActivity
         {
             e.printStackTrace();
         }
-       return (super.onPrepareOptionsMenu(menu));
+        return (super.onPrepareOptionsMenu(menu));
     }
 
     /**
@@ -184,33 +183,6 @@ public class ExtensionActivity extends AppCompatActivity
     }
 
     /**
-     *  ダイアログ表示の準備
-     * 
-     */
-    @Override
-    protected Dialog onCreateDialog(int id)
-    {
-       return (listener.onCreateDialog(id));
-    }
-
-    /**
-     *  ダイアログ表示の準備
-     * 
-     */
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog)
-    {
-        try
-        {
-            listener.onPrepareDialog(id, dialog);
-        }
-        catch (Exception e)
-        {
-            e.printStackTrace();
-        }
-    }
-    
-    /**
      *  子画面から応答をもらったときの処理
      */
     @Override
index d9c757a..6b7d8fa 100644 (file)
@@ -10,7 +10,6 @@ import java.util.List;
 import java.util.Locale;
 
 import android.app.Activity;
-import android.app.Dialog;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.net.Uri;
@@ -23,7 +22,6 @@ import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.AdapterView;
 import android.widget.ImageButton;
 import android.widget.ListAdapter;
 import android.widget.ListView;
@@ -51,17 +49,19 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
 {
     private final String TAG = toString();
     private static final int PICK_CSV_FILE = 2020;
+    private static final int PICK_XML_FILE = 2030;
+
     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 final int MENU_ID_EXPORT_XML = (Menu.FIRST + 2);
+    private final int MENU_ID_SHARE = (Menu.FIRST + 3);
+    private final int MENU_ID_IMPORT = (Menu.FIRST + 4);
+    private final int MENU_ID_IMPORT_XML = (Menu.FIRST + 5);
+    private final int MENU_ID_DELETE = (Menu.FIRST + 6);
 
        private final MeMoMaObjectHolder objectHolder;
-       private FileSelectionDialog fileSelectionDialog = null;
-       
+       //private FileSelectionDialog fileSelectionDialog = null;
        private boolean isShareExportedData = false;
-
        private List<SymbolListArrayItem> listItems = null;
-    
     private final AppCompatActivity parent;  // 親分
 
        /**
@@ -84,13 +84,12 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
          }
         catch (Exception ex)
         {
-            Log.v(TAG, "Exception :" + ex.toString());
+            Log.v(TAG, "Exception :" + ex.getMessage());
         }        
     }
 
     /**
      *  がっつりこのクラスにイベントリスナを接続する
-     * 
      */
     public void prepareListener()
     {
@@ -151,7 +150,95 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
     {
        
     }
-    
+
+    private void imporObjectFromCsv(final Uri uri)
+    {
+        try
+        {
+            // 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();
+                    }
+                });
+            });
+            thread.start();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private void importDataFromXml(final Uri uri)
+    {
+        try
+        {
+            // Perform operations on the document using its URI.
+            Thread thread = new Thread(() -> {
+                SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
+                String backgroundUri = preferences.getString("backgroundUri","");
+                String userCheckboxString = preferences.getString("userCheckboxString","");
+
+                // データの保管を実施する (現状)
+                MeMoMaFileSavingEngine savingEngine = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
+                String result0 = savingEngine.saveObjects(objectHolder);
+                Log.v(TAG, "Saved : " + result0);
+
+                //
+                ExtensionXmlImport importer = new ExtensionXmlImport(parent, objectHolder, uri);
+                String result1 = importer.importFromXmlFile();
+
+                // データの保管を実施する (新規)
+                MeMoMaFileSavingEngine savingEngine2 = new MeMoMaFileSavingEngine(parent, backgroundUri, userCheckboxString);
+                String result = savingEngine2.saveObjects(objectHolder) + " " + result1;
+                Log.v(TAG, "=== Data Saved : " + objectHolder.getDataTitle() + " " + result + " " + result1);
+                parent.runOnUiThread(() -> {
+                    try
+                    {
+                        // 読み込んだファイル名をタイトルに設定する
+                        parent.setTitle(objectHolder.getDataTitle());
+
+                        // タイトルバーの更新...
+                        ActionBar bar = parent.getSupportActionBar();
+                        if (bar != null)
+                        {
+                            bar.setIcon(R.drawable.icon1);
+                            bar.setTitle(objectHolder.getDataTitle());
+                            bar.show();
+                        }
+                        onImportedResultXml(result);
+                    }
+                    catch (Exception e)
+                    {
+                        e.printStackTrace();
+                    }
+                });
+            });
+            thread.start();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
     /**
      *  他画面から戻ってきたとき...
      */
@@ -159,44 +246,22 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
     {
         try
         {
-            if ((requestCode == PICK_CSV_FILE)&&(resultCode == Activity.RESULT_OK))
+            if (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
+                    if (requestCode == PICK_CSV_FILE)
+                    {
+                        imporObjectFromCsv(uri);
+                    }
+                    else if (requestCode == PICK_XML_FILE)
                     {
-                        thread.start();
+                        importDataFromXml(uri);
                     }
-                    catch (Exception ee)
+                    else
                     {
-                        ee.printStackTrace();
+                        Log.v(TAG, "========== rc: " + requestCode + " rs: " + resultCode + " uri: "  + uri.toString());
                     }
                 }
             }
@@ -240,6 +305,19 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
             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);
+
+            menuItem = menu.add(Menu.NONE, MENU_ID_EXPORT_XML, Menu.NONE, parent.getString(R.string.export_xml));
+            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            menuItem.setIcon(android.R.drawable.ic_menu_send);
+
+            menuItem = menu.add(Menu.NONE, MENU_ID_IMPORT_XML, Menu.NONE, parent.getString(R.string.import_xml));
+            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            menuItem.setIcon(android.R.drawable.ic_menu_add);
+
+            menuItem = menu.add(Menu.NONE, MENU_ID_DELETE, Menu.NONE, parent.getString(R.string.delete_content));
+            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            menuItem.setIcon(android.R.drawable.ic_menu_delete);
+
         }
         catch (Exception e)
         {
@@ -258,7 +336,10 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
         {
             menu.findItem(MENU_ID_SHARE).setVisible(true);
             menu.findItem(MENU_ID_EXPORT).setVisible(true);
+            menu.findItem(MENU_ID_EXPORT_XML).setVisible(true);
             menu.findItem(MENU_ID_IMPORT).setVisible(true);
+            menu.findItem(MENU_ID_IMPORT_XML).setVisible(true);
+            menu.findItem(MENU_ID_DELETE).setVisible(true);
         }
         catch (Exception e)
         {
@@ -280,6 +361,11 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
                 export_as_csv(false);
                 result = true;
             }
+            case MENU_ID_EXPORT_XML -> {
+                // 表示中データのエクスポート
+                export_as_xml();
+                result = true;
+            }
             case MENU_ID_SHARE -> {
                 export_as_csv(true);
                 result = true;
@@ -289,11 +375,72 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
                 importObjectFromCsv();
                 result = true;
             }
+            case MENU_ID_IMPORT_XML -> {
+                // データのインポート(XML形式)
+                importObjectFromXml();
+                result = true;
+            }
+            case MENU_ID_DELETE -> {
+                // データの削除
+                deleteContent();
+                result = true;
+            }
             default -> result = false;
         }
        return (result);
     }
 
+    /**
+     *   XML形式でデータをインポートする
+     */
+    private void importObjectFromXml()
+    {
+        try
+        {
+            // ファイル選択のダイアログを取得する
+            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_XML_FILE);
+            }
+            else
+            {
+                // 旧バージョンの Android での処理... (File Picker ってあったっけ?)
+
+
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     *   データを削除する
+     */
+    private void deleteContent()
+    {
+        try
+        {
+            //  データの一覧を取得する
+
+
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
 
     /**
      *   CSV形式でデータをインポートする
@@ -333,30 +480,39 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
        MeMoMaFileExportCsvProcess asyncTask = new MeMoMaFileExportCsvProcess(parent, this);
         asyncTask.execute(objectHolder);
     }
-    
-    /**
-     *  ダイアログの生成
-     */
-    public Dialog onCreateDialog(int id)
-    {
-       if (id == R.id.listdialog)
-       {
-               fileSelectionDialog = new FileSelectionDialog(parent, parent.getString(R.string.dialogtitle_selectcsv), ".csv",  this);
-               return (fileSelectionDialog.getDialog());
-       }
-           return (null);
-    }
 
     /**
-     *    ファイル選択ダイアログの表示を準備する
-     * 
+     *   データをXML形式で出力する
      */
-    private void prepareFileSelectionDialog(Dialog dialog)
+    private void export_as_xml()
     {
         try
         {
-            Log.v(TAG, " " + dialog.toString());
-            fileSelectionDialog.prepare();
+            Thread thread = new Thread(() -> {
+                try
+                {
+                    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
+                    String backgroundUri = preferences.getString("backgroundUri", "");
+                    String userCheckboxString = preferences.getString("userCheckboxString", "");
+                    ExtensionXmlExport exporter = new ExtensionXmlExport(parent, objectHolder, backgroundUri, userCheckboxString);
+                    final String result = exporter.exportToXmlFile();
+                    parent.runOnUiThread(() -> {
+                        try
+                        {
+                            onExportedResultXml(result);
+                        }
+                        catch (Exception e)
+                        {
+                            e.printStackTrace();
+                        }
+                    });
+                }
+                catch (Exception ee)
+                {
+                    ee.printStackTrace();
+                }
+            });
+            thread.start();
         }
         catch (Exception e)
         {
@@ -365,19 +521,6 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
     }
 
     /**
-     *  ダイアログ表示の準備
-     * 
-     */
-    public void onPrepareDialog(int id, Dialog dialog)
-    {
-        if (id == R.id.listdialog)
-        {
-               // CSVインポートダイアログを準備する
-               prepareFileSelectionDialog(dialog);
-        }
-    }
-
-    /**
      *    ファイルをロードする途中のバックグラウンド処理...
      * 
      */
@@ -440,18 +583,18 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
      */
     public void onExportedResult(Uri documentUri, String detail)
     {
-               Log.v(TAG, "ExtensionActivityListener::onExportedResult() '"  + objectHolder.getDataTitle() +"' : " + detail);
+        Log.v(TAG, "ExtensionActivityListener::onExportedResult() '"  + objectHolder.getDataTitle() +"' : " + detail);
 
-               // エクスポートしたことを伝達する
-               String outputMessage = parent.getString(R.string.export_csv) + " " + objectHolder.getDataTitle() + " " + detail;
+        // エクスポートしたことを伝達する
+        String outputMessage = parent.getString(R.string.export_csv) + " " + objectHolder.getDataTitle() + " " + detail;
         Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
-        
+
         if (isShareExportedData)
         {
-               // エクスポートしたファイルを共有する
+            // エクスポートしたファイルを共有する
             shareContent(documentUri);
         }
-       isShareExportedData = false;
+        isShareExportedData = false;
     }
     
     /**
@@ -467,16 +610,12 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
             listView.setAdapter(adapter);
 
             // アイテムを選択したときの処理
-            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-                //@Override
-                public void onItemClick(AdapterView<?> parentView, View view, int position, long id)
-                {
-                    ListView listView = (ListView) parentView;
-                    SymbolListArrayItem item = (SymbolListArrayItem) listView.getItemAtPosition(position);
+            listView.setOnItemClickListener((parentView, view, position, id) -> {
+                ListView listView1 = (ListView) parentView;
+                SymbolListArrayItem item = (SymbolListArrayItem) listView1.getItemAtPosition(position);
 
-                    /// リストが選択されたときの処理...データを開く
-                    showDetailData(item.getTextResource1st(), item.getTextResource2nd(), item.getTextResource3rd());
-                }
+                /// リストが選択されたときの処理...データを開く
+                showDetailData(item.getTextResource1st(), item.getTextResource2nd(), item.getTextResource3rd());
             });
             System.gc();   // いらない(参照が切れた)クラスを消したい
        }
@@ -544,5 +683,27 @@ public class ExtensionActivityListener  implements OnClickListener, MeMoMaFileLo
         // 一覧のリストを作りなおす
         onLoadingProcess();
         updateObjectList();
-    }    
+    }
+
+    private void onImportedResultXml(String detail)
+    {
+        Log.v(TAG, "ExtensionActivityListener::onImportedResultXml() '"  + objectHolder.getDataTitle() +"' : " + detail);
+
+        // インポートしたことを伝達する
+        String outputMessage = parent.getString(R.string.import_xml) + " " + objectHolder.getDataTitle() + " " + detail;
+        Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
+
+        // 一覧のリストを作りなおす
+        onLoadingProcess();
+        updateObjectList();
+    }
+    private void onExportedResultXml(String detail)
+    {
+        Log.v(TAG, "ExtensionActivityListener::onExportedResultXml() '"  + objectHolder.getDataTitle() +"' : " + detail);
+
+        // エクスポートしたことを伝達する
+        String outputMessage = parent.getString(R.string.export_xml) + " " + objectHolder.getDataTitle() + " " + detail;
+        Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
+    }
+
 }
index a1c447e..22f549f 100644 (file)
@@ -8,7 +8,6 @@ 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()
@@ -144,5 +143,4 @@ class ExtensionCsvImport(private val context: Context, private val objectHolder:
     companion object {
         private val TAG = ExtensionCsvImport::class.java.simpleName
     }
-
 }
\ No newline at end of file
diff --git a/app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlExport.kt b/app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlExport.kt
new file mode 100644 (file)
index 0000000..701cee3
--- /dev/null
@@ -0,0 +1,196 @@
+package jp.sourceforge.gokigen.memoma.extension
+
+import android.content.ContentValues
+import android.content.Context
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.MediaStore
+import android.util.Log
+import android.util.Xml
+import jp.sourceforge.gokigen.memoma.Main
+import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder
+import java.io.File
+import java.io.OutputStreamWriter
+import java.text.SimpleDateFormat
+import java.util.Calendar
+import java.util.Locale
+
+class ExtensionXmlExport(private val context: Context, private val objectHolder: MeMoMaObjectHolder, private val backgroundUri: String, private val userCheckboxString: String)
+{
+    fun exportToXmlFile(): String
+    {
+        var resultMessage = ""
+        try
+        {
+            val outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path + "/" + Main.APP_NAMESPACE + "/"
+            val resolver = context.contentResolver
+
+            // エクスポートするファイル名を決定する
+            val calendar = Calendar.getInstance()
+            val outFormat = SimpleDateFormat("yyyyMMdd_HHmmss_", Locale.US)
+            val exportedFileName = outFormat.format(calendar.time) + objectHolder.dataTitle + ".xml"
+            val extStorageUri: Uri
+            val values = ContentValues()
+            values.put(MediaStore.Downloads.TITLE, exportedFileName)
+            values.put(MediaStore.Downloads.DISPLAY_NAME, exportedFileName)
+            values.put(MediaStore.Downloads.MIME_TYPE, "text/xml") // text/plain or text/xml
+            extStorageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+            {
+                values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/" + Main.APP_NAMESPACE)
+                values.put(MediaStore.Downloads.IS_PENDING, true)
+                MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
+            }
+            else
+            {
+                val path = File(outputDir)
+                values.put(MediaStore.Downloads.DATA, path.absolutePath + File.separator + exportedFileName)
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+            }
+            Log.v(TAG, "---------- $exportedFileName $values")
+            val documentUri = resolver.insert(extStorageUri, values)
+            if (documentUri == null)
+            {
+                resultMessage = "documentUri is NULL."
+                return resultMessage
+            }
+            val outputStream = resolver.openOutputStream(documentUri, "wa")
+            val writer = OutputStreamWriter(outputStream)
+            val serializer = Xml.newSerializer()
+            serializer.setOutput(writer)
+            serializer.startDocument("UTF-8", true)
+            serializer.startTag(Main.APP_NAMESPACE, "memoma")
+
+            // タイトルの出力
+            serializer.startTag(Main.APP_NAMESPACE, "title")
+            serializer.text(objectHolder.dataTitle)
+            serializer.endTag(Main.APP_NAMESPACE, "title")
+
+            // 背景情報の出力
+            serializer.startTag(Main.APP_NAMESPACE, "background")
+            serializer.text(objectHolder.background)
+            serializer.endTag(Main.APP_NAMESPACE, "background")
+
+            // 背景画像URIの出力
+            serializer.startTag(Main.APP_NAMESPACE, "backgroundUri")
+            serializer.text(backgroundUri)
+            serializer.endTag(Main.APP_NAMESPACE, "backgroundUri")
+
+            // ユーザチェックボックス名の出力
+            serializer.startTag(Main.APP_NAMESPACE, "userCheckboxString")
+            serializer.text(userCheckboxString)
+            serializer.endTag(Main.APP_NAMESPACE, "userCheckboxString")
+
+            serializer.startTag(Main.APP_NAMESPACE, "objserial")
+            serializer.text(objectHolder.serialNumber.toString())
+            serializer.endTag(Main.APP_NAMESPACE, "objserial")
+
+            serializer.startTag(Main.APP_NAMESPACE, "lineserial")
+            serializer.text(objectHolder.connectLineHolder.serialNumber.toString())
+            serializer.endTag(Main.APP_NAMESPACE, "lineserial")
+
+            // オブジェクトの出力 (保持しているものはすべて表示する)
+            val keys = objectHolder.objectKeys
+            while (keys.hasMoreElements())
+            {
+                val key = keys.nextElement()
+                val pos = objectHolder.getPosition(key)
+                val posRect = pos.rect
+                serializer.startTag(Main.APP_NAMESPACE, "object")
+                serializer.attribute(Main.APP_NAMESPACE, "key", key.toString())
+                serializer.startTag(Main.APP_NAMESPACE, "rect")
+                serializer.startTag(Main.APP_NAMESPACE, "top")
+                serializer.text(posRect.top.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "top")
+                serializer.startTag(Main.APP_NAMESPACE, "left")
+                serializer.text(posRect.left.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "left")
+                serializer.startTag(Main.APP_NAMESPACE, "right")
+                serializer.text(posRect.right.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "right")
+                serializer.startTag(Main.APP_NAMESPACE, "bottom")
+                serializer.text(posRect.bottom.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "bottom")
+                serializer.endTag(Main.APP_NAMESPACE, "rect")
+                serializer.startTag(Main.APP_NAMESPACE, "drawStyle")
+                serializer.text(pos.drawStyle.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "drawStyle")
+                serializer.startTag(Main.APP_NAMESPACE, "icon")
+                serializer.text(pos.icon.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "icon")
+                serializer.startTag(Main.APP_NAMESPACE, "label")
+                serializer.text(pos.label)
+                serializer.endTag(Main.APP_NAMESPACE, "label")
+                serializer.startTag(Main.APP_NAMESPACE, "detail")
+                serializer.text(pos.detail)
+                serializer.endTag(Main.APP_NAMESPACE, "detail")
+                serializer.startTag(Main.APP_NAMESPACE, "userChecked")
+                serializer.text(pos.userChecked.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "userChecked")
+                serializer.startTag(Main.APP_NAMESPACE, "labelColor")
+                serializer.text(pos.labelColor.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "labelColor")
+                serializer.startTag(Main.APP_NAMESPACE, "objectColor")
+                serializer.text(pos.objectColor.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "objectColor")
+                serializer.startTag(Main.APP_NAMESPACE, "paintStyle")
+                serializer.text(pos.paintStyle)
+                serializer.endTag(Main.APP_NAMESPACE, "paintStyle")
+                serializer.startTag(Main.APP_NAMESPACE, "strokeWidth")
+                serializer.text(pos.getstrokeWidth().toString())
+                serializer.endTag(Main.APP_NAMESPACE, "strokeWidth")
+                serializer.startTag(Main.APP_NAMESPACE, "fontSize")
+                serializer.text(pos.fontSize.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "fontSize")
+                serializer.endTag(Main.APP_NAMESPACE, "object")
+            }
+
+            // 接続線の出力 (保持しているものはすべて表示する)
+            val lineKeys = objectHolder.connectLineHolder.lineKeys
+            while (lineKeys.hasMoreElements())
+            {
+                val key = lineKeys.nextElement()
+                val line = objectHolder.connectLineHolder.getLine(key)
+                serializer.startTag(Main.APP_NAMESPACE, "line")
+                serializer.attribute(Main.APP_NAMESPACE, "key", key.toString())
+                serializer.startTag(Main.APP_NAMESPACE, "fromObjectKey")
+                serializer.text(line.fromObjectKey.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "fromObjectKey")
+                serializer.startTag(Main.APP_NAMESPACE, "toObjectKey")
+                serializer.text(line.toObjectKey.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "toObjectKey")
+                serializer.startTag(Main.APP_NAMESPACE, "lineStyle")
+                serializer.text(line.lineStyle.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "lineStyle")
+                serializer.startTag(Main.APP_NAMESPACE, "lineShape")
+                serializer.text(line.lineShape.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "lineShape")
+                serializer.startTag(Main.APP_NAMESPACE, "lineThickness")
+                serializer.text(line.lineThickness.toString())
+                serializer.endTag(Main.APP_NAMESPACE, "lineThickness")
+                serializer.endTag(Main.APP_NAMESPACE, "line")
+            }
+
+            serializer.endTag(Main.APP_NAMESPACE, "memoma")
+            serializer.endDocument()
+            writer.flush()
+            writer.close()
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+            {
+                values.put(MediaStore.Downloads.IS_PENDING, false)
+                resolver.update(documentUri, values, null, null)
+            }
+        }
+        catch (e: Exception)
+        {
+            resultMessage = " ERR " + e.message
+            Log.v(TAG, resultMessage)
+            e.printStackTrace()
+        }
+        return resultMessage
+    }
+
+    companion object {
+        private val TAG = ExtensionXmlExport::class.java.simpleName
+    }
+}
diff --git a/app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlImport.kt b/app/src/main/java/jp/sourceforge/gokigen/memoma/extension/ExtensionXmlImport.kt
new file mode 100644 (file)
index 0000000..c3a8e27
--- /dev/null
@@ -0,0 +1,175 @@
+package jp.sourceforge.gokigen.memoma.extension
+
+import android.content.Context
+import android.graphics.RectF
+import android.net.Uri
+import android.util.Log
+import android.util.Xml
+import jp.sourceforge.gokigen.memoma.Main
+import jp.sourceforge.gokigen.memoma.holders.MeMoMaObjectHolder
+import jp.sourceforge.gokigen.memoma.holders.ObjectConnector
+import jp.sourceforge.gokigen.memoma.holders.PositionObject
+import org.xmlpull.v1.XmlPullParser
+import java.io.BufferedReader
+import java.io.InputStream
+import java.io.InputStreamReader
+
+class ExtensionXmlImport(private val context: Context, private val objectHolder: MeMoMaObjectHolder, private val importUri: Uri)
+{
+    private var position: PositionObject? = null
+    private var line: ObjectConnector? = null
+    private var backgroundUri = ""
+    private var userCheckboxString = ""
+
+    fun importFromXmlFile() : String
+    {
+        var resultMessage = ""
+        val parser = Xml.newPullParser()
+        try
+        {
+            val inputStream: InputStream? = context.contentResolver.openInputStream(importUri)
+            val reader = BufferedReader(InputStreamReader(inputStream))
+            parser.setInput(reader)
+            var eventType = parser.eventType
+
+            // オブジェクトとラインをすべてクリアする
+            objectHolder.removeAllPositions()
+            val lineHolder = objectHolder.connectLineHolder ?: return "ERR>lineHolder is null."
+            lineHolder.removeAllLines()
+            while (eventType != XmlPullParser.END_DOCUMENT)
+            {
+                when (eventType)
+                {
+                    XmlPullParser.START_DOCUMENT -> {}
+                    XmlPullParser.START_TAG -> parseStartTag(parser.name, parser, objectHolder)
+                    XmlPullParser.END_TAG -> parseEndTag(parser.name)
+                    else -> {}
+                }
+                eventType = parser.next()
+            }
+            reader.close()
+        }
+        catch (e: Exception)
+        {
+            resultMessage = " ERR " + e.message
+            Log.v(TAG, resultMessage)
+            e.printStackTrace()
+        }
+        return resultMessage
+    }
+
+    private fun parseStartTag(
+        name: String,
+        parser: XmlPullParser,
+        objectHolder: MeMoMaObjectHolder?
+    )
+    {
+        try
+        {
+            if (name.equals("top", ignoreCase = true) && position != null) {
+                position?.setRectTop(parser.nextText().toFloat())
+            } else if (name.equals("bottom", ignoreCase = true) && position != null) {
+                position?.setRectBottom(parser.nextText().toFloat())
+            } else if (name.equals("left", ignoreCase = true) && position != null) {
+                position?.setRectLeft(parser.nextText().toFloat())
+            } else if (name.equals("right", ignoreCase = true) && position != null) {
+                position?.setRectRight(parser.nextText().toFloat())
+            } else if (name.equals("drawStyle", ignoreCase = true) && position != null) {
+                position?.setDrawStyle(parser.nextText().toInt())
+            } else if (name.equals("icon", ignoreCase = true) && position != null) {
+                position?.setIcon(parser.nextText().toInt())
+            } else if (name.equals("label", ignoreCase = true) && position != null) {
+                position?.setLabel(parser.nextText())
+            } else if (name.equals("detail", ignoreCase = true) && position != null) {
+                position?.setDetail(parser.nextText())
+            } else if (name.equals("userChecked", ignoreCase = true) && position != null) {
+                val parseData = parser.nextText()
+                position?.setUserChecked(parseData.equals("true", ignoreCase = true))
+            } else if (name.equals("labelColor", ignoreCase = true) && position != null) {
+                position?.setLabelColor(parser.nextText().toInt())
+            } else if (name.equals("objectColor", ignoreCase = true) && position != null) {
+                position?.setObjectColor(parser.nextText().toInt())
+            } else if (name.equals("paintStyle", ignoreCase = true) && position != null) {
+                position?.setPaintStyle(parser.nextText())
+            } else if (name.equals("strokeWidth", ignoreCase = true) && position != null) {
+                position?.setStrokeWidth(parser.nextText().toFloat())
+            } else if (name.equals("fontSize", ignoreCase = true) && position != null) {
+                position?.setFontSize(parser.nextText().toFloat())
+            } else if (name.equals("fromObjectKey", ignoreCase = true) && line != null) {
+                line?.setFromObjectKey(parser.nextText().toInt())
+            } else if (name.equals("toObjectKey", ignoreCase = true) && line != null) {
+                line?.setToObjectKey(parser.nextText().toInt())
+            } else if (name.equals("lineStyle", ignoreCase = true) && line != null) {
+                line?.setLineStyle(parser.nextText().toInt())
+            } else if (name.equals("lineShape", ignoreCase = true) && line != null) {
+                line?.setLineShape(parser.nextText().toInt())
+            } else if (name.equals("lineThickness", ignoreCase = true) && line != null) {
+                line?.setLineThickness(parser.nextText().toInt())
+            } else if (name.equals("title", ignoreCase = true) && objectHolder != null) {
+                objectHolder.dataTitle = parser.nextText()
+            } else if (name.equals("background", ignoreCase = true) && objectHolder != null) {
+                objectHolder.background = parser.nextText()
+            } else if (name.equals("backgroundUri", ignoreCase = true) && objectHolder != null) {
+                backgroundUri = parser.nextText()
+            } else if (name.equals(
+                    "userCheckboxString",
+                    ignoreCase = true
+                ) && objectHolder != null
+            ) {
+                userCheckboxString = parser.nextText()
+            } else if (name.equals("objserial", ignoreCase = true) && objectHolder != null) {
+                objectHolder.serialNumber = parser.nextText().toInt()
+                //Log.v(Main.APP_IDENTIFIER, "objSerial : " + objectHolder.getSerialNumber());
+            } else if (name.equals("lineserial", ignoreCase = true) && objectHolder != null) {
+                objectHolder.connectLineHolder.serialNumber = parser.nextText().toInt()
+                //Log.v(Main.APP_IDENTIFIER, "lineSerial : " + objectHolder.getSerialNumber());
+            } else if (name.equals("object", ignoreCase = true)) {
+                val key = parser.getAttributeValue(Main.APP_NAMESPACE, "key").toInt()
+                //Log.v(Main.APP_IDENTIFIER, "create object, key :" + key);
+                if (objectHolder != null) {
+                    position = objectHolder.createPosition(key)
+                }
+            } else if (name.equals("line", ignoreCase = true)) {
+                val key = parser.getAttributeValue(Main.APP_NAMESPACE, "key").toInt()
+                //Log.v(Main.APP_IDENTIFIER, "create line, key :" + key);
+                line = null
+                if (objectHolder != null) {
+                    line = objectHolder.connectLineHolder.createLine(key)
+                }
+            }
+        } catch (e: java.lang.Exception) {
+            Log.v(TAG, "ERR>parseStartTag() name:$name $e")
+        }
+    }
+    private fun parseEndTag(name: String)
+    {
+        try
+        {
+            if (name.equals("object", ignoreCase = true))
+            {
+                // 領域サイズがおかしい場合には、オブジェクトサイズを補正する (ふつーありえないはずなんだけど...)
+                val posRect: RectF? = position?.rect
+                if (posRect != null)
+                {
+                    if (posRect.left > posRect.right || posRect.top > posRect.bottom)
+                    {
+                        Log.v(
+                            TAG,
+                            "RECT IS ILLEGAL. : [" + posRect.left + "," + posRect.top + "-[" + posRect.right + "," + posRect.bottom + "]"
+                        )
+                        position?.setRectRight(posRect.left + MeMoMaObjectHolder.OBJECTSIZE_DEFAULT_X)
+                        position?.setRectBottom(posRect.top + MeMoMaObjectHolder.OBJECTSIZE_DEFAULT_Y)
+                    }
+                }
+            }
+        }
+        catch (e: Exception)
+        {
+            Log.v(TAG, "ERR>parseEndTag() name:$name $e")
+        }
+    }
+
+    companion object {
+        private val TAG = ExtensionXmlImport::class.java.simpleName
+    }
+}
index 9750c98..ae32006 100644 (file)
@@ -269,12 +269,12 @@ public class MeMoMaDataInOutManager implements MeMoMaFileSavingProcess.ISavingSt
      *    ファイルのエクスポート結果を受け取る
      */
        public void onCaptureLayoutExportedResult(Uri exportedUri, String detail, int id)
-    {
+       {
                Log.v(TAG, "MeMoMaDataInOutManager::onCaptureExportedResult() '"  + objectHolder.getDataTitle() +"' : " + detail + " " + exportedUri.toString());
 
                // エクスポートしたことを伝達する
                String outputMessage = parent.getString(R.string.capture_data) + " " + objectHolder.getDataTitle() + " " + detail;
-        Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
+               Toast.makeText(parent, outputMessage, Toast.LENGTH_SHORT).show();
 
                try
                {
@@ -289,7 +289,7 @@ public class MeMoMaDataInOutManager implements MeMoMaFileSavingProcess.ISavingSt
                        e.printStackTrace();
                }
                isShareExportedData = false;
-    }
+       }
 
     /**
      *    エクスポートしたファイルを共有する
index e79e2d8..b2ee38b 100644 (file)
@@ -193,10 +193,7 @@ public class MeMoMaFileImportCsvProcess extends AsyncTask<MeMoMaObjectHolder, In
     
     /**
      *    (CSV形式の)データを読み込んで格納する。
-     * 
-     * @param fileName
-     * @param objectHolder
-     * @return
+     *
      */
     private String importFromCsvFile(String fileName, MeMoMaObjectHolder objectHolder)
     {
@@ -208,7 +205,7 @@ public class MeMoMaFileImportCsvProcess extends AsyncTask<MeMoMaObjectHolder, In
             String dataLine = readRecord(buf);
             while (dataLine != null)
             {
-                       if (dataLine.startsWith(";") != true)
+                       if (!dataLine.startsWith(";"))
                        {
                                // データ行だった。ログに出力する!
                     parseRecord(dataLine, objectHolder);
@@ -219,7 +216,7 @@ public class MeMoMaFileImportCsvProcess extends AsyncTask<MeMoMaObjectHolder, In
         }
         catch (Exception e)
         {
-               resultMessage = " ERR(import)>" + e.toString();
+               resultMessage = " ERR(import) " + e.getMessage();
             Log.v(TAG, resultMessage);
             e.printStackTrace();
         } 
index 159c24a..d27b461 100644 (file)
@@ -29,13 +29,13 @@ public class MeMoMaFileSavingEngine
        /**
         *   コンストラクタ
         */
-       public MeMoMaFileSavingEngine(Context context, String bgUri, String checkBoxLabel)
+    public MeMoMaFileSavingEngine(Context context, String bgUri, String checkBoxLabel)
     {
         this.context = context;
 
-       //  設定データ読み出し用...。
-       backgroundUri = bgUri;
-       userCheckboxString = checkBoxLabel;
+        //  設定データ読み出し用...。
+        backgroundUri = bgUri;
+        userCheckboxString = checkBoxLabel;
     }
 
     /**
index 3b08ee9..fc0b617 100644 (file)
@@ -72,6 +72,9 @@
     <string name="labelLineShapeSelection">形状</string>
     <string name="Title_SelectLineShape">接続線の設定</string>
     <string name="undo_operation">1つ戻す</string>
-    <string name="permission_not_granted">許å\8f¯ã\81\8cå¾\97ã\82\89ã\82\8cã\81¾ã\81\9bã\82\93ã\81§ã\81\97ã\81\9fã\81®ã\81§çµ\82äº\86ã\81\97ã\81¾ã\81\99ã\80\82</string>
+    <string name="permission_not_granted">許可が得られませんでした。</string>
     <string name="permission_capture_error">許可を得るタイミングでエラーが発生しました。</string>
+    <string name="import_xml">XMLファイルから取り込み&#8230;</string>
+    <string name="export_xml">XMLファイルとして出力&#8230;</string>
+    <string name="delete_content">データの削除&#8230;</string>
 </resources>
index 0752ff1..fdd3381 100644 (file)
@@ -74,4 +74,7 @@
     <string name="undo_operation">Undo</string>
     <string name="permission_not_granted">Permissions not granted by the user.</string>
     <string name="permission_capture_error">Error Occurs at the request permission sequence.</string>
+    <string name="import_xml">Import from XML&#8230;</string>
+    <string name="export_xml">Export from XML&#8230;</string>
+    <string name="delete_content">Delete Content&#8230;</string>
 </resources>