From f72dd4f466e9d8f179d0533366c7a50a63ef55f2 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Sat, 2 Mar 2013 17:29:10 +0000 Subject: [PATCH] DroidFish: When receiving a fen file from an external program, let the user select which fen position to use. --- DroidFish/AndroidManifest.xml | 4 + DroidFish/res/layout-land/load_fen.xml | 53 +++ DroidFish/res/layout/load_fen.xml | 49 +++ DroidFish/res/values/strings.xml | 4 + .../src/org/petero/droidfish/DroidFish.java | 91 +++-- .../BufferedRandomAccessFileReader.java | 100 ++++++ .../droidfish/activities/EditBoard.java | 31 +- .../petero/droidfish/activities/FENFile.java | 108 ++++++ .../petero/droidfish/activities/LoadFEN.java | 317 ++++++++++++++++++ .../petero/droidfish/activities/PGNFile.java | 82 +---- 10 files changed, 709 insertions(+), 130 deletions(-) create mode 100644 DroidFish/res/layout-land/load_fen.xml create mode 100644 DroidFish/res/layout/load_fen.xml create mode 100644 DroidFish/src/org/petero/droidfish/activities/BufferedRandomAccessFileReader.java create mode 100644 DroidFish/src/org/petero/droidfish/activities/FENFile.java create mode 100644 DroidFish/src/org/petero/droidfish/activities/LoadFEN.java diff --git a/DroidFish/AndroidManifest.xml b/DroidFish/AndroidManifest.xml index e7d6672..be857bb 100644 --- a/DroidFish/AndroidManifest.xml +++ b/DroidFish/AndroidManifest.xml @@ -62,6 +62,10 @@ android:label="@string/load_scid_game_title" android:configChanges="orientation"> + + diff --git a/DroidFish/res/layout-land/load_fen.xml b/DroidFish/res/layout-land/load_fen.xml new file mode 100644 index 0000000..a85deb3 --- /dev/null +++ b/DroidFish/res/layout-land/load_fen.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + diff --git a/DroidFish/res/layout/load_fen.xml b/DroidFish/res/layout/load_fen.xml new file mode 100644 index 0000000..4bc40d6 --- /dev/null +++ b/DroidFish/res/layout/load_fen.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + diff --git a/DroidFish/res/values/strings.xml b/DroidFish/res/values/strings.xml index 027e240..0cb3afb 100644 --- a/DroidFish/res/values/strings.xml +++ b/DroidFish/res/values/strings.xml @@ -76,6 +76,7 @@ you are not actively using the program.\ Load Save Reading PGN file + Reading FEN file Reading Scid file <New File> <New Engine> @@ -111,6 +112,8 @@ you are not actively using the program.\ Load Next Game No previous game No next game + No previous position + No next position Select Action Flip Board Blindfold mode @@ -160,6 +163,7 @@ you are not actively using the program.\ Edit File / Save Game Select an existing game to control where to save the game. Long press an existing game to delete it. Load Scid Game + Load Position CPU Warning Failed to read PGN data Var: diff --git a/DroidFish/src/org/petero/droidfish/DroidFish.java b/DroidFish/src/org/petero/droidfish/DroidFish.java index 7651895..6b59b44 100644 --- a/DroidFish/src/org/petero/droidfish/DroidFish.java +++ b/DroidFish/src/org/petero/droidfish/DroidFish.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011-2012 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2013 Peter Österlund, peterosterlund2@gmail.com Copyright (C) 2012 Leo Mayer This program is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ package org.petero.droidfish; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; @@ -40,6 +39,7 @@ import org.petero.droidfish.activities.CPUWarning; import org.petero.droidfish.activities.EditBoard; import org.petero.droidfish.activities.EditPGNLoad; import org.petero.droidfish.activities.EditPGNSave; +import org.petero.droidfish.activities.LoadFEN; import org.petero.droidfish.activities.LoadScid; import org.petero.droidfish.activities.Preferences; import org.petero.droidfish.book.BookOptions; @@ -1161,6 +1161,7 @@ public class DroidFish extends Activity implements GUIInterface { static private final int RESULT_OI_PGN_SAVE = 4; static private final int RESULT_OI_PGN_LOAD = 5; static private final int RESULT_GET_FEN = 6; + static private final int RESULT_LOAD_FEN = 7; @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -1296,32 +1297,15 @@ public class DroidFish extends Activity implements GUIInterface { String fen = data.getStringExtra(Intent.EXTRA_TEXT); if (fen == null) { String pathName = getFilePathFromUri(data.getData()); - if (pathName != null) { - InputStream is = null; - try { - is = new FileInputStream(pathName); - fen = Util.readFromStream(is); - } catch (FileNotFoundException e) { - Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); - } finally { - if (is != null) - try { is.close(); } catch (IOException e) {} - } - } - } - if (fen != null) { - try { - ctrl.setFENOrPGN(fen); - } catch (ChessParseError e) { - // If FEN corresponds to illegal chess position, go into edit board mode. - try { - TextIO.readFEN(fen); - } catch (ChessParseError e2) { - if (e2.pos != null) - startEditBoard(fen); - } - } + loadFENFromFile(pathName); } + setFenHelper(fen); + } + break; + case RESULT_LOAD_FEN: + if (resultCode == RESULT_OK) { + String fen = data.getAction(); + setFenHelper(fen); } break; } @@ -2439,12 +2423,18 @@ public class DroidFish extends Activity implements GUIInterface { i = new Intent(DroidFish.this, EditPGNLoad.class); i.setAction("org.petero.droidfish.loadFilePrevGame"); i.putExtra("org.petero.droidfish.pathname", currPathName); - } else { + startActivityForResult(i, RESULT_LOAD_PGN); + } else if (currFT == FT_SCID) { i = new Intent(DroidFish.this, LoadScid.class); i.setAction("org.petero.droidfish.loadScidPrevGame"); i.putExtra("org.petero.droidfish.pathname", currPathName); + startActivityForResult(i, RESULT_LOAD_PGN); + } else if (currFT == FT_FEN) { + i = new Intent(DroidFish.this, LoadFEN.class); + i.setAction("org.petero.droidfish.loadPrevFen"); + i.putExtra("org.petero.droidfish.pathname", currPathName); + startActivityForResult(i, RESULT_LOAD_FEN); } - startActivityForResult(i, RESULT_LOAD_PGN); break; } } @@ -2483,12 +2473,18 @@ public class DroidFish extends Activity implements GUIInterface { i = new Intent(DroidFish.this, EditPGNLoad.class); i.setAction("org.petero.droidfish.loadFileNextGame"); i.putExtra("org.petero.droidfish.pathname", currPathName); - } else { + startActivityForResult(i, RESULT_LOAD_PGN); + } else if (currFT == FT_SCID) { i = new Intent(DroidFish.this, LoadScid.class); i.setAction("org.petero.droidfish.loadScidNextGame"); i.putExtra("org.petero.droidfish.pathname", currPathName); + startActivityForResult(i, RESULT_LOAD_PGN); + } else if (currFT == FT_FEN) { + i = new Intent(DroidFish.this, LoadFEN.class); + i.setAction("org.petero.droidfish.loadNextFen"); + i.putExtra("org.petero.droidfish.pathname", currPathName); + startActivityForResult(i, RESULT_LOAD_FEN); } - startActivityForResult(i, RESULT_LOAD_PGN); break; } } @@ -2874,6 +2870,7 @@ public class DroidFish extends Activity implements GUIInterface { final static int FT_NONE = 0; final static int FT_PGN = 1; final static int FT_SCID = 2; + final static int FT_FEN = 3; private final int currFileType() { if (gameMode.clocksActive()) @@ -2895,6 +2892,8 @@ public class DroidFish extends Activity implements GUIInterface { } case FT_SCID: return settings.getString("currentScidFile", ""); + case FT_FEN: + return settings.getString("currentFENFile", ""); default: return ""; } @@ -2952,6 +2951,36 @@ public class DroidFish extends Activity implements GUIInterface { startActivityForResult(i, RESULT_LOAD_PGN); } + /** Load a FEN position from a file. */ + private final void loadFENFromFile(String pathName) { + if (pathName == null) + return; + Editor editor = settings.edit(); + editor.putString("currentFENFile", pathName); + editor.putInt("currFT", FT_FEN); + editor.commit(); + Intent i = new Intent(DroidFish.this, LoadFEN.class); + i.setAction("org.petero.droidfish.loadFen"); + i.putExtra("org.petero.droidfish.pathname", pathName); + startActivityForResult(i, RESULT_LOAD_FEN); + } + + private final void setFenHelper(String fen) { + if (fen == null) + return; + try { + ctrl.setFENOrPGN(fen); + } catch (ChessParseError e) { + // If FEN corresponds to illegal chess position, go into edit board mode. + try { + TextIO.readFEN(fen); + } catch (ChessParseError e2) { + if (e2.pos != null) + startEditBoard(fen); + } + } + } + @Override public void requestPromotePiece() { showDialog(PROMOTE_DIALOG); diff --git a/DroidFish/src/org/petero/droidfish/activities/BufferedRandomAccessFileReader.java b/DroidFish/src/org/petero/droidfish/activities/BufferedRandomAccessFileReader.java new file mode 100644 index 0000000..0ba8243 --- /dev/null +++ b/DroidFish/src/org/petero/droidfish/activities/BufferedRandomAccessFileReader.java @@ -0,0 +1,100 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2013 Peter Österlund, peterosterlund2@gmail.com + + This program 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. + + This program 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 this program. If not, see . +*/ +package org.petero.droidfish.activities; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; + +final class BufferedRandomAccessFileReader { + RandomAccessFile f; + byte[] buffer = new byte[8192]; + long bufStartFilePos = 0; + int bufLen = 0; + int bufPos = 0; + + BufferedRandomAccessFileReader(String fileName) throws FileNotFoundException { + f = new RandomAccessFile(fileName, "r"); + } + final long length() throws IOException { + return f.length(); + } + final long getFilePointer() throws IOException { + return bufStartFilePos + bufPos; + } + final void close() throws IOException { + f.close(); + } + + private final static int EOF = -1024; + + final String readLine() throws IOException { + // First handle the common case where the next line is entirely + // contained in the buffer + for (int i = bufPos; i < bufLen; i++) { + byte b = buffer[i]; + if ((b == '\n') || (b == '\r')) { + String line = new String(buffer, bufPos, i - bufPos); + for ( ; i < bufLen; i++) { + b = buffer[i]; + if ((b != '\n') && (b != '\r')) { + bufPos = i; + return line; + } + } + break; + } + } + + // Generic case + byte[] lineBuf = new byte[8192]; + int lineLen = 0; + int b; + while (true) { + b = getByte(); + if (b == '\n' || b == '\r' || b == EOF) + break; + lineBuf[lineLen++] = (byte)b; + if (lineLen >= lineBuf.length) + break; + } + while (true) { + b = getByte(); + if ((b != '\n') && (b != '\r')) { + if (b != EOF) + bufPos--; + break; + } + } + if ((b == EOF) && (lineLen == 0)) + return null; + else + return new String(lineBuf, 0, lineLen); + } + + private final int getByte() throws IOException { + if (bufPos >= bufLen) { + bufStartFilePos = f.getFilePointer(); + bufLen = f.read(buffer); + bufPos = 0; + if (bufLen <= 0) + return EOF; + } + return buffer[bufPos++]; + } +} diff --git a/DroidFish/src/org/petero/droidfish/activities/EditBoard.java b/DroidFish/src/org/petero/droidfish/activities/EditBoard.java index 31b20fa..bb162c6 100644 --- a/DroidFish/src/org/petero/droidfish/activities/EditBoard.java +++ b/DroidFish/src/org/petero/droidfish/activities/EditBoard.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2013 Peter Österlund, peterosterlund2@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,10 +18,6 @@ package org.petero.droidfish.activities; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -605,7 +601,8 @@ public class EditBoard extends Activity { checkValidAndUpdateMaterialDiff(); } - static private final int RESULT_GET_FEN = 0; + static private final int RESULT_GET_FEN = 0; + static private final int RESULT_LOAD_FEN = 1; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -615,22 +612,20 @@ public class EditBoard extends Activity { String fen = data.getStringExtra(Intent.EXTRA_TEXT); if (fen == null) { String pathName = DroidFish.getFilePathFromUri(data.getData()); - if (pathName != null) { - InputStream is = null; - try { - is = new FileInputStream(pathName); - fen = Util.readFromStream(is); - } catch (FileNotFoundException e) { - Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); - } finally { - if (is != null) - try { is.close(); } catch (IOException e) {} - } - } + Intent i = new Intent(EditBoard.this, LoadFEN.class); + i.setAction("org.petero.droidfish.loadFen"); + i.putExtra("org.petero.droidfish.pathname", pathName); + startActivityForResult(i, RESULT_LOAD_FEN); } setFEN(fen); } break; + case RESULT_LOAD_FEN: + if (resultCode == RESULT_OK) { + String fen = data.getAction(); + setFEN(fen); + } + break; } } } diff --git a/DroidFish/src/org/petero/droidfish/activities/FENFile.java b/DroidFish/src/org/petero/droidfish/activities/FENFile.java new file mode 100644 index 0000000..e026afa --- /dev/null +++ b/DroidFish/src/org/petero/droidfish/activities/FENFile.java @@ -0,0 +1,108 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2013 Peter Österlund, peterosterlund2@gmail.com + + This program 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. + + This program 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 this program. If not, see . +*/ + +package org.petero.droidfish.activities; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +import org.petero.droidfish.gamelogic.Pair; + +import android.app.Activity; +import android.app.ProgressDialog; + +public class FENFile { + private final File fileName; + + public FENFile(String fileName) { + this.fileName = new File(fileName); + } + + public final String getName() { + return fileName.getAbsolutePath(); + } + + static final class FenInfo { + int gameNo; + String fen; + + FenInfo(int gameNo, String fen) { + this.gameNo = gameNo; + this.fen = fen; + } + + public String toString() { + StringBuilder info = new StringBuilder(128); + info.append(gameNo); + info.append(". "); + info.append(fen); + return info.toString(); + } + } + + public static enum FenInfoResult { + OK, + CANCEL, + OUT_OF_MEMORY; + } + + /** Read all FEN strings (one per line) in a file. */ + public final Pair> getFenInfo(Activity activity, + final ProgressDialog progress) { + ArrayList fensInFile = new ArrayList(); + try { + int percent = -1; + fensInFile.clear(); + BufferedRandomAccessFileReader f = new BufferedRandomAccessFileReader(fileName.getAbsolutePath()); + long fileLen = f.length(); + long filePos = 0; + int fenNo = 1; + while (true) { + filePos = f.getFilePointer(); + String line = f.readLine(); + if (line == null) + break; // EOF + if ((line.length() == 0) || (line.charAt(0) == '#')) + continue; + FenInfo fi = new FenInfo(fenNo++, line.trim()); + fensInFile.add(fi); + final int newPercent = (int)(filePos * 100 / fileLen); + if (newPercent > percent) { + percent = newPercent; + if (progress != null) { + activity.runOnUiThread(new Runnable() { + public void run() { + progress.setProgress(newPercent); + } + }); + } + } + if (Thread.currentThread().isInterrupted()) + return new Pair>(FenInfoResult.CANCEL, null); + } + f.close(); + } catch (IOException e) { + } catch (OutOfMemoryError e) { + fensInFile.clear(); + fensInFile = null; + return new Pair>(FenInfoResult.OUT_OF_MEMORY, null); + } + return new Pair>(FenInfoResult.OK, fensInFile); + } +} diff --git a/DroidFish/src/org/petero/droidfish/activities/LoadFEN.java b/DroidFish/src/org/petero/droidfish/activities/LoadFEN.java new file mode 100644 index 0000000..f0e8f89 --- /dev/null +++ b/DroidFish/src/org/petero/droidfish/activities/LoadFEN.java @@ -0,0 +1,317 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2013 Peter Österlund, peterosterlund2@gmail.com + + This program 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. + + This program 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 this program. If not, see . +*/ + +package org.petero.droidfish.activities; + +import java.io.File; +import java.util.ArrayList; + +import org.petero.droidfish.ChessBoardPlay; +import org.petero.droidfish.ColorTheme; +import org.petero.droidfish.R; +import org.petero.droidfish.Util; +import org.petero.droidfish.activities.FENFile.FenInfo; +import org.petero.droidfish.activities.FENFile.FenInfoResult; +import org.petero.droidfish.gamelogic.ChessParseError; +import org.petero.droidfish.gamelogic.Pair; +import org.petero.droidfish.gamelogic.Position; +import org.petero.droidfish.gamelogic.TextIO; + +import android.app.Dialog; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.DialogInterface.OnCancelListener; +import android.content.SharedPreferences.Editor; +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; + +public class LoadFEN extends ListActivity { + private static ArrayList fensInFile = new ArrayList(); + private static boolean cacheValid = false; + private FENFile fenFile; + private ProgressDialog progress; + private FenInfo selectedFi = null; + private ArrayAdapter aa = null; + + private SharedPreferences settings; + private int defaultItem = 0; + private String lastFileName = ""; + private long lastModTime = -1; + + private Thread workThread = null; + + private ChessBoardPlay cb; + private Button okButton; + private Button cancelButton; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + settings = PreferenceManager.getDefaultSharedPreferences(this); + Util.setFullScreenMode(this, settings); + + if (savedInstanceState != null) { + defaultItem = savedInstanceState.getInt("defaultItem"); + lastFileName = savedInstanceState.getString("lastFenFileName"); + if (lastFileName == null) lastFileName = ""; + lastModTime = savedInstanceState.getLong("lastFenModTime"); + } else { + defaultItem = settings.getInt("defaultItem", 0); + lastFileName = settings.getString("lastFenFileName", ""); + lastModTime = settings.getLong("lastFenModTime", 0); + } + + Intent i = getIntent(); + String action = i.getAction(); + String fileName = i.getStringExtra("org.petero.droidfish.pathname"); + if (action.equals("org.petero.droidfish.loadFen")) { + fenFile = new FENFile(fileName); + showDialog(PROGRESS_DIALOG); + final LoadFEN lfen = this; + workThread = new Thread(new Runnable() { + public void run() { + if (!readFile()) + return; + runOnUiThread(new Runnable() { + public void run() { + lfen.showList(); + } + }); + } + }); + workThread.start(); + } else if (action.equals("org.petero.droidfish.loadNextFen") || + action.equals("org.petero.droidfish.loadPrevFen")) { + fenFile = new FENFile(fileName); + boolean next = action.equals("org.petero.droidfish.loadNextFen"); + final int loadItem = defaultItem + (next ? 1 : -1); + if (loadItem < 0) { + Toast.makeText(getApplicationContext(), R.string.no_prev_fen, + Toast.LENGTH_SHORT).show(); + setResult(RESULT_CANCELED); + finish(); + } else { + workThread = new Thread(new Runnable() { + public void run() { + if (!readFile()) + return; + runOnUiThread(new Runnable() { + public void run() { + if (loadItem >= fensInFile.size()) { + Toast.makeText(getApplicationContext(), R.string.no_next_fen, + Toast.LENGTH_SHORT).show(); + setResult(RESULT_CANCELED); + finish(); + } else { + defaultItem = loadItem; + sendBackResult(fensInFile.get(loadItem)); + } + } + }); + } + }); + workThread.start(); + } + } else { // Unsupported action + setResult(RESULT_CANCELED); + finish(); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt("defaultItem", defaultItem); + outState.putString("lastFenFileName", lastFileName); + outState.putLong("lastFenModTime", lastModTime); + } + + @Override + protected void onPause() { + Editor editor = settings.edit(); + editor.putInt("defaultItem", defaultItem); + editor.putString("lastFenFileName", lastFileName); + editor.putLong("lastFenModTime", lastModTime); + editor.commit(); + super.onPause(); + } + + @Override + protected void onDestroy() { + if (workThread != null) { + workThread.interrupt(); + try { + workThread.join(); + } catch (InterruptedException e) { + } + workThread = null; + } + super.onDestroy(); + } + + private final void showList() { + progress.dismiss(); + setContentView(R.layout.load_fen); + + cb = (ChessBoardPlay)findViewById(R.id.loadfen_chessboard); + okButton = (Button)findViewById(R.id.loadfen_ok); + cancelButton = (Button)findViewById(R.id.loadfen_cancel); + + okButton.setEnabled(false); + okButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + if (selectedFi != null) + sendBackResult(selectedFi); + } + }); + cancelButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + setResult(RESULT_CANCELED); + finish(); + } + }); + + Util.overrideFonts(findViewById(android.R.id.content)); + aa = new ArrayAdapter(this, R.layout.select_game_list_item, fensInFile) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + if (view instanceof TextView) { + int fg = ColorTheme.instance().getColor(ColorTheme.FONT_FOREGROUND); + ((TextView) view).setTextColor(fg); + } + return view; + } + }; + setListAdapter(aa); + final ListView lv = getListView(); + lv.setSelectionFromTop(defaultItem, 0); + lv.setFastScrollEnabled(true); + lv.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int pos, long id) { + selectedFi = aa.getItem(pos); + if (selectedFi == null) + return; + defaultItem = pos; + Position chessPos; + try { + chessPos = TextIO.readFEN(selectedFi.fen); + } catch (ChessParseError e2) { + chessPos = e2.pos; + } + if (chessPos != null) { + cb.setPosition(chessPos); + okButton.setEnabled(true); + } + } + }); + lv.requestFocus(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Position pos = cb.pos; + showList(); + cb.setPosition(pos); + okButton.setEnabled(selectedFi != null); + } + + final static int PROGRESS_DIALOG = 0; + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + case PROGRESS_DIALOG: + progress = new ProgressDialog(this); + progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progress.setTitle(R.string.reading_fen_file); + progress.setMessage(getString(R.string.please_wait)); + progress.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + Thread thr = workThread; + if (thr != null) + thr.interrupt(); + } + }); + return progress; + default: + return null; + } + } + + private final boolean readFile() { + String fileName = fenFile.getName(); + if (!fileName.equals(lastFileName)) + defaultItem = 0; + long modTime = new File(fileName).lastModified(); + if (cacheValid && (modTime == lastModTime) && fileName.equals(lastFileName)) + return true; + fenFile = new FENFile(fileName); + Pair> p = fenFile.getFenInfo(this, progress); + if (p.first != FenInfoResult.OK) { + fensInFile = new ArrayList(); + switch (p.first) { + case OUT_OF_MEMORY: + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(getApplicationContext(), R.string.file_too_large, + Toast.LENGTH_SHORT).show(); + } + }); + break; + } + setResult(RESULT_CANCELED); + finish(); + return false; + } + fensInFile = p.second; + cacheValid = true; + lastModTime = modTime; + lastFileName = fileName; + return true; + } + + private final void sendBackResult(FenInfo fi) { + String fen = fi.fen; + if (fen != null) { + setResult(RESULT_OK, (new Intent()).setAction(fen)); + finish(); + } else { + setResult(RESULT_CANCELED); + finish(); + } + } +} diff --git a/DroidFish/src/org/petero/droidfish/activities/PGNFile.java b/DroidFish/src/org/petero/droidfish/activities/PGNFile.java index 846593f..afe064f 100644 --- a/DroidFish/src/org/petero/droidfish/activities/PGNFile.java +++ b/DroidFish/src/org/petero/droidfish/activities/PGNFile.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2013 Peter Österlund, peterosterlund2@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +19,6 @@ package org.petero.droidfish.activities; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; @@ -65,85 +64,6 @@ public class PGNFile { } } - - static private final class BufferedRandomAccessFileReader { - RandomAccessFile f; - byte[] buffer = new byte[8192]; - long bufStartFilePos = 0; - int bufLen = 0; - int bufPos = 0; - - BufferedRandomAccessFileReader(String fileName) throws FileNotFoundException { - f = new RandomAccessFile(fileName, "r"); - } - final long length() throws IOException { - return f.length(); - } - final long getFilePointer() throws IOException { - return bufStartFilePos + bufPos; - } - final void close() throws IOException { - f.close(); - } - - private final static int EOF = -1024; - - final String readLine() throws IOException { - // First handle the common case where the next line is entirely - // contained in the buffer - for (int i = bufPos; i < bufLen; i++) { - byte b = buffer[i]; - if ((b == '\n') || (b == '\r')) { - String line = new String(buffer, bufPos, i - bufPos); - for ( ; i < bufLen; i++) { - b = buffer[i]; - if ((b != '\n') && (b != '\r')) { - bufPos = i; - return line; - } - } - break; - } - } - - // Generic case - byte[] lineBuf = new byte[8192]; - int lineLen = 0; - int b; - while (true) { - b = getByte(); - if (b == '\n' || b == '\r' || b == EOF) - break; - lineBuf[lineLen++] = (byte)b; - if (lineLen >= lineBuf.length) - break; - } - while (true) { - b = getByte(); - if ((b != '\n') && (b != '\r')) { - if (b != EOF) - bufPos--; - break; - } - } - if ((b == EOF) && (lineLen == 0)) - return null; - else - return new String(lineBuf, 0, lineLen); - } - - private final int getByte() throws IOException { - if (bufPos >= bufLen) { - bufStartFilePos = f.getFilePointer(); - bufLen = f.read(buffer); - bufPos = 0; - if (bufLen <= 0) - return EOF; - } - return buffer[bufPos++]; - } - } - private final static class HeaderInfo { int gameNo; String event = "";