paulscode.android.mupen64plusae.cheat.CheatEditorActivity.java Source code

Java tutorial

Introduction

Here is the source code for paulscode.android.mupen64plusae.cheat.CheatEditorActivity.java

Source

/**
 * Mupen64PlusAE, an N64 emulator for the Android platform
 * 
 * Copyright (C) 2013 Paul Lamb
 * 
 * This file is part of Mupen64PlusAE.
 * 
 * Mupen64PlusAE is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * Mupen64PlusAE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with Mupen64PlusAE. If
 * not, see <http://www.gnu.org/licenses/>.
 * 
 * Authors: xperia64
 */
package paulscode.android.mupen64plusae.cheat;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.mupen64plusae.v3.alpha.R;

import paulscode.android.mupen64plusae.ActivityHelper;
import paulscode.android.mupen64plusae.MenuListView;
import paulscode.android.mupen64plusae.cheat.CheatUtils.Cheat;
import paulscode.android.mupen64plusae.compat.AppCompatListActivity;
import paulscode.android.mupen64plusae.dialog.EditCheatAdvancedDialog;
import paulscode.android.mupen64plusae.dialog.EditCheatAdvancedDialog.OnAdvancedEditCompleteListener;
import paulscode.android.mupen64plusae.dialog.EditCheatDialog;
import paulscode.android.mupen64plusae.dialog.EditCheatDialog.OnEditCompleteListener;
import paulscode.android.mupen64plusae.dialog.MenuDialogFragment;
import paulscode.android.mupen64plusae.dialog.MenuDialogFragment.OnDialogMenuItemSelectedListener;
import paulscode.android.mupen64plusae.persistent.AppData;
import paulscode.android.mupen64plusae.persistent.GlobalPrefs;
import paulscode.android.mupen64plusae.task.ExtractCheatsTask;
import paulscode.android.mupen64plusae.task.ExtractCheatsTask.ExtractCheatListener;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class CheatEditorActivity extends AppCompatListActivity implements ExtractCheatListener,
        OnDialogMenuItemSelectedListener, OnEditCompleteListener, OnAdvancedEditCompleteListener {

    static public final class CheatOptionData {
        public String description;
        public int value;
    }

    static public final class CheatAddressData {
        public long address;
        public int value;
    }

    private static class CheatListAdapter extends ArrayAdapter<Cheat> {
        private static final int RESID = R.layout.list_item_two_text_icon;

        public CheatListAdapter(Context context, List<Cheat> cheats) {
            super(context, RESID, cheats);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Context context = getContext();
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = convertView;
            if (view == null)
                view = inflater.inflate(RESID, null);

            Cheat item = getItem(position);
            if (item != null) {
                TextView text1 = (TextView) view.findViewById(R.id.text1);
                TextView text2 = (TextView) view.findViewById(R.id.text2);
                ImageView icon = (ImageView) view.findViewById(R.id.icon);

                text1.setText(item.name);
                text2.setText(item.desc);
                icon.setImageResource(R.drawable.ic_key);
            }
            return view;
        }
    }

    private static final String STATE_MENU_DIALOG_FRAGMENT = "STATE_MENU_DIALOG_FRAGMENT";
    private static final String STATE_CHEAT_EDIT_DIALOG_FRAGMENT = "STATE_CHEAT_EDIT_DIALOG_FRAGMENT";

    private final ArrayList<Cheat> userCheats = new ArrayList<Cheat>();
    private final ArrayList<Cheat> systemCheats = new ArrayList<Cheat>();
    private CheatListAdapter cheatListAdapter = null;
    private AppData mAppData = null;
    private GlobalPrefs mGlobalPrefs = null;
    private String mRomCrc = null;
    private String mRomHeaderName = null;
    private byte mRomCountryCode = 0;
    private int mSelectedCheat = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAppData = new AppData(this);
        mGlobalPrefs = new GlobalPrefs(this, mAppData);
        mGlobalPrefs.enforceLocale(this);

        // Get the ROM header info
        Bundle extras = getIntent().getExtras();
        if (extras == null)
            throw new Error("ROM path must be passed via the extras bundle when starting CheatEditorActivity");

        mRomCrc = extras.getString(ActivityHelper.Keys.ROM_CRC);
        mRomHeaderName = extras.getString(ActivityHelper.Keys.ROM_HEADER_NAME);
        mRomCountryCode = extras.getByte(ActivityHelper.Keys.ROM_COUNTRY_CODE);

        setContentView(R.layout.cheat_editor);
        reload(mRomCrc, mRomCountryCode);
        findViewById(R.id.imgBtnChtAdd).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //Add a cheat
                mSelectedCheat = -1;
                int stringId = R.string.cheatEditor_edit1;
                EditCheatDialog editCheatDialogFragment = EditCheatDialog.newInstance(getString(stringId), null,
                        null, null, null, getCheatTitles());

                FragmentManager fm = getSupportFragmentManager();
                editCheatDialogFragment.show(fm, STATE_CHEAT_EDIT_DIALOG_FRAGMENT);
            }
        });
        findViewById(R.id.imgBtnChtAddAvanced).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //Add a cheat
                mSelectedCheat = -1;
                int stringId = R.string.cheatEditor_edit2;
                EditCheatAdvancedDialog editCheatDialogFragment = EditCheatAdvancedDialog
                        .newInstance(getString(stringId), null, null, null, null, getCheatTitles());

                FragmentManager fm = getSupportFragmentManager();
                editCheatDialogFragment.show(fm, STATE_CHEAT_EDIT_DIALOG_FRAGMENT);
            }
        });

        //default state is cancelled unless we save
        setResult(RESULT_CANCELED, null);
    }

    private void reload(String crc, byte countryCode) {
        Log.v("CheatEditorActivity", "building from CRC = " + crc);

        if (crc == null)
            return;

        //Do this in a separate task since it takes longer
        ExtractCheatsTask cheatsTask = new ExtractCheatsTask(this, this, mAppData.mupencheat_default, crc,
                countryCode);
        cheatsTask.execute((String) null);

        //We don't extract user cheats in a separate task since there aren't as many
        CheatFile usrcheat_txt = new CheatFile(mGlobalPrefs.customCheats_txt, true);
        userCheats.clear();
        userCheats.addAll(CheatUtils.populate(mRomCrc, mRomCountryCode, usrcheat_txt, false, this));

        cheatListAdapter = new CheatListAdapter(this, userCheats);
        setListAdapter(cheatListAdapter);
    }

    @Override
    public void onExtractFinished(ArrayList<Cheat> moreCheats) {
        systemCheats.clear();
        systemCheats.addAll(moreCheats);
    }

    private void save(String crc) {
        ArrayList<Cheat> combinedCheats;
        combinedCheats = new ArrayList<Cheat>();
        combinedCheats.addAll(systemCheats);
        combinedCheats.addAll(userCheats);
        Collections.sort(combinedCheats);

        new File(mGlobalPrefs.customCheats_txt).getParentFile().mkdirs();

        CheatFile usrcheat_txt = new CheatFile(mGlobalPrefs.customCheats_txt, true);
        CheatFile mupencheat_txt = new CheatFile(mAppData.mupencheat_txt, true);
        CheatUtils.save(crc, usrcheat_txt, userCheats, mRomHeaderName, mRomCountryCode, this, false);
        CheatUtils.save(crc, mupencheat_txt, combinedCheats, mRomHeaderName, mRomCountryCode, this, true);

        setResult(RESULT_OK, null);
    }

    @Override
    protected void onListItemClick(ListView l, View v, final int position, long id) {
        int resId = R.menu.cheat_editor_activity;
        int stringId = R.string.touchscreenProfileActivity_menuTitle;
        mSelectedCheat = position;

        MenuDialogFragment menuDialogFragment = MenuDialogFragment.newInstance(0, getString(stringId), resId);

        FragmentManager fm = getSupportFragmentManager();
        menuDialogFragment.show(fm, STATE_MENU_DIALOG_FRAGMENT);
    }

    @Override
    public void onPrepareMenuList(MenuListView listView) {
        //Nothing to do here
    }

    @Override
    public void onDialogMenuItemSelected(int dialogId, MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menuItem_edit:
            CreateCheatEditorDialog(false);
            break;
        case R.id.menuItem_advaned_edit:
            CreateCheatEditorDialog(true);
            break;
        case R.id.menuItem_delete:
            promptDelete(mSelectedCheat);
            break;
        default:
            return;
        }
    }

    private void CreateCheatEditorDialog(boolean advanced) {
        int stringId = R.string.cheatEditor_edit1;
        final Cheat cheat = userCheats.get(mSelectedCheat);
        ArrayList<CheatAddressData> addressList = new ArrayList<CheatAddressData>();
        ArrayList<CheatOptionData> optionsList = new ArrayList<CheatOptionData>();
        String addresses = cheat.code;
        String options = cheat.option;

        //Convert address string to a list of addresses
        if (!TextUtils.isEmpty(addresses)) {
            String[] addressStrings = null;
            addressStrings = addresses.split("\n");

            for (String address : addressStrings) {
                CheatAddressData addressData = new CheatAddressData();

                String addressString = address.substring(0, 8);
                String valueString = address.substring(address.length() - 4, address.length());

                addressData.address = Long.valueOf(addressString, 16);
                if (!valueString.contains("?")) {
                    addressData.value = Integer.valueOf(valueString, 16);
                    addressList.add(addressData);
                } else {
                    //The cheat with the option goes at the front
                    addressData.value = -1;
                    addressList.add(0, addressData);
                }
            }

        }

        //Convert options into a list of options
        if (!TextUtils.isEmpty(options)) {
            String[] optionStrings = null;
            optionStrings = options.split("\n");

            for (String option : optionStrings) {
                CheatOptionData cheatData = new CheatOptionData();
                String valueString = option.substring(option.length() - 4, option.length());
                cheatData.value = Integer.valueOf(valueString, 16);
                cheatData.description = option.substring(0, option.length() - 5);
                optionsList.add(cheatData);
            }
        }

        if (advanced) {
            EditCheatAdvancedDialog editCheatDialogFragment = EditCheatAdvancedDialog.newInstance(
                    getString(stringId), cheat.name, cheat.desc, addressList, optionsList, getCheatTitles());

            FragmentManager fm = getSupportFragmentManager();
            editCheatDialogFragment.show(fm, STATE_CHEAT_EDIT_DIALOG_FRAGMENT);
        } else {
            EditCheatDialog editCheatDialogFragment = EditCheatDialog.newInstance(getString(stringId), cheat.name,
                    cheat.desc, addressList, optionsList, getCheatTitles());

            FragmentManager fm = getSupportFragmentManager();
            editCheatDialogFragment.show(fm, STATE_CHEAT_EDIT_DIALOG_FRAGMENT);
        }
    }

    private List<String> getCheatTitles() {
        List<String> cheatTitles = new ArrayList<String>();

        for (Cheat cheat : userCheats) {
            cheatTitles.add(cheat.name);
        }
        return cheatTitles;
    }

    private void promptDelete(final int pos) {
        final OnClickListener listener = new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (which == DialogInterface.BUTTON_POSITIVE) {
                    userCheats.remove(pos);
                    cheatListAdapter.notifyDataSetChanged();

                    save(mRomCrc);
                }
            }
        };
        Builder builder = new Builder(this);
        builder.setTitle(R.string.cheatEditor_delete);
        builder.setMessage(R.string.cheatEditor_confirm);
        builder.setPositiveButton(android.R.string.yes, listener);
        builder.setNegativeButton(android.R.string.no, listener);
        builder.create().show();
    }

    @Override
    public void onEditComplete(int selectedButton, String name, String comment, List<CheatAddressData> address,
            List<CheatOptionData> options) {
        if (selectedButton == DialogInterface.BUTTON_POSITIVE) {
            Cheat cheat = null;

            if (mSelectedCheat != -1) {
                cheat = userCheats.get(mSelectedCheat);
            } else {
                cheat = new Cheat();
            }

            cheat.option = "";

            if (!name.isEmpty()) {
                cheat.name = name;
            }

            cheat.desc = comment.replace('\n', ' ');

            String optionAddressString = new String();

            //Build the codes
            StringBuilder builder = new StringBuilder();
            for (CheatAddressData data : address) {
                if (data.value != -1) {
                    builder.append(String.format("%08X %04X\n", data.address, data.value));
                } else {
                    optionAddressString = String.format("%08X ????\n", data.address);
                }
            }

            cheat.code = builder.toString() + optionAddressString;

            //Build the options
            builder = new StringBuilder();
            for (CheatOptionData data : options) {
                builder.append(String.format("%s %04X\n", data.description, data.value));
            }
            cheat.option = builder.toString();

            boolean ValidCheat = !name.isEmpty() && cheat.code.length() > 12;

            if (ValidCheat) {
                if (mSelectedCheat == -1) {
                    userCheats.add(cheat);
                }

                Collections.sort(userCheats);
                save(mRomCrc);
                cheatListAdapter.notifyDataSetChanged();
            }
        }
    }

    @Override
    public void onAdvancedEditComplete(int selectedButton, String name, String comment,
            List<CheatAddressData> address, List<CheatOptionData> options) {
        onEditComplete(selectedButton, name, comment, address, options);
    }
}