package app.create.rpg.file; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.FileObserver; import android.os.Parcelable; import android.util.Log; import android.widget.Toast; import app.create.rpg.ActivityProject; import app.create.rpg.BuildConfig; import app.create.rpg.R; import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Set; import android.os.Parcel; import java.util.Locale; public abstract class CachedFile extends FileObserver implements Parcelable { protected Object mData; protected File mFile; protected Set<User> mUsers; protected ActivityProject mMain; protected String mName; protected boolean mHasChanged, mDiscarded; public interface User { public void onOpen(CachedFile file); public void onUpdate(CachedFile file); public void onClosed(CachedFile file); } protected void updateSelf () { } protected void notifyAllUsers () { for (User u : mUsers) u.onUpdate(this); } public void notifyChanged () { mHasChanged = true; notifyAllUsers(); } public void onDiscard (boolean byUser) { mHasChanged = false; if (!byUser) { if (mMain == null) mDiscarded = true; else Toast.makeText(mMain, "!stub! err data discarded", Toast.LENGTH_SHORT).show(); } notifyAllUsers(); } public boolean isModified () { return mHasChanged; } public CachedFile(File file, ActivityProject main, String name) { super(file.getAbsolutePath(), MODIFY | DELETE_SELF | MOVE_SELF); mData = null; mFile = file; mUsers = new HashSet<User>(); mMain = main; mName = name; } public CachedFile(Parcel source) { this(new File(source.readString()), null, null); mName = source.readString(); } public void recover (ActivityProject project) { mMain = project; if (mDiscarded) { Toast.makeText (project, "!stub! data discarded 2", Toast.LENGTH_SHORT).show(); mDiscarded = false; } } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mFile.getPath()); dest.writeString(mName); } public Object getData() { return mData; } public File getFile() { return mFile; } public Set<User> getUsers() { return mUsers; } public ActivityProject getMain() { return mMain; } public String getName() { return mName; } public void registerUser(User user) { if (!mUsers.add(user)) return; startWatching(); if (mData == null) { try { load(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(mMain, "Error loading " + mFile.getAbsolutePath(), Toast.LENGTH_SHORT).show(); return; } } user.onOpen(this); } public void unregisterUser(User user) { mUsers.remove(user); if (mUsers.isEmpty()) { terminate(); } } public void terminate() { stopWatching(); for (User u : mUsers) u.onClosed(CachedFile.this); mData = null; System.gc(); mMain.mCache.remove(mName); } public abstract void load() throws IOException; public abstract void save() throws IOException; @Override public void onEvent(final int event, String path) { try { final AlertDialog.Builder builder = new AlertDialog.Builder(mMain); DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { if ((event & MODIFY) == MODIFY) { try { load(); for (User u : mUsers) u.onUpdate(CachedFile.this); } catch (IOException e) { e.printStackTrace(); Toast.makeText(mMain, "Error", Toast.LENGTH_SHORT).show(); } } else if ((event & (DELETE_SELF | MOVE_SELF)) != 0) { terminate(); } } } }; if ((event & MODIFY) == MODIFY) { builder.setMessage(R.string.str_notify_edited); } else if ((event & (DELETE_SELF | MOVE_SELF)) != 0) { builder.setMessage(R.string.str_ask_close_page); } else return; builder.setPositiveButton(android.R.string.yes, ocl) .setNegativeButton(android.R.string.no, ocl); mMain.runOnUiThread(new Runnable(){ public void run() { builder.show(); } }); } catch (Throwable e) { Log.e("CreateRPG", "Weird that" + event + " of " + path + " caused", e); } finally { if (BuildConfig.DEBUG) Log.d("CreateRPG", String.format(Locale.US, "On %s at %s, event %u with flag 0x%08X occurred.", mName, mFile.getPath(), event & ALL_EVENTS, event & ~ALL_EVENTS)); } } }