├── Ted ├── res │ ├── drawable-hdpi │ │ ├── file.png │ │ ├── up.png │ │ ├── folder.png │ │ ├── folder_r.png │ │ ├── folder_rw.png │ │ ├── ic_search.png │ │ ├── file_locked.png │ │ ├── ic_launcher.png │ │ ├── file_private.png │ │ ├── file_unknown.png │ │ ├── folder_locked.png │ │ ├── folder_private.png │ │ ├── ic_menu_recent.png │ │ ├── ic_menu_save.png │ │ ├── ic_menu_search.png │ │ ├── ic_menu_undo.png │ │ ├── ic_menu_file_new.png │ │ ├── textfield_sky.9.png │ │ ├── file_text_favorite.png │ │ ├── ic_menu_file_open.png │ │ ├── textfield_black.9.png │ │ ├── textfield_dracula.9.png │ │ ├── textfield_matrix.9.png │ │ ├── textfield_white.9.png │ │ └── file_text_favorite_readonly.png │ ├── values │ │ ├── styles.xml │ │ ├── dimens.xml │ │ ├── toasts.xml │ │ ├── arrays.xml │ │ ├── history.xml │ │ └── strings.xml │ ├── values-es │ │ ├── styles.xml │ │ ├── dimens.xml │ │ ├── history.xml │ │ ├── toasts.xml │ │ ├── arrays.xml │ │ └── strings.xml │ ├── values-v11 │ │ └── dimens.xml │ ├── values-fr │ │ ├── arrays.xml │ │ ├── toasts.xml │ │ ├── history.xml │ │ └── strings.xml │ ├── drawable │ │ └── widget_title_background.xml │ ├── xml │ │ ├── ted_widget.xml │ │ └── ted_prefs.xml │ ├── layout │ │ ├── dialog_save.xml │ │ ├── layout_open.xml │ │ ├── layout_prefs.xml │ │ ├── layout_widget_config.xml │ │ ├── layout_save_as.xml │ │ ├── layout_editor.xml │ │ ├── widget.xml │ │ ├── search.xml │ │ └── layout_about.xml │ ├── values-sk │ │ ├── arrays.xml │ │ ├── toasts.xml │ │ └── strings.xml │ └── layout-v11 │ │ └── widget.xml ├── libs │ └── juniversalchardet-1.0.3.jar ├── .classpath ├── project.properties ├── src │ └── fr │ │ └── xgouchet │ │ └── texteditor │ │ ├── common │ │ ├── FontUtils.java │ │ ├── ComparatorFilesAlpha.java │ │ ├── TedChangelog.java │ │ ├── RecentFiles.java │ │ ├── WidgetPrefs.java │ │ ├── Settings.java │ │ ├── TextFileUtils.java │ │ └── Constants.java │ │ ├── TedAboutActivity.java │ │ ├── ui │ │ ├── adapter │ │ │ ├── FontListAdapter.java │ │ │ └── PathListAdapter.java │ │ └── view │ │ │ └── AdvancedEditText.java │ │ ├── undo │ │ ├── TextChangeDelete.java │ │ ├── TextChange.java │ │ ├── TextChangeInsert.java │ │ └── TextChangeWatcher.java │ │ ├── TedAppWidgetProvider.java │ │ ├── TedFontActivity.java │ │ ├── TedWidgetConfigActivity.java │ │ ├── TedOpenActivity.java │ │ ├── TedSaveAsActivity.java │ │ ├── TedOpenRecentActivity.java │ │ ├── TedSettingsActivity.java │ │ └── TedActivity.java ├── .project ├── proguard.cfg ├── changelog.txt └── AndroidManifest.xml ├── .gitmodules ├── .gitignore └── README.md /Ted/res/drawable-hdpi/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/up.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/folder.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "AndroidLib"] 2 | path = AndroidLib 3 | url = git://github.com/xgouchet/AndroidLib.git 4 | -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/folder_r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/folder_r.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/folder_rw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/folder_rw.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_search.png -------------------------------------------------------------------------------- /Ted/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Ted/libs/juniversalchardet-1.0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/libs/juniversalchardet-1.0.3.jar -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/file_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file_locked.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Ted/res/values-es/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/file_private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file_private.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/file_unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file_unknown.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/folder_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/folder_locked.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/folder_private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/folder_private.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_recent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_recent.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_save.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_search.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_undo.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_file_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_file_new.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/textfield_sky.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/textfield_sky.9.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/file_text_favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file_text_favorite.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/ic_menu_file_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/ic_menu_file_open.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/textfield_black.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/textfield_black.9.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/textfield_dracula.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/textfield_dracula.9.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/textfield_matrix.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/textfield_matrix.9.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/textfield_white.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/textfield_white.9.png -------------------------------------------------------------------------------- /Ted/res/drawable-hdpi/file_text_favorite_readonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xgouchet/Ted/HEAD/Ted/res/drawable-hdpi/file_text_favorite_readonly.png -------------------------------------------------------------------------------- /Ted/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4dp 5 | 72dp 6 | 7 | -------------------------------------------------------------------------------- /Ted/res/values-es/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4dp 5 | 72dp 6 | 7 | -------------------------------------------------------------------------------- /Ted/res/values-v11/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4dp 5 | 40dp 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | .gitattributes 18 | 19 | # Eclipse project files 20 | #.classpath 21 | #.project 22 | .metadata 23 | -------------------------------------------------------------------------------- /Ted/res/values-fr/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Classique 7 | Negatif 8 | Matrix 9 | Ciel Bleu 10 | Dracula 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Ted/res/drawable/widget_title_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Ted/res/xml/ted_widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /Ted/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Ted/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system use, 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=android-17 12 | android.library.reference.1=../AndroidLib 13 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/FontUtils.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.File; 4 | 5 | import android.content.Context; 6 | 7 | public class FontUtils { 8 | 9 | /** 10 | * @param ctx 11 | * the current application context 12 | * @return the app folder for fonts 13 | */ 14 | public static File getAppFontFolder(Context ctx) { 15 | return ctx.getDir(Constants.FONT_FOLDER_NAME, Context.MODE_PRIVATE); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedAboutActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import android.os.Bundle; 4 | import fr.xgouchet.androidlib.ui.activity.AboutActivity; 5 | 6 | public class TedAboutActivity extends AboutActivity { 7 | 8 | /** 9 | * @see android.app.Activity#onCreate(android.os.Bundle) 10 | */ 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | 14 | setContentView(R.layout.layout_about); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Ted/res/layout/dialog_save.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_open.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 20 | 21 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/ComparatorFilesAlpha.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.File; 4 | import java.util.Comparator; 5 | 6 | /** 7 | * Compare files Alphabetically (w/ folders listed first) 8 | * 9 | * @author x.gouchet 10 | * 11 | */ 12 | public class ComparatorFilesAlpha implements Comparator { 13 | 14 | /** 15 | * @see Comparator#compare(Object, Object) 16 | */ 17 | public int compare(File file1, File file2) { 18 | // sort folders first 19 | if ((file1.isDirectory()) && (!file2.isDirectory())) 20 | return -1; 21 | if ((!file1.isDirectory()) && (file2.isDirectory())) 22 | return 1; 23 | 24 | // here both are folders or both are files : sort alpha 25 | return file1.getName().toLowerCase().compareTo( 26 | file2.getName().toLowerCase()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/TedChangelog.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import fr.xgouchet.androidlib.common.AbstractChangeLog; 4 | import fr.xgouchet.texteditor.R; 5 | 6 | public class TedChangelog extends AbstractChangeLog { 7 | 8 | /** 9 | * @see fr.xgouchet.androidlib.common.ChangeLog#getTitleResourceForVersion(int) 10 | */ 11 | public int getTitleResourceForVersion(int version) { 12 | int res = 0; 13 | switch (version) { 14 | case 18: 15 | default: 16 | res = R.string.release18; 17 | } 18 | return res; 19 | } 20 | 21 | /** 22 | * @see fr.xgouchet.androidlib.common.ChangeLog#getChangeLogResourceForVersion(int) 23 | */ 24 | public int getChangeLogResourceForVersion(int version) { 25 | int res = 0; 26 | switch (version) { 27 | case 18: 28 | default: 29 | res = R.string.release18_log; 30 | } 31 | return res; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Ted/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ted 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_prefs.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_widget_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 21 | 22 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /Ted/res/values-sk/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Klasická 6 | Negatív 7 | Matrix 8 | Obloha 9 | Drakula 10 | 11 | 12 | 13 | 6 bodov 14 | 8 bodov 15 | 10 bodov 16 | 12 bodov 17 | 14 bodov 18 | 16 bodov 19 | 18 bodov 20 | 24 bodov 21 | 32 bodov 22 | 48 bodov 23 | 24 | 25 | 26 | Android/Linux/Unix 27 | Windows/Symbian/Palm 28 | Mac/iPhone 29 | 30 | 31 | 32 | ASCII 33 | Latin 1 34 | UTF 8 35 | 36 | 37 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_save_as.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_editor.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /Ted/res/layout-v11/widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 32 | 33 | -------------------------------------------------------------------------------- /Ted/proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembers class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers class * extends android.app.Activity { 30 | public void *(android.view.View); 31 | } 32 | 33 | -keepclassmembers enum * { 34 | public static **[] values(); 35 | public static ** valueOf(java.lang.String); 36 | } 37 | 38 | -keep class * implements android.os.Parcelable { 39 | public static final android.os.Parcelable$Creator *; 40 | } 41 | -------------------------------------------------------------------------------- /Ted/res/layout/widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 34 | 35 | -------------------------------------------------------------------------------- /Ted/res/layout/search.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 24 | 25 | 31 | 32 | 38 | 39 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/ui/adapter/FontListAdapter.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.ui.adapter; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | import android.content.Context; 7 | import android.graphics.Typeface; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | import fr.xgouchet.androidlib.R; 13 | import fr.xgouchet.androidlib.data.FileUtils; 14 | import fr.xgouchet.androidlib.ui.adapter.FileListAdapter; 15 | 16 | public class FontListAdapter extends FileListAdapter { 17 | 18 | /** 19 | * Constructor 20 | * 21 | * @param context 22 | * The current context 23 | * @param objects 24 | * The objects to represent in the ListView. 25 | * @param folder 26 | * the parent folder of the items presented, or null if the top 27 | * folder should not be displayed as up 28 | */ 29 | public FontListAdapter(Context context, List objects) { 30 | super(context, objects, null); 31 | } 32 | 33 | /** 34 | * @see fr.xgouchet.androidlib.ui.adapter.FileListAdapter#getView(int, 35 | * android.view.View, android.view.ViewGroup) 36 | */ 37 | public View getView(int position, View convertView, ViewGroup parent) { 38 | View v = super.getView(position, convertView, parent); 39 | 40 | File f = getItem(position); 41 | 42 | if (FileUtils.getFileExtension(f).equalsIgnoreCase("ttf")) { 43 | TextView t = (TextView) v.findViewById(R.id.textFileName); 44 | Typeface font = Typeface.DEFAULT; 45 | try { 46 | font = Typeface.createFromFile(f); 47 | t.setTypeface(font); 48 | } catch (RuntimeException e) { 49 | Log.w("TED", "Unable to create a font from " + f.getName()); 50 | } 51 | } 52 | 53 | return v; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ABOUT 3 | 4 | Ted is an Open Source, Ad-free, lightweight text editor for Android, meant as a Notepad application, and not meant to edit big files. 5 | You can create new text file, open existing files and of course save them. You can also display line numbers and open recent files. You can also search for text inside the opened file. 6 | 7 | The official Ted app is available on the [Google Play Store](https://play.google.com/store/apps/details?id=fr.xgouchet.texteditor). 8 | 9 | ## Icons 10 | 11 | All the icons and graphics used in Ted are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. 12 | 13 | 14 | # LICENCE 15 | 16 | Copyright (C) 2012 by Xavier GOUCHET (http://xgouchet.fr, android@xgouchet.fr) 17 | MIT Licence / Expat 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS ( XAVIER GOUCHET ) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/ui/adapter/PathListAdapter.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.ui.adapter; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.content.Context; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ArrayAdapter; 10 | import android.widget.TextView; 11 | import fr.xgouchet.texteditor.R; 12 | 13 | /** 14 | * A File List Adapter 15 | * 16 | * @author x.gouchet 17 | * 18 | */ 19 | public class PathListAdapter extends ArrayAdapter { 20 | 21 | /** 22 | * Constructor 23 | * 24 | * @param context 25 | * The current context 26 | * @param objects 27 | * The objects to represent in the ListView. 28 | */ 29 | public PathListAdapter(Context context, ArrayList objects) { 30 | super(context, R.layout.item_file, objects); 31 | } 32 | 33 | /** 34 | * @see ArrayAdapter#getView(int, View, ViewGroup) 35 | */ 36 | public View getView(int position, View convertView, ViewGroup parent) { 37 | View v; 38 | String path; 39 | TextView compound; 40 | 41 | // recycle view 42 | v = convertView; 43 | if (v == null) { 44 | LayoutInflater vi = (LayoutInflater) getContext().getSystemService( 45 | Context.LAYOUT_INFLATER_SERVICE); 46 | v = vi.inflate(R.layout.item_file, null); 47 | } 48 | 49 | // get displayed file and current view 50 | path = getItem(position); 51 | 52 | // set the layout content 53 | compound = (TextView) v.findViewById(R.id.textFileName); 54 | if (compound != null) { 55 | if (path == null) { 56 | compound.setText(""); 57 | compound.setCompoundDrawablesWithIntrinsicBounds( 58 | R.drawable.file_unknown, 0, 0, 0); 59 | } else { 60 | compound.setText(path); 61 | compound.setCompoundDrawablesWithIntrinsicBounds( 62 | R.drawable.file, 0, 0, 0); 63 | } 64 | } 65 | return v; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Ted/res/values-es/history.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1.8 (10 nov 2012) 7 | "- Corrección de bug : archivo actual / último archivo abierto 8 | - Sistema de notificaciones actualizado 9 | - Ahora es posible modificar la fuente empleada por el editor (posibilidad de cargar cualquier fuente TTF desde el almacenamiento externo)" 10 | 11 | 12 | 1.7 (16 julio 2012) 13 | "- Correción de bug : Cuelgue al guardar en algunos teléfonos 14 | - Ahora es posible desactivar el autoguardado en los archivos ya existentes" 15 | 16 | 17 | 1.6 (9 julio 2012) 18 | "- Añadido guardado automático 19 | - Arreglado un bug con la búsqueda de archivos " 20 | 21 | 22 | 1.5 (21 junio 2012) 23 | "- Adaptación para Ice Cream Sandwich 24 | - Mejora en la característica de deshacer 25 | - Añadido Widget 26 | - Añadida opción de abrir un archivo al inicio 27 | - Nuevos gráficos (hechos por mí ^^)" 28 | 29 | 30 | 1.3 (5 mayo 2012) 31 | "- Implementada opción de deshacer 32 | - Añadidas optimizaciones de rendimiento" 33 | 34 | 35 | 1.2 (18 abr. 2012) 36 | "- Arreglado un bug en el scroll" 37 | 38 | 39 | 1.1 (10 abr. 2012) 40 | "- Arreglados los cuelgues al inicio 41 | - Añadido scroll por deslizamiento (fling) 42 | - Muestra la línea activa 43 | - Añadido un tema nuevo (si necesitas más, pídelos) 44 | 1.0 (27 feb. 2012) 45 | "- Nueva versión remozada 46 | - Soporte de diversas codificaciones (incluye UTF-8) 47 | - Previene pérdida de datos al guardar archivos muy grande (ojo! Ted no está pensado para abrir grandes archivos!) 48 | - Añadido un tema nuevo (si necesitas más, pídelos) 49 | - El autoguardado ahora pide confirmación (previene el guardado de cambios no deseados)" 50 | 51 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/undo/TextChangeDelete.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.undo; 2 | 3 | import fr.xgouchet.texteditor.BuildConfig; 4 | import android.text.Editable; 5 | import android.util.Log; 6 | 7 | public class TextChangeDelete implements TextChange { 8 | 9 | protected StringBuffer mSequence; 10 | protected int mStart; 11 | 12 | /** 13 | * @param seq 14 | * the sequence being deleted 15 | * @param start 16 | * the start index 17 | */ 18 | public TextChangeDelete(CharSequence seq, int start) { 19 | mSequence = new StringBuffer(); 20 | mSequence.append(seq); 21 | mStart = start; 22 | } 23 | 24 | /** 25 | * @see fr.xgouchet.texteditor.undo.TextChange#undo(android.text.Editable) 26 | */ 27 | public int undo(Editable s) { 28 | s.insert(mStart, mSequence); 29 | return mStart + mSequence.length(); 30 | } 31 | 32 | /** 33 | * @see fr.xgouchet.texteditor.undo.TextChange#getCaret() 34 | */ 35 | public int getCaret() { 36 | if (mSequence.toString().contains(" ")) 37 | return -1; 38 | if (mSequence.toString().contains("\n")) 39 | return -1; 40 | return mStart; 41 | } 42 | 43 | /** 44 | * @see fr.xgouchet.texteditor.undo.TextChange#append(java.lang.CharSequence) 45 | */ 46 | public void append(CharSequence seq) { 47 | mSequence.insert(0, seq); 48 | if (BuildConfig.DEBUG) 49 | Log.d(TAG, mSequence.toString()); 50 | mStart -= seq.length(); 51 | } 52 | 53 | /** 54 | * @see fr.xgouchet.texteditor.undo.TextChange#canMergeChangeAfter(java.lang.CharSequence, 55 | * int, int, int) 56 | */ 57 | public boolean canMergeChangeBefore(CharSequence s, int start, int count, int after) { 58 | CharSequence sub; 59 | if (mSequence.toString().contains(" ")) 60 | return false; 61 | if (mSequence.toString().contains("\n")) 62 | return false; 63 | if ((count != 1) || (start + count != mStart)) 64 | return false; 65 | 66 | sub = s.subSequence(start, start + count); 67 | append(sub); 68 | return true; 69 | } 70 | 71 | /** 72 | * @see fr.xgouchet.texteditor.undo.TextChange#canMergeChangeBefore(java.lang.CharSequence, 73 | * int, int, int) 74 | */ 75 | public boolean canMergeChangeAfter(CharSequence s, int start, int before, int count) { 76 | return false; 77 | } 78 | 79 | /** 80 | * @see java.lang.Object#toString() 81 | */ 82 | public String toString() { 83 | return "-\"" + mSequence.toString().replaceAll("\n", "~") + "\" @" + mStart; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/undo/TextChange.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.undo; 2 | 3 | import android.text.Editable; 4 | import fr.xgouchet.texteditor.common.Constants; 5 | 6 | public interface TextChange extends Constants { 7 | 8 | /** 9 | * Undo this change 10 | * 11 | * @param text 12 | * the editable object on which the undo is done 13 | * @return the caret position after the undo 14 | */ 15 | public int undo(Editable text); 16 | 17 | /** 18 | * Method is deprecated, you should use the canMergeXXX methods instead 19 | * 20 | * @return the caret position after this change 21 | */ 22 | @Deprecated 23 | public int getCaret(); 24 | 25 | /** 26 | * Method is deprecated, you should use the canMergeXXX methods instead 27 | * 28 | * @param sequence 29 | * the sequence being appended to this {@link TextChange} 30 | */ 31 | @Deprecated 32 | public void append(CharSequence sequence); 33 | 34 | /** 35 | * A change to the text {@linkplain s} will be made, where the 36 | * {@linkplain count} characters starting at {@linkplain start} will be 37 | * replaced by {@linkplain after} characters 38 | * 39 | * If possible, this change is merged in this {@link TextChange} 40 | * 41 | * @param s 42 | * the sequence being changed 43 | * @param start 44 | * the start index 45 | * @param count 46 | * the number of characters that will change 47 | * @param after 48 | * the number of characters that will replace the old ones 49 | * @return if the change can be merged with this {@link TextChange} 50 | */ 51 | public boolean canMergeChangeBefore(CharSequence s, int start, int count, 52 | int after); 53 | 54 | /** 55 | * A change to the text {@linkplain s} has been made, where the 56 | * {@linkplain count} characters starting at {@linkplain start} have 57 | * replaced the substring of length {@linkplain before} 58 | * 59 | * If possible, this change is merged in this {@link TextChange} 60 | * 61 | * @param s 62 | * the sequence being changed 63 | * @param start 64 | * the start index 65 | * @param before 66 | * the number of character that were replaced 67 | * @param count 68 | * the number of characters that will change 69 | * @return if the change can be merged with this {@link TextChange} 70 | */ 71 | public boolean canMergeChangeAfter(CharSequence s, int start, int before, 72 | int count); 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Ted/changelog.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | RELEASE 1.5 (30 june 2012) 4 | - New Graphics 5 | - Undo bugs with ICS 6 | - New file extensions added (.ini, .rc, .sh, .log, .db, .conf, .cfg, .bat) 7 | - Better integration with ICS 8 | 9 | 10 | RELEASE 1.3 (5 may 2012) 11 | - Added an undo option (check the settings) 12 | - Added some performance tweaks 13 | 14 | RELEASE 1.2 (18 apr. 2012) 15 | - Fixed the scroll bug since last update 16 | - fixed the fling options in the settings (option was always active) 17 | 18 | RELEASE 1.1 (10 apr. 2012) 19 | - Fixed the crash at start caused by the last update 20 | - Added Fling to Scroll (launches the scroll to navigate in large files) 21 | - Display the active line 22 | - Added new color theme (ask for more if needed) 23 | 24 | RELEASE 1.0 (27 feb. 2012) 25 | - Brand new release version 26 | - Supports multiple encoding (including UTF-8) 27 | - Prevent data loss when saving really big files (note that Ted is not meant to open big files though) 28 | - Added new color theme (ask for more if needed) 29 | - Replaced the autosave with a warning and popup (prevent saving unwanted changes) 30 | 31 | ----------------------------------------------------------------------- 32 | βetα 0.9 (7 janv. 2010) 33 | - Bug fixed : severall crash on start 34 | - Added a search tool 35 | - Ted is listed when opening html, rss, css, php and xml files from any file browser (ask for other types if needed) 36 | 37 | βetα 0.8 (23 dec. 2010) 38 | - Automatic save can be disabled in the settings 39 | 40 | βetα 0.7 (19 dec. 2010) 41 | - App can be installed on the SD Card (on Android 2.2) 42 | - Automatic detection of end of line in opened files, possibility to define a default end of line for new files 43 | - Bigger dialog boxes 44 | - Bug fixed when openning big files 45 | 46 | βetα 0.6 (8 dec. 2010) 47 | - Possibility to change text size in the settings. 48 | - Possibility to open read-only text files from other location than the SD card 49 | - Added a backup function for unsaved text 50 | 51 | βetα 0.5 (29 nov. 2010) 52 | - Bug fixed while opening some files 53 | - New Graphics 54 | 55 | βetα 0.4 (27 nov. 2010) 56 | - Remembers the files opened recently (number of recent files can be changed) 57 | - display lines numbers (can be changed in the settings) 58 | - automatically break lines to keep a width of one page (can be changed in the settings) 59 | 60 | βetα 0.3 (25 nov. 2010) 61 | - Bug fixed : crash when trying to open online files 62 | 63 | βetα 0.2 (13 nov. 2010) 64 | - Open existing files 65 | - Save and save as -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/RecentFiles.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | 6 | import fr.xgouchet.texteditor.BuildConfig; 7 | 8 | import android.content.SharedPreferences; 9 | import android.content.SharedPreferences.Editor; 10 | import android.util.Log; 11 | 12 | /** 13 | * Storage for a recent files list 14 | * 15 | * TODO code review 16 | */ 17 | public class RecentFiles implements Constants { 18 | 19 | /** 20 | * loads the recent files from shared preferences 21 | * 22 | * @param saved 23 | * the previously saved string 24 | */ 25 | public static void loadRecentFiles(String saved) { 26 | PATHS = new ArrayList(); 27 | String[] paths = saved.split(File.pathSeparator); 28 | for (String path : paths) { 29 | if (path.length() > 0) { 30 | PATHS.add(path); 31 | } 32 | if (PATHS.size() == Settings.MAX_RECENT_FILES) { 33 | break; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * Saves the preferences when they have been edited 40 | * 41 | * @param prefs 42 | * the preferences to save to 43 | */ 44 | public static void saveRecentList(SharedPreferences prefs) { 45 | String str = ""; 46 | Editor editor; 47 | 48 | for (String path : PATHS) { 49 | str += path; 50 | str += File.pathSeparator; 51 | } 52 | 53 | editor = prefs.edit(); 54 | editor.putString(PREFERENCE_RECENTS, str); 55 | editor.commit(); 56 | } 57 | 58 | /** 59 | * @return the list of most recent files 60 | */ 61 | public static ArrayList getRecentFiles() { 62 | return PATHS; 63 | } 64 | 65 | /** 66 | * Updates the recent list with a path. If the path is already in the list, 67 | * bring it back to top, else add it. 68 | * 69 | * @param path 70 | * the path to insert 71 | */ 72 | public static void updateRecentList(String path) { 73 | if (PATHS.contains(path)) { 74 | PATHS.remove(path); 75 | } 76 | 77 | PATHS.add(0, path); 78 | while (PATHS.size() > Settings.MAX_RECENT_FILES) { 79 | PATHS.remove(Settings.MAX_RECENT_FILES); 80 | } 81 | if (BuildConfig.DEBUG) { 82 | Log.d(TAG, "added path to recent files : " + path); 83 | } 84 | } 85 | 86 | /** 87 | * Removes a path from the recent files list 88 | * 89 | * @param path 90 | * the path to remove 91 | */ 92 | public static void removePath(String path) { 93 | if (PATHS.contains(path)) { 94 | PATHS.remove(path); 95 | } 96 | } 97 | 98 | /** the list of paths in the recent list */ 99 | private static ArrayList PATHS; 100 | } 101 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedAppWidgetProvider.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | 5 | import android.app.PendingIntent; 6 | import android.appwidget.AppWidgetManager; 7 | import android.appwidget.AppWidgetProvider; 8 | import android.content.ComponentName; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.net.Uri; 12 | import android.util.Log; 13 | import android.widget.RemoteViews; 14 | import fr.xgouchet.texteditor.common.Constants; 15 | import fr.xgouchet.texteditor.common.WidgetPrefs; 16 | 17 | public class TedAppWidgetProvider extends AppWidgetProvider implements Constants { 18 | 19 | /** 20 | * @see android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 21 | * android.appwidget.AppWidgetManager, int[]) 22 | */ 23 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 24 | 25 | AppWidgetManager manager; 26 | ComponentName widgetName; 27 | 28 | if (BuildConfig.DEBUG) 29 | Log.i(TAG, "onUpdate widgets"); 30 | 31 | manager = AppWidgetManager.getInstance(context); 32 | widgetName = new ComponentName(context, TedAppWidgetProvider.class); 33 | int[] widgetIds = manager.getAppWidgetIds(widgetName); 34 | 35 | for (int widgetId : widgetIds) { 36 | updateWidget(context, manager, widgetId); 37 | } 38 | } 39 | 40 | /** 41 | * @see android.appwidget.AppWidgetProvider#onDeleted(android.content.Context, 42 | * int[]) 43 | */ 44 | public void onDeleted(Context context, int[] appWidgetIds) { 45 | 46 | for (int widgetId : appWidgetIds) { 47 | WidgetPrefs.delete(context, widgetId); 48 | } 49 | } 50 | 51 | public static void updateWidget(Context context, AppWidgetManager manager, int widgetId) { 52 | Intent intent; 53 | PendingIntent pendingIntent; 54 | RemoteViews views; 55 | WidgetPrefs pref; 56 | File targetFile; 57 | 58 | pref = new WidgetPrefs(); 59 | pref.load(context, widgetId); 60 | 61 | if (BuildConfig.DEBUG) 62 | Log.i(TAG, "Updating widgetId " + String.valueOf(widgetId)); 63 | 64 | targetFile = new File(pref.mTargetPath); 65 | 66 | intent = new Intent(context, TedActivity.class); 67 | intent.setAction(ACTION_WIDGET_OPEN); 68 | intent.setData(Uri.fromFile(targetFile)); 69 | intent.putExtra(EXTRA_FORCE_READ_ONLY, pref.mReadOnly); 70 | 71 | pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 72 | 73 | views = new RemoteViews(context.getPackageName(), R.layout.widget); 74 | 75 | views.setOnClickPendingIntent(R.id.widgetLayout, pendingIntent); 76 | if (pref.mReadOnly) 77 | views.setImageViewResource(R.id.icon, R.drawable.file_text_favorite_readonly); 78 | else 79 | views.setImageViewResource(R.id.icon, R.drawable.file_text_favorite); 80 | views.setTextViewText(R.id.textFileName, targetFile.getName()); 81 | 82 | manager.updateAppWidget(widgetId, views); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Ted/res/values/toasts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | There are no recent files to load 5 | "File doesn't exist anymore, removing from recent list." 6 | File deleted from recent list 7 | Unable to open the file, URI is invalid 8 | Unable to open the file 9 | Unable to load the file browser 10 | Unable to open the recent files list 11 | Unable to load the file browser 12 | Unable to load the settings page 13 | Unable to load the about page 14 | Unable to open the file, not enough memory 15 | Unable to open the file (maybe the file is too big, or corrupted) 16 | Unable to save, path is null 17 | Unable to save to temp file 18 | Unable to save (error while copying temp file to save location) 19 | Unable to save (error while copying temp file to save location) 20 | File saved 21 | "Can't use this folder cause it isn't writeable" 22 | "Can't use this file cause it isn't readable" 23 | No match was found in the current file 24 | No more match found in the current file 25 | Type a text to search in the search bar 26 | The filename must not be empty 27 | Nothing to undo anymore. 28 | Nothing to undo anymore. Press Back one more time to quit. 29 | Default file not found, try setting a new one in the settings. 30 | "Can't open default file cause it isn't readable" 31 | Select a file to associate with this new widget 32 | Select a file to open 33 | Select a file to open when you launch Ted from your home screen 34 | "The opened file was saved automatically, and will be opened at next startup" 35 | 36 | -------------------------------------------------------------------------------- /Ted/res/values-es/toasts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | No hay archivos recientes 5 | "Ya no existe el archivo. Se elimina de la lista de recientes." 6 | Elemento eliminado de la lista de recientes 7 | Error al abrir el archivo, dirección no válida 8 | Error al abrir el archivo 9 | Error al cargar el explorador de archivos 10 | Error al cargar la lista de archivos recientes 11 | Error al cargar el explorador de archivos 12 | Error al cargar la pantalla de configuración 13 | Error al cargar "Acerca de" 14 | Error al abrir el archivo. Memoria insuficiente 15 | Error al abrir el archivo (Archivo demasiado grande o corrupto) 16 | Error al guardar. Escribe un destino 17 | Error al guardar el archivo temporal 18 | Error al guardar (fallo al escribir el archivo en su ubicación definitiva) 19 | Error al guardar (fallo al escribir el archivo en su ubicación definitiva) 20 | Archivo guardado 21 | "No se puede escribir en el directorio. Permiso denegado" 22 | "No se puede leer el directorio. Permiso denegado" 23 | No se encuentran coincidencias 24 | No se encuentran más coincidencias 25 | Escribe algo en la barra de búsqueda 26 | Escribe un nombre de archivo 27 | No se puede deshacer más. 28 | No se puede deshacer más. Pulsa atrás otra vez para salir. 29 | Archivo por defecto no encontrado. 30 | "No se puede leer el archivo por defecto" 31 | Elige un archivo para asociar a este widget 32 | Elige un archivo para abrir 33 | Elige un archivo para abrir desde la pantalla de inicio 34 | "El archivo abierto se ha guardado automáticamente y será abierto en el siguiente inicio" 35 | 36 | 37 | -------------------------------------------------------------------------------- /Ted/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Classic 7 | Negative 8 | Matrix 9 | Sky 10 | Dracula 11 | 12 | 13 | 0 14 | 1 15 | 2 16 | 3 17 | 4 18 | 19 | 20 | 21 | 22 | 6 pt 23 | 8 pt 24 | 10 pt 25 | 12 pt 26 | 14 pt 27 | 16 pt 28 | 18 pt 29 | 24 pt 30 | 32 pt 31 | 48 pt 32 | 33 | 34 | 6 35 | 8 36 | 10 37 | 12 38 | 14 39 | 16 40 | 18 41 | 24 42 | 32 43 | 48 44 | 45 | 46 | 47 | 48 | Android / Linux / Unix 49 | Windows / Symbian / Palm 50 | Mac / iPhone 51 | 52 | 53 | 0 54 | 1 55 | 2 56 | 57 | 58 | 59 | 60 | 10 61 | 25 62 | 50 63 | 100 64 | 200 65 | 500 66 | 67 | 68 | 69 | 70 | 0 71 | 1 72 | 2 73 | 3 74 | 4 75 | 5 76 | 6 77 | 7 78 | 8 79 | 9 80 | 10 81 | 11 82 | 12 83 | 13 84 | 14 85 | 15 86 | 87 | 88 | 89 | 90 | ASCII 91 | Latin 1 92 | UTF 8 93 | 94 | 95 | US-ASCII 96 | ISO-8859-1 97 | UTF-8 98 | 99 | 100 | -------------------------------------------------------------------------------- /Ted/res/values-es/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Clásico 7 | Negativo 8 | Matrix 9 | Azul 10 | Drácula 11 | 12 | 13 | 0 14 | 1 15 | 2 16 | 3 17 | 4 18 | 19 | 20 | 21 | 22 | 6 pt 23 | 8 pt 24 | 10 pt 25 | 12 pt 26 | 14 pt 27 | 16 pt 28 | 18 pt 29 | 24 pt 30 | 32 pt 31 | 48 pt 32 | 33 | 34 | 6 35 | 8 36 | 10 37 | 12 38 | 14 39 | 16 40 | 18 41 | 24 42 | 32 43 | 48 44 | 45 | 46 | 47 | 48 | Android / Linux / Unix 49 | Windows / Symbian / Palm 50 | Mac / iPhone 51 | 52 | 53 | 0 54 | 1 55 | 2 56 | 57 | 58 | 59 | 60 | 10 61 | 25 62 | 50 63 | 100 64 | 200 65 | 500 66 | 67 | 68 | 69 | 70 | 0 71 | 1 72 | 2 73 | 3 74 | 4 75 | 5 76 | 6 77 | 7 78 | 8 79 | 9 80 | 10 81 | 11 82 | 12 83 | 13 84 | 14 85 | 15 86 | 87 | 88 | 89 | 90 | ASCII 91 | Latin 1 92 | UTF 8 93 | 94 | 95 | US-ASCII 96 | ISO-8859-1 97 | UTF-8 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Ted/res/values-sk/toasts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Žiadne nedávne súbory na načítanie 5 | "Súbor už neexistuje, vymaže sa zo zoznamu nedávnych súborov." 6 | Súbor bol vymazaný zo zoznamu nedávnych súborov 7 | Nemožno otvoriť súbor, URI je neplatné 8 | Nemožno otvoriť súbor 9 | Nemožno načítať prehliadač súborov 10 | Nemožno otvoriť zoznam nedávnych súborov 11 | Nemožno načítať prehliadač súborov 12 | Nemožno načítať stránku s nastaveniami 13 | Nemožno načítať stránku o aplikácii 14 | Nemožno otvoriť súbor, nedostatok pamäte 15 | Nemožno otvoriť súbor (súbor je možno príliš veľký alebo poškodený) 16 | Nemožno uložiť, cesta nie je určená 17 | Nemožno uložiť do dočasného súboru 18 | Nemožno uložiť (chyba pri kopírovaní dočasného súbora do umiestnenia na uloženie) 19 | Nemožno uložiť (chyba pri kopírovaní dočasného súbora do umiestnenia na uloženie) 20 | Súbor bol uložený 21 | "Nemožno použiť tento priečinok, pretože nie je na zapisovanie" 22 | "Nemožno použiť tento súbor, pretože nie je na čítanie" 23 | Nenašla sa žiadna zhoda v súčasnom súbore 24 | Nenašla sa žiadna ďalšia zhoda v súčasnom súbore 25 | Zadajte text dp vyhľadávacieho riadku, ktorý chcete vyhľadať 26 | Názov súboru nesmie byť prázdny 27 | Nič na vrátenie. 28 | Nič na vrátenie. Stlačte tlačidlo Späť ešte raz pre ukončenie. 29 | Predvolený súbor nebol nájdený, skúste nastaviť nový v nastaveniach. 30 | "Nemožno otvoriť predvolený súbor, pretože nie je na čítanie" 31 | Vyberte súbor, ktorý chcete spojiť s touto novou miniaplikáciou 32 | Vyberte súbor na otvorenie 33 | Vyberte súbor, ktorý chcete otvoriť pri spustení Teda z domovskej obrazovky 34 | "Otvorený súbor sa uložil automaticky a bude otvorený pri ďalšom spustení" 35 | 36 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedFontActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | import java.util.LinkedList; 5 | 6 | import android.app.Activity; 7 | import android.content.Intent; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.view.KeyEvent; 11 | import android.view.View; 12 | import android.view.View.OnClickListener; 13 | import de.neofonie.mobile.app.android.widget.crouton.Crouton; 14 | import de.neofonie.mobile.app.android.widget.crouton.Style; 15 | import fr.xgouchet.androidlib.ui.activity.AbstractBrowsingActivity; 16 | import fr.xgouchet.texteditor.ui.adapter.FontListAdapter; 17 | 18 | public class TedFontActivity extends AbstractBrowsingActivity implements 19 | OnClickListener { 20 | 21 | /** 22 | * @see android.app.Activity#onCreate(android.os.Bundle) 23 | */ 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | 27 | setContentView(R.layout.layout_open); 28 | mExtWhiteList.add("ttf"); 29 | 30 | // set default result 31 | setResult(RESULT_CANCELED, null); 32 | 33 | // buttons 34 | findViewById(R.id.buttonCancel).setOnClickListener(this); 35 | 36 | mListAdapter = new FontListAdapter(this, new LinkedList()); 37 | } 38 | 39 | /** 40 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFileClick(java.io.File) 41 | */ 42 | protected void onFileClick(File file) { 43 | if (setOpenResult(file)) 44 | finish(); 45 | } 46 | 47 | /** 48 | * @see fr.xgouchet.androidlib.ui.activity.BrowsingActivity#onFolderClick(java.io.File) 49 | */ 50 | protected boolean onFolderClick(File folder) { 51 | return true; 52 | } 53 | 54 | /** 55 | * @see fr.xgouchet.androidlib.ui.activity.BrowsingActivity#onFolderViewFilled() 56 | */ 57 | protected void onFolderViewFilled() { 58 | 59 | } 60 | 61 | /** 62 | * @see Activity#onKeyUp(int, KeyEvent) 63 | */ 64 | public boolean onKeyUp(int keyCode, KeyEvent event) { 65 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { 66 | // navigate to parent folder 67 | File parent = mCurrentFolder.getParentFile(); 68 | if ((parent != null) && (parent.exists())) { 69 | fillFolderView(parent); 70 | return true; 71 | } 72 | } 73 | return super.onKeyUp(keyCode, event); 74 | } 75 | 76 | /** 77 | * @see android.view.View.OnClickListener#onClick(android.view.View) 78 | */ 79 | public void onClick(View v) { 80 | if (v.getId() == R.id.buttonCancel) { 81 | setResult(RESULT_CANCELED); 82 | finish(); 83 | } 84 | } 85 | 86 | /** 87 | * Set the result of this activity to open a file 88 | * 89 | * @param file 90 | * the file to return 91 | * @return if the result was set correctly 92 | */ 93 | protected boolean setOpenResult(File file) { 94 | Intent result; 95 | 96 | if (!file.canRead()) { 97 | Crouton.showText(this, R.string.toast_file_cant_read, Style.ALERT); 98 | return false; 99 | } 100 | 101 | result = new Intent(); 102 | result.setData(Uri.fromFile(file)); 103 | 104 | setResult(RESULT_OK, result); 105 | return true; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Ted/res/values-fr/toasts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | "Il n'y a pas de fichier recent à charger" 5 | "Le fichier selectionné n'existe plus" 6 | Fichier supprimé de la liste 7 | "Impossible d'ouvrir le fichier : adresse invalide" 8 | "Impossible d'ouvrir le fichier" 9 | "Impossible d'ouvrir l'explorateur de fichier" 10 | "Impossible d'ouvrir la liste de fichiers récents" 11 | "Impossible d'ouvrir l'explorateur de fichier" 12 | "Impossible d'ouvrir la page de paramètres" 13 | "Impossible d'ouvrir la page 'A propos'" 14 | "Impossible d'ouvrir le fichier, pas assez de mémoire" 15 | "Impossible d'ouvrir le fichier (le fichier est peut-être trop grand, ou corrompu)" 16 | "Impossible de sauver, le chemin d'accès est vide" 17 | "Impossible de sauvegarder le fichier temporaire" 18 | "Impossible de sauvegarder (erreur lors de la copie du fichier temporaire)" 19 | "Impossible de sauvegarder (erreur lors de la copie du fichier temporaire)" 20 | Fichier sauvegardé 21 | "Impossible d'ouvrir, ce dossier n'existe pas" 22 | "Impossible d'ouvrir, le fichier est protégé en lecture" 23 | "Can't use this file cause it isn't readable" 24 | "Pas de résultat dans ce fichier" 25 | "Pas d'autre résultat dans ce fichier" 26 | "Recherche vide" 27 | Le nom de fichier ne doit pas être vide 28 | Rien à annuler 29 | "Rien à annuler. Pressez retour pour quitter l'application" 30 | "Fichier par défaut non trouvé. Essayez d'en sélectionner un autre dans les options" 31 | "Impossible d'ouvrir, le fichier par défaut est protégé en lecture" 32 | Sélectionnez un fichier à associer à ce widget 33 | Sélectionnez un fichier à ouvrir 34 | Sélectionnez un fichier à ouvrir au démarrage de Ted 35 | "Le document a été sauvegardé et sera réouvert au prochain démarrage de Ted" 36 | 37 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/WidgetPrefs.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.content.SharedPreferences.Editor; 6 | 7 | public class WidgetPrefs { 8 | 9 | public final static String WIDGET_PREFERENCES = "fr.xgouchet.texteditor.widget"; 10 | 11 | public final static String WIDGET_TARGET_PATH = "target_path_"; 12 | 13 | public final static String WIDGET_READ_ONLY = "read_only_"; 14 | 15 | public final static String WIDGET_PRESENT_KEY = "widget_present_"; 16 | 17 | public String mTargetPath; 18 | public boolean mReadOnly; 19 | 20 | public WidgetPrefs() { 21 | mTargetPath = ""; 22 | } 23 | 24 | /** 25 | * Loads the widget prefs from the shared preferences 26 | * 27 | * @param context 28 | * the current context 29 | * @param widgetId 30 | * this widget id 31 | * @return if the widget is still present 32 | */ 33 | public boolean load(Context context, int widgetId) { 34 | String key; 35 | SharedPreferences prefs; 36 | 37 | prefs = context.getSharedPreferences(WIDGET_PREFERENCES, 38 | Context.MODE_PRIVATE); 39 | 40 | if (prefs != null) { 41 | key = WIDGET_TARGET_PATH + String.valueOf(widgetId); 42 | mTargetPath = prefs.getString(key, ""); 43 | 44 | key = WIDGET_READ_ONLY + String.valueOf(widgetId); 45 | mReadOnly = prefs.getBoolean(key, false); 46 | 47 | key = WIDGET_PRESENT_KEY + String.valueOf(widgetId); 48 | return prefs.getBoolean(key, false); 49 | } 50 | 51 | return false; 52 | } 53 | 54 | /** 55 | * Store this widget prefs in the shared preferences 56 | * 57 | * @param context 58 | * the current context 59 | * @param widgetId 60 | * this widget id 61 | */ 62 | public void store(Context context, int widgetId) { 63 | String key; 64 | SharedPreferences prefs; 65 | Editor edit; 66 | 67 | prefs = context.getSharedPreferences(WIDGET_PREFERENCES, 68 | Context.MODE_PRIVATE); 69 | 70 | if (prefs != null) { 71 | edit = prefs.edit(); 72 | 73 | if (edit != null) { 74 | key = WIDGET_TARGET_PATH + String.valueOf(widgetId); 75 | edit.putString(key, mTargetPath); 76 | 77 | key = WIDGET_READ_ONLY + String.valueOf(widgetId); 78 | edit.putBoolean(key, mReadOnly); 79 | 80 | key = WIDGET_PRESENT_KEY + String.valueOf(widgetId); 81 | edit.putBoolean(key, true); 82 | 83 | edit.commit(); 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * Delete the data associated with a widget ID 90 | * 91 | * @param context 92 | * the current context 93 | * @param widgetId 94 | * the id to delete 95 | */ 96 | public static void delete(Context context, int widgetId) { 97 | String key; 98 | SharedPreferences prefs; 99 | Editor edit; 100 | 101 | prefs = context.getSharedPreferences(WIDGET_PREFERENCES, 102 | Context.MODE_PRIVATE); 103 | if (prefs != null) { 104 | edit = prefs.edit(); 105 | 106 | if (edit != null) { 107 | key = WIDGET_TARGET_PATH + String.valueOf(widgetId); 108 | edit.remove(key); 109 | 110 | key = WIDGET_READ_ONLY + String.valueOf(widgetId); 111 | edit.remove(key); 112 | 113 | key = WIDGET_PRESENT_KEY + String.valueOf(widgetId); 114 | edit.remove(key); 115 | 116 | edit.commit(); 117 | } 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedWidgetConfigActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | 5 | import android.appwidget.AppWidgetManager; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.CheckBox; 11 | import fr.xgouchet.androidlib.data.FileUtils; 12 | import fr.xgouchet.androidlib.ui.Toaster; 13 | import fr.xgouchet.androidlib.ui.activity.AbstractBrowsingActivity; 14 | import fr.xgouchet.texteditor.common.Constants; 15 | import fr.xgouchet.texteditor.common.WidgetPrefs; 16 | 17 | public class TedWidgetConfigActivity extends AbstractBrowsingActivity implements Constants, OnClickListener { 18 | 19 | /** 20 | * @see android.app.Activity#onCreate(android.os.Bundle) 21 | */ 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.layout_widget_config); 25 | 26 | setResult(RESULT_CANCELED, null); 27 | 28 | // buttons 29 | findViewById(R.id.buttonCancel).setOnClickListener(this); 30 | 31 | Toaster.showToast(this, R.string.toast_widget_select, false); 32 | } 33 | 34 | /** 35 | * @see android.app.Activity#onResume() 36 | */ 37 | protected void onResume() { 38 | super.onResume(); 39 | 40 | // get widget id 41 | Intent intent = getIntent(); 42 | Bundle extras = intent.getExtras(); 43 | if (extras != null) { 44 | mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, 45 | AppWidgetManager.INVALID_APPWIDGET_ID); 46 | } 47 | } 48 | 49 | /** 50 | * @see android.view.View.OnClickListener#onClick(android.view.View) 51 | */ 52 | public void onClick(View v) { 53 | switch (v.getId()) { 54 | case R.id.buttonCancel: 55 | setResult(RESULT_CANCELED); 56 | finish(); 57 | break; 58 | } 59 | } 60 | 61 | /** 62 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFileClick(java.io.File) 63 | */ 64 | protected void onFileClick(File file) { 65 | if (file.canRead()) { 66 | mSelectedFile = file; 67 | setResultComplete(); 68 | } 69 | } 70 | 71 | /** 72 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFolderClick(java.io.File) 73 | */ 74 | protected boolean onFolderClick(File folder) { 75 | mSelectedFile = null; 76 | return true; 77 | } 78 | 79 | /** 80 | * @see fr.xgouchet.androidlib.ui.activity.BrowsingActivity#onFolderViewFilled() 81 | */ 82 | protected void onFolderViewFilled() { 83 | 84 | } 85 | 86 | /** 87 | * 88 | */ 89 | protected void setResultComplete() { 90 | AppWidgetManager appWidgetManager; 91 | Intent resultValue; 92 | WidgetPrefs prefs; 93 | boolean readOnly; 94 | 95 | readOnly = ((CheckBox) findViewById(R.id.readOnly)).isChecked(); 96 | 97 | prefs = new WidgetPrefs(); 98 | prefs.mTargetPath = FileUtils.getCanonizePath(mSelectedFile); 99 | prefs.mReadOnly = readOnly; 100 | prefs.store(this, mAppWidgetId); 101 | 102 | appWidgetManager = AppWidgetManager.getInstance(this); 103 | TedAppWidgetProvider.updateWidget(this, appWidgetManager, mAppWidgetId); 104 | 105 | // 106 | resultValue = new Intent(); 107 | resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); 108 | setResult(RESULT_OK, resultValue); 109 | finish(); 110 | } 111 | 112 | /** the id of the widget being configured */ 113 | protected int mAppWidgetId; 114 | 115 | /** the selected file */ 116 | protected File mSelectedFile; 117 | } 118 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedOpenActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | 5 | import android.app.Activity; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.view.KeyEvent; 9 | import android.view.View; 10 | import android.view.View.OnClickListener; 11 | import de.neofonie.mobile.app.android.widget.crouton.Crouton; 12 | import de.neofonie.mobile.app.android.widget.crouton.Style; 13 | import fr.xgouchet.androidlib.ui.activity.AbstractBrowsingActivity; 14 | import fr.xgouchet.texteditor.common.Constants; 15 | 16 | public class TedOpenActivity extends AbstractBrowsingActivity implements 17 | OnClickListener, Constants { 18 | 19 | /** 20 | * @see android.app.Activity#onCreate(android.os.Bundle) 21 | */ 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | int request; 25 | Bundle extras; 26 | 27 | // Setup content view 28 | setContentView(R.layout.layout_open); 29 | 30 | // buttons 31 | findViewById(R.id.buttonCancel).setOnClickListener(this); 32 | 33 | // set default result 34 | setResult(RESULT_CANCELED, null); 35 | 36 | // show the title as toast 37 | extras = getIntent().getExtras(); 38 | if (extras != null) 39 | request = extras.getInt(EXTRA_REQUEST_CODE); 40 | else 41 | request = -1; 42 | 43 | switch (request) { 44 | case REQUEST_OPEN: 45 | Crouton.showText(this, R.string.toast_open_select, Style.INFO); 46 | break; 47 | case REQUEST_HOME_PAGE: 48 | Crouton.showText(this, R.string.toast_home_page_select, Style.INFO); 49 | break; 50 | } 51 | 52 | } 53 | 54 | /** 55 | * @see Activity#onKeyUp(int, KeyEvent) 56 | */ 57 | public boolean onKeyUp(int keyCode, KeyEvent event) { 58 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { 59 | // navigate to parent folder 60 | File parent = mCurrentFolder.getParentFile(); 61 | if ((parent != null) && (parent.exists())) { 62 | fillFolderView(parent); 63 | return true; 64 | } 65 | } 66 | return super.onKeyUp(keyCode, event); 67 | } 68 | 69 | /** 70 | * @see android.view.View.OnClickListener#onClick(android.view.View) 71 | */ 72 | public void onClick(View v) { 73 | if (v.getId() == R.id.buttonCancel) { 74 | setResult(RESULT_CANCELED); 75 | finish(); 76 | } 77 | } 78 | 79 | /** 80 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFolderClick(java.io.File) 81 | */ 82 | protected boolean onFolderClick(File folder) { 83 | return true; 84 | } 85 | 86 | /** 87 | * @see fr.xgouchet.androidlib.ui.activity.BrowsingActivity#onFolderViewFilled() 88 | */ 89 | protected void onFolderViewFilled() { 90 | 91 | } 92 | 93 | /** 94 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFileClick(java.io.File) 95 | */ 96 | protected void onFileClick(File file) { 97 | if (setOpenResult(file)) 98 | finish(); 99 | } 100 | 101 | /** 102 | * Set the result of this activity to open a file 103 | * 104 | * @param file 105 | * the file to return 106 | * @return if the result was set correctly 107 | */ 108 | protected boolean setOpenResult(File file) { 109 | Intent result; 110 | 111 | if (!file.canRead()) { 112 | Crouton.showText(this, R.string.toast_file_cant_read, Style.ALERT); 113 | return false; 114 | } 115 | 116 | result = new Intent(); 117 | result.putExtra("path", file.getAbsolutePath()); 118 | 119 | setResult(RESULT_OK, result); 120 | return true; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedSaveAsActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import static fr.xgouchet.androidlib.ui.Toaster.showToast; 4 | 5 | import java.io.File; 6 | 7 | import android.content.Intent; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Bundle; 10 | import android.view.View; 11 | import android.view.View.OnClickListener; 12 | import android.widget.Button; 13 | import android.widget.EditText; 14 | import fr.xgouchet.androidlib.ui.activity.AbstractBrowsingActivity; 15 | import fr.xgouchet.texteditor.common.Constants; 16 | 17 | public class TedSaveAsActivity extends AbstractBrowsingActivity implements 18 | Constants, OnClickListener { 19 | 20 | /** 21 | * @see android.app.Activity#onCreate(android.os.Bundle) 22 | */ 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | 26 | // Setup content view 27 | setContentView(R.layout.layout_save_as); 28 | 29 | // buttons 30 | findViewById(R.id.buttonCancel).setOnClickListener(this); 31 | findViewById(R.id.buttonOk).setOnClickListener(this); 32 | ((Button) findViewById(R.id.buttonOk)).setText(R.string.ui_save); 33 | 34 | // widgets 35 | mFileName = (EditText) findViewById(R.id.editFileName); 36 | 37 | // drawables 38 | mWriteable = getResources().getDrawable(R.drawable.folder_rw); 39 | mLocked = getResources().getDrawable(R.drawable.folder_r); 40 | } 41 | 42 | /** 43 | * @see android.view.View.OnClickListener#onClick(android.view.View) 44 | */ 45 | public void onClick(View v) { 46 | switch (v.getId()) { 47 | case R.id.buttonCancel: 48 | setResult(RESULT_CANCELED); 49 | finish(); 50 | break; 51 | case R.id.buttonOk: 52 | if (setSaveResult()) 53 | finish(); 54 | } 55 | } 56 | 57 | /** 58 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFileClick(java.io.File) 59 | */ 60 | protected void onFileClick(File file) { 61 | if (file.canWrite()) 62 | mFileName.setText(file.getName()); 63 | } 64 | 65 | /** 66 | * @see fr.xgouchet.androidlib.ui.activity.BrowserActivity#onFolderClick(java.io.File) 67 | */ 68 | protected boolean onFolderClick(File folder) { 69 | return true; 70 | } 71 | 72 | /** 73 | * @see fr.xgouchet.androidlib.ui.activity.BrowsingActivity#onFolderViewFilled() 74 | */ 75 | protected void onFolderViewFilled() { 76 | 77 | } 78 | 79 | /** 80 | * Sets the result data when the user presses save 81 | * 82 | * @return if the result is OK (if not, it means the user must change its 83 | * selection / input) 84 | */ 85 | protected boolean setSaveResult() { 86 | Intent result; 87 | String fileName; 88 | 89 | if ((mCurrentFolder == null) || (!mCurrentFolder.exists())) { 90 | showToast(this, R.string.toast_folder_doesnt_exist, true); 91 | return false; 92 | } 93 | 94 | if (!mCurrentFolder.canWrite()) { 95 | showToast(this, R.string.toast_folder_cant_write, true); 96 | return false; 97 | } 98 | 99 | fileName = mFileName.getText().toString(); 100 | if (fileName.length() == 0) { 101 | showToast(this, R.string.toast_filename_empty, true); 102 | return false; 103 | } 104 | 105 | result = new Intent(); 106 | result.putExtra("path", mCurrentFolder.getAbsolutePath() 107 | + File.separator + fileName); 108 | 109 | setResult(RESULT_OK, result); 110 | return true; 111 | } 112 | 113 | /** the edit text input */ 114 | protected EditText mFileName; 115 | 116 | /** */ 117 | protected Drawable mWriteable; 118 | /** */ 119 | protected Drawable mLocked; 120 | 121 | } 122 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/undo/TextChangeInsert.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.undo; 2 | 3 | import fr.xgouchet.texteditor.BuildConfig; 4 | import android.text.Editable; 5 | import android.util.Log; 6 | 7 | public class TextChangeInsert implements TextChange { 8 | 9 | protected StringBuffer mSequence; 10 | protected int mStart; 11 | 12 | /** 13 | * @param seq 14 | * the initial sequence 15 | * @param start 16 | * the start index for this sequence 17 | * 18 | */ 19 | public TextChangeInsert(CharSequence seq, int start) { 20 | mSequence = new StringBuffer(); 21 | mSequence.append(seq); 22 | mStart = start; 23 | } 24 | 25 | /** 26 | * @see fr.xgouchet.texteditor.undo.TextChange#getCaret() 27 | */ 28 | public int getCaret() { 29 | if (mSequence.toString().contains(" ")) 30 | return -1; 31 | if (mSequence.toString().contains("\n")) 32 | return -1; 33 | return mStart + mSequence.length(); 34 | } 35 | 36 | /** 37 | * @see fr.xgouchet.texteditor.undo.TextChange#append(java.lang.CharSequence) 38 | */ 39 | public void append(CharSequence seq) { 40 | mSequence.append(seq); 41 | } 42 | 43 | /** 44 | * @see fr.xgouchet.texteditor.undo.TextChange#canMergeChangeBefore(java.lang.CharSequence, 45 | * int, int, int) 46 | */ 47 | public boolean canMergeChangeBefore(CharSequence s, int start, int count, int after) { 48 | 49 | CharSequence sub; 50 | boolean append, replace; 51 | 52 | if (mSequence.toString().contains(" ")) 53 | return false; 54 | if (mSequence.toString().contains("\n")) 55 | return false; 56 | 57 | sub = s.subSequence(start, start + count); 58 | append = (start == mStart + mSequence.length()); 59 | replace = (start == mStart) && (after >= mSequence.length()) 60 | && (sub.toString().startsWith(mSequence.toString())); 61 | 62 | if (append) { 63 | // mSequence.append(sub); 64 | return true; 65 | } 66 | 67 | if (replace) { 68 | // mSequence = new StringBuffer(); 69 | // mSequence.append(sub); 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | /** 76 | * @see fr.xgouchet.texteditor.undo.TextChange#canMergeChangeAfter(java.lang.CharSequence, 77 | * int, int, int) 78 | */ 79 | public boolean canMergeChangeAfter(CharSequence s, int start, int before, int count) { 80 | CharSequence sub; 81 | boolean append, replace; 82 | 83 | if (mSequence.toString().contains(" ")) 84 | return false; 85 | if (mSequence.toString().contains("\n")) 86 | return false; 87 | 88 | sub = s.subSequence(start, start + count); 89 | append = (start == mStart + mSequence.length()); 90 | replace = (start == mStart) && (count >= mSequence.length()) 91 | && (sub.toString().startsWith(mSequence.toString())); 92 | 93 | if (append) { 94 | mSequence.append(sub); 95 | return true; 96 | } 97 | 98 | if (replace) { 99 | mSequence = new StringBuffer(); 100 | mSequence.append(sub); 101 | return true; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | /** 108 | * @see fr.xgouchet.texteditor.undo.TextChange#undo(java.lang.String) 109 | */ 110 | public int undo(Editable s) { 111 | if (BuildConfig.DEBUG) 112 | Log.i(TAG, "Undo Insert : deleting " + mStart + " to " + (mStart + mSequence.length())); 113 | s.replace(mStart, mStart + mSequence.length(), ""); 114 | return mStart; 115 | } 116 | 117 | /** 118 | * @see java.lang.Object#toString() 119 | */ 120 | public String toString() { 121 | return "+\"" + mSequence.toString().replaceAll("\n", "~") + "\" @" + mStart; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /Ted/res/values/history.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1.8 (10 nov 2012) 7 | "- Bug fixed : current file / last loaded file 8 | - Updated notification system 9 | - Possibility to modify the text font used by the editor (You can use any ttf font located on your device's internal and/or external storage)" 10 | 11 | 12 | 1.7 (16 july 2012) 13 | "- Bug fixed : Save/Save As crash on some phone 14 | - Added option to disable autosave on existing files" 15 | 16 | 17 | 1.6 (9 july 2012) 18 | "- Added the Auto Save feature 19 | - fixed the bug with Search case " 20 | 21 | 22 | 1.5 (21 june 2012) 23 | "- Adapted for Ice Cream Sandwich 24 | - Improved the Undo option (bugs with suggestions) 25 | - Added a Home Screen Widgets (shortcut to favorite files) 26 | - Added option to open a file by default when starting Ted 27 | - New Graphics (all made by myself ^^)" 28 | 29 | 30 | 1.3 (5 may 2012) 31 | "- Added an undo option (check the settings) 32 | - Added some performance tweaks" 33 | 34 | 35 | 1.2 (18 apr. 2012) 36 | "- Fixed the scroll bug since last update 37 | - fixed the fling options in the settings (option was always active)" 38 | 39 | 40 | 1.1 (10 apr. 2012) 41 | "- Fixed the crash at start caused by the last update 42 | - Added Fling to Scroll (launches the scroll to navigate in large files) 43 | - Display the active line 44 | - Added new color theme (ask for more if needed)" 45 | 1.0 (27 feb. 2012) 46 | "- Brand new release version 47 | - Supports multiple encoding (including UTF-8) 48 | - Prevent data loss when saving really big files (note that Ted is not meant to open big files though) 49 | - Added new color theme (ask for more if needed) 50 | - Replaced the autosave with a warning and popup (prevent saving unwanted changes)" 51 | βetα 0.9 (7 jan. 2010) 52 | "- Bug fixed : severall crash on start 53 | - Added a search tool 54 | - Ted is listed when opening html, rss, css, php and xml files from any file browser (ask for other types if needed)" 55 | βetα 0.8 (23 dec. 2010) 56 | "- Automatic save can be disabled in the settings" 57 | βetα 0.7 (19 dec. 2010) 58 | "- App can be installed on the SD Card (on Android 2.2) 59 | - Automatic detection of end of line in opened files, possibility to define a default end of line for new files 60 | - Bigger dialog boxes 61 | - Bug fixed when openning big files" 62 | βetα 0.6 (8 dec. 2010) 63 | "- Possibility to change text size in the settings. 64 | - Possibility to open read-only text files from other location than the SD card 65 | - Added a backup function for unsaved text " 66 | βetα 0.5 (29 nov. 2010) 67 | "- Bug fixed while opening some files 68 | - New Graphics" 69 | βetα 0.4 (27 nov. 2010) 70 | "- Remembers the files opened recently (number of recent files can be changed) 71 | - display lines numbers (can be changed in the settings) 72 | - automatically break lines to keep a width of one page (can be changed in the settings)" 73 | βetα 0.3 (25 nov. 2010) 74 | "- Bug fixed : crash when trying to open online files" 75 | βetα 0.2 (13 nov. 2010) 76 | "- Open existing files - Save and save as" 77 | 78 | -------------------------------------------------------------------------------- /Ted/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ted 5 | Ted (Text Editor) 6 | 7 | 8 | Ted Internal Permission 9 | 10 | 11 | Ted - %1$s 12 | Ted - %1$s * 13 | Ted - [%1$s] 14 | Ted - Save as ... 15 | Ted - Open Recent 16 | Ted - Settings 17 | Ted - About ... 18 | Ted - Text Font 19 | 20 | 21 | Display 22 | Other 23 | Saving 24 | Undo 25 | Search 26 | Miscellaneous 27 | Show line numbers 28 | Word wrap 29 | Change text font 30 | Text size 31 | Color theme 32 | End of lines 33 | Maximum recent files 34 | Search wrap 35 | Search match case 36 | Encoding 37 | Fling to scroll faster 38 | Allow undo 39 | Maximum undo history 40 | Use the back button to undo previous modifications 41 | Use a default file 42 | Auto Save 43 | Overwrite existing files 44 | Automatically saves the file being edited when the app goes in background 45 | Display the line number at the left of the page 46 | Lines will break in new lines if they are too wide for the screen 47 | Uncheck if you have performance issues 48 | Select a file to open when you launch Ted from your home screen 49 | Auto save will overwrite existing files 50 | Auto save will only work with new files 51 | 52 | 53 | New 54 | Open 55 | Recent files 56 | Save 57 | Save as 58 | Settings 59 | About 60 | Search 61 | Undo 62 | Quit 63 | 64 | 65 | "Do you want to save your document? \nAny unsaved changes will be lost. " 66 | Save 67 | Delete 68 | "Don't save" 69 | Cancel 70 | File name 71 | Search 72 | Artistic Licence 73 | History 74 | Open as read only 75 | 76 | 77 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas porttitor neque semper sem fermentum pretium. Sed pharetra dui faucibus massa malesuada in condimentum mi gravida." 78 | "All icons for this app were created and belong to the author of the app : Xavier Gouchet (android@xgouchet.fr)." 79 | 80 | -------------------------------------------------------------------------------- /Ted/res/values-sk/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ted 5 | Ted (Textový editor) 6 | 7 | 8 | Interné povolenie Ted 9 | 10 | 11 | Ted - %1$s 12 | Ted - %1$s * 13 | Ted - [%1$s] 14 | Ted - Uložiť ako... 15 | Ted - Otvoriť nedávne 16 | Ted - Nastavenia 17 | Ted - O aplikácii ... 18 | Ted - Písmo textu 19 | 20 | 21 | Zobrazenie 22 | Ostatné 23 | Ukladanie 24 | Krok späť 25 | Hľadať 26 | Rôzne 27 | Zobraziť čísla riadkov 28 | Zalomiť text 29 | Zmeniť písmo textu 30 | Veľkosť písma 31 | Farebná téma 32 | Koniec riadkov 33 | Maximálny počet nedávnych súborov 34 | Zalomiť hľadanie 35 | Hľadať veľké a malé písmená 36 | Kódovanie 37 | Vrhnúť pre rýchlejší posun 38 | Povoliť krok späť 39 | Maximálna história pre krok späť 40 | Použiť tlačidlo Späť pre vrátenie predchádzajúcej úpravy 41 | Použiť predvolený súbor 42 | Automatické ukladanie 43 | Prepísať existujúce súbory 44 | Automaticky uložiť editovaný súbor, keď je aplikácia prepnutá do pozadia 45 | Zobraziť číslo riadku v ľavej časti stránky 46 | Riadky sa rozdelia do nových riadkov, ak sú príliš široké na obrazovke 47 | Zakážte, ak máte problémy s výkonom 48 | Vybrať súbor, ktorý chcete otvoriť pri spustení Teda z domovskej obrazovky 49 | Automatické ukladanie prepíše existujúce súbory 50 | Automatické ukladanie bude pracovať iba s novými súbormi 51 | 52 | 53 | Nový 54 | Otvoriť 55 | Nedávne súbory 56 | Uložiť 57 | Uložiť ako 58 | Nastavenia 59 | O aplikácii 60 | Hľadať 61 | Krok späť 62 | Ukončiť 63 | 64 | 65 | Chcete uložiť dokument?\nAkékoľvek neuložené zmeny budú stratené. 66 | Uložiť 67 | Vymazať 68 | Neukladať 69 | Zrušiť 70 | Názov súboru 71 | Hľadať 72 | Umelecká licencia 73 | História 74 | Otvoriť len na čítanie 75 | 76 | 77 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas porttitor neque semper sem fermentum pretium. Sed pharetra dui faucibus massa malesuada in condimentum mi gravida." 78 | "Všetky ikony pre túto aplikáciu boli vytvorené a patria autorovi aplikácie: Xavier Gouchet (android@xgouchet.fr)." 79 | 80 | -------------------------------------------------------------------------------- /Ted/res/values-fr/history.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1.8 (10 nov 2012) 7 | "- Bug fixed : problèmes avec la sauvegarde du dernier fichier ouvert 8 | - Mise a jour du système de notifications 9 | - Possibilité de changer la police d'écriture utilisée par l'éditeur (Vous pouvez importer n'importe quel fichier TTF situé sur l'appareil et/ou la carte mémoire)" 10 | 11 | 12 | 1.7 (16 juillet 2012) 13 | "- Correction de bug lors de la sauvegarde sur certains appareils \n 14 | - Option pour désactiver la sauvegarde automatique sur les fichiers existants \n" 15 | 16 | 17 | 1.6 (9 juillet 2012) 18 | "- Ajout de la sauvegarde automatique \n 19 | - correction de la recherche sensible à la casse \n" 20 | 21 | 22 | 1.5 (21 juin 2012) 23 | "- Adaptation à Ice Cream Sandwich \n 24 | - Amélioration de l'option Annuler (bugs avec les suggestions) \n 25 | - Ajout d'un widget (raccourci vers un fichier)\n 26 | - Ajout d'une option pour ouvrir automatiquement un fichier favori au démarrage de l'application\n 27 | - Refonte graphique (nouveaux icones réalisés par votre serviteur ^^) \n" 28 | 29 | 30 | 1.3 (5 mai 2012) 31 | "- Ajout d'une option Annuler\n 32 | - Optimisation des performances" 33 | 1.2 (18 avr. 2012) 34 | "- Correction du bug de défilement depuis la dernière MAJ\n 35 | - correction de l'option défilement rapide (l'option restait activée quelle que soit la valeur dans les préferences)" 36 | 1.1 (10 avr. 2012) 37 | "- Correction du crash du à la dernière mise à jour\n 38 | - Ajout d'un défilement par lancé (pour naviguer dans les longs fichiers)\n 39 | - Affiche la ligne active\n 40 | - Ajout de thèmes de couleurs (n'hesitez pas à en demander plus)" 41 | 1.0 (27 fev. 2012) 42 | "- Refonte du logiciel dans une toute nouvelle version\n 43 | - Support d'encodages multiples (entre autres UTF-8)\n 44 | - Evite la perte de donnée en cas de crash de sauvegarde sur les gros fichiers (cela dit, Ted n'est pas fait pour manipuler des fichiers trops lourds)\n 45 | - Ajout de thèmes de couleurs (n'hesitez pas à en demander plus)\n 46 | - Replaced the autosave with a warning and popup (prevent saving unwanted changes)" 47 | βetα 0.9 (7 jan. 2010) 48 | "- Bug corrigé : différents crash à l'ouverture \n 49 | - Ajout de recherche de texte dans le fichier ouvert \n 50 | - Ted est utilisable depuis un explorateur de fichiers pour ouvrir les fichiers html, rss, css, php et xml (demandez s'il vous en manque d'autres)" 51 | βetα 0.8 (23 dec. 2010) 52 | "- La sauvegarde automatique peut être désactivée dans les paramètres" 53 | βetα 0.7 (19 dec. 2010) 54 | "- Possibilité d'installer l'application sur carte SD (Android 2.2) \n 55 | - Détection automatique des fins de lignes des fichiers ouverts, possibilité de définir un format pour les nouveaux fichiers \n 56 | - Boites de dialogue plus grandes \n 57 | - Bug lors de l'ouverture de fichier trop grands corrigés \n" 58 | βetα 0.6 (8 dec. 2010) 59 | "- Possibilité de changer la taille du texte dans les parametres. \n 60 | - Possibilité d'ouvrir des fichiers textes en lecture seule, ailleurs que sur la carte SD \n 61 | - Un texte non sauvé est gardé en mémoire lorsque l'application se ferme et s'ouvre à la prochaine utilisation de l'éditeur \n" 62 | βetα 0.5 (29 nov. 2010) 63 | "- Bug à l'ouverture de certains fichiers corrigé \n 64 | - Nouveaux icones " 65 | βetα 0.4 (27 nov. 2010) 66 | "- Enregistrement des fichiers recemment ouvert (nombre de fichier récents paramétrable) \n 67 | - Affichage des numeros de lignes (parametrable) \n 68 | - Coupure automatique des lignes pour garder le texte sur une page horizontale (paramétrable) " 69 | βetα 0.3 (25 nov. 2010) 70 | "- Bug sur les fichiers en ligne corrigé" 71 | βetα 0.2 (13 nov. 2010) 72 | "- Ouvrir un fichier existant \n 73 | - Sauver et Sauver sous" 74 | 75 | -------------------------------------------------------------------------------- /Ted/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ted 5 | Ted (Editeur de texte) 6 | Ted - Permission Interne 7 | 8 | 9 | Ted - Sauver sous ... 10 | Ted - Documents récents 11 | Ted - Paramètres 12 | Ted - A propos ... 13 | Ted - Police 14 | Ted - %1$s 15 | Ted - %1$s * 16 | Ted - [%1$s] 17 | 18 | 19 | Affichage 20 | Autres 21 | Sauvegarde 22 | Recherche 23 | Historique 24 | Divers 25 | Changer la police 26 | Afficher les numéros de ligne 27 | Coupure de lignes automatique 28 | Taille du texte 29 | Thèmes de couleurs 30 | Fin de lignes 31 | Fichiers récents 32 | Recherche en boucle 33 | Recherche sensible à la casse 34 | Encodage 35 | Défilement par lancé 36 | "Activer l'option \"Annuler\"" 37 | Nombre maximum de changements enregistrés 38 | Utiliser le bouton retour pour annuler la dernière opération 39 | Utiliser un fichier par défaut 40 | Sauvegarde auto 41 | Ecraser les fichiers existants 42 | "Sauvegarde automatique du fichier en cours lorsque l'application passe en arrière plan" 43 | Les numéros de lignes sont affichés en début de ligne 44 | "Les lignes trop longues sont ajustées à la taille de l'écran" 45 | "Décocher l'option en cas de problèmes de performances" 46 | Selectionner un fichier à ouvrir au démarrage de Ted 47 | "La sauvegarde automatique ecrasera les fichiers existants" 48 | "La sauvegarde automatique ne fonctionnera que pour les nouveaux fichiers" 49 | 50 | 51 | Nouveau 52 | Ouvrir 53 | Documents récents 54 | Sauver 55 | Sauver sous 56 | Paramètres 57 | A propos 58 | Rechercher 59 | Annuler 60 | Quitter 61 | 62 | 63 | "Voulez vous sauver votre document? \nTout changement non sauvé sera perdu. " 64 | Sauver 65 | "Ne pas sauver" 66 | Annuler 67 | Supprimer 68 | Nom du fichier 69 | Rechercher 70 | Historique 71 | Licence Artistique 72 | Ouvrir en lecture seule 73 | 74 | 75 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas porttitor neque semper sem fermentum pretium. Sed pharetra dui faucibus massa malesuada in condimentum mi gravida." 76 | "Toutes les icônes de cette application ont été créées et appartiennent à l'auteur de l'application : Xavier Gouchet (android@xgouchet.fr)." 77 | 78 | -------------------------------------------------------------------------------- /Ted/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ted 5 | Ted (Editor de texto) 6 | 7 | 8 | Ted Internal Permission 9 | 10 | 11 | Ted - %1$s 12 | Ted - %1$s * 13 | Ted - [%1$s] 14 | Ted - Guardar como ... 15 | Ted - Abrir reciente 16 | Ted - Configuración 17 | Ted - Acerca de ... 18 | Ted - Fuente del texto 19 | 20 | 21 | Display 22 | Otros 23 | Guardado 24 | Configurar deshacer 25 | Búsqueda 26 | Configuración avanzada 27 | Mostrar números en cada línea 28 | Agrupar líneas 29 | Cambiar fuente del texto 30 | Tamaño del texto 31 | Tema de la interfaz 32 | Retorno de carro 33 | Máximo número de archivos recientes 34 | Buscar en todo el documento 35 | Respetar mayúsculas y minúsculas 36 | Codificación 37 | Efecto de scroll 38 | Habilitar deshacer 39 | Historial máximo para deshacer 40 | Asignar "deshacer" al botón de atrás 41 | Usar un archivo por defecto 42 | Autoguardado 43 | Sobreescribir archivos existentes 44 | Salva automáticamente si la aplicación pasa a segundo plano 45 | Se muestran los números de cada línea a la izquierda de la página 46 | Las líneas se ajustarán para que quepan en la pantalla 47 | Desmarcar si se experimentan problemas de rendimiento 48 | Selecciona un archivo para abrir cada vez que se ejecute Ted 49 | El autoguardado sobreescribirá los archivos existentes 50 | El autoguardado sólo funcionará con los nuevos archivos 51 | 52 | 53 | Nuevo 54 | Abrir 55 | Abrir reciente 56 | Guardar 57 | Guardar como 58 | Configuración 59 | Acerca de 60 | Buscar 61 | Deshacer 62 | Salir 63 | 64 | 65 | "¿Quieres guardar el archivo? \nSe perderán los cambios no guardados. " 66 | Guardar 67 | Borrar 68 | "Descartar" 69 | Cancelar 70 | Nombre de archivo 71 | Buscar 72 | Licencia artística 73 | Historial 74 | Abrir como sólo lectura 75 | 76 | 77 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas porttitor neque semper sem fermentum pretium. Sed pharetra dui faucibus massa malesuada in condimentum mi gravida." 78 | "Todos los iconos de esta aplicación fueron creados por el desarrollador de la misma. Derechos de propiedad intelectual reservados por Xavier Gouchet (android@xgouchet.fr)." 79 | 80 | 81 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedOpenRecentActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | 6 | import android.app.Activity; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.view.ContextMenu; 10 | import android.view.ContextMenu.ContextMenuInfo; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.view.View.OnClickListener; 15 | import android.widget.AdapterView; 16 | import android.widget.AdapterView.AdapterContextMenuInfo; 17 | import android.widget.AdapterView.OnItemClickListener; 18 | import android.widget.ListAdapter; 19 | import android.widget.ListView; 20 | import fr.xgouchet.androidlib.ui.Toaster; 21 | import fr.xgouchet.texteditor.common.Constants; 22 | import fr.xgouchet.texteditor.common.RecentFiles; 23 | import fr.xgouchet.texteditor.ui.adapter.PathListAdapter; 24 | 25 | public class TedOpenRecentActivity extends Activity implements Constants, OnClickListener, 26 | OnItemClickListener { 27 | 28 | /** 29 | * @see android.app.Activity#onCreate(android.os.Bundle) 30 | */ 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | 34 | // Setup content view 35 | setContentView(R.layout.layout_open); 36 | 37 | // buttons 38 | findViewById(R.id.buttonCancel).setOnClickListener(this); 39 | 40 | // widgets 41 | mFilesList = (ListView) findViewById(android.R.id.list); 42 | mFilesList.setOnItemClickListener(this); 43 | mFilesList.setOnCreateContextMenuListener(this); 44 | } 45 | 46 | /** 47 | * @see android.app.Activity#onResume() 48 | */ 49 | protected void onResume() { 50 | super.onResume(); 51 | 52 | fillRecentFilesView(); 53 | } 54 | 55 | /** 56 | * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, 57 | * android.view.View, android.view.ContextMenu.ContextMenuInfo) 58 | */ 59 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 60 | super.onCreateContextMenu(menu, v, menuInfo); 61 | AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; 62 | mContextPath = (String) mFilesList.getAdapter().getItem(info.position); 63 | 64 | menu.setHeaderTitle(mContextPath); 65 | menu.add(Menu.NONE, 0, Menu.NONE, R.string.ui_delete); 66 | } 67 | 68 | /** 69 | * @see android.app.Activity#onContextItemSelected(android.view.MenuItem) 70 | */ 71 | public boolean onContextItemSelected(MenuItem item) { 72 | 73 | RecentFiles.removePath(mContextPath); 74 | RecentFiles.saveRecentList(getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE)); 75 | 76 | fillRecentFilesView(); 77 | Toaster.showToast(this, R.string.toast_recent_files_deleted, false); 78 | 79 | return true; 80 | } 81 | 82 | /** 83 | * @see android.view.View.OnClickListener#onClick(android.view.View) 84 | */ 85 | public void onClick(View v) { 86 | switch (v.getId()) { 87 | case R.id.buttonCancel: 88 | setResult(RESULT_CANCELED); 89 | finish(); 90 | break; 91 | } 92 | } 93 | 94 | /** 95 | * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, 96 | * android.view.View, int, long) 97 | */ 98 | public void onItemClick(AdapterView parent, View view, int position, long id) { 99 | String path; 100 | 101 | path = mList.get(position); 102 | 103 | if (setOpenResult(new File(path))) { 104 | finish(); 105 | } else { 106 | RecentFiles.removePath(path); 107 | RecentFiles.saveRecentList(getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE)); 108 | ((PathListAdapter) mListAdapter).notifyDataSetChanged(); 109 | Toaster.showToast(this, R.string.toast_recent_files_invalid, true); 110 | } 111 | 112 | } 113 | 114 | /** 115 | * Fills the files list with the recent files 116 | * 117 | */ 118 | protected void fillRecentFilesView() { 119 | mList = RecentFiles.getRecentFiles(); 120 | 121 | if (mList.size() == 0) { 122 | setResult(RESULT_CANCELED); 123 | finish(); 124 | return; 125 | } 126 | 127 | // create string list adapter 128 | mListAdapter = new PathListAdapter(this, mList); 129 | 130 | // set adpater 131 | mFilesList.setAdapter(mListAdapter); 132 | } 133 | 134 | /** 135 | * Set the result of this activity to open a file 136 | * 137 | * @param file 138 | * the file to return 139 | * @return if the result was set correctly 140 | */ 141 | protected boolean setOpenResult(File file) { 142 | Intent result; 143 | 144 | if ((file == null) || (!file.isFile()) || (!file.canRead())) { 145 | return false; 146 | } 147 | 148 | result = new Intent(); 149 | result.putExtra("path", file.getAbsolutePath()); 150 | 151 | setResult(RESULT_OK, result); 152 | return true; 153 | } 154 | 155 | protected String mContextPath; 156 | 157 | /** the dialog's list view */ 158 | protected ListView mFilesList; 159 | /** The list adapter */ 160 | protected ListAdapter mListAdapter; 161 | 162 | /** the list of recent files */ 163 | protected ArrayList mList; 164 | } 165 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/undo/TextChangeWatcher.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.undo; 2 | 3 | import java.util.Stack; 4 | 5 | import android.text.Editable; 6 | import android.util.Log; 7 | import fr.xgouchet.texteditor.BuildConfig; 8 | import fr.xgouchet.texteditor.common.Constants; 9 | import fr.xgouchet.texteditor.common.Settings; 10 | 11 | public class TextChangeWatcher implements Constants { 12 | 13 | /** 14 | * 15 | */ 16 | public TextChangeWatcher() { 17 | mChanges = new Stack(); 18 | } 19 | 20 | /** 21 | * Undo the last operation 22 | * 23 | * @param text 24 | * the text to undo on 25 | * @return the caret position 26 | */ 27 | public int undo(Editable text) { 28 | pushCurrentChange(); 29 | 30 | if (mChanges.size() == 0) { 31 | if (BuildConfig.DEBUG) 32 | Log.i(TAG, "Nothing to undo"); 33 | return -1; 34 | } 35 | 36 | TextChange change = mChanges.pop(); 37 | if (change != null) 38 | return change.undo(text); 39 | else if (BuildConfig.DEBUG) 40 | Log.w(TAG, "Null change ?!"); 41 | 42 | return -1; 43 | } 44 | 45 | /** 46 | * A change to the text {@linkplain s} will be made, where the 47 | * {@linkplain count} characters starting at {@linkplain start} will be 48 | * replaced by {@linkplain after} characters 49 | * 50 | * @param s 51 | * the sequence being changed 52 | * @param start 53 | * the start index 54 | * @param count 55 | * the number of characters that will change 56 | * @param after 57 | * the number of characters that will replace the old ones 58 | * 59 | */ 60 | public void beforeChange(CharSequence s, int start, int count, int after) { 61 | if ((mCurrentChange != null) 62 | && (mCurrentChange.canMergeChangeBefore(s, start, count, after))) { 63 | } else { 64 | if (count == 0) { 65 | // no existing character changed 66 | // ignore, will be processed after 67 | } else if (after == 0) { 68 | // existing character replaced by none => delete 69 | processDelete(s, start, count); 70 | } else { 71 | // n chars replaced by m other chars => replace 72 | // replace is a delete AND an insert... 73 | processDelete(s, start, count); 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * A change to the text {@linkplain s} has been made, where the 80 | * {@linkplain count} characters starting at {@linkplain start} have 81 | * replaced the substring of length {@linkplain before} 82 | * 83 | * @param s 84 | * the sequence being changed 85 | * @param start 86 | * the start index 87 | * @param before 88 | * the number of character that were replaced 89 | * @param count 90 | * the number of characters that will change 91 | */ 92 | public void afterChange(CharSequence s, int start, int before, int count) { 93 | if ((mCurrentChange != null) 94 | && (mCurrentChange.canMergeChangeAfter(s, start, before, count))) { 95 | 96 | } else { 97 | if (before == 0) { 98 | // 0 charactes replaced by count => insert 99 | processInsert(s, start, count); 100 | } else if (count == 0) { 101 | // existing character replaced by none => delete, already done 102 | // before 103 | } else { 104 | // n chars replaced by m other chars => replace 105 | // replace is a delete AND an insert... 106 | processInsert(s, start, count); 107 | } 108 | } 109 | 110 | // printStack(); 111 | } 112 | 113 | /** 114 | * @param s 115 | * the sequence being modified 116 | * @param start 117 | * the first character index 118 | * @param count 119 | * the number of inserted text 120 | */ 121 | public void processInsert(CharSequence s, int start, int count) { 122 | CharSequence sub = s.subSequence(start, start + count); 123 | 124 | if (mCurrentChange != null) 125 | pushCurrentChange(); 126 | 127 | mCurrentChange = new TextChangeInsert(sub, start); 128 | } 129 | 130 | /** 131 | * @param s 132 | * the sequence being modified 133 | * @param start 134 | * the first character index 135 | * @param count 136 | * the number of inserted text 137 | */ 138 | public void processDelete(CharSequence s, int start, int count) { 139 | CharSequence sub = s.subSequence(start, start + count); 140 | 141 | if (mCurrentChange != null) 142 | pushCurrentChange(); 143 | 144 | mCurrentChange = new TextChangeDelete(sub, start); 145 | } 146 | 147 | /** 148 | * Pushes the current change on top of the stack 149 | */ 150 | protected void pushCurrentChange() { 151 | if (mCurrentChange == null) 152 | return; 153 | 154 | mChanges.push(mCurrentChange); 155 | while (mChanges.size() > Settings.UNDO_MAX_STACK) { 156 | mChanges.remove(0); 157 | } 158 | mCurrentChange = null; 159 | } 160 | 161 | /** 162 | * Prints the current stack 163 | */ 164 | public void printStack() { 165 | if (!BuildConfig.DEBUG) 166 | return; 167 | Log.i(TAG, "STACK"); 168 | for (TextChange change : mChanges) { 169 | Log.d(TAG, change.toString()); 170 | } 171 | Log.d(TAG, "Current change : " + mCurrentChange.toString()); 172 | } 173 | 174 | protected TextChange mCurrentChange; 175 | protected final Stack mChanges; 176 | 177 | } 178 | -------------------------------------------------------------------------------- /Ted/res/xml/ted_prefs.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 12 | 17 | 18 | 23 | 29 | 30 | 33 | 34 | 35 | 36 | 42 | 48 | 54 | 55 | 60 | 67 | 68 | 69 | 73 | 74 | 80 | 81 | 85 | 86 | 87 | 91 | 95 | 96 | 97 | 102 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/Settings.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.File; 4 | 5 | import android.content.Context; 6 | import android.content.SharedPreferences; 7 | import android.content.SharedPreferences.Editor; 8 | import android.graphics.Typeface; 9 | 10 | public class Settings implements Constants { 11 | 12 | /** Number of recent files to remember */ 13 | public static int MAX_RECENT_FILES = 10; 14 | 15 | /** Show the lines numbers */ 16 | public static boolean SHOW_LINE_NUMBERS = true; 17 | /** automatic break line to fit one page */ 18 | public static boolean WORDWRAP = false; 19 | /** color setting */ 20 | public static int COLOR = COLOR_CLASSIC; 21 | 22 | /** when search reaches the end of a file, search wrap */ 23 | public static boolean SEARCHWRAP = false; 24 | /** only search for matchin case */ 25 | public static boolean SEARCHMATCHCASE = false; 26 | 27 | /** Text size setting */ 28 | public static int TEXT_SIZE = 12; 29 | 30 | /** Default end of line */ 31 | public static int DEFAULT_END_OF_LINE = EOL_LINUX; 32 | /** End Of Line style */ 33 | public static int END_OF_LINE = EOL_LINUX; 34 | /** Encoding */ 35 | public static String ENCODING = ENC_UTF8; 36 | 37 | /** Let auto save on quit be triggered */ 38 | public static boolean FORCE_AUTO_SAVE = false; 39 | public static boolean AUTO_SAVE_OVERWRITE = false; 40 | 41 | /** enable fling to scroll */ 42 | public static boolean FLING_TO_SCROLL = false; 43 | 44 | /** Use Undo instead of quit ? */ 45 | public static boolean UNDO = true; 46 | /** Undo stack capacity */ 47 | public static int UNDO_MAX_STACK = 25; 48 | /** Use back button as undo */ 49 | public static boolean BACK_BTN_AS_UNDO = false; 50 | 51 | /** Use a Home Page */ 52 | public static boolean USE_HOME_PAGE = false; 53 | /** Home Page Path */ 54 | public static String HOME_PAGE_PATH = ""; 55 | 56 | /** 57 | * @return the end of line characters according to the current settings 58 | */ 59 | public static String getEndOfLine() { 60 | switch (END_OF_LINE) { 61 | case EOL_MAC: // Mac OS 62 | return "\r"; 63 | case EOL_WINDOWS: // Windows 64 | return "\r\n"; 65 | case EOL_LINUX: // Linux / Android 66 | default: 67 | return "\n"; 68 | } 69 | } 70 | 71 | /** 72 | * Update the settings from the given {@link SharedPreferences} 73 | * 74 | * @param settings 75 | * the settings to read from 76 | */ 77 | public static void updateFromPreferences(SharedPreferences settings) { 78 | 79 | MAX_RECENT_FILES = getStringPreferenceAsInteger(settings, 80 | PREFERENCE_MAX_RECENTS, "10"); 81 | SHOW_LINE_NUMBERS = settings.getBoolean(PREFERENCE_SHOW_LINE_NUMBERS, 82 | true); 83 | WORDWRAP = settings.getBoolean(PREFERENCE_WORDWRAP, false); 84 | TEXT_SIZE = getStringPreferenceAsInteger(settings, 85 | PREFERENCE_TEXT_SIZE, "12"); 86 | DEFAULT_END_OF_LINE = getStringPreferenceAsInteger(settings, 87 | PREFERENCE_END_OF_LINES, ("" + EOL_LINUX)); 88 | FORCE_AUTO_SAVE = settings.getBoolean(PREFERENCE_AUTO_SAVE, false); 89 | AUTO_SAVE_OVERWRITE = settings.getBoolean( 90 | PREFERENCE_AUTO_SAVE_OVERWRITE, false); 91 | COLOR = getStringPreferenceAsInteger(settings, PREFERENCE_COLOR_THEME, 92 | ("" + COLOR_CLASSIC)); 93 | SEARCHWRAP = settings.getBoolean(PREFERENCE_SEARCHWRAP, false); 94 | SEARCHMATCHCASE = settings.getBoolean(PREFERENCE_SEARCH_MATCH_CASE, 95 | false); 96 | ENCODING = settings.getString(PREFERENCE_ENCODING, ENC_UTF8); 97 | FLING_TO_SCROLL = settings.getBoolean(PREFERENCE_FLING_TO_SCROLL, true); 98 | 99 | BACK_BTN_AS_UNDO = settings.getBoolean(PREFERENCE_BACK_BUTTON_AS_UNDO, 100 | false); 101 | UNDO = settings.getBoolean(PREFERENCE_ALLOW_UNDO, true); 102 | UNDO_MAX_STACK = getStringPreferenceAsInteger(settings, 103 | PREFERENCE_MAX_UNDO_STACK, "25"); 104 | 105 | USE_HOME_PAGE = settings.getBoolean(PREFERENCE_USE_HOME_PAGE, false); 106 | HOME_PAGE_PATH = settings.getString(PREFERENCE_HOME_PAGE_PATH, ""); 107 | 108 | RecentFiles.loadRecentFiles(settings.getString(PREFERENCE_RECENTS, "")); 109 | } 110 | 111 | /** 112 | * Reads a preference stored as a string and returns the numeric value 113 | * 114 | * @param prefs 115 | * the prefernce to read from 116 | * @param key 117 | * the key 118 | * @param def 119 | * the default value 120 | * @return the value as an int 121 | */ 122 | protected static int getStringPreferenceAsInteger(SharedPreferences prefs, 123 | String key, String def) { 124 | String strVal; 125 | int intVal; 126 | 127 | strVal = null; 128 | try { 129 | strVal = prefs.getString(key, def); 130 | } catch (Exception e) { 131 | strVal = def; 132 | } 133 | 134 | try { 135 | intVal = Integer.parseInt(strVal); 136 | } catch (NumberFormatException e) { 137 | intVal = 0; 138 | } 139 | 140 | return intVal; 141 | } 142 | 143 | /** 144 | * Save the Home page settings 145 | * 146 | * @param settings 147 | * the settings to write to 148 | */ 149 | public static void saveHomePage(SharedPreferences settings) { 150 | Editor editor = settings.edit(); 151 | editor.putString(PREFERENCE_HOME_PAGE_PATH, HOME_PAGE_PATH); 152 | editor.commit(); 153 | 154 | } 155 | 156 | public static File getFontFile(Context ctx) { 157 | return new File(ctx.getDir(FONT_FOLDER_NAME, Context.MODE_PRIVATE), 158 | FONT_FILE_NAME); 159 | } 160 | 161 | public static Typeface getTypeface(Context ctx) { 162 | File fontFile = getFontFile(ctx); 163 | Typeface res = Typeface.MONOSPACE; 164 | if (fontFile.exists() && fontFile.canRead()) { 165 | res = Typeface.createFromFile(getFontFile(ctx)); 166 | } 167 | return res; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/TextFileUtils.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStreamReader; 11 | import java.io.OutputStreamWriter; 12 | 13 | import fr.xgouchet.texteditor.BuildConfig; 14 | import org.mozilla.universalchardet.UniversalDetector; 15 | 16 | import android.content.Context; 17 | import android.util.Log; 18 | 19 | /** 20 | * Misc file utilities 21 | * 22 | * TODO code review 23 | * 24 | */ 25 | public class TextFileUtils implements Constants { 26 | 27 | /** 28 | * @param path 29 | * the absolute path to the file to save 30 | * @param text 31 | * the text to write 32 | * @return if the file was saved successfully 33 | */ 34 | public static boolean writeTextFile(String path, String text) { 35 | File file = new File(path); 36 | OutputStreamWriter writer; 37 | FileOutputStream stream; 38 | BufferedWriter out; 39 | String eol_text = text; 40 | try { 41 | if (Settings.END_OF_LINE != EOL_LINUX) { 42 | eol_text = eol_text.replaceAll("\n", Settings.getEndOfLine()); 43 | } 44 | 45 | stream = new FileOutputStream(file); 46 | writer = new OutputStreamWriter(stream, Settings.ENCODING); 47 | out = new BufferedWriter(writer); 48 | out.write(eol_text); 49 | out.flush(); 50 | stream.getFD().sync(); 51 | out.close(); 52 | } catch (OutOfMemoryError e) { 53 | Log.w(TAG, "Out of memory error", e); 54 | return false; 55 | } catch (IOException e) { 56 | Log.w(TAG, "Can't write to file " + path, e); 57 | return false; 58 | } 59 | return true; 60 | } 61 | 62 | /** 63 | * @param file 64 | * the file to read 65 | * @return the content of the file as text 66 | */ 67 | public static String readTextFile(File file) { 68 | InputStreamReader reader; 69 | BufferedReader in; 70 | StringBuffer text = new StringBuffer(); 71 | int c; 72 | try { 73 | reader = new InputStreamReader(new FileInputStream(file), 74 | detectCharSet(file.getAbsolutePath())); 75 | in = new BufferedReader(reader); 76 | do { 77 | c = in.read(); 78 | if (c != -1) { 79 | text.append((char) c); 80 | } 81 | } while (c != -1); 82 | in.close(); 83 | } catch (IOException e) { 84 | Log.w(TAG, "Can't read file " + file.getName(), e); 85 | return null; 86 | } catch (OutOfMemoryError e) { 87 | Log.w(TAG, "File is to big to read", e); 88 | return null; 89 | } 90 | 91 | // detect end of lines 92 | String content = text.toString(); 93 | int windows = content.indexOf("\r\n"); 94 | int macos = content.indexOf("\r"); 95 | 96 | if (windows != -1) { 97 | Settings.END_OF_LINE = EOL_WINDOWS; 98 | content = content.replaceAll("\r\n", "\n"); 99 | } else { 100 | if (macos != -1) { 101 | Settings.END_OF_LINE = EOL_MAC; 102 | content = content.replaceAll("\r", "\n"); 103 | } else { 104 | Settings.END_OF_LINE = EOL_LINUX; 105 | } 106 | } 107 | 108 | if (BuildConfig.DEBUG) { 109 | Log.d(TAG, "Using End of Line : " + Settings.END_OF_LINE); 110 | } 111 | return content; 112 | } 113 | 114 | /** 115 | * @param context 116 | * the current context 117 | * @param text 118 | * the text to write 119 | * @return if the file was saved successfully 120 | */ 121 | public static boolean writeInternal(Context context, String text) { 122 | FileOutputStream fos; 123 | try { 124 | fos = context 125 | .openFileOutput(BACKUP_FILE_NAME, Context.MODE_PRIVATE); 126 | fos.write(text.getBytes()); 127 | fos.close(); 128 | if (BuildConfig.DEBUG) { 129 | Log.i(TAG, "Saved to file " + context.getFilesDir().getPath() 130 | + File.separator + BACKUP_FILE_NAME); 131 | } 132 | } catch (FileNotFoundException e) { 133 | Log.w(TAG, "Couldn't write to internal storage ", e); 134 | return false; 135 | } catch (IOException e) { 136 | Log.w(TAG, "Error occured while writing to internal storage ", e); 137 | return false; 138 | } 139 | return true; 140 | } 141 | 142 | /** 143 | * @param context 144 | * the current context 145 | * @return the content of the file as text 146 | */ 147 | public static String readInternal(Context context) { 148 | FileInputStream fis; 149 | StringBuffer text = new StringBuffer(); 150 | 151 | try { 152 | fis = context.openFileInput(BACKUP_FILE_NAME); 153 | while (fis.available() > 0) { 154 | text.append((char) fis.read()); 155 | } 156 | } catch (FileNotFoundException e) { 157 | Log.w(TAG, "No backup file available", e); 158 | return null; 159 | } catch (IOException e) { 160 | Log.w(TAG, "Can't read backup file ", e); 161 | return null; 162 | } 163 | return text.toString(); 164 | } 165 | 166 | /** 167 | * @param context 168 | * the current context 169 | */ 170 | public static void clearInternal(Context context) { 171 | writeInternal(context, ""); 172 | } 173 | 174 | /** 175 | * Detect charset 176 | * @see https://code.google.com/p/juniversalchardet/ 177 | * @param fileName 178 | * the absolute path of the file to open 179 | * @return charset name 180 | * 181 | * */ 182 | public static String detectCharSet(String fileName) throws IOException { 183 | byte[] buf = new byte[4096]; 184 | FileInputStream fis = new FileInputStream(fileName); 185 | 186 | UniversalDetector detector = new UniversalDetector(null); 187 | 188 | int nread; 189 | while ((nread = fis.read(buf)) > 0 && !detector.isDone()) { 190 | detector.handleData(buf, 0, nread); 191 | } 192 | detector.dataEnd(); 193 | 194 | String encoding = detector.getDetectedCharset(); 195 | 196 | detector.reset(); 197 | return encoding; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedSettingsActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import java.io.File; 4 | 5 | import android.content.ActivityNotFoundException; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.SharedPreferences; 9 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 10 | import android.os.Bundle; 11 | import android.preference.CheckBoxPreference; 12 | import android.preference.ListPreference; 13 | import android.preference.Preference; 14 | import android.preference.Preference.OnPreferenceClickListener; 15 | import android.preference.PreferenceActivity; 16 | import android.util.Log; 17 | import de.neofonie.mobile.app.android.widget.crouton.Crouton; 18 | import de.neofonie.mobile.app.android.widget.crouton.Style; 19 | import fr.xgouchet.androidlib.data.FileUtils; 20 | import fr.xgouchet.texteditor.common.Constants; 21 | import fr.xgouchet.texteditor.common.Settings; 22 | import fr.xgouchet.texteditor.ui.view.AdvancedEditText; 23 | 24 | @SuppressWarnings("deprecation") 25 | public class TedSettingsActivity extends PreferenceActivity implements 26 | Constants, OnSharedPreferenceChangeListener { 27 | 28 | /** 29 | * @see android.preference.PreferenceActivity#onCreate(android.os.Bundle) 30 | */ 31 | 32 | protected void onCreate(Bundle icicle) { 33 | super.onCreate(icicle); 34 | 35 | getPreferenceManager().setSharedPreferencesName(PREFERENCES_NAME); 36 | 37 | addPreferencesFromResource(R.xml.ted_prefs); 38 | setContentView(R.layout.layout_prefs); 39 | 40 | getPreferenceManager().getSharedPreferences() 41 | .registerOnSharedPreferenceChangeListener(this); 42 | 43 | mSampleTED = (AdvancedEditText) findViewById(R.id.sampleEditor); 44 | 45 | Settings.updateFromPreferences(getPreferenceManager() 46 | .getSharedPreferences()); 47 | mSampleTED.updateFromSettings(); 48 | mSampleTED.setEnabled(false); 49 | 50 | mPreviousHP = Settings.USE_HOME_PAGE; 51 | 52 | findPreference(PREFERENCE_SELECT_FONT).setOnPreferenceClickListener( 53 | new OnPreferenceClickListener() { 54 | public boolean onPreferenceClick(Preference preference) { 55 | Intent selectFont = new Intent(); 56 | selectFont.setClass(getApplicationContext(), 57 | TedFontActivity.class); 58 | try { 59 | startActivityForResult(selectFont, REQUEST_FONT); 60 | } catch (ActivityNotFoundException e) { 61 | Crouton.showText(TedSettingsActivity.this, 62 | R.string.toast_activity_open, Style.ALERT); 63 | } 64 | return true; 65 | } 66 | }); 67 | 68 | updateSummaries(); 69 | } 70 | 71 | /** 72 | * @see android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(android.content.SharedPreferences, 73 | * java.lang.String) 74 | */ 75 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 76 | String key) { 77 | Settings.updateFromPreferences(sharedPreferences); 78 | mSampleTED.updateFromSettings(); 79 | updateSummaries(); 80 | 81 | CheckBoxPreference checkBox = (CheckBoxPreference) findPreference(PREFERENCE_USE_HOME_PAGE); 82 | checkBox.setSummaryOn(Settings.HOME_PAGE_PATH); 83 | 84 | if (Settings.USE_HOME_PAGE && !mPreviousHP) { 85 | Intent setHomePage = new Intent(); 86 | setHomePage.setClass(this, TedOpenActivity.class); 87 | setHomePage.putExtra(EXTRA_REQUEST_CODE, REQUEST_HOME_PAGE); 88 | try { 89 | startActivityForResult(setHomePage, REQUEST_HOME_PAGE); 90 | } catch (ActivityNotFoundException e) { 91 | Crouton.showText(this, R.string.toast_activity_open, 92 | Style.ALERT); 93 | } 94 | } 95 | 96 | mPreviousHP = Settings.USE_HOME_PAGE; 97 | } 98 | 99 | /** 100 | * @see android.preference.PreferenceActivity#onActivityResult(int, int, 101 | * android.content.Intent) 102 | */ 103 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 104 | Bundle extras; 105 | 106 | if (BuildConfig.DEBUG) 107 | Log.d(TAG, "onActivityResult"); 108 | 109 | if (resultCode == RESULT_CANCELED) { 110 | if (BuildConfig.DEBUG) 111 | Log.d(TAG, "Result canceled"); 112 | ((CheckBoxPreference) findPreference(PREFERENCE_USE_HOME_PAGE)) 113 | .setChecked(false); 114 | return; 115 | } 116 | 117 | if ((resultCode != RESULT_OK) || (data == null)) { 118 | if (BuildConfig.DEBUG) 119 | Log.e(TAG, "Result error or null data! / " + resultCode); 120 | ((CheckBoxPreference) findPreference(PREFERENCE_USE_HOME_PAGE)) 121 | .setChecked(false); 122 | return; 123 | } 124 | 125 | switch (requestCode) { 126 | case REQUEST_HOME_PAGE: 127 | extras = data.getExtras(); 128 | if (extras != null) { 129 | if (BuildConfig.DEBUG) 130 | Log.d(TAG, "Open : " + extras.getString("path")); 131 | Settings.HOME_PAGE_PATH = extras.getString("path"); 132 | Settings.saveHomePage(getSharedPreferences(PREFERENCES_NAME, 133 | Context.MODE_PRIVATE)); 134 | updateSummaries(); 135 | } 136 | break; 137 | case REQUEST_FONT: 138 | Log.i(TAG, "Selected Font : " + data.getData().getPath()); 139 | File src = new File(data.getData().getPath()); 140 | FileUtils.copyFile(src, Settings.getFontFile(this)); 141 | mSampleTED.updateFromSettings(); 142 | break; 143 | } 144 | } 145 | 146 | /** 147 | * Updates the summaries for every list 148 | */ 149 | protected void updateSummaries() { 150 | ListPreference listPref; 151 | CheckBoxPreference cbPref; 152 | 153 | listPref = (ListPreference) findPreference(PREFERENCE_COLOR_THEME); 154 | listPref.setSummary(listPref.getEntry()); 155 | 156 | listPref = (ListPreference) findPreference(PREFERENCE_TEXT_SIZE); 157 | listPref.setSummary(listPref.getEntry()); 158 | 159 | listPref = (ListPreference) findPreference(PREFERENCE_END_OF_LINES); 160 | listPref.setSummary(listPref.getEntry()); 161 | 162 | listPref = (ListPreference) findPreference(PREFERENCE_ENCODING); 163 | listPref.setSummary(listPref.getEntry()); 164 | 165 | listPref = (ListPreference) findPreference(PREFERENCE_MAX_RECENTS); 166 | listPref.setSummary(listPref.getEntry()); 167 | 168 | listPref = (ListPreference) findPreference(PREFERENCE_MAX_UNDO_STACK); 169 | listPref.setSummary(listPref.getEntry()); 170 | 171 | cbPref = (CheckBoxPreference) findPreference(PREFERENCE_USE_HOME_PAGE); 172 | if (cbPref.isChecked()) { 173 | cbPref.setSummaryOn(Settings.HOME_PAGE_PATH); 174 | } 175 | } 176 | 177 | protected AdvancedEditText mSampleTED; 178 | protected boolean mPreviousHP; 179 | 180 | } 181 | -------------------------------------------------------------------------------- /Ted/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 62 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 103 | 104 | 105 | 106 | 110 | 111 | 112 | 113 | 117 | 118 | 119 | 120 | 123 | 124 | 125 | 126 | 130 | 131 | 132 | 133 | 137 | 138 | 139 | 140 | 144 | 145 | 146 | 147 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 160 | 161 | 162 | 163 | 164 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/common/Constants.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.common; 2 | 3 | import java.io.File; 4 | 5 | import android.os.Environment; 6 | 7 | /** 8 | * @author x.gouchet 9 | * 10 | */ 11 | public interface Constants { 12 | 13 | /** Tag for the log ( = {@value} ) */ 14 | public static final String TAG = "TED"; 15 | 16 | public static final String ACTION_WIDGET_OPEN = "fr.xgouchet.texteditor.ACTION_TED_WIDGET_OPEN"; 17 | 18 | /** Fonts folder */ 19 | public static final String FONT_FOLDER_NAME = "fonts"; 20 | /** Font file */ 21 | public static final String FONT_FILE_NAME = "ted_font.ttf"; 22 | 23 | /** clears the current text ( = {@value} ) */ 24 | public static final int MENU_ID_NEW = 0; 25 | /** Saves the file ( = {@value} ) */ 26 | public static final int MENU_ID_SAVE = 1; 27 | /** Savesas a new file ( = {@value} ) */ 28 | public static final int MENU_ID_SAVE_AS = 2; 29 | /** open an existing file */ 30 | public static final int MENU_ID_OPEN = 3; 31 | /** open an existing file ( = {@value} ) */ 32 | public static final int MENU_ID_OPEN_RECENT = 4; 33 | /** open the settings ( = {@value} ) */ 34 | public static final int MENU_ID_SETTINGS = 5; 35 | /** open the about page ( = {@value} ) */ 36 | public static final int MENU_ID_ABOUT = 6; 37 | /** Search a string in the file ( = {@value} ) */ 38 | public static final int MENU_ID_SEARCH = 7; 39 | /** undo last change ( = {@value} ) */ 40 | public static final int MENU_ID_UNDO = 8; 41 | /** redo last change ( = {@value} ) */ 42 | public static final int MENU_ID_REDO = 9; 43 | /** Quit the app ( = {@value} ) */ 44 | public static final int MENU_ID_QUIT = 666; 45 | 46 | /** File of the external storage data */ 47 | public static final File STORAGE = Environment 48 | .getExternalStorageDirectory(); 49 | /** Path to the external storage data */ 50 | public static final String STORAGE_PATH = STORAGE.getAbsolutePath(); 51 | /** name of the backup file */ 52 | public static final String BACKUP_FILE_NAME = "temp.bak"; 53 | 54 | /** name of the shared preferences for this app ( = {@value} ) */ 55 | public static final String PREFERENCES_NAME = "fr.xgouchet.texteditor"; 56 | /** Preference tag to retrieve the recent files ( = {@value} ) */ 57 | public static final String PREFERENCE_RECENTS = "recent_files"; 58 | /** Preference tag to retrieve the recent files ( = {@value} ) */ 59 | public static final String PREFERENCE_MAX_RECENTS = "max_recent_files"; 60 | /** Preference tag to retrieve the show line number ( = {@value} ) */ 61 | public static final String PREFERENCE_SHOW_LINE_NUMBERS = "show_line_numbers"; 62 | /** Preference tag to retrieve the wordwrap ( = {@value} ) */ 63 | public static final String PREFERENCE_WORDWRAP = "auto_break_lines"; 64 | /** Preference tag to retrieve the searchwrap ( = {@value} ) */ 65 | public static final String PREFERENCE_SEARCHWRAP = "search_wrap"; 66 | /** Preference tag to retrieve the search match case ( = {@value} ) */ 67 | public static final String PREFERENCE_SEARCH_MATCH_CASE = "search_match_case"; 68 | /** Preference tag to retrieve the Syntax Highlight ( = {@value} ) */ 69 | public static final String PREFERENCE_HIGHLIGHT = "highlight_syntax"; 70 | /** Preference tag to retrieve the Text Size ( = {@value} ) */ 71 | public static final String PREFERENCE_TEXT_SIZE = "text_size"; 72 | /** Preference tag to retrieve the End of lines pref ( = {@value} ) */ 73 | public static final String PREFERENCE_END_OF_LINES = "end_of_lines"; 74 | /** Preference tag to retrieve the Encoding pref ( = {@value} ) */ 75 | public static final String PREFERENCE_ENCODING = "encoding"; 76 | /** Preference tag to retrieve the Auto mode ( = {@value} ) */ 77 | public static final String PREFERENCE_AUTO_SAVE = "force_auto_save"; 78 | /** Preference tag to retrieve the Auto mode ( = {@value} ) */ 79 | public static final String PREFERENCE_AUTO_SAVE_OVERWRITE = "auto_save_overwrite"; 80 | /** Preference tag to retrieve the Color Theme ( = {@value} ) */ 81 | public static final String PREFERENCE_COLOR_THEME = "color_theme"; 82 | /** Preference tag to retrieve the fling to scroll ( = {@value} ) */ 83 | public static final String PREFERENCE_FLING_TO_SCROLL = "fling_to_scroll"; 84 | /** Preference tag to retrieve if undo history is allowed ( = {@value} ) */ 85 | public static final String PREFERENCE_ALLOW_UNDO = "allow_undo"; 86 | /** Preference tag to retrieve the max undo stack ( = {@value} ) */ 87 | public static final String PREFERENCE_MAX_UNDO_STACK = "max_undo_stack"; 88 | /** Preference tag to retrieve the back button as undo ( = {@value} ) */ 89 | public static final String PREFERENCE_BACK_BUTTON_AS_UNDO = "back_button_as_undo"; 90 | /** Preference tag to retrieve the use home page ( = {@value} ) */ 91 | public static final String PREFERENCE_USE_HOME_PAGE = "use_home_page"; 92 | /** Preference tag to retrieve the home page path ( = {@value} ) */ 93 | public static final String PREFERENCE_HOME_PAGE_PATH = "home_page_path"; 94 | /** Preference tag to select the font ( = {@value} ) */ 95 | public static final String PREFERENCE_SELECT_FONT = "select_font"; 96 | /** Preference tag to the text font ( = {@value} ) */ 97 | public static final String PREFERENCE_FONT = "text_font"; 98 | 99 | /** minimum text size */ 100 | public static final int TEXT_SIZE_MIN = 9; 101 | /** maximum text size */ 102 | public static final int TEXT_SIZE_MAX = 40; 103 | 104 | /** End of line setting for Linux files ( = {@value} ) */ 105 | public static final int EOL_LINUX = 0; 106 | /** End of line setting for Windows files ( = {@value} ) */ 107 | public static final int EOL_WINDOWS = 1; 108 | /** End of line setting for Mac files ( = {@value} ) */ 109 | public static final int EOL_MAC = 2; 110 | 111 | /** Encoding : 7 bit ASCII ( = {@value} ) */ 112 | public static final String ENC_ASCII = "US-ASCII"; 113 | /** Encoding : ISO Latin Alphabet, aka ISO-LATIN-1 ( = {@value} ) */ 114 | public static final String ENC_LATIN = "ISO-8859-1"; 115 | /** Encoding : 8 bit UCS Transformation Format ( = {@value} ) */ 116 | public static final String ENC_UTF8 = "UTF-8"; 117 | 118 | /** color theme default : black on white ( = {@value} ) */ 119 | public static final int COLOR_CLASSIC = 0; 120 | /** color theme negative : white on black ( = {@value} ) */ 121 | public static final int COLOR_NEGATIVE = 1; 122 | /** color theme matrix : green on dark green ( = {@value} ) */ 123 | public static final int COLOR_MATRIX = 2; 124 | /** color theme sky : darkblue on skyblue ( = {@value} ) */ 125 | public static final int COLOR_SKY = 3; 126 | /** color theme dracula : red on black ( = {@value} ) */ 127 | public static final int COLOR_DRACULA = 4; 128 | 129 | /** Request code for Save As Activity */ 130 | public static final int REQUEST_SAVE_AS = 107; 131 | /** Request code for Open Activity */ 132 | public static final int REQUEST_OPEN = 108; 133 | /** Request code for Home Page Activity */ 134 | public static final int REQUEST_HOME_PAGE = 109; 135 | /** Request code for Font Activity */ 136 | public static final int REQUEST_FONT = 110; 137 | 138 | /** extra when browsing for file */ 139 | public static final String EXTRA_REQUEST_CODE = "request_code"; 140 | /** Extra to force read only from widget */ 141 | public static final String EXTRA_FORCE_READ_ONLY = "force_read_only"; 142 | 143 | /** an error result */ 144 | public static final int RESULT_ERROR = 1; 145 | } 146 | -------------------------------------------------------------------------------- /Ted/res/layout/layout_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 15 | 21 | 22 | 27 | 28 | 33 | 34 | 39 | 40 | 45 | 46 | 51 | 52 | 57 | 58 | 63 | 64 | 69 | 70 | 75 | 76 | 81 | 82 | 87 | 88 | 93 | 94 | 99 | 100 | 105 | 106 | 111 | 112 | 117 | 118 | 123 | 124 | 129 | 130 | 135 | 136 | 141 | 142 | 147 | 148 | 153 | 154 | 159 | 160 | 165 | 166 | 171 | 172 | 177 | 178 | 183 | 184 | 189 | 190 | 195 | 196 | 201 | 202 | 207 | 208 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/ui/view/AdvancedEditText.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor.ui.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Point; 8 | import android.graphics.Rect; 9 | import android.graphics.Typeface; 10 | import android.util.AttributeSet; 11 | import android.view.GestureDetector; 12 | import android.view.GestureDetector.OnGestureListener; 13 | import android.view.KeyEvent; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.view.View.OnKeyListener; 17 | import android.view.inputmethod.InputMethodManager; 18 | import android.widget.EditText; 19 | import android.widget.Scroller; 20 | import fr.xgouchet.texteditor.R; 21 | import fr.xgouchet.texteditor.common.Constants; 22 | import fr.xgouchet.texteditor.common.Settings; 23 | 24 | /** 25 | * TODO create a syntax highlighter 26 | */ 27 | public class AdvancedEditText extends EditText implements Constants, 28 | OnKeyListener, OnGestureListener { 29 | 30 | /** 31 | * @param context 32 | * the current context 33 | * @param attrs 34 | * some attributes 35 | * @category ObjectLifecycle 36 | */ 37 | public AdvancedEditText(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | 40 | mPaintNumbers = new Paint(); 41 | mPaintNumbers.setTypeface(Typeface.MONOSPACE); 42 | mPaintNumbers.setAntiAlias(true); 43 | 44 | mPaintHighlight = new Paint(); 45 | 46 | mScale = context.getResources().getDisplayMetrics().density; 47 | mPadding = (int) (mPaddingDP * mScale); 48 | 49 | mHighlightedLine = mHighlightStart = -1; 50 | 51 | mDrawingRect = new Rect(); 52 | mLineBounds = new Rect(); 53 | 54 | mGestureDetector = new GestureDetector(getContext(), this); 55 | 56 | updateFromSettings(); 57 | } 58 | 59 | /** 60 | * @see android.widget.TextView#computeScroll() 61 | * @category View 62 | */ 63 | public void computeScroll() { 64 | 65 | if (mTedScroller != null) { 66 | if (mTedScroller.computeScrollOffset()) { 67 | scrollTo(mTedScroller.getCurrX(), mTedScroller.getCurrY()); 68 | } 69 | } else { 70 | super.computeScroll(); 71 | } 72 | } 73 | 74 | /** 75 | * @see EditText#onDraw(Canvas) 76 | * @category View 77 | */ 78 | public void onDraw(Canvas canvas) { 79 | int count, lineX, baseline; 80 | 81 | count = getLineCount(); 82 | 83 | if (Settings.SHOW_LINE_NUMBERS) { 84 | int padding = (int) (Math.floor(Math.log10(count)) + 1); 85 | padding = (int) ((padding * mPaintNumbers.getTextSize()) + mPadding + (Settings.TEXT_SIZE 86 | * mScale * 0.5)); 87 | if (mLinePadding != padding) { 88 | mLinePadding = padding; 89 | setPadding(mLinePadding, mPadding, mPadding, mPadding); 90 | } 91 | } 92 | 93 | // get the drawing boundaries 94 | getDrawingRect(mDrawingRect); 95 | 96 | // display current line 97 | computeLineHighlight(); 98 | 99 | // draw line numbers 100 | lineX = (int) (mDrawingRect.left + mLinePadding - (Settings.TEXT_SIZE 101 | * mScale * 0.5)); 102 | int min = 0; 103 | int max = count; 104 | getLineBounds(0, mLineBounds); 105 | int startBottom = mLineBounds.bottom; 106 | int startTop = mLineBounds.top; 107 | getLineBounds(count - 1, mLineBounds); 108 | int endBottom = mLineBounds.bottom; 109 | int endTop = mLineBounds.top; 110 | if (count > 1 && endBottom > startBottom && endTop > startTop) { 111 | min = Math.max(min, ((mDrawingRect.top - startBottom) * (count - 1)) / (endBottom - startBottom)); 112 | max = Math.min(max, ((mDrawingRect.bottom - startTop) * (count - 1)) / (endTop - startTop) + 1); 113 | } 114 | for (int i = min; i < max; i++) { 115 | baseline = getLineBounds(i, mLineBounds); 116 | if ((mMaxSize != null) && (mMaxSize.x < mLineBounds.right)) { 117 | mMaxSize.x = mLineBounds.right; 118 | } 119 | 120 | if ((i == mHighlightedLine) && (!Settings.WORDWRAP)) { 121 | canvas.drawRect(mLineBounds, mPaintHighlight); 122 | } 123 | 124 | if (Settings.SHOW_LINE_NUMBERS) { 125 | canvas.drawText("" + (i + 1), mDrawingRect.left + mPadding, 126 | baseline, mPaintNumbers); 127 | } 128 | if (Settings.SHOW_LINE_NUMBERS) { 129 | canvas.drawLine(lineX, mDrawingRect.top, lineX, 130 | mDrawingRect.bottom, mPaintNumbers); 131 | } 132 | } 133 | getLineBounds(count - 1, mLineBounds); 134 | if (mMaxSize != null) { 135 | mMaxSize.y = mLineBounds.bottom; 136 | mMaxSize.x = Math.max(mMaxSize.x + mPadding - mDrawingRect.width(), 137 | 0); 138 | mMaxSize.y = Math.max( 139 | mMaxSize.y + mPadding - mDrawingRect.height(), 0); 140 | } 141 | 142 | super.onDraw(canvas); 143 | } 144 | 145 | /** 146 | * @see android.view.View.OnKeyListener#onKey(android.view.View, int, 147 | * android.view.KeyEvent) 148 | */ 149 | public boolean onKey(View v, int keyCode, KeyEvent event) { 150 | return false; 151 | } 152 | 153 | /** 154 | * @see android.widget.TextView#onTouchEvent(android.view.MotionEvent) 155 | * @category GestureDetection 156 | */ 157 | public boolean onTouchEvent(MotionEvent event) { 158 | 159 | super.onTouchEvent(event); 160 | if (mGestureDetector != null) { 161 | return mGestureDetector.onTouchEvent(event); 162 | } 163 | 164 | return true; 165 | } 166 | 167 | /** 168 | * @see android.view.GestureDetector.OnGestureListener#onDown(android.view.MotionEvent) 169 | * @category GestureDetection 170 | */ 171 | public boolean onDown(MotionEvent e) { 172 | return true; 173 | } 174 | 175 | /** 176 | * @see android.view.GestureDetector.OnGestureListener#onSingleTapUp(android.view.MotionEvent) 177 | * @category GestureDetection 178 | */ 179 | public boolean onSingleTapUp(MotionEvent e) { 180 | if (isEnabled()) { 181 | ((InputMethodManager) getContext().getSystemService( 182 | Context.INPUT_METHOD_SERVICE)).showSoftInput(this, 183 | InputMethodManager.SHOW_IMPLICIT); 184 | } 185 | return true; 186 | } 187 | 188 | /** 189 | * @see android.view.GestureDetector.OnGestureListener#onShowPress(android.view.MotionEvent) 190 | * @category GestureDetection 191 | */ 192 | public void onShowPress(MotionEvent e) { 193 | } 194 | 195 | /** 196 | * @see android.view.GestureDetector.OnGestureListener#onLongPress(android.view.MotionEvent) 197 | */ 198 | public void onLongPress(MotionEvent e) { 199 | 200 | } 201 | 202 | /** 203 | * @see android.view.GestureDetector.OnGestureListener#onScroll(android.view.MotionEvent, 204 | * android.view.MotionEvent, float, float) 205 | */ 206 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 207 | float distanceY) { 208 | // mTedScroller.setFriction(0); 209 | return true; 210 | } 211 | 212 | /** 213 | * @see android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, 214 | * android.view.MotionEvent, float, float) 215 | */ 216 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 217 | float velocityY) { 218 | if (!Settings.FLING_TO_SCROLL) { 219 | return true; 220 | } 221 | 222 | if (mTedScroller != null) { 223 | mTedScroller.fling(getScrollX(), getScrollY(), -(int) velocityX, 224 | -(int) velocityY, 0, mMaxSize.x, 0, mMaxSize.y); 225 | } 226 | return true; 227 | } 228 | 229 | /** 230 | * Update view settings from the app preferences 231 | * 232 | * @category Custom 233 | */ 234 | public void updateFromSettings() { 235 | 236 | if (isInEditMode()) { 237 | return; 238 | } 239 | 240 | setTypeface(Settings.getTypeface(getContext())); 241 | 242 | // wordwrap 243 | setHorizontallyScrolling(!Settings.WORDWRAP); 244 | 245 | // color Theme 246 | switch (Settings.COLOR) { 247 | case COLOR_NEGATIVE: 248 | setBackgroundResource(R.drawable.textfield_black); 249 | setTextColor(Color.WHITE); 250 | mPaintHighlight.setColor(Color.WHITE); 251 | mPaintNumbers.setColor(Color.GRAY); 252 | break; 253 | case COLOR_MATRIX: 254 | setBackgroundResource(R.drawable.textfield_matrix); 255 | setTextColor(Color.GREEN); 256 | mPaintHighlight.setColor(Color.GREEN); 257 | mPaintNumbers.setColor(Color.rgb(0, 128, 0)); 258 | break; 259 | case COLOR_SKY: 260 | setBackgroundResource(R.drawable.textfield_sky); 261 | setTextColor(Color.rgb(0, 0, 64)); 262 | mPaintHighlight.setColor(Color.rgb(0, 0, 64)); 263 | mPaintNumbers.setColor(Color.rgb(0, 128, 255)); 264 | break; 265 | case COLOR_DRACULA: 266 | setBackgroundResource(R.drawable.textfield_dracula); 267 | setTextColor(Color.RED); 268 | mPaintHighlight.setColor(Color.RED); 269 | mPaintNumbers.setColor(Color.rgb(192, 0, 0)); 270 | break; 271 | case COLOR_CLASSIC: 272 | default: 273 | setBackgroundResource(R.drawable.textfield_white); 274 | setTextColor(Color.BLACK); 275 | mPaintHighlight.setColor(Color.BLACK); 276 | mPaintNumbers.setColor(Color.GRAY); 277 | break; 278 | } 279 | mPaintHighlight.setAlpha(48); 280 | 281 | // text size 282 | setTextSize(Settings.TEXT_SIZE); 283 | mPaintNumbers.setTextSize(Settings.TEXT_SIZE * mScale * 0.85f); 284 | 285 | // refresh view 286 | postInvalidate(); 287 | refreshDrawableState(); 288 | 289 | // use Fling when scrolling settings ? 290 | if (Settings.FLING_TO_SCROLL) { 291 | mTedScroller = new Scroller(getContext()); 292 | mMaxSize = new Point(); 293 | } else { 294 | mTedScroller = null; 295 | mMaxSize = null; 296 | } 297 | 298 | // padding 299 | mLinePadding = mPadding; 300 | int count = getLineCount(); 301 | if (Settings.SHOW_LINE_NUMBERS) { 302 | mLinePadding = (int) (Math.floor(Math.log10(count)) + 1); 303 | mLinePadding = (int) ((mLinePadding * mPaintNumbers.getTextSize()) 304 | + mPadding + (Settings.TEXT_SIZE * mScale * 0.5)); 305 | setPadding(mLinePadding, mPadding, mPadding, mPadding); 306 | } else { 307 | setPadding(mPadding, mPadding, mPadding, mPadding); 308 | } 309 | } 310 | 311 | /** 312 | * Compute the line to highlight based on selection 313 | */ 314 | protected void computeLineHighlight() { 315 | int i, line, selStart; 316 | String text; 317 | 318 | if (!isEnabled()) { 319 | mHighlightedLine = -1; 320 | return; 321 | } 322 | 323 | selStart = getSelectionStart(); 324 | if (mHighlightStart != selStart) { 325 | text = getText().toString(); 326 | 327 | line = i = 0; 328 | while (i < selStart) { 329 | i = text.indexOf("\n", i); 330 | if (i < 0) { 331 | break; 332 | } 333 | if (i < selStart) { 334 | ++line; 335 | } 336 | ++i; 337 | } 338 | 339 | mHighlightedLine = line; 340 | } 341 | } 342 | 343 | /** The line numbers paint */ 344 | protected Paint mPaintNumbers; 345 | /** The line numbers paint */ 346 | protected Paint mPaintHighlight; 347 | /** the offset value in dp */ 348 | protected int mPaddingDP = 6; 349 | /** the padding scaled */ 350 | protected int mPadding, mLinePadding; 351 | /** the scale for desnity pixels */ 352 | protected float mScale; 353 | 354 | /** the scroller instance */ 355 | protected Scroller mTedScroller; 356 | /** the velocity tracker */ 357 | protected GestureDetector mGestureDetector; 358 | /** the Max size of the view */ 359 | protected Point mMaxSize; 360 | 361 | /** the highlighted line index */ 362 | protected int mHighlightedLine; 363 | protected int mHighlightStart; 364 | 365 | protected Rect mDrawingRect, mLineBounds; 366 | } 367 | -------------------------------------------------------------------------------- /Ted/src/fr/xgouchet/texteditor/TedActivity.java: -------------------------------------------------------------------------------- 1 | package fr.xgouchet.texteditor; 2 | 3 | import static fr.xgouchet.androidlib.data.FileUtils.deleteItem; 4 | import static fr.xgouchet.androidlib.data.FileUtils.getCanonizePath; 5 | import static fr.xgouchet.androidlib.data.FileUtils.renameItem; 6 | import static fr.xgouchet.androidlib.ui.Toaster.showToast; 7 | import static fr.xgouchet.androidlib.ui.activity.ActivityDecorator.addMenuItem; 8 | import static fr.xgouchet.androidlib.ui.activity.ActivityDecorator.showMenuItemAsAction; 9 | 10 | import java.io.File; 11 | import java.net.URI; 12 | import java.net.URISyntaxException; 13 | 14 | import android.annotation.TargetApi; 15 | import android.app.Activity; 16 | import android.app.AlertDialog.Builder; 17 | import android.content.ActivityNotFoundException; 18 | import android.content.Context; 19 | import android.content.DialogInterface; 20 | import android.content.Intent; 21 | import android.content.SharedPreferences; 22 | import android.content.res.Configuration; 23 | import android.os.Build.VERSION; 24 | import android.os.Build.VERSION_CODES; 25 | import android.os.Bundle; 26 | import android.text.Editable; 27 | import android.text.TextUtils; 28 | import android.text.TextWatcher; 29 | import android.util.Log; 30 | import android.view.KeyEvent; 31 | import android.view.Menu; 32 | import android.view.MenuItem; 33 | import android.view.View; 34 | import android.view.View.OnClickListener; 35 | import android.widget.EditText; 36 | import de.neofonie.mobile.app.android.widget.crouton.Crouton; 37 | import de.neofonie.mobile.app.android.widget.crouton.Style; 38 | import fr.xgouchet.texteditor.common.Constants; 39 | import fr.xgouchet.texteditor.common.RecentFiles; 40 | import fr.xgouchet.texteditor.common.Settings; 41 | import fr.xgouchet.texteditor.common.TedChangelog; 42 | import fr.xgouchet.texteditor.common.TextFileUtils; 43 | import fr.xgouchet.texteditor.ui.view.AdvancedEditText; 44 | import fr.xgouchet.texteditor.undo.TextChangeWatcher; 45 | 46 | public class TedActivity extends Activity implements Constants, TextWatcher, 47 | OnClickListener { 48 | 49 | /** 50 | * @see android.app.Activity#onCreate(android.os.Bundle) 51 | */ 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | if (BuildConfig.DEBUG) 55 | Log.d(TAG, "onCreate"); 56 | 57 | setContentView(R.layout.layout_editor); 58 | 59 | Settings.updateFromPreferences(getSharedPreferences(PREFERENCES_NAME, 60 | MODE_PRIVATE)); 61 | 62 | // 63 | mReadIntent = true; 64 | 65 | // editor 66 | mEditor = (AdvancedEditText) findViewById(R.id.editor); 67 | mEditor.addTextChangedListener(this); 68 | mEditor.updateFromSettings(); 69 | mWatcher = new TextChangeWatcher(); 70 | mWarnedShouldQuit = false; 71 | mDoNotBackup = false; 72 | 73 | // search 74 | mSearchLayout = findViewById(R.id.searchLayout); 75 | mSearchInput = (EditText) findViewById(R.id.textSearch); 76 | findViewById(R.id.buttonSearchClose).setOnClickListener(this); 77 | findViewById(R.id.buttonSearchNext).setOnClickListener(this); 78 | findViewById(R.id.buttonSearchPrev).setOnClickListener(this); 79 | } 80 | 81 | /** 82 | * @see android.app.Activity#onStart() 83 | */ 84 | protected void onStart() { 85 | super.onStart(); 86 | 87 | TedChangelog changeLog; 88 | SharedPreferences prefs; 89 | 90 | changeLog = new TedChangelog(); 91 | prefs = getSharedPreferences(Constants.PREFERENCES_NAME, 92 | Context.MODE_PRIVATE); 93 | 94 | if (changeLog.isFirstLaunchAfterUpdate(this, prefs)) { 95 | Builder builder = new Builder(this); 96 | String message = getString(changeLog.getTitleResource(this)) 97 | + "\n\n" + getString(changeLog.getChangeLogResource(this)); 98 | builder.setTitle(R.string.ui_whats_new); 99 | builder.setMessage(message); 100 | builder.setCancelable(true); 101 | builder.setPositiveButton(android.R.string.ok, 102 | new DialogInterface.OnClickListener() { 103 | public void onClick(DialogInterface dialog, int which) { 104 | dialog.dismiss(); 105 | } 106 | }); 107 | 108 | builder.create().show(); 109 | } 110 | 111 | changeLog.saveCurrentVersion(this, prefs); 112 | } 113 | 114 | /** 115 | * @see android.app.Activity#onRestart() 116 | */ 117 | protected void onRestart() { 118 | super.onRestart(); 119 | mReadIntent = false; 120 | } 121 | 122 | /** 123 | * @see android.app.Activity#onRestoreInstanceState(android.os.Bundle) 124 | */ 125 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 126 | super.onRestoreInstanceState(savedInstanceState); 127 | Log.d("TED", "onRestoreInstanceState"); 128 | Log.v("TED", mEditor.getText().toString()); 129 | } 130 | 131 | /** 132 | * @see android.app.Activity#onResume() 133 | */ 134 | protected void onResume() { 135 | super.onResume(); 136 | if (BuildConfig.DEBUG) 137 | Log.d(TAG, "onResume"); 138 | 139 | if (mReadIntent) { 140 | readIntent(); 141 | } 142 | 143 | mReadIntent = false; 144 | 145 | updateTitle(); 146 | mEditor.updateFromSettings(); 147 | } 148 | 149 | /** 150 | * @see android.app.Activity#onPause() 151 | */ 152 | protected void onPause() { 153 | super.onPause(); 154 | if (BuildConfig.DEBUG) 155 | Log.d(TAG, "onPause"); 156 | 157 | if (Settings.FORCE_AUTO_SAVE && mDirty && (!mReadOnly)) { 158 | if ((mCurrentFilePath == null) || (mCurrentFilePath.length() == 0)) 159 | doAutoSaveFile(); 160 | else if (Settings.AUTO_SAVE_OVERWRITE) 161 | doSaveFile(mCurrentFilePath); 162 | } 163 | } 164 | 165 | /** 166 | * @see android.app.Activity#onActivityResult(int, int, 167 | * android.content.Intent) 168 | * 169 | */ 170 | @TargetApi(11) 171 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 172 | Bundle extras; 173 | if (BuildConfig.DEBUG) 174 | Log.d(TAG, "onActivityResult"); 175 | mReadIntent = false; 176 | 177 | if (resultCode == RESULT_CANCELED) { 178 | if (BuildConfig.DEBUG) 179 | Log.d(TAG, "Result canceled"); 180 | return; 181 | } 182 | 183 | if ((resultCode != RESULT_OK) || (data == null)) { 184 | if (BuildConfig.DEBUG) 185 | Log.e(TAG, "Result error or null data! / " + resultCode); 186 | return; 187 | } 188 | 189 | extras = data.getExtras(); 190 | if (extras == null) { 191 | if (BuildConfig.DEBUG) 192 | Log.e(TAG, "No extra data ! "); 193 | return; 194 | } 195 | 196 | switch (requestCode) { 197 | case REQUEST_SAVE_AS: 198 | if (BuildConfig.DEBUG) 199 | Log.d(TAG, "Save as : " + extras.getString("path")); 200 | doSaveFile(extras.getString("path")); 201 | break; 202 | case REQUEST_OPEN: 203 | if (BuildConfig.DEBUG) 204 | Log.d(TAG, "Open : " + extras.getString("path")); 205 | doOpenFile(new File(extras.getString("path")), false); 206 | break; 207 | } 208 | } 209 | 210 | /** 211 | * @see android.app.Activity#onConfigurationChanged(android.content.res.Configuration) 212 | */ 213 | public void onConfigurationChanged(Configuration newConfig) { 214 | super.onConfigurationChanged(newConfig); 215 | if (BuildConfig.DEBUG) 216 | Log.d(TAG, "onConfigurationChanged"); 217 | } 218 | 219 | /** 220 | * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) 221 | */ 222 | public boolean onCreateOptionsMenu(Menu menu) { 223 | super.onCreateOptionsMenu(menu); 224 | 225 | return true; 226 | } 227 | 228 | /** 229 | * @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu) 230 | */ 231 | @TargetApi(11) 232 | public boolean onPrepareOptionsMenu(Menu menu) { 233 | super.onPrepareOptionsMenu(menu); 234 | 235 | menu.clear(); 236 | 237 | addMenuItem(menu, MENU_ID_NEW, R.string.menu_new, 238 | R.drawable.ic_menu_file_new); 239 | addMenuItem(menu, MENU_ID_OPEN, R.string.menu_open, 240 | R.drawable.ic_menu_file_open); 241 | 242 | if (!mReadOnly) 243 | addMenuItem(menu, MENU_ID_SAVE, R.string.menu_save, 244 | R.drawable.ic_menu_save); 245 | 246 | if ((!mReadOnly) && Settings.UNDO) 247 | addMenuItem(menu, MENU_ID_UNDO, R.string.menu_undo, 248 | R.drawable.ic_menu_undo); 249 | 250 | addMenuItem(menu, MENU_ID_SEARCH, R.string.menu_search, 251 | R.drawable.ic_menu_search); 252 | 253 | if (RecentFiles.getRecentFiles().size() > 0) 254 | addMenuItem(menu, MENU_ID_OPEN_RECENT, R.string.menu_open_recent, 255 | R.drawable.ic_menu_recent); 256 | 257 | addMenuItem(menu, MENU_ID_SAVE_AS, R.string.menu_save_as, 0); 258 | 259 | addMenuItem(menu, MENU_ID_SETTINGS, R.string.menu_settings, 0); 260 | 261 | addMenuItem(menu, MENU_ID_ABOUT, R.string.menu_about, 0); 262 | 263 | if (Settings.BACK_BTN_AS_UNDO && Settings.UNDO) 264 | addMenuItem(menu, MENU_ID_QUIT, R.string.menu_quit, 0); 265 | 266 | if ((!mReadOnly) && Settings.UNDO) 267 | showMenuItemAsAction(menu.findItem(MENU_ID_UNDO), 268 | R.drawable.ic_menu_undo); 269 | showMenuItemAsAction(menu.findItem(MENU_ID_SEARCH), 270 | R.drawable.ic_menu_search); 271 | 272 | return true; 273 | } 274 | 275 | /** 276 | * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem) 277 | */ 278 | public boolean onOptionsItemSelected(MenuItem item) { 279 | mWarnedShouldQuit = false; 280 | switch (item.getItemId()) { 281 | case MENU_ID_NEW: 282 | newContent(); 283 | return true; 284 | case MENU_ID_SAVE: 285 | saveContent(); 286 | break; 287 | case MENU_ID_SAVE_AS: 288 | saveContentAs(); 289 | break; 290 | case MENU_ID_OPEN: 291 | openFile(); 292 | break; 293 | case MENU_ID_OPEN_RECENT: 294 | openRecentFile(); 295 | break; 296 | case MENU_ID_SEARCH: 297 | search(); 298 | break; 299 | case MENU_ID_SETTINGS: 300 | settingsActivity(); 301 | return true; 302 | case MENU_ID_ABOUT: 303 | aboutActivity(); 304 | return true; 305 | case MENU_ID_QUIT: 306 | quit(); 307 | return true; 308 | case MENU_ID_UNDO: 309 | if (!undo()) { 310 | Crouton.showText(this, R.string.toast_warn_no_undo, Style.INFO); 311 | } 312 | return true; 313 | } 314 | return super.onOptionsItemSelected(item); 315 | } 316 | 317 | /** 318 | * @see android.text.TextWatcher#beforeTextChanged(java.lang.CharSequence, 319 | * int, int, int) 320 | */ 321 | public void beforeTextChanged(CharSequence s, int start, int count, 322 | int after) { 323 | if (Settings.UNDO && (!mInUndo) && (mWatcher != null)) 324 | mWatcher.beforeChange(s, start, count, after); 325 | } 326 | 327 | /** 328 | * @see android.text.TextWatcher#onTextChanged(java.lang.CharSequence, int, 329 | * int, int) 330 | */ 331 | public void onTextChanged(CharSequence s, int start, int before, int count) { 332 | if (mInUndo) 333 | return; 334 | 335 | if (Settings.UNDO && (!mInUndo) && (mWatcher != null)) 336 | mWatcher.afterChange(s, start, before, count); 337 | 338 | } 339 | 340 | /** 341 | * @see android.text.TextWatcher#afterTextChanged(android.text.Editable) 342 | */ 343 | public void afterTextChanged(Editable s) { 344 | if (!mDirty) { 345 | mDirty = true; 346 | updateTitle(); 347 | } 348 | } 349 | 350 | /** 351 | * @see android.app.Activity#onKeyUp(int, android.view.KeyEvent) 352 | */ 353 | public boolean onKeyUp(int keyCode, KeyEvent event) { 354 | switch (keyCode) { 355 | case KeyEvent.KEYCODE_BACK: 356 | if (mSearchLayout.getVisibility() != View.GONE) 357 | search(); 358 | else if (Settings.UNDO && Settings.BACK_BTN_AS_UNDO) { 359 | if (!undo()) 360 | warnOrQuit(); 361 | } else 362 | quit(); 363 | return true; 364 | case KeyEvent.KEYCODE_SEARCH: 365 | search(); 366 | mWarnedShouldQuit = false; 367 | return true; 368 | } 369 | mWarnedShouldQuit = false; 370 | return super.onKeyUp(keyCode, event); 371 | } 372 | 373 | /** 374 | * @see OnClickListener#onClick(View) 375 | */ 376 | public void onClick(View v) { 377 | mWarnedShouldQuit = false; 378 | switch (v.getId()) { 379 | case R.id.buttonSearchClose: 380 | search(); 381 | break; 382 | case R.id.buttonSearchNext: 383 | searchNext(); 384 | break; 385 | case R.id.buttonSearchPrev: 386 | searchPrevious(); 387 | break; 388 | } 389 | } 390 | 391 | /** 392 | * Read the intent used to start this activity (open the text file) as well 393 | * as the non configuration instance if activity is started after a screen 394 | * rotate 395 | */ 396 | protected void readIntent() { 397 | Intent intent; 398 | String action; 399 | File file; 400 | 401 | intent = getIntent(); 402 | if (intent == null) { 403 | if (BuildConfig.DEBUG) 404 | Log.d(TAG, "No intent found, use default instead"); 405 | doDefaultAction(); 406 | return; 407 | } 408 | 409 | action = intent.getAction(); 410 | if (action == null) { 411 | if (BuildConfig.DEBUG) 412 | Log.d(TAG, "Intent w/o action, default action"); 413 | doDefaultAction(); 414 | } else if ((action.equals(Intent.ACTION_VIEW)) 415 | || (action.equals(Intent.ACTION_EDIT))) { 416 | try { 417 | file = new File(new URI(intent.getData().toString())); 418 | doOpenFile(file, false); 419 | } catch (URISyntaxException e) { 420 | Crouton.showText(this, R.string.toast_intent_invalid_uri, 421 | Style.ALERT); 422 | } catch (IllegalArgumentException e) { 423 | Crouton.showText(this, R.string.toast_intent_illegal, 424 | Style.ALERT); 425 | } 426 | } else if (action.equals(ACTION_WIDGET_OPEN)) { 427 | try { 428 | file = new File(new URI(intent.getData().toString())); 429 | doOpenFile(file, 430 | intent.getBooleanExtra(EXTRA_FORCE_READ_ONLY, false)); 431 | } catch (URISyntaxException e) { 432 | Crouton.showText(this, R.string.toast_intent_invalid_uri, 433 | Style.ALERT); 434 | } catch (IllegalArgumentException e) { 435 | Crouton.showText(this, R.string.toast_intent_illegal, 436 | Style.ALERT); 437 | } 438 | } else { 439 | doDefaultAction(); 440 | } 441 | } 442 | 443 | /** 444 | * Run the default startup action 445 | */ 446 | protected void doDefaultAction() { 447 | File file; 448 | boolean loaded; 449 | loaded = false; 450 | 451 | if (doOpenBackup()) 452 | loaded = true; 453 | 454 | if ((!loaded) && Settings.USE_HOME_PAGE) { 455 | file = new File(Settings.HOME_PAGE_PATH); 456 | if ((file == null) || (!file.exists())) { 457 | Crouton.showText(this, R.string.toast_open_home_page_error, 458 | Style.ALERT); 459 | } else if (!file.canRead()) { 460 | Crouton.showText(this, R.string.toast_home_page_cant_read, 461 | Style.ALERT); 462 | } else { 463 | loaded = doOpenFile(file, false); 464 | } 465 | } 466 | 467 | if (!loaded) 468 | doClearContents(); 469 | } 470 | 471 | /** 472 | * Clears the content of the editor. Assumes that user was prompted and 473 | * previous data was saved 474 | */ 475 | protected void doClearContents() { 476 | mWatcher = null; 477 | mInUndo = true; 478 | mEditor.setText(""); 479 | mCurrentFilePath = null; 480 | mCurrentFileName = null; 481 | Settings.END_OF_LINE = Settings.DEFAULT_END_OF_LINE; 482 | mDirty = false; 483 | mReadOnly = false; 484 | mWarnedShouldQuit = false; 485 | mWatcher = new TextChangeWatcher(); 486 | mInUndo = false; 487 | mDoNotBackup = false; 488 | 489 | TextFileUtils.clearInternal(getApplicationContext()); 490 | 491 | updateTitle(); 492 | } 493 | 494 | /** 495 | * Opens the given file and replace the editors content with the file. 496 | * Assumes that user was prompted and previous data was saved 497 | * 498 | * @param file 499 | * the file to load 500 | * @param forceReadOnly 501 | * force the file to be used as read only 502 | * @return if the file was loaded successfully 503 | */ 504 | protected boolean doOpenFile(File file, boolean forceReadOnly) { 505 | String text; 506 | 507 | if (file == null) 508 | return false; 509 | 510 | if (BuildConfig.DEBUG) 511 | Log.i(TAG, "Openning file " + file.getName()); 512 | 513 | try { 514 | text = TextFileUtils.readTextFile(file); 515 | if (text != null) { 516 | mInUndo = true; 517 | mEditor.setText(text); 518 | mWatcher = new TextChangeWatcher(); 519 | mCurrentFilePath = getCanonizePath(file); 520 | mCurrentFileName = file.getName(); 521 | RecentFiles.updateRecentList(mCurrentFilePath); 522 | RecentFiles.saveRecentList(getSharedPreferences( 523 | PREFERENCES_NAME, MODE_PRIVATE)); 524 | mDirty = false; 525 | mInUndo = false; 526 | mDoNotBackup = false; 527 | if (file.canWrite() && (!forceReadOnly)) { 528 | mReadOnly = false; 529 | mEditor.setEnabled(true); 530 | } else { 531 | mReadOnly = true; 532 | mEditor.setEnabled(false); 533 | } 534 | 535 | updateTitle(); 536 | 537 | return true; 538 | } else { 539 | Crouton.showText(this, R.string.toast_open_error, Style.ALERT); 540 | } 541 | } catch (OutOfMemoryError e) { 542 | Crouton.showText(this, R.string.toast_memory_open, Style.ALERT); 543 | } 544 | 545 | return false; 546 | } 547 | 548 | /** 549 | * Open the last backup file 550 | * 551 | * @return if a backup file was loaded 552 | */ 553 | protected boolean doOpenBackup() { 554 | 555 | String text; 556 | 557 | try { 558 | text = TextFileUtils.readInternal(this); 559 | if (!TextUtils.isEmpty(text)) { 560 | mInUndo = true; 561 | mEditor.setText(text); 562 | mWatcher = new TextChangeWatcher(); 563 | mCurrentFilePath = null; 564 | mCurrentFileName = null; 565 | mDirty = false; 566 | mInUndo = false; 567 | mDoNotBackup = false; 568 | mReadOnly = false; 569 | mEditor.setEnabled(true); 570 | 571 | updateTitle(); 572 | 573 | return true; 574 | } else { 575 | return false; 576 | } 577 | } catch (OutOfMemoryError e) { 578 | Crouton.showText(this, R.string.toast_memory_open, Style.ALERT); 579 | } 580 | 581 | return true; 582 | } 583 | 584 | /** 585 | * Saves the text editor's content into a file at the given path. If an 586 | * after save {@link Runnable} exists, run it 587 | * 588 | * @param path 589 | * the path to the file (must be a valid path and not null) 590 | */ 591 | protected void doSaveFile(String path) { 592 | String content; 593 | 594 | if (path == null) { 595 | Crouton.showText(this, R.string.toast_save_null, Style.ALERT); 596 | return; 597 | } 598 | 599 | content = mEditor.getText().toString(); 600 | 601 | if (!TextFileUtils.writeTextFile(path + ".tmp", content)) { 602 | Crouton.showText(this, R.string.toast_save_temp, Style.ALERT); 603 | return; 604 | } 605 | 606 | if (!deleteItem(path)) { 607 | Crouton.showText(this, R.string.toast_save_delete, Style.ALERT); 608 | return; 609 | } 610 | 611 | if (!renameItem(path + ".tmp", path)) { 612 | Crouton.showText(this, R.string.toast_save_rename, Style.ALERT); 613 | return; 614 | } 615 | 616 | mCurrentFilePath = getCanonizePath(new File(path)); 617 | mCurrentFileName = (new File(path)).getName(); 618 | RecentFiles.updateRecentList(path); 619 | RecentFiles.saveRecentList(getSharedPreferences(PREFERENCES_NAME, 620 | MODE_PRIVATE)); 621 | mReadOnly = false; 622 | mDirty = false; 623 | updateTitle(); 624 | Crouton.showText(this, R.string.toast_save_success, Style.CONFIRM); 625 | 626 | runAfterSave(); 627 | } 628 | 629 | protected void doAutoSaveFile() { 630 | if (mDoNotBackup) { 631 | doClearContents(); 632 | } 633 | 634 | String text = mEditor.getText().toString(); 635 | if (text.length() == 0) 636 | return; 637 | 638 | if (TextFileUtils.writeInternal(this, text)) { 639 | showToast(this, R.string.toast_file_saved_auto, false); 640 | } 641 | } 642 | 643 | /** 644 | * Undo the last change 645 | * 646 | * @return if an undo was don 647 | */ 648 | protected boolean undo() { 649 | boolean didUndo = false; 650 | mInUndo = true; 651 | int caret; 652 | caret = mWatcher.undo(mEditor.getText()); 653 | if (caret >= 0) { 654 | mEditor.setSelection(caret, caret); 655 | didUndo = true; 656 | } 657 | mInUndo = false; 658 | 659 | return didUndo; 660 | } 661 | 662 | /** 663 | * Prompt the user to save the current file before doing something else 664 | */ 665 | protected void promptSaveDirty() { 666 | Builder builder; 667 | 668 | if (!mDirty) { 669 | runAfterSave(); 670 | return; 671 | } 672 | 673 | builder = new Builder(this); 674 | builder.setTitle(R.string.app_name); 675 | builder.setMessage(R.string.ui_save_text); 676 | 677 | builder.setPositiveButton(R.string.ui_save, 678 | new DialogInterface.OnClickListener() { 679 | public void onClick(DialogInterface dialog, int which) { 680 | saveContent(); 681 | mDoNotBackup = true; 682 | } 683 | }); 684 | builder.setNegativeButton(R.string.ui_cancel, 685 | new DialogInterface.OnClickListener() { 686 | public void onClick(DialogInterface dialog, int which) { 687 | 688 | } 689 | }); 690 | builder.setNeutralButton(R.string.ui_no_save, 691 | new DialogInterface.OnClickListener() { 692 | public void onClick(DialogInterface dialog, int which) { 693 | runAfterSave(); 694 | mDoNotBackup = true; 695 | } 696 | }); 697 | 698 | builder.create().show(); 699 | 700 | } 701 | 702 | /** 703 | * 704 | */ 705 | protected void newContent() { 706 | mAfterSave = new Runnable() { 707 | public void run() { 708 | doClearContents(); 709 | } 710 | }; 711 | 712 | promptSaveDirty(); 713 | } 714 | 715 | /** 716 | * Runs the after save to complete 717 | */ 718 | protected void runAfterSave() { 719 | if (mAfterSave == null) { 720 | if (BuildConfig.DEBUG) 721 | Log.d(TAG, "No After shave, ignoring..."); 722 | return; 723 | } 724 | 725 | mAfterSave.run(); 726 | 727 | mAfterSave = null; 728 | } 729 | 730 | /** 731 | * Starts an activity to choose a file to open 732 | */ 733 | protected void openFile() { 734 | if (BuildConfig.DEBUG) 735 | Log.d(TAG, "openFile"); 736 | 737 | mAfterSave = new Runnable() { 738 | public void run() { 739 | Intent open = new Intent(); 740 | open.setClass(getApplicationContext(), TedOpenActivity.class); 741 | // open = new Intent(ACTION_OPEN); 742 | open.putExtra(EXTRA_REQUEST_CODE, REQUEST_OPEN); 743 | try { 744 | startActivityForResult(open, REQUEST_OPEN); 745 | } catch (ActivityNotFoundException e) { 746 | Crouton.showText(TedActivity.this, 747 | R.string.toast_activity_open, Style.ALERT); 748 | } 749 | } 750 | }; 751 | 752 | promptSaveDirty(); 753 | } 754 | 755 | /** 756 | * Open the recent files activity to open 757 | */ 758 | protected void openRecentFile() { 759 | if (BuildConfig.DEBUG) 760 | Log.d(TAG, "openRecentFile"); 761 | 762 | if (RecentFiles.getRecentFiles().size() == 0) { 763 | Crouton.showText(this, R.string.toast_no_recent_files, Style.ALERT); 764 | return; 765 | } 766 | 767 | mAfterSave = new Runnable() { 768 | public void run() { 769 | Intent open; 770 | 771 | open = new Intent(); 772 | open.setClass(TedActivity.this, TedOpenRecentActivity.class); 773 | try { 774 | startActivityForResult(open, REQUEST_OPEN); 775 | } catch (ActivityNotFoundException e) { 776 | Crouton.showText(TedActivity.this, 777 | R.string.toast_activity_open_recent, Style.ALERT); 778 | } 779 | } 780 | }; 781 | 782 | promptSaveDirty(); 783 | } 784 | 785 | /** 786 | * Warns the user that the next back press will qui the application, or quit 787 | * if the warning has already been shown 788 | */ 789 | protected void warnOrQuit() { 790 | if (mWarnedShouldQuit) { 791 | quit(); 792 | } else { 793 | Crouton.showText(this, R.string.toast_warn_no_undo_will_quit, 794 | Style.INFO); 795 | mWarnedShouldQuit = true; 796 | } 797 | } 798 | 799 | /** 800 | * Quit the app (user pressed back) 801 | */ 802 | protected void quit() { 803 | mAfterSave = new Runnable() { 804 | public void run() { 805 | finish(); 806 | } 807 | }; 808 | 809 | promptSaveDirty(); 810 | } 811 | 812 | /** 813 | * General save command : check if a path exist for the current content, 814 | * then save it , else invoke the {@link TedActivity#saveContentAs()} method 815 | */ 816 | protected void saveContent() { 817 | if ((mCurrentFilePath == null) || (mCurrentFilePath.length() == 0)) { 818 | saveContentAs(); 819 | } else { 820 | doSaveFile(mCurrentFilePath); 821 | } 822 | } 823 | 824 | /** 825 | * General Save as command : prompt the user for a location and file name, 826 | * then save the editor'd content 827 | */ 828 | protected void saveContentAs() { 829 | if (BuildConfig.DEBUG) 830 | Log.d(TAG, "saveContentAs"); 831 | Intent saveAs; 832 | saveAs = new Intent(); 833 | saveAs.setClass(this, TedSaveAsActivity.class); 834 | try { 835 | startActivityForResult(saveAs, REQUEST_SAVE_AS); 836 | } catch (ActivityNotFoundException e) { 837 | Crouton.showText(this, R.string.toast_activity_save_as, Style.ALERT); 838 | } 839 | } 840 | 841 | /** 842 | * Opens / close the search interface 843 | */ 844 | protected void search() { 845 | if (BuildConfig.DEBUG) 846 | Log.d(TAG, "search"); 847 | switch (mSearchLayout.getVisibility()) { 848 | case View.GONE: 849 | mSearchLayout.setVisibility(View.VISIBLE); 850 | break; 851 | case View.VISIBLE: 852 | default: 853 | mSearchLayout.setVisibility(View.GONE); 854 | break; 855 | } 856 | } 857 | 858 | /** 859 | * Uses the user input to search a file 860 | */ 861 | protected void searchNext() { 862 | String search, text; 863 | int selection, next; 864 | 865 | search = mSearchInput.getText().toString(); 866 | text = mEditor.getText().toString(); 867 | selection = mEditor.getSelectionEnd(); 868 | 869 | if (search.length() == 0) { 870 | Crouton.showText(this, R.string.toast_search_no_input, Style.INFO); 871 | return; 872 | } 873 | 874 | if (!Settings.SEARCHMATCHCASE) { 875 | search = search.toLowerCase(); 876 | text = text.toLowerCase(); 877 | } 878 | 879 | next = text.indexOf(search, selection); 880 | 881 | if (next > -1) { 882 | mEditor.setSelection(next, next + search.length()); 883 | if (!mEditor.isFocused()) 884 | mEditor.requestFocus(); 885 | } else { 886 | if (Settings.SEARCHWRAP) { 887 | next = text.indexOf(search); 888 | if (next > -1) { 889 | mEditor.setSelection(next, next + search.length()); 890 | if (!mEditor.isFocused()) 891 | mEditor.requestFocus(); 892 | } else { 893 | Crouton.showText(this, R.string.toast_search_not_found, 894 | Style.INFO); 895 | } 896 | } else { 897 | Crouton.showText(this, R.string.toast_search_eof, Style.INFO); 898 | } 899 | } 900 | } 901 | 902 | /** 903 | * Uses the user input to search a file 904 | */ 905 | protected void searchPrevious() { 906 | String search, text; 907 | int selection, next; 908 | 909 | search = mSearchInput.getText().toString(); 910 | text = mEditor.getText().toString(); 911 | selection = mEditor.getSelectionStart() - 1; 912 | 913 | if (search.length() == 0) { 914 | Crouton.showText(this, R.string.toast_search_no_input, Style.INFO); 915 | return; 916 | } 917 | 918 | if (!Settings.SEARCHMATCHCASE) { 919 | search = search.toLowerCase(); 920 | text = text.toLowerCase(); 921 | } 922 | 923 | next = text.lastIndexOf(search, selection); 924 | 925 | if (next > -1) { 926 | mEditor.setSelection(next, next + search.length()); 927 | if (!mEditor.isFocused()) 928 | mEditor.requestFocus(); 929 | } else { 930 | if (Settings.SEARCHWRAP) { 931 | next = text.lastIndexOf(search); 932 | if (next > -1) { 933 | mEditor.setSelection(next, next + search.length()); 934 | if (!mEditor.isFocused()) 935 | mEditor.requestFocus(); 936 | } else { 937 | Crouton.showText(this, R.string.toast_search_not_found, 938 | Style.INFO); 939 | } 940 | } else { 941 | Crouton.showText(this, R.string.toast_search_eof, Style.INFO); 942 | } 943 | } 944 | } 945 | 946 | /** 947 | * Opens the about activity 948 | */ 949 | protected void aboutActivity() { 950 | Intent about = new Intent(); 951 | about.setClass(this, TedAboutActivity.class); 952 | try { 953 | startActivity(about); 954 | } catch (ActivityNotFoundException e) { 955 | Crouton.showText(this, R.string.toast_activity_about, Style.ALERT); 956 | } 957 | } 958 | 959 | /** 960 | * Opens the settings activity 961 | */ 962 | protected void settingsActivity() { 963 | 964 | mAfterSave = new Runnable() { 965 | public void run() { 966 | Intent settings = new Intent(); 967 | settings.setClass(TedActivity.this, TedSettingsActivity.class); 968 | try { 969 | startActivity(settings); 970 | } catch (ActivityNotFoundException e) { 971 | Crouton.showText(TedActivity.this, 972 | R.string.toast_activity_settings, Style.ALERT); 973 | } 974 | } 975 | }; 976 | 977 | promptSaveDirty(); 978 | } 979 | 980 | /** 981 | * Update the window title 982 | */ 983 | @TargetApi(11) 984 | protected void updateTitle() { 985 | String title; 986 | String name; 987 | 988 | name = "?"; 989 | if ((mCurrentFileName != null) && (mCurrentFileName.length() > 0)) 990 | name = mCurrentFileName; 991 | 992 | if (mReadOnly) 993 | title = getString(R.string.title_editor_readonly, name); 994 | else if (mDirty) 995 | title = getString(R.string.title_editor_dirty, name); 996 | else 997 | title = getString(R.string.title_editor, name); 998 | 999 | setTitle(title); 1000 | 1001 | if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) 1002 | invalidateOptionsMenu(); 1003 | } 1004 | 1005 | /** the text editor */ 1006 | protected AdvancedEditText mEditor; 1007 | /** the path of the file currently opened */ 1008 | protected String mCurrentFilePath; 1009 | /** the name of the file currently opened */ 1010 | protected String mCurrentFileName; 1011 | /** the runable to run after a save */ 1012 | protected Runnable mAfterSave; // Mennen ? Axe ? 1013 | 1014 | /** is dirty ? */ 1015 | protected boolean mDirty; 1016 | /** is read only */ 1017 | protected boolean mReadOnly; 1018 | 1019 | /** the search layout root */ 1020 | protected View mSearchLayout; 1021 | /** the search input */ 1022 | protected EditText mSearchInput; 1023 | 1024 | /** Undo watcher */ 1025 | protected TextChangeWatcher mWatcher; 1026 | protected boolean mInUndo; 1027 | protected boolean mWarnedShouldQuit; 1028 | protected boolean mDoNotBackup; 1029 | 1030 | /** are we in a post activity result ? */ 1031 | protected boolean mReadIntent; 1032 | 1033 | } --------------------------------------------------------------------------------