| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.ex.editstyledtext; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| |
| import com.android.ex.editstyledtext.EditStyledText.EditModeActions.EditModeActionBase; |
| import com.android.ex.editstyledtext.EditStyledText.EditStyledTextSpans.HorizontalLineSpan; |
| import com.android.ex.editstyledtext.EditStyledText.EditStyledTextSpans.MarqueeSpan; |
| import com.android.ex.editstyledtext.EditStyledText.EditStyledTextSpans.RescalableImageSpan; |
| |
| import android.R; |
| import android.app.AlertDialog; |
| import android.app.AlertDialog.Builder; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.DialogInterface.OnCancelListener; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapFactory; |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Rect; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.graphics.drawable.ShapeDrawable; |
| import android.graphics.drawable.shapes.RectShape; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.os.ResultReceiver; |
| import android.text.ClipboardManager; |
| import android.text.Editable; |
| import android.text.Html; |
| import android.text.Layout; |
| import android.text.NoCopySpan; |
| import android.text.NoCopySpan.Concrete; |
| import android.text.Selection; |
| import android.text.Spannable; |
| import android.text.SpannableStringBuilder; |
| import android.text.Spanned; |
| import android.text.TextPaint; |
| import android.text.Html.ImageGetter; |
| import android.text.Html.TagHandler; |
| import android.text.method.ArrowKeyMovementMethod; |
| import android.text.style.AbsoluteSizeSpan; |
| import android.text.style.AlignmentSpan; |
| import android.text.style.BackgroundColorSpan; |
| import android.text.style.CharacterStyle; |
| import android.text.style.DynamicDrawableSpan; |
| import android.text.style.ForegroundColorSpan; |
| import android.text.style.ImageSpan; |
| import android.text.style.ParagraphStyle; |
| import android.text.style.QuoteSpan; |
| import android.text.style.UnderlineSpan; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.ContextMenu; |
| import android.view.Gravity; |
| import android.view.KeyEvent; |
| import android.view.MenuItem; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.inputmethod.EditorInfo; |
| import android.view.inputmethod.InputConnection; |
| import android.view.inputmethod.InputConnectionWrapper; |
| import android.view.inputmethod.InputMethodManager; |
| import android.widget.Button; |
| import android.widget.EditText; |
| import android.widget.LinearLayout; |
| import android.widget.TextView; |
| |
| /** |
| * EditStyledText extends EditText for managing the flow and status to edit the styled text. This |
| * manages the states and flows of editing, supports inserting image, import/export HTML. |
| */ |
| public class EditStyledText extends EditText { |
| |
| private static final String TAG = "EditStyledText"; |
| /** |
| * DBG should be false at checking in. |
| */ |
| private static final boolean DBG = true; |
| |
| /** |
| * Modes of editing actions. |
| */ |
| /** The mode that no editing action is done. */ |
| public static final int MODE_NOTHING = 0; |
| /** The mode of copy. */ |
| public static final int MODE_COPY = 1; |
| /** The mode of paste. */ |
| public static final int MODE_PASTE = 2; |
| /** The mode of changing size. */ |
| public static final int MODE_SIZE = 3; |
| /** The mode of changing color. */ |
| public static final int MODE_COLOR = 4; |
| /** The mode of selection. */ |
| public static final int MODE_SELECT = 5; |
| /** The mode of changing alignment. */ |
| public static final int MODE_ALIGN = 6; |
| /** The mode of changing cut. */ |
| public static final int MODE_CUT = 7; |
| public static final int MODE_TELOP = 8; |
| public static final int MODE_SWING = 9; |
| public static final int MODE_MARQUEE = 10; |
| public static final int MODE_SELECTALL = 11; |
| public static final int MODE_HORIZONTALLINE = 12; |
| public static final int MODE_STOP_SELECT = 13; |
| public static final int MODE_CLEARSTYLES = 14; |
| public static final int MODE_IMAGE = 15; |
| public static final int MODE_BGCOLOR = 16; |
| public static final int MODE_PREVIEW = 17; |
| public static final int MODE_CANCEL = 18; |
| public static final int MODE_TEXTVIEWFUNCTION = 19; |
| public static final int MODE_START_EDIT = 20; |
| public static final int MODE_END_EDIT = 21; |
| public static final int MODE_RESET = 22; |
| public static final int MODE_SHOW_MENU = 23; |
| |
| /** |
| * States of selection. |
| */ |
| /** The state that selection isn't started. */ |
| public static final int STATE_SELECT_OFF = 0; |
| /** The state that selection is started. */ |
| public static final int STATE_SELECT_ON = 1; |
| /** The state that selection is done, but not fixed. */ |
| public static final int STATE_SELECTED = 2; |
| /** The state that selection is done and not fixed. */ |
| public static final int STATE_SELECT_FIX = 3; |
| |
| /** |
| * Help message strings. |
| */ |
| public static final int HINT_MSG_NULL = 0; |
| public static final int HINT_MSG_COPY_BUF_BLANK = 1; |
| public static final int HINT_MSG_SELECT_START = 2; |
| public static final int HINT_MSG_SELECT_END = 3; |
| public static final int HINT_MSG_PUSH_COMPETE = 4; |
| public static final int HINT_MSG_BIG_SIZE_ERROR = 5; |
| public static final int HINT_MSG_END_PREVIEW = 6; |
| public static final int HINT_MSG_END_COMPOSE = 7; |
| |
| /** |
| * Fixed Values. |
| */ |
| public static final int DEFAULT_TRANSPARENT_COLOR = 0x00FFFFFF; |
| public static final int DEFAULT_FOREGROUND_COLOR = 0xFF000000; |
| public static final char ZEROWIDTHCHAR = '\u2060'; |
| public static final char IMAGECHAR = '\uFFFC'; |
| private static final int ID_SELECT_ALL = android.R.id.selectAll; |
| private static final int ID_START_SELECTING_TEXT = android.R.id.startSelectingText; |
| private static final int ID_STOP_SELECTING_TEXT = android.R.id.stopSelectingText; |
| private static final int ID_PASTE = android.R.id.paste; |
| private static final int ID_COPY = android.R.id.copy; |
| private static final int ID_CUT = android.R.id.cut; |
| private static final int ID_HORIZONTALLINE = 0x00FFFF01; |
| private static final int ID_CLEARSTYLES = 0x00FFFF02; |
| private static final int ID_SHOWEDIT = 0x00FFFF03; |
| private static final int ID_HIDEEDIT = 0x00FFFF04; |
| private static final int MAXIMAGEWIDTHDIP = 300; |
| |
| /** |
| * Strings for context menu. TODO: Extract the strings to strings.xml. |
| */ |
| private static CharSequence STR_HORIZONTALLINE; |
| private static CharSequence STR_CLEARSTYLES; |
| private static CharSequence STR_PASTE; |
| |
| private float mPaddingScale = 0; |
| private ArrayList<EditStyledTextNotifier> mESTNotifiers; |
| private Drawable mDefaultBackground; |
| // EditStyledTextEditorManager manages the flow and status of each function of StyledText. |
| private EditorManager mManager; |
| private InputConnection mInputConnection; |
| private StyledTextConverter mConverter; |
| private StyledTextDialog mDialog; |
| |
| private static final Concrete SELECTING = new NoCopySpan.Concrete(); |
| private static final int PRESSED = Spannable.SPAN_MARK_MARK | (1 << Spannable.SPAN_USER_SHIFT); |
| |
| /** |
| * EditStyledText extends EditText for managing flow of each editing action. |
| */ |
| public EditStyledText(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| init(); |
| } |
| |
| public EditStyledText(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| init(); |
| } |
| |
| public EditStyledText(Context context) { |
| super(context); |
| init(); |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event) { |
| boolean superResult; |
| if (event.getAction() == MotionEvent.ACTION_UP) { |
| cancelLongPress(); |
| boolean editting = isEditting(); |
| // If View is touched but not in Edit Mode, starts Edit Mode. |
| if (!editting) { |
| onStartEdit(); |
| } |
| int oldSelStart = Selection.getSelectionStart(getText()); |
| int oldSelEnd = Selection.getSelectionEnd(getText()); |
| superResult = super.onTouchEvent(event); |
| if (isFocused()) { |
| // If selection is started, don't open soft key by |
| // touching. |
| if (getSelectState() == STATE_SELECT_OFF) { |
| if (editting) { |
| mManager.showSoftKey(Selection.getSelectionStart(getText()), |
| Selection.getSelectionEnd(getText())); |
| } else { |
| mManager.showSoftKey(oldSelStart, oldSelEnd); |
| } |
| } |
| } |
| mManager.onCursorMoved(); |
| mManager.unsetTextComposingMask(); |
| } else { |
| superResult = super.onTouchEvent(event); |
| } |
| sendOnTouchEvent(event); |
| return superResult; |
| } |
| |
| @Override |
| public Parcelable onSaveInstanceState() { |
| Parcelable superState = super.onSaveInstanceState(); |
| SavedStyledTextState ss = new SavedStyledTextState(superState); |
| ss.mBackgroundColor = mManager.getBackgroundColor(); |
| return ss; |
| } |
| |
| @Override |
| public void onRestoreInstanceState(Parcelable state) { |
| if (!(state instanceof SavedStyledTextState)) { |
| super.onRestoreInstanceState(state); |
| return; |
| } |
| SavedStyledTextState ss = (SavedStyledTextState) state; |
| super.onRestoreInstanceState(ss.getSuperState()); |
| setBackgroundColor(ss.mBackgroundColor); |
| } |
| |
| @Override |
| protected void drawableStateChanged() { |
| super.drawableStateChanged(); |
| if (mManager != null) { |
| mManager.onRefreshStyles(); |
| } |
| } |
| |
| @Override |
| public boolean onTextContextMenuItem(int id) { |
| boolean selection = getSelectionStart() != getSelectionEnd(); |
| switch (id) { |
| case ID_SELECT_ALL: |
| onStartSelectAll(); |
| return true; |
| case ID_START_SELECTING_TEXT: |
| onStartSelect(); |
| mManager.blockSoftKey(); |
| break; |
| case ID_STOP_SELECTING_TEXT: |
| onFixSelectedItem(); |
| break; |
| case ID_PASTE: |
| onStartPaste(); |
| return true; |
| case ID_COPY: |
| if (selection) { |
| onStartCopy(); |
| } else { |
| mManager.onStartSelectAll(false); |
| onStartCopy(); |
| } |
| return true; |
| case ID_CUT: |
| if (selection) { |
| onStartCut(); |
| } else { |
| mManager.onStartSelectAll(false); |
| onStartCut(); |
| } |
| return true; |
| case ID_HORIZONTALLINE: |
| onInsertHorizontalLine(); |
| return true; |
| case ID_CLEARSTYLES: |
| onClearStyles(); |
| return true; |
| case ID_SHOWEDIT: |
| onStartEdit(); |
| return true; |
| case ID_HIDEEDIT: |
| onEndEdit(); |
| return true; |
| } |
| return super.onTextContextMenuItem(id); |
| } |
| |
| @Override |
| protected void onCreateContextMenu(ContextMenu menu) { |
| super.onCreateContextMenu(menu); |
| MenuHandler handler = new MenuHandler(); |
| if (STR_HORIZONTALLINE != null) { |
| menu.add(0, ID_HORIZONTALLINE, 0, STR_HORIZONTALLINE).setOnMenuItemClickListener( |
| handler); |
| } |
| if (isStyledText() && STR_CLEARSTYLES != null) { |
| menu.add(0, ID_CLEARSTYLES, 0, STR_CLEARSTYLES) |
| .setOnMenuItemClickListener(handler); |
| } |
| if (mManager.canPaste()) { |
| menu.add(0, ID_PASTE, 0, STR_PASTE) |
| .setOnMenuItemClickListener(handler).setAlphabeticShortcut('v'); |
| } |
| } |
| |
| @Override |
| protected void onTextChanged(CharSequence text, int start, int before, int after) { |
| // onTextChanged will be called super's constructor. |
| if (mManager != null) { |
| mManager.updateSpanNextToCursor(getText(), start, before, after); |
| mManager.updateSpanPreviousFromCursor(getText(), start, before, after); |
| if (after > before) { |
| mManager.setTextComposingMask(start, start + after); |
| } else if (before < after) { |
| mManager.unsetTextComposingMask(); |
| } |
| if (mManager.isWaitInput()) { |
| if (after > before) { |
| mManager.onCursorMoved(); |
| onFixSelectedItem(); |
| } else if (after < before) { |
| mManager.onAction(MODE_RESET); |
| } |
| } |
| } |
| super.onTextChanged(text, start, before, after); |
| } |
| |
| @Override |
| public InputConnection onCreateInputConnection(EditorInfo outAttrs) { |
| mInputConnection = |
| new StyledTextInputConnection(super.onCreateInputConnection(outAttrs), this); |
| return mInputConnection; |
| } |
| |
| @Override |
| protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { |
| super.onFocusChanged(focused, direction, previouslyFocusedRect); |
| if (focused) { |
| onStartEdit(); |
| } else if (!isButtonsFocused()) { |
| onEndEdit(); |
| } |
| } |
| |
| /** |
| * Initialize members. |
| */ |
| private void init() { |
| mConverter = new StyledTextConverter(this, new StyledTextHtmlStandard()); |
| mDialog = new StyledTextDialog(this); |
| mManager = new EditorManager(this, mDialog); |
| setMovementMethod(new StyledTextArrowKeyMethod(mManager)); |
| mDefaultBackground = getBackground(); |
| requestFocus(); |
| } |
| |
| public interface StyledTextHtmlConverter { |
| public String toHtml(Spanned text); |
| |
| public String toHtml(Spanned text, boolean escapeNonAsciiChar); |
| |
| public String toHtml(Spanned text, boolean escapeNonAsciiChar, int width, float scale); |
| |
| public Spanned fromHtml(String string); |
| |
| public Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler); |
| } |
| |
| public void setStyledTextHtmlConverter(StyledTextHtmlConverter html) { |
| mConverter.setStyledTextHtmlConverter(html); |
| } |
| |
| /** |
| * EditStyledTextInterface provides functions for notifying messages to calling class. |
| */ |
| public interface EditStyledTextNotifier { |
| public void sendHintMsg(int msgId); |
| |
| public void onStateChanged(int mode, int state); |
| |
| public boolean sendOnTouchEvent(MotionEvent event); |
| |
| public boolean isButtonsFocused(); |
| |
| public boolean showPreview(); |
| |
| public void cancelViewManager(); |
| |
| public boolean showInsertImageSelectAlertDialog(); |
| |
| public boolean showMenuAlertDialog(); |
| } |
| |
| /** |
| * Add Notifier. |
| */ |
| public void addEditStyledTextListener(EditStyledTextNotifier estInterface) { |
| if (mESTNotifiers == null) { |
| mESTNotifiers = new ArrayList<EditStyledTextNotifier>(); |
| } |
| mESTNotifiers.add(estInterface); |
| } |
| |
| /** |
| * Remove Notifier. |
| */ |
| public void removeEditStyledTextListener(EditStyledTextNotifier estInterface) { |
| if (mESTNotifiers != null) { |
| int i = mESTNotifiers.indexOf(estInterface); |
| |
| if (i > 0) { |
| mESTNotifiers.remove(i); |
| } |
| } |
| } |
| |
| private void sendOnTouchEvent(MotionEvent event) { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| notifier.sendOnTouchEvent(event); |
| } |
| } |
| } |
| |
| public boolean isButtonsFocused() { |
| boolean retval = false; |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| retval |= notifier.isButtonsFocused(); |
| } |
| } |
| return retval; |
| } |
| |
| private void showPreview() { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| if (notifier.showPreview()) { |
| break; |
| } |
| } |
| } |
| } |
| |
| private void cancelViewManagers() { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| notifier.cancelViewManager(); |
| } |
| } |
| } |
| |
| private void showInsertImageSelectAlertDialog() { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| if (notifier.showInsertImageSelectAlertDialog()) { |
| break; |
| } |
| } |
| } |
| } |
| |
| private void showMenuAlertDialog() { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| if (notifier.showMenuAlertDialog()) { |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Notify hint messages what action is expected to calling class. |
| * |
| * @param msgId Id of the hint message. |
| */ |
| private void sendHintMessage(int msgId) { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| notifier.sendHintMsg(msgId); |
| } |
| } |
| } |
| |
| /** |
| * Notify the event that the mode and state are changed. |
| * |
| * @param mode Mode of the editing action. |
| * @param state Mode of the selection state. |
| */ |
| private void notifyStateChanged(int mode, int state) { |
| if (mESTNotifiers != null) { |
| for (EditStyledTextNotifier notifier : mESTNotifiers) { |
| notifier.onStateChanged(mode, state); |
| } |
| } |
| } |
| |
| /** Start to edit styled text */ |
| public void onStartEdit() { |
| mManager.onAction(MODE_START_EDIT); |
| } |
| |
| /** End of editing styled text */ |
| public void onEndEdit() { |
| mManager.onAction(MODE_END_EDIT); |
| } |
| |
| public void onResetEdit() { |
| mManager.onAction(MODE_RESET); |
| } |
| |
| /** Start to copy styled text */ |
| public void onStartCopy() { |
| mManager.onAction(MODE_COPY); |
| } |
| |
| /** Start to cut styled text */ |
| public void onStartCut() { |
| mManager.onAction(MODE_CUT); |
| } |
| |
| /** Start to paste styled text */ |
| public void onStartPaste() { |
| mManager.onAction(MODE_PASTE); |
| } |
| |
| /** Start to change size */ |
| public void onStartSize() { |
| mManager.onAction(MODE_SIZE); |
| } |
| |
| /** Start to change color */ |
| public void onStartColor() { |
| mManager.onAction(MODE_COLOR); |
| } |
| |
| /** Start to change background color */ |
| public void onStartBackgroundColor() { |
| mManager.onAction(MODE_BGCOLOR); |
| } |
| |
| /** Start to change Alignment */ |
| public void onStartAlign() { |
| mManager.onAction(MODE_ALIGN); |
| } |
| |
| public void onStartTelop() { |
| mManager.onAction(MODE_TELOP); |
| } |
| |
| public void onStartSwing() { |
| mManager.onAction(MODE_SWING); |
| } |
| |
| public void onStartMarquee() { |
| mManager.onAction(MODE_MARQUEE); |
| } |
| |
| /** Start to select a text */ |
| public void onStartSelect() { |
| mManager.onStartSelect(true); |
| } |
| |
| /** Start to select all characters */ |
| public void onStartSelectAll() { |
| mManager.onStartSelectAll(true); |
| } |
| |
| public void onStartShowPreview() { |
| mManager.onAction(MODE_PREVIEW); |
| } |
| |
| public void onStartShowMenuAlertDialog() { |
| mManager.onStartShowMenuAlertDialog(); |
| } |
| |
| public void onStartAction(int mode, boolean notifyStateChanged) { |
| mManager.onAction(mode, notifyStateChanged); |
| } |
| |
| /** Fix selection */ |
| public void onFixSelectedItem() { |
| mManager.onFixSelectedItem(); |
| } |
| |
| public void onInsertImage() { |
| mManager.onAction(MODE_IMAGE); |
| } |
| |
| /** |
| * InsertImage to TextView by using URI |
| * |
| * @param uri URI of the iamge inserted to TextView. |
| */ |
| public void onInsertImage(Uri uri) { |
| mManager.onInsertImage(uri); |
| } |
| |
| /** |
| * InsertImage to TextView by using resource ID |
| * |
| * @param resId Resource ID of the iamge inserted to TextView. |
| */ |
| public void onInsertImage(int resId) { |
| mManager.onInsertImage(resId); |
| } |
| |
| public void onInsertHorizontalLine() { |
| mManager.onAction(MODE_HORIZONTALLINE); |
| } |
| |
| public void onClearStyles() { |
| mManager.onClearStyles(); |
| } |
| |
| public void onBlockSoftKey() { |
| mManager.blockSoftKey(); |
| } |
| |
| public void onUnblockSoftKey() { |
| mManager.unblockSoftKey(); |
| } |
| |
| public void onCancelViewManagers() { |
| mManager.onCancelViewManagers(); |
| } |
| |
| private void onRefreshStyles() { |
| mManager.onRefreshStyles(); |
| } |
| |
| private void onRefreshZeoWidthChar() { |
| mManager.onRefreshZeoWidthChar(); |
| } |
| |
| /** |
| * Set Size of the Item. |
| * |
| * @param size The size of the Item. |
| */ |
| public void setItemSize(int size) { |
| mManager.setItemSize(size, true); |
| } |
| |
| /** |
| * Set Color of the Item. |
| * |
| * @param color The color of the Item. |
| */ |
| public void setItemColor(int color) { |
| mManager.setItemColor(color, true); |
| } |
| |
| /** |
| * Set Alignment of the Item. |
| * |
| * @param align The color of the Item. |
| */ |
| public void setAlignment(Layout.Alignment align) { |
| mManager.setAlignment(align); |
| } |
| |
| /** |
| * Set Background color of View. |
| * |
| * @param color The background color of view. |
| */ |
| @Override |
| public void setBackgroundColor(int color) { |
| if (color != DEFAULT_TRANSPARENT_COLOR) { |
| super.setBackgroundColor(color); |
| } else { |
| setBackgroundDrawable(mDefaultBackground); |
| } |
| mManager.setBackgroundColor(color); |
| onRefreshStyles(); |
| } |
| |
| public void setMarquee(int marquee) { |
| mManager.setMarquee(marquee); |
| } |
| |
| /** |
| * Set html to EditStyledText. |
| * |
| * @param html The html to be set. |
| */ |
| public void setHtml(String html) { |
| mConverter.SetHtml(html); |
| } |
| |
| /** |
| * Set Builder for AlertDialog. |
| * |
| * @param builder Builder for opening Alert Dialog. |
| */ |
| public void setBuilder(Builder builder) { |
| mDialog.setBuilder(builder); |
| } |
| |
| /** |
| * Set Parameters for ColorAlertDialog. |
| * |
| * @param colortitle Title for Alert Dialog. |
| * @param colornames List of name of selecting color. |
| * @param colorints List of int of color. |
| */ |
| public void setColorAlertParams(CharSequence colortitle, CharSequence[] colornames, |
| CharSequence[] colorints, CharSequence transparent) { |
| mDialog.setColorAlertParams(colortitle, colornames, colorints, transparent); |
| } |
| |
| /** |
| * Set Parameters for SizeAlertDialog. |
| * |
| * @param sizetitle Title for Alert Dialog. |
| * @param sizenames List of name of selecting size. |
| * @param sizedisplayints List of int of size displayed in TextView. |
| * @param sizesendints List of int of size exported to HTML. |
| */ |
| public void setSizeAlertParams(CharSequence sizetitle, CharSequence[] sizenames, |
| CharSequence[] sizedisplayints, CharSequence[] sizesendints) { |
| mDialog.setSizeAlertParams(sizetitle, sizenames, sizedisplayints, sizesendints); |
| } |
| |
| public void setAlignAlertParams(CharSequence aligntitle, CharSequence[] alignnames) { |
| mDialog.setAlignAlertParams(aligntitle, alignnames); |
| } |
| |
| public void setMarqueeAlertParams(CharSequence marqueetitle, CharSequence[] marqueenames) { |
| mDialog.setMarqueeAlertParams(marqueetitle, marqueenames); |
| } |
| |
| public void setContextMenuStrings(CharSequence horizontalline, CharSequence clearstyles, |
| CharSequence paste) { |
| STR_HORIZONTALLINE = horizontalline; |
| STR_CLEARSTYLES = clearstyles; |
| STR_PASTE = paste; |
| } |
| |
| /** |
| * Check whether editing is started or not. |
| * |
| * @return Whether editing is started or not. |
| */ |
| public boolean isEditting() { |
| return mManager.isEditting(); |
| } |
| |
| /** |
| * Check whether styled text or not. |
| * |
| * @return Whether styled text or not. |
| */ |
| public boolean isStyledText() { |
| return mManager.isStyledText(); |
| } |
| |
| /** |
| * Check whether SoftKey is Blocked or not. |
| * |
| * @return whether SoftKey is Blocked or not. |
| */ |
| public boolean isSoftKeyBlocked() { |
| return mManager.isSoftKeyBlocked(); |
| } |
| |
| /** |
| * Get the mode of the action. |
| * |
| * @return The mode of the action. |
| */ |
| public int getEditMode() { |
| return mManager.getEditMode(); |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @return The state of the selection. |
| */ |
| public int getSelectState() { |
| return mManager.getSelectState(); |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @return The state of the selection. |
| */ |
| public String getHtml() { |
| return mConverter.getHtml(true); |
| } |
| |
| public String getHtml(boolean escapeFlag) { |
| return mConverter.getHtml(escapeFlag); |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @param uris The array of used uris. |
| * @return The state of the selection. |
| */ |
| public String getHtml(ArrayList<Uri> uris, boolean escapeFlag) { |
| mConverter.getUriArray(uris, getText()); |
| return mConverter.getHtml(escapeFlag); |
| } |
| |
| public String getPreviewHtml() { |
| return mConverter.getPreviewHtml(); |
| } |
| |
| /** |
| * Get Background color of View. |
| * |
| * @return The background color of View. |
| */ |
| public int getBackgroundColor() { |
| return mManager.getBackgroundColor(); |
| } |
| |
| public EditorManager getEditStyledTextManager() { |
| return mManager; |
| } |
| |
| /** |
| * Get Foreground color of View. |
| * |
| * @return The background color of View. |
| */ |
| public int getForegroundColor(int pos) { |
| if (pos < 0 || pos > getText().length()) { |
| return DEFAULT_FOREGROUND_COLOR; |
| } else { |
| ForegroundColorSpan[] spans = |
| getText().getSpans(pos, pos, ForegroundColorSpan.class); |
| if (spans.length > 0) { |
| return spans[0].getForegroundColor(); |
| } else { |
| return DEFAULT_FOREGROUND_COLOR; |
| } |
| } |
| } |
| |
| private void finishComposingText() { |
| if (mInputConnection != null && !mManager.mTextIsFinishedFlag) { |
| mInputConnection.finishComposingText(); |
| mManager.mTextIsFinishedFlag = true; |
| } |
| } |
| |
| private float getPaddingScale() { |
| if (mPaddingScale <= 0) { |
| mPaddingScale = getContext().getResources().getDisplayMetrics().density; |
| } |
| return mPaddingScale; |
| } |
| |
| /** Convert pixcel to DIP */ |
| private int dipToPx(int dip) { |
| if (mPaddingScale <= 0) { |
| mPaddingScale = getContext().getResources().getDisplayMetrics().density; |
| } |
| return (int) ((float) dip * getPaddingScale() + 0.5); |
| } |
| |
| private int getMaxImageWidthDip() { |
| return MAXIMAGEWIDTHDIP; |
| } |
| |
| private int getMaxImageWidthPx() { |
| return dipToPx(MAXIMAGEWIDTHDIP); |
| } |
| |
| public void addAction(int mode, EditModeActionBase action) { |
| mManager.addAction(mode, action); |
| } |
| |
| public void addInputExtra(boolean create, String extra) { |
| Bundle bundle = super.getInputExtras(create); |
| if (bundle != null) { |
| bundle.putBoolean(extra, true); |
| } |
| } |
| |
| private static void startSelecting(View view, Spannable content) { |
| content.setSpan(SELECTING, 0, 0, PRESSED); |
| } |
| |
| private static void stopSelecting(View view, Spannable content) { |
| content.removeSpan(SELECTING); |
| } |
| |
| /** |
| * EditorManager manages the flow and status of editing actions. |
| */ |
| private class EditorManager { |
| |
| static final private String LOG_TAG = "EditStyledText.EditorManager"; |
| |
| private boolean mEditFlag = false; |
| private boolean mSoftKeyBlockFlag = false; |
| private boolean mKeepNonLineSpan = false; |
| private boolean mWaitInputFlag = false; |
| private boolean mTextIsFinishedFlag = false; |
| private int mMode = MODE_NOTHING; |
| private int mState = STATE_SELECT_OFF; |
| private int mCurStart = 0; |
| private int mCurEnd = 0; |
| private int mColorWaitInput = DEFAULT_TRANSPARENT_COLOR; |
| private int mSizeWaitInput = 0; |
| private int mBackgroundColor = DEFAULT_TRANSPARENT_COLOR; |
| |
| private BackgroundColorSpan mComposingTextMask; |
| private EditStyledText mEST; |
| private EditModeActions mActions; |
| private SoftKeyReceiver mSkr; |
| private SpannableStringBuilder mCopyBuffer; |
| |
| EditorManager(EditStyledText est, StyledTextDialog dialog) { |
| mEST = est; |
| mActions = new EditModeActions(mEST, this, dialog); |
| mSkr = new SoftKeyReceiver(mEST); |
| } |
| |
| public void addAction(int mode, EditModeActionBase action) { |
| mActions.addAction(mode, action); |
| } |
| |
| public void onAction(int mode) { |
| onAction(mode, true); |
| } |
| |
| public void onAction(int mode, boolean notifyStateChanged) { |
| mActions.onAction(mode); |
| if (notifyStateChanged) { |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| } |
| |
| private void startEdit() { |
| resetEdit(); |
| showSoftKey(); |
| } |
| |
| public void onStartSelect(boolean notifyStateChanged) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickSelect"); |
| } |
| mMode = MODE_SELECT; |
| if (mState == STATE_SELECT_OFF) { |
| mActions.onSelectAction(); |
| } else { |
| unsetSelect(); |
| mActions.onSelectAction(); |
| } |
| if (notifyStateChanged) { |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| } |
| |
| public void onCursorMoved() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickView"); |
| } |
| if (mState == STATE_SELECT_ON || mState == STATE_SELECTED) { |
| mActions.onSelectAction(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| } |
| |
| public void onStartSelectAll(boolean notifyStateChanged) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickSelectAll"); |
| } |
| handleSelectAll(); |
| if (notifyStateChanged) { |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| } |
| |
| public void onStartShowMenuAlertDialog() { |
| mActions.onAction(MODE_SHOW_MENU); |
| // don't call notify state changed because it have to continue |
| // to the next action. |
| // mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onFixSelectedItem() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onFixSelectedItem"); |
| } |
| fixSelectionAndDoNextAction(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onInsertImage(Uri uri) { |
| mActions.onAction(MODE_IMAGE, uri); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onInsertImage(int resId) { |
| mActions.onAction(MODE_IMAGE, resId); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| private void insertImageFromUri(Uri uri) { |
| insertImageSpan(new EditStyledTextSpans.RescalableImageSpan(mEST.getContext(), |
| uri, mEST.getMaxImageWidthPx()), mEST.getSelectionStart()); |
| } |
| |
| private void insertImageFromResId(int resId) { |
| insertImageSpan(new EditStyledTextSpans.RescalableImageSpan(mEST.getContext(), |
| resId, mEST.getMaxImageWidthDip()), mEST.getSelectionStart()); |
| } |
| |
| private void insertHorizontalLine() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onInsertHorizontalLine:"); |
| } |
| int curpos = mEST.getSelectionStart(); |
| if (curpos > 0 && mEST.getText().charAt(curpos - 1) != '\n') { |
| mEST.getText().insert(curpos++, "\n"); |
| } |
| insertImageSpan( |
| new HorizontalLineSpan(0xFF000000, mEST.getWidth(), mEST.getText()), |
| curpos++); |
| mEST.getText().insert(curpos++, "\n"); |
| mEST.setSelection(curpos); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| private void clearStyles(CharSequence txt) { |
| if (DBG) { |
| Log.d("EditStyledText", "--- onClearStyles"); |
| } |
| int len = txt.length(); |
| if (txt instanceof Editable) { |
| Editable editable = (Editable) txt; |
| Object[] styles = editable.getSpans(0, len, Object.class); |
| for (Object style : styles) { |
| if (style instanceof ParagraphStyle || style instanceof QuoteSpan |
| || style instanceof CharacterStyle |
| && !(style instanceof UnderlineSpan)) { |
| if (style instanceof ImageSpan || style instanceof HorizontalLineSpan) { |
| int start = editable.getSpanStart(style); |
| int end = editable.getSpanEnd(style); |
| editable.replace(start, end, ""); |
| } |
| editable.removeSpan(style); |
| } |
| } |
| } |
| } |
| |
| public void onClearStyles() { |
| mActions.onAction(MODE_CLEARSTYLES); |
| } |
| |
| public void onCancelViewManagers() { |
| mActions.onAction(MODE_CANCEL); |
| } |
| |
| private void clearStyles() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClearStyles"); |
| } |
| clearStyles(mEST.getText()); |
| mEST.setBackgroundDrawable(mEST.mDefaultBackground); |
| mBackgroundColor = DEFAULT_TRANSPARENT_COLOR; |
| onRefreshZeoWidthChar(); |
| } |
| |
| public void onRefreshZeoWidthChar() { |
| Editable txt = mEST.getText(); |
| for (int i = 0; i < txt.length(); i++) { |
| if (txt.charAt(i) == ZEROWIDTHCHAR) { |
| txt.replace(i, i + 1, ""); |
| i--; |
| } |
| } |
| } |
| |
| public void onRefreshStyles() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onRefreshStyles"); |
| } |
| Editable txt = mEST.getText(); |
| int len = txt.length(); |
| int width = mEST.getWidth(); |
| HorizontalLineSpan[] lines = txt.getSpans(0, len, HorizontalLineSpan.class); |
| for (HorizontalLineSpan line : lines) { |
| line.resetWidth(width); |
| } |
| MarqueeSpan[] marquees = txt.getSpans(0, len, MarqueeSpan.class); |
| for (MarqueeSpan marquee : marquees) { |
| marquee.resetColor(mEST.getBackgroundColor()); |
| } |
| |
| if (lines.length > 0) { |
| // This is hack, bad needed for renewing View |
| // by inserting new line. |
| txt.replace(0, 1, "" + txt.charAt(0)); |
| } |
| } |
| |
| public void setBackgroundColor(int color) { |
| mBackgroundColor = color; |
| } |
| |
| public void setItemSize(int size, boolean reset) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setItemSize"); |
| } |
| if (isWaitingNextAction()) { |
| mSizeWaitInput = size; |
| } else if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| if (size > 0) { |
| changeSizeSelectedText(size); |
| } |
| if (reset) { |
| resetEdit(); |
| } |
| } |
| } |
| |
| public void setItemColor(int color, boolean reset) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setItemColor"); |
| } |
| if (isWaitingNextAction()) { |
| mColorWaitInput = color; |
| } else if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| if (color != DEFAULT_TRANSPARENT_COLOR) { |
| changeColorSelectedText(color); |
| } |
| if (reset) { |
| resetEdit(); |
| } |
| } |
| } |
| |
| public void setAlignment(Layout.Alignment align) { |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| changeAlign(align); |
| resetEdit(); |
| } |
| } |
| |
| public void setTelop() { |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| addTelop(); |
| resetEdit(); |
| } |
| } |
| |
| public void setSwing() { |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| addSwing(); |
| resetEdit(); |
| } |
| } |
| |
| public void setMarquee(int marquee) { |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| addMarquee(marquee); |
| resetEdit(); |
| } |
| } |
| |
| public void setTextComposingMask(int start, int end) { |
| if (DBG) { |
| Log.d(TAG, "--- setTextComposingMask:" + start + "," + end); |
| } |
| int min = Math.min(start, end); |
| int max = Math.max(start, end); |
| int foregroundColor; |
| if (isWaitInput() && mColorWaitInput != DEFAULT_TRANSPARENT_COLOR) { |
| foregroundColor = mColorWaitInput; |
| } else { |
| foregroundColor = mEST.getForegroundColor(min); |
| } |
| int backgroundColor = mEST.getBackgroundColor(); |
| if (DBG) { |
| Log.d(TAG, |
| "--- fg:" + Integer.toHexString(foregroundColor) + ",bg:" |
| + Integer.toHexString(backgroundColor) + "," + isWaitInput() |
| + "," + "," + mMode); |
| } |
| if (foregroundColor == backgroundColor) { |
| int maskColor = 0x80000000 | ~(backgroundColor | 0xFF000000); |
| if (mComposingTextMask == null |
| || mComposingTextMask.getBackgroundColor() != maskColor) { |
| mComposingTextMask = new BackgroundColorSpan(maskColor); |
| } |
| mEST.getText().setSpan(mComposingTextMask, min, max, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| } |
| |
| private void setEditMode(int mode) { |
| mMode = mode; |
| } |
| |
| private void setSelectState(int state) { |
| mState = state; |
| } |
| |
| public void unsetTextComposingMask() { |
| if (DBG) { |
| Log.d(TAG, "--- unsetTextComposingMask"); |
| } |
| if (mComposingTextMask != null) { |
| mEST.getText().removeSpan(mComposingTextMask); |
| mComposingTextMask = null; |
| } |
| } |
| |
| public boolean isEditting() { |
| return mEditFlag; |
| } |
| |
| /* If the style of the span is added, add check case for that style */ |
| public boolean isStyledText() { |
| Editable txt = mEST.getText(); |
| int len = txt.length(); |
| if (txt.getSpans(0, len, ParagraphStyle.class).length > 0 |
| || txt.getSpans(0, len, QuoteSpan.class).length > 0 |
| || txt.getSpans(0, len, CharacterStyle.class).length > 0 |
| || mBackgroundColor != DEFAULT_TRANSPARENT_COLOR) { |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean isSoftKeyBlocked() { |
| return mSoftKeyBlockFlag; |
| } |
| |
| public boolean isWaitInput() { |
| return mWaitInputFlag; |
| } |
| |
| public int getBackgroundColor() { |
| return mBackgroundColor; |
| } |
| |
| public int getEditMode() { |
| return mMode; |
| } |
| |
| public int getSelectState() { |
| return mState; |
| } |
| |
| public int getSelectionStart() { |
| return mCurStart; |
| } |
| |
| public int getSelectionEnd() { |
| return mCurEnd; |
| } |
| |
| public int getSizeWaitInput() { |
| return mSizeWaitInput; |
| } |
| |
| public int getColorWaitInput() { |
| return mColorWaitInput; |
| } |
| |
| private void setInternalSelection(int curStart, int curEnd) { |
| mCurStart = curStart; |
| mCurEnd = curEnd; |
| } |
| |
| public void |
| updateSpanPreviousFromCursor(Editable txt, int start, int before, int after) { |
| if (DBG) { |
| Log.d(LOG_TAG, "updateSpanPrevious:" + start + "," + before + "," + after); |
| } |
| int end = start + after; |
| int min = Math.min(start, end); |
| int max = Math.max(start, end); |
| Object[] spansBefore = txt.getSpans(min, min, Object.class); |
| for (Object span : spansBefore) { |
| if (span instanceof ForegroundColorSpan || span instanceof AbsoluteSizeSpan |
| || span instanceof MarqueeSpan || span instanceof AlignmentSpan) { |
| int spanstart = txt.getSpanStart(span); |
| int spanend = txt.getSpanEnd(span); |
| if (DBG) { |
| Log.d(LOG_TAG, "spantype:" + span.getClass() + "," + spanstart); |
| } |
| int tempmax = max; |
| if (span instanceof MarqueeSpan || span instanceof AlignmentSpan) { |
| // Line Span |
| tempmax = findLineEnd(mEST.getText(), max); |
| } else { |
| if (mKeepNonLineSpan) { |
| tempmax = spanend; |
| } |
| } |
| if (spanend < tempmax) { |
| if (DBG) { |
| Log.d(LOG_TAG, "updateSpanPrevious: extend span"); |
| } |
| txt.setSpan(span, spanstart, tempmax, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| } else if (span instanceof HorizontalLineSpan) { |
| int spanstart = txt.getSpanStart(span); |
| int spanend = txt.getSpanEnd(span); |
| if (before > after) { |
| // When text is deleted just after horizontalLineSpan, horizontalLineSpan |
| // has to be deleted, because the charactor just after horizontalLineSpan |
| // is '\n'. |
| txt.replace(spanstart, spanend, ""); |
| txt.removeSpan(span); |
| } else { |
| // When text is added just after horizontalLineSpan add '\n' just after |
| // horizontalLineSpan. |
| if (spanend == end && end < txt.length() |
| && mEST.getText().charAt(end) != '\n') { |
| mEST.getText().insert(end, "\n"); |
| } |
| } |
| } |
| } |
| } |
| |
| public void updateSpanNextToCursor(Editable txt, int start, int before, int after) { |
| if (DBG) { |
| Log.d(LOG_TAG, "updateSpanNext:" + start + "," + before + "," + after); |
| } |
| int end = start + after; |
| int min = Math.min(start, end); |
| int max = Math.max(start, end); |
| Object[] spansAfter = txt.getSpans(max, max, Object.class); |
| for (Object span : spansAfter) { |
| if (span instanceof MarqueeSpan || span instanceof AlignmentSpan) { |
| int spanstart = txt.getSpanStart(span); |
| int spanend = txt.getSpanEnd(span); |
| if (DBG) { |
| Log.d(LOG_TAG, "spantype:" + span.getClass() + "," + spanend); |
| } |
| int tempmin = min; |
| if (span instanceof MarqueeSpan || span instanceof AlignmentSpan) { |
| tempmin = findLineStart(mEST.getText(), min); |
| } |
| if (tempmin < spanstart && before > after) { |
| txt.removeSpan(span); |
| } else if (spanstart > min) { |
| txt.setSpan(span, min, spanend, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| } else if (span instanceof HorizontalLineSpan) { |
| int spanstart = txt.getSpanStart(span); |
| // Whene text is changed just before horizontalLineSpan and there is no '\n' |
| // just before horizontalLineSpan add '\n' |
| if (spanstart == end && end > 0 && mEST.getText().charAt(end - 1) != '\n') { |
| mEST.getText().insert(end, "\n"); |
| mEST.setSelection(end); |
| } |
| } |
| } |
| } |
| |
| /** canPaste returns true only if ClipboardManager doen't contain text. */ |
| public boolean canPaste() { |
| return (mCopyBuffer != null && mCopyBuffer.length() > 0 && removeImageChar( |
| mCopyBuffer).length() == 0); |
| } |
| |
| private void endEdit() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleCancel"); |
| } |
| mMode = MODE_NOTHING; |
| mState = STATE_SELECT_OFF; |
| mEditFlag = false; |
| mColorWaitInput = DEFAULT_TRANSPARENT_COLOR; |
| mSizeWaitInput = 0; |
| mWaitInputFlag = false; |
| mSoftKeyBlockFlag = false; |
| mKeepNonLineSpan = false; |
| mTextIsFinishedFlag = false; |
| unsetSelect(); |
| mEST.setOnClickListener(null); |
| unblockSoftKey(); |
| } |
| |
| private void fixSelectionAndDoNextAction() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleComplete:" + mCurStart + "," + mCurEnd); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| if (mCurStart == mCurEnd) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- cancel handle complete:" + mCurStart); |
| } |
| resetEdit(); |
| return; |
| } |
| if (mState == STATE_SELECTED) { |
| mState = STATE_SELECT_FIX; |
| } |
| // When the complete button is clicked, this should do action. |
| mActions.doNext(mMode); |
| //MetaKeyKeyListener.stopSelecting(mEST, mEST.getText()); |
| stopSelecting(mEST, mEST.getText()); |
| } |
| |
| // Remove obj character for DynamicDrawableSpan from clipboard. |
| private SpannableStringBuilder removeImageChar(SpannableStringBuilder text) { |
| SpannableStringBuilder buf = new SpannableStringBuilder(text); |
| DynamicDrawableSpan[] styles = |
| buf.getSpans(0, buf.length(), DynamicDrawableSpan.class); |
| for (DynamicDrawableSpan style : styles) { |
| if (style instanceof HorizontalLineSpan |
| || style instanceof RescalableImageSpan) { |
| int start = buf.getSpanStart(style); |
| int end = buf.getSpanEnd(style); |
| buf.replace(start, end, ""); |
| } |
| } |
| return buf; |
| } |
| |
| private void copyToClipBoard() { |
| int min = Math.min(getSelectionStart(), getSelectionEnd()); |
| int max = Math.max(getSelectionStart(), getSelectionEnd()); |
| mCopyBuffer = (SpannableStringBuilder) mEST.getText().subSequence(min, max); |
| SpannableStringBuilder clipboardtxt = removeImageChar(mCopyBuffer); |
| ClipboardManager clip = |
| (ClipboardManager) getContext() |
| .getSystemService(Context.CLIPBOARD_SERVICE); |
| clip.setText(clipboardtxt); |
| if (DBG) { |
| dumpSpannableString(clipboardtxt); |
| dumpSpannableString(mCopyBuffer); |
| } |
| } |
| |
| private void cutToClipBoard() { |
| copyToClipBoard(); |
| int min = Math.min(getSelectionStart(), getSelectionEnd()); |
| int max = Math.max(getSelectionStart(), getSelectionEnd()); |
| mEST.getText().delete(min, max); |
| } |
| |
| private boolean isClipBoardChanged(CharSequence clipboardText) { |
| if (DBG) { |
| Log.d(TAG, "--- isClipBoardChanged:" + clipboardText); |
| } |
| if (mCopyBuffer == null) { |
| return true; |
| } |
| int len = clipboardText.length(); |
| CharSequence removedClipBoard = removeImageChar(mCopyBuffer); |
| if (DBG) { |
| Log.d(TAG, "--- clipBoard:" + len + "," + removedClipBoard + clipboardText); |
| } |
| if (len != removedClipBoard.length()) { |
| return true; |
| } |
| for (int i = 0; i < len; ++i) { |
| if (clipboardText.charAt(i) != removedClipBoard.charAt(i)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void pasteFromClipboard() { |
| int min = Math.min(mEST.getSelectionStart(), mEST.getSelectionEnd()); |
| int max = Math.max(mEST.getSelectionStart(), mEST.getSelectionEnd()); |
| // TODO: Find more smart way to set Span to Clipboard. |
| Selection.setSelection(mEST.getText(), max); |
| ClipboardManager clip = |
| (ClipboardManager) getContext() |
| .getSystemService(Context.CLIPBOARD_SERVICE); |
| mKeepNonLineSpan = true; |
| mEST.getText().replace(min, max, clip.getText()); |
| if (!isClipBoardChanged(clip.getText())) { |
| if (DBG) { |
| Log.d(TAG, "--- handlePaste: startPasteImage"); |
| } |
| DynamicDrawableSpan[] styles = |
| mCopyBuffer.getSpans(0, mCopyBuffer.length(), |
| DynamicDrawableSpan.class); |
| for (DynamicDrawableSpan style : styles) { |
| int start = mCopyBuffer.getSpanStart(style); |
| if (style instanceof HorizontalLineSpan) { |
| insertImageSpan(new HorizontalLineSpan(0xFF000000, mEST.getWidth(), |
| mEST.getText()), min + start); |
| } else if (style instanceof RescalableImageSpan) { |
| insertImageSpan( |
| new RescalableImageSpan(mEST.getContext(), |
| ((RescalableImageSpan) style).getContentUri(), |
| mEST.getMaxImageWidthPx()), min + start); |
| } |
| } |
| } |
| } |
| |
| private void handleSelectAll() { |
| if (!mEditFlag) { |
| return; |
| } |
| mActions.onAction(MODE_SELECTALL); |
| } |
| |
| private void selectAll() { |
| Selection.selectAll(mEST.getText()); |
| mCurStart = mEST.getSelectionStart(); |
| mCurEnd = mEST.getSelectionEnd(); |
| mMode = MODE_SELECT; |
| mState = STATE_SELECT_FIX; |
| } |
| |
| private void resetEdit() { |
| endEdit(); |
| mEditFlag = true; |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| private void setSelection() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onSelect:" + mCurStart + "," + mCurEnd); |
| } |
| if (mCurStart >= 0 && mCurStart <= mEST.getText().length() && mCurEnd >= 0 |
| && mCurEnd <= mEST.getText().length()) { |
| if (mCurStart < mCurEnd) { |
| mEST.setSelection(mCurStart, mCurEnd); |
| mState = STATE_SELECTED; |
| } else if (mCurStart > mCurEnd) { |
| mEST.setSelection(mCurEnd, mCurStart); |
| mState = STATE_SELECTED; |
| } else { |
| mState = STATE_SELECT_ON; |
| } |
| } else { |
| Log.e(LOG_TAG, "Select is on, but cursor positions are illigal.:" |
| + mEST.getText().length() + "," + mCurStart + "," + mCurEnd); |
| } |
| } |
| |
| private void unsetSelect() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- offSelect"); |
| } |
| //MetaKeyKeyListener.stopSelecting(mEST, mEST.getText()); |
| stopSelecting(mEST, mEST.getText()); |
| int currpos = mEST.getSelectionStart(); |
| mEST.setSelection(currpos, currpos); |
| mState = STATE_SELECT_OFF; |
| } |
| |
| private void setSelectStartPos() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setSelectStartPos"); |
| } |
| mCurStart = mEST.getSelectionStart(); |
| mState = STATE_SELECT_ON; |
| } |
| |
| private void setSelectEndPos() { |
| if (mEST.getSelectionEnd() == mCurStart) { |
| setEndPos(mEST.getSelectionStart()); |
| } else { |
| setEndPos(mEST.getSelectionEnd()); |
| } |
| } |
| |
| public void setEndPos(int pos) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setSelectedEndPos:" + pos); |
| } |
| mCurEnd = pos; |
| setSelection(); |
| } |
| |
| private boolean isWaitingNextAction() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- waitingNext:" + mCurStart + "," + mCurEnd + "," + mState); |
| } |
| if (mCurStart == mCurEnd && mState == STATE_SELECT_FIX) { |
| waitSelection(); |
| return true; |
| } else { |
| resumeSelection(); |
| return false; |
| } |
| } |
| |
| private void waitSelection() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- waitSelection"); |
| } |
| mWaitInputFlag = true; |
| if (mCurStart == mCurEnd) { |
| mState = STATE_SELECT_ON; |
| } else { |
| mState = STATE_SELECTED; |
| } |
| //MetaKeyKeyListener.startSelecting(mEST, mEST.getText()); |
| startSelecting(mEST, mEST.getText()); |
| } |
| |
| private void resumeSelection() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- resumeSelection"); |
| } |
| mWaitInputFlag = false; |
| mState = STATE_SELECT_FIX; |
| //MetaKeyKeyListener.stopSelecting(mEST, mEST.getText()); |
| stopSelecting(mEST, mEST.getText()); |
| } |
| |
| private boolean isTextSelected() { |
| return (mState == STATE_SELECTED || mState == STATE_SELECT_FIX); |
| } |
| |
| private void setStyledTextSpan(Object span, int start, int end) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setStyledTextSpan:" + mMode + "," + start + "," + end); |
| } |
| int min = Math.min(start, end); |
| int max = Math.max(start, end); |
| mEST.getText().setSpan(span, min, max, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| Selection.setSelection(mEST.getText(), max); |
| } |
| |
| private void setLineStyledTextSpan(Object span) { |
| int min = Math.min(mCurStart, mCurEnd); |
| int max = Math.max(mCurStart, mCurEnd); |
| int current = mEST.getSelectionStart(); |
| int start = findLineStart(mEST.getText(), min); |
| int end = findLineEnd(mEST.getText(), max); |
| if (start == end) { |
| mEST.getText().insert(end, "\n"); |
| setStyledTextSpan(span, start, end + 1); |
| } else { |
| setStyledTextSpan(span, start, end); |
| } |
| Selection.setSelection(mEST.getText(), current); |
| } |
| |
| private void changeSizeSelectedText(int size) { |
| if (mCurStart != mCurEnd) { |
| setStyledTextSpan(new AbsoluteSizeSpan(size), mCurStart, mCurEnd); |
| } else { |
| Log.e(LOG_TAG, "---changeSize: Size of the span is zero"); |
| } |
| } |
| |
| private void changeColorSelectedText(int color) { |
| if (mCurStart != mCurEnd) { |
| setStyledTextSpan(new ForegroundColorSpan(color), mCurStart, mCurEnd); |
| } else { |
| Log.e(LOG_TAG, "---changeColor: Size of the span is zero"); |
| } |
| } |
| |
| private void changeAlign(Layout.Alignment align) { |
| setLineStyledTextSpan(new AlignmentSpan.Standard(align)); |
| } |
| |
| private void addTelop() { |
| addMarquee(MarqueeSpan.ALTERNATE); |
| } |
| |
| private void addSwing() { |
| addMarquee(MarqueeSpan.SCROLL); |
| } |
| |
| private void addMarquee(int marquee) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- addMarquee:" + marquee); |
| } |
| setLineStyledTextSpan(new MarqueeSpan(marquee, mEST.getBackgroundColor())); |
| } |
| |
| private void insertImageSpan(DynamicDrawableSpan span, int curpos) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- insertImageSpan:"); |
| } |
| if (span != null && span.getDrawable() != null) { |
| mEST.getText().insert(curpos, "" + IMAGECHAR); |
| mEST.getText().setSpan(span, curpos, curpos + 1, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| mEST.notifyStateChanged(mMode, mState); |
| } else { |
| Log.e(LOG_TAG, "--- insertImageSpan: null span was inserted"); |
| mEST.sendHintMessage(HINT_MSG_BIG_SIZE_ERROR); |
| } |
| } |
| |
| private int findLineStart(Editable text, int current) { |
| int pos = current; |
| for (; pos > 0; pos--) { |
| if (text.charAt(pos - 1) == '\n') { |
| break; |
| } |
| } |
| if (DBG) { |
| Log.d(LOG_TAG, "--- findLineStart:" + current + "," + text.length() + "," |
| + pos); |
| } |
| return pos; |
| } |
| |
| private int findLineEnd(Editable text, int current) { |
| int pos = current; |
| for (; pos < text.length(); pos++) { |
| if (text.charAt(pos) == '\n') { |
| pos++; |
| break; |
| } |
| } |
| if (DBG) { |
| Log.d(LOG_TAG, "--- findLineEnd:" + current + "," + text.length() + "," + pos); |
| } |
| return pos; |
| } |
| |
| // Only for debug. |
| private void dumpSpannableString(CharSequence txt) { |
| if (txt instanceof Spannable) { |
| Spannable spannable = (Spannable) txt; |
| int len = spannable.length(); |
| if (DBG) { |
| Log.d(TAG, "--- dumpSpannableString, txt:" + spannable + ", len:" + len); |
| } |
| Object[] styles = spannable.getSpans(0, len, Object.class); |
| for (Object style : styles) { |
| if (DBG) { |
| Log.d(TAG, |
| "--- dumpSpannableString, class:" + style + "," |
| + spannable.getSpanStart(style) + "," |
| + spannable.getSpanEnd(style) + "," |
| + spannable.getSpanFlags(style)); |
| } |
| } |
| } |
| } |
| |
| public void showSoftKey() { |
| showSoftKey(mEST.getSelectionStart(), mEST.getSelectionEnd()); |
| } |
| |
| public void showSoftKey(int oldSelStart, int oldSelEnd) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- showsoftkey"); |
| } |
| if (!mEST.isFocused() || isSoftKeyBlocked()) { |
| return; |
| } |
| mSkr.mNewStart = Selection.getSelectionStart(mEST.getText()); |
| mSkr.mNewEnd = Selection.getSelectionEnd(mEST.getText()); |
| InputMethodManager imm = |
| (InputMethodManager) getContext().getSystemService( |
| Context.INPUT_METHOD_SERVICE); |
| if (imm.showSoftInput(mEST, 0, mSkr) && mSkr != null) { |
| Selection.setSelection(getText(), oldSelStart, oldSelEnd); |
| } |
| } |
| |
| public void hideSoftKey() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- hidesoftkey"); |
| } |
| if (!mEST.isFocused()) { |
| return; |
| } |
| mSkr.mNewStart = Selection.getSelectionStart(mEST.getText()); |
| mSkr.mNewEnd = Selection.getSelectionEnd(mEST.getText()); |
| InputMethodManager imm = |
| (InputMethodManager) mEST.getContext().getSystemService( |
| Context.INPUT_METHOD_SERVICE); |
| imm.hideSoftInputFromWindow(mEST.getWindowToken(), 0, mSkr); |
| } |
| |
| public void blockSoftKey() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- blockSoftKey:"); |
| } |
| hideSoftKey(); |
| mSoftKeyBlockFlag = true; |
| } |
| |
| public void unblockSoftKey() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- unblockSoftKey:"); |
| } |
| mSoftKeyBlockFlag = false; |
| } |
| } |
| |
| private class StyledTextHtmlStandard implements StyledTextHtmlConverter { |
| public String toHtml(Spanned text) { |
| return Html.toHtml(text); |
| } |
| |
| public String toHtml(Spanned text, boolean escapeNonAsciiChar) { |
| return Html.toHtml(text); |
| } |
| |
| public String toHtml(Spanned text, boolean escapeNonAsciiChar, int width, float scale) { |
| return Html.toHtml(text); |
| } |
| |
| public Spanned fromHtml(String source) { |
| return Html.fromHtml(source); |
| } |
| |
| public Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler) { |
| return Html.fromHtml(source, imageGetter, tagHandler); |
| } |
| } |
| |
| private class StyledTextConverter { |
| private EditStyledText mEST; |
| private StyledTextHtmlConverter mHtml; |
| |
| public StyledTextConverter(EditStyledText est, StyledTextHtmlConverter html) { |
| mEST = est; |
| mHtml = html; |
| } |
| |
| public void setStyledTextHtmlConverter(StyledTextHtmlConverter html) { |
| mHtml = html; |
| } |
| |
| public String getHtml(boolean escapeFlag) { |
| mEST.clearComposingText(); |
| mEST.onRefreshZeoWidthChar(); |
| String htmlBody = mHtml.toHtml(mEST.getText(), escapeFlag); |
| if (DBG) { |
| Log.d(TAG, "--- getHtml:" + htmlBody); |
| } |
| return htmlBody; |
| } |
| |
| public String getPreviewHtml() { |
| mEST.clearComposingText(); |
| mEST.onRefreshZeoWidthChar(); |
| String html = |
| mHtml.toHtml(mEST.getText(), true, getMaxImageWidthDip(), |
| getPaddingScale()); |
| int bgColor = mEST.getBackgroundColor(); |
| html = |
| String.format("<body bgcolor=\"#%02X%02X%02X\">%s</body>", |
| Color.red(bgColor), Color.green(bgColor), Color.blue(bgColor), |
| html); |
| if (DBG) { |
| Log.d(TAG, "--- getPreviewHtml:" + html + "," + mEST.getWidth()); |
| } |
| return html; |
| } |
| |
| public void getUriArray(ArrayList<Uri> uris, Editable text) { |
| uris.clear(); |
| if (DBG) { |
| Log.d(TAG, "--- getUriArray:"); |
| } |
| int len = text.length(); |
| int next; |
| for (int i = 0; i < text.length(); i = next) { |
| next = text.nextSpanTransition(i, len, ImageSpan.class); |
| ImageSpan[] images = text.getSpans(i, next, ImageSpan.class); |
| for (int j = 0; j < images.length; j++) { |
| if (DBG) { |
| Log.d(TAG, "--- getUriArray: foundArray" + images[j].getSource()); |
| } |
| uris.add(Uri.parse(images[j].getSource())); |
| } |
| } |
| } |
| |
| public void SetHtml(String html) { |
| final Spanned spanned = mHtml.fromHtml(html, new Html.ImageGetter() { |
| public Drawable getDrawable(String src) { |
| Log.d(TAG, "--- sethtml: src=" + src); |
| if (src.startsWith("content://")) { |
| Uri uri = Uri.parse(src); |
| try { |
| Drawable drawable = null; |
| Bitmap bitmap = null; |
| System.gc(); |
| InputStream is = |
| mEST.getContext().getContentResolver().openInputStream(uri); |
| BitmapFactory.Options opt = new BitmapFactory.Options(); |
| opt.inJustDecodeBounds = true; |
| BitmapFactory.decodeStream(is, null, opt); |
| is.close(); |
| is = mEST.getContext().getContentResolver().openInputStream(uri); |
| int width, height; |
| width = opt.outWidth; |
| height = opt.outHeight; |
| if (opt.outWidth > getMaxImageWidthPx()) { |
| width = getMaxImageWidthPx(); |
| height = height * getMaxImageWidthPx() / opt.outWidth; |
| Rect padding = new Rect(0, 0, width, height); |
| bitmap = BitmapFactory.decodeStream(is, padding, null); |
| } else { |
| bitmap = BitmapFactory.decodeStream(is); |
| } |
| drawable = new BitmapDrawable( |
| mEST.getContext().getResources(), bitmap); |
| drawable.setBounds(0, 0, width, height); |
| is.close(); |
| return drawable; |
| } catch (Exception e) { |
| Log.e(TAG, "--- set html: Failed to loaded content " + uri, e); |
| return null; |
| } catch (OutOfMemoryError e) { |
| Log.e(TAG, "OutOfMemoryError"); |
| mEST.setHint(HINT_MSG_BIG_SIZE_ERROR); |
| |
| return null; |
| } |
| } |
| return null; |
| } |
| }, null); |
| mEST.setText(spanned); |
| } |
| } |
| |
| private static class SoftKeyReceiver extends ResultReceiver { |
| int mNewStart; |
| int mNewEnd; |
| EditStyledText mEST; |
| |
| SoftKeyReceiver(EditStyledText est) { |
| super(est.getHandler()); |
| mEST = est; |
| } |
| |
| @Override |
| protected void onReceiveResult(int resultCode, Bundle resultData) { |
| if (resultCode != InputMethodManager.RESULT_SHOWN) { |
| Selection.setSelection(mEST.getText(), mNewStart, mNewEnd); |
| } |
| } |
| } |
| |
| public static class SavedStyledTextState extends BaseSavedState { |
| public int mBackgroundColor; |
| |
| SavedStyledTextState(Parcelable superState) { |
| super(superState); |
| } |
| |
| @Override |
| public void writeToParcel(Parcel out, int flags) { |
| super.writeToParcel(out, flags); |
| out.writeInt(mBackgroundColor); |
| } |
| |
| @Override |
| public String toString() { |
| return "EditStyledText.SavedState{" |
| + Integer.toHexString(System.identityHashCode(this)) + " bgcolor=" |
| + mBackgroundColor + "}"; |
| } |
| } |
| |
| private static class StyledTextDialog { |
| private static final int TYPE_FOREGROUND = 0; |
| private static final int TYPE_BACKGROUND = 1; |
| private Builder mBuilder; |
| private AlertDialog mAlertDialog; |
| private CharSequence mColorTitle; |
| private CharSequence mSizeTitle; |
| private CharSequence mAlignTitle; |
| private CharSequence mMarqueeTitle; |
| private CharSequence[] mColorNames; |
| private CharSequence[] mColorInts; |
| private CharSequence[] mSizeNames; |
| private CharSequence[] mSizeDisplayInts; |
| private CharSequence[] mSizeSendInts; |
| private CharSequence[] mAlignNames; |
| private CharSequence[] mMarqueeNames; |
| private CharSequence mColorDefaultMessage; |
| private EditStyledText mEST; |
| |
| public StyledTextDialog(EditStyledText est) { |
| mEST = est; |
| } |
| |
| public void setBuilder(Builder builder) { |
| mBuilder = builder; |
| } |
| |
| public void setColorAlertParams(CharSequence colortitle, CharSequence[] colornames, |
| CharSequence[] colorInts, CharSequence defaultColorMessage) { |
| mColorTitle = colortitle; |
| mColorNames = colornames; |
| mColorInts = colorInts; |
| mColorDefaultMessage = defaultColorMessage; |
| } |
| |
| public void setSizeAlertParams(CharSequence sizetitle, CharSequence[] sizenames, |
| CharSequence[] sizedisplayints, CharSequence[] sizesendints) { |
| mSizeTitle = sizetitle; |
| mSizeNames = sizenames; |
| mSizeDisplayInts = sizedisplayints; |
| mSizeSendInts = sizesendints; |
| } |
| |
| public void setAlignAlertParams(CharSequence aligntitle, CharSequence[] alignnames) { |
| mAlignTitle = aligntitle; |
| mAlignNames = alignnames; |
| } |
| |
| public void setMarqueeAlertParams(CharSequence marqueetitle, |
| CharSequence[] marqueenames) { |
| mMarqueeTitle = marqueetitle; |
| mMarqueeNames = marqueenames; |
| } |
| |
| private boolean checkColorAlertParams() { |
| if (DBG) { |
| Log.d(TAG, "--- checkParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(TAG, "--- builder is null."); |
| return false; |
| } else if (mColorTitle == null || mColorNames == null || mColorInts == null) { |
| Log.e(TAG, "--- color alert params are null."); |
| return false; |
| } else if (mColorNames.length != mColorInts.length) { |
| Log.e(TAG, "--- the length of color alert params are " + "different."); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkSizeAlertParams() { |
| if (DBG) { |
| Log.d(TAG, "--- checkParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(TAG, "--- builder is null."); |
| return false; |
| } else if (mSizeTitle == null || mSizeNames == null || mSizeDisplayInts == null |
| || mSizeSendInts == null) { |
| Log.e(TAG, "--- size alert params are null."); |
| return false; |
| } else if (mSizeNames.length != mSizeDisplayInts.length |
| && mSizeSendInts.length != mSizeDisplayInts.length) { |
| Log.e(TAG, "--- the length of size alert params are " + "different."); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkAlignAlertParams() { |
| if (DBG) { |
| Log.d(TAG, "--- checkAlignAlertParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(TAG, "--- builder is null."); |
| return false; |
| } else if (mAlignTitle == null) { |
| Log.e(TAG, "--- align alert params are null."); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkMarqueeAlertParams() { |
| if (DBG) { |
| Log.d(TAG, "--- checkMarqueeAlertParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(TAG, "--- builder is null."); |
| return false; |
| } else if (mMarqueeTitle == null) { |
| Log.e(TAG, "--- Marquee alert params are null."); |
| return false; |
| } |
| return true; |
| } |
| |
| private void buildDialogue(CharSequence title, CharSequence[] names, |
| DialogInterface.OnClickListener l) { |
| mBuilder.setTitle(title); |
| mBuilder.setIcon(0); |
| mBuilder.setPositiveButton(null, null); |
| mBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| mEST.onStartEdit(); |
| } |
| }); |
| mBuilder.setItems(names, l); |
| mBuilder.setView(null); |
| mBuilder.setCancelable(true); |
| mBuilder.setOnCancelListener(new OnCancelListener() { |
| public void onCancel(DialogInterface arg0) { |
| if (DBG) { |
| Log.d(TAG, "--- oncancel"); |
| } |
| mEST.onStartEdit(); |
| } |
| }); |
| mBuilder.show(); |
| } |
| |
| private void buildAndShowColorDialogue(int type, CharSequence title, int[] colors) { |
| final int HORIZONTAL_ELEMENT_NUM = 5; |
| final int BUTTON_SIZE = mEST.dipToPx(50); |
| final int BUTTON_MERGIN = mEST.dipToPx(2); |
| final int BUTTON_PADDING = mEST.dipToPx(15); |
| mBuilder.setTitle(title); |
| mBuilder.setIcon(0); |
| mBuilder.setPositiveButton(null, null); |
| mBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| mEST.onStartEdit(); |
| } |
| }); |
| mBuilder.setItems(null, null); |
| LinearLayout verticalLayout = new LinearLayout(mEST.getContext()); |
| verticalLayout.setOrientation(LinearLayout.VERTICAL); |
| verticalLayout.setGravity(Gravity.CENTER_HORIZONTAL); |
| verticalLayout.setPadding(BUTTON_PADDING, BUTTON_PADDING, BUTTON_PADDING, |
| BUTTON_PADDING); |
| LinearLayout horizontalLayout = null; |
| for (int i = 0; i < colors.length; i++) { |
| if (i % HORIZONTAL_ELEMENT_NUM == 0) { |
| horizontalLayout = new LinearLayout(mEST.getContext()); |
| verticalLayout.addView(horizontalLayout); |
| } |
| Button button = new Button(mEST.getContext()); |
| button.setHeight(BUTTON_SIZE); |
| button.setWidth(BUTTON_SIZE); |
| ColorPaletteDrawable cp = |
| new ColorPaletteDrawable(colors[i], BUTTON_SIZE, BUTTON_SIZE, |
| BUTTON_MERGIN); |
| button.setBackgroundDrawable(cp); |
| button.setDrawingCacheBackgroundColor(colors[i]); |
| if (type == TYPE_FOREGROUND) { |
| button.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View view) { |
| mEST.setItemColor(view.getDrawingCacheBackgroundColor()); |
| if (mAlertDialog != null) { |
| mAlertDialog.setView(null); |
| mAlertDialog.dismiss(); |
| mAlertDialog = null; |
| } else { |
| Log.e(TAG, |
| "--- buildAndShowColorDialogue: can't find alertDialog"); |
| } |
| } |
| }); |
| } else if (type == TYPE_BACKGROUND) { |
| button.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View view) { |
| mEST.setBackgroundColor(view.getDrawingCacheBackgroundColor()); |
| if (mAlertDialog != null) { |
| mAlertDialog.setView(null); |
| mAlertDialog.dismiss(); |
| mAlertDialog = null; |
| } else { |
| Log.e(TAG, |
| "--- buildAndShowColorDialogue: can't find alertDialog"); |
| } |
| } |
| }); |
| } |
| horizontalLayout.addView(button); |
| } |
| |
| if (type == TYPE_BACKGROUND) { |
| mBuilder.setPositiveButton(mColorDefaultMessage, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| mEST.setBackgroundColor(DEFAULT_TRANSPARENT_COLOR); |
| } |
| }); |
| } else if (type == TYPE_FOREGROUND) { |
| mBuilder.setPositiveButton(mColorDefaultMessage, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| mEST.setItemColor(DEFAULT_FOREGROUND_COLOR); |
| } |
| }); |
| } |
| |
| mBuilder.setView(verticalLayout); |
| mBuilder.setCancelable(true); |
| mBuilder.setOnCancelListener(new OnCancelListener() { |
| public void onCancel(DialogInterface arg0) { |
| mEST.onStartEdit(); |
| } |
| }); |
| mAlertDialog = mBuilder.show(); |
| } |
| |
| private void onShowForegroundColorAlertDialog() { |
| if (DBG) { |
| Log.d(TAG, "--- onShowForegroundColorAlertDialog"); |
| } |
| if (!checkColorAlertParams()) { |
| return; |
| } |
| int[] colorints = new int[mColorInts.length]; |
| for (int i = 0; i < colorints.length; i++) { |
| colorints[i] = Integer.parseInt((String) mColorInts[i], 16) - 0x01000000; |
| } |
| buildAndShowColorDialogue(TYPE_FOREGROUND, mColorTitle, colorints); |
| } |
| |
| private void onShowBackgroundColorAlertDialog() { |
| if (DBG) { |
| Log.d(TAG, "--- onShowBackgroundColorAlertDialog"); |
| } |
| if (!checkColorAlertParams()) { |
| return; |
| } |
| int[] colorInts = new int[mColorInts.length]; |
| for (int i = 0; i < colorInts.length; i++) { |
| colorInts[i] = Integer.parseInt((String) mColorInts[i], 16) - 0x01000000; |
| } |
| buildAndShowColorDialogue(TYPE_BACKGROUND, mColorTitle, colorInts); |
| } |
| |
| private void onShowSizeAlertDialog() { |
| if (DBG) { |
| Log.d(TAG, "--- onShowSizeAlertDialog"); |
| } |
| if (!checkSizeAlertParams()) { |
| return; |
| } |
| buildDialogue(mSizeTitle, mSizeNames, new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Log.d(TAG, "mBuilder.onclick:" + which); |
| int size = |
| mEST.dipToPx(Integer.parseInt((String) mSizeDisplayInts[which])); |
| mEST.setItemSize(size); |
| } |
| }); |
| } |
| |
| private void onShowAlignAlertDialog() { |
| if (DBG) { |
| Log.d(TAG, "--- onShowAlignAlertDialog"); |
| } |
| if (!checkAlignAlertParams()) { |
| return; |
| } |
| buildDialogue(mAlignTitle, mAlignNames, new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Layout.Alignment align = Layout.Alignment.ALIGN_NORMAL; |
| switch (which) { |
| case 0: |
| align = Layout.Alignment.ALIGN_NORMAL; |
| break; |
| case 1: |
| align = Layout.Alignment.ALIGN_CENTER; |
| break; |
| case 2: |
| align = Layout.Alignment.ALIGN_OPPOSITE; |
| break; |
| default: |
| Log.e(TAG, "--- onShowAlignAlertDialog: got illigal align."); |
| break; |
| } |
| mEST.setAlignment(align); |
| } |
| }); |
| } |
| |
| private void onShowMarqueeAlertDialog() { |
| if (DBG) { |
| Log.d(TAG, "--- onShowMarqueeAlertDialog"); |
| } |
| if (!checkMarqueeAlertParams()) { |
| return; |
| } |
| buildDialogue(mMarqueeTitle, mMarqueeNames, new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| if (DBG) { |
| Log.d(TAG, "mBuilder.onclick:" + which); |
| } |
| mEST.setMarquee(which); |
| } |
| }); |
| } |
| } |
| |
| private class MenuHandler implements MenuItem.OnMenuItemClickListener { |
| public boolean onMenuItemClick(MenuItem item) { |
| return onTextContextMenuItem(item.getItemId()); |
| } |
| } |
| |
| private static class StyledTextArrowKeyMethod extends ArrowKeyMovementMethod { |
| EditorManager mManager; |
| String LOG_TAG = "StyledTextArrowKeyMethod"; |
| |
| StyledTextArrowKeyMethod(EditorManager manager) { |
| super(); |
| mManager = manager; |
| } |
| |
| @Override |
| public boolean |
| onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { |
| if (DBG) { |
| Log.d(LOG_TAG, "---onkeydown:" + keyCode); |
| } |
| mManager.unsetTextComposingMask(); |
| if (mManager.getSelectState() == STATE_SELECT_ON |
| || mManager.getSelectState() == STATE_SELECTED) { |
| return executeDown(widget, buffer, keyCode); |
| } else { |
| return super.onKeyDown(widget, buffer, keyCode, event); |
| } |
| } |
| |
| private int getEndPos(TextView widget) { |
| int end; |
| if (widget.getSelectionStart() == mManager.getSelectionStart()) { |
| end = widget.getSelectionEnd(); |
| } else { |
| end = widget.getSelectionStart(); |
| } |
| return end; |
| } |
| |
| protected boolean up(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- up:"); |
| } |
| Layout layout = widget.getLayout(); |
| int end = getEndPos(widget); |
| int line = layout.getLineForOffset(end); |
| if (line > 0) { |
| int to; |
| if (layout.getParagraphDirection(line) == layout |
| .getParagraphDirection(line - 1)) { |
| float h = layout.getPrimaryHorizontal(end); |
| to = layout.getOffsetForHorizontal(line - 1, h); |
| } else { |
| to = layout.getLineStart(line - 1); |
| } |
| mManager.setEndPos(to); |
| mManager.onCursorMoved(); |
| } |
| return true; |
| } |
| |
| protected boolean down(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- down:"); |
| } |
| Layout layout = widget.getLayout(); |
| int end = getEndPos(widget); |
| int line = layout.getLineForOffset(end); |
| if (line < layout.getLineCount() - 1) { |
| int to; |
| if (layout.getParagraphDirection(line) == layout |
| .getParagraphDirection(line + 1)) { |
| float h = layout.getPrimaryHorizontal(end); |
| to = layout.getOffsetForHorizontal(line + 1, h); |
| } else { |
| to = layout.getLineStart(line + 1); |
| } |
| mManager.setEndPos(to); |
| mManager.onCursorMoved(); |
| } |
| return true; |
| } |
| |
| protected boolean left(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- left:"); |
| } |
| Layout layout = widget.getLayout(); |
| int to = layout.getOffsetToLeftOf(getEndPos(widget)); |
| mManager.setEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| |
| protected boolean right(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- right:"); |
| } |
| Layout layout = widget.getLayout(); |
| int to = layout.getOffsetToRightOf(getEndPos(widget)); |
| mManager.setEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| |
| private boolean executeDown(TextView widget, Spannable buffer, int keyCode) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- executeDown: " + keyCode); |
| } |
| boolean handled = false; |
| |
| switch (keyCode) { |
| case KeyEvent.KEYCODE_DPAD_UP: |
| handled |= up(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_DOWN: |
| handled |= down(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_LEFT: |
| handled |= left(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_RIGHT: |
| handled |= right(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_CENTER: |
| mManager.onFixSelectedItem(); |
| handled = true; |
| break; |
| } |
| return handled; |
| } |
| } |
| |
| public static class StyledTextInputConnection extends InputConnectionWrapper { |
| EditStyledText mEST; |
| |
| public StyledTextInputConnection(InputConnection target, EditStyledText est) { |
| super(target, true); |
| mEST = est; |
| } |
| |
| @Override |
| public boolean commitText(CharSequence text, int newCursorPosition) { |
| if (DBG) { |
| Log.d(TAG, "--- commitText:"); |
| } |
| mEST.mManager.unsetTextComposingMask(); |
| return super.commitText(text, newCursorPosition); |
| } |
| |
| @Override |
| public boolean finishComposingText() { |
| if (DBG) { |
| Log.d(TAG, "--- finishcomposing:"); |
| } |
| if (!mEST.isSoftKeyBlocked() && !mEST.isButtonsFocused() && !mEST.isEditting()) { |
| // TODO onEndEdit isn't called temporally . |
| mEST.onEndEdit(); |
| } |
| return super.finishComposingText(); |
| } |
| } |
| |
| public static class EditStyledTextSpans { |
| private static final String LOG_TAG = "EditStyledTextSpan"; |
| |
| public static class HorizontalLineSpan extends DynamicDrawableSpan { |
| HorizontalLineDrawable mDrawable; |
| |
| public HorizontalLineSpan(int color, int width, Spannable spannable) { |
| super(ALIGN_BOTTOM); |
| mDrawable = new HorizontalLineDrawable(color, width, spannable); |
| } |
| |
| @Override |
| public Drawable getDrawable() { |
| return mDrawable; |
| } |
| |
| public void resetWidth(int width) { |
| mDrawable.renewBounds(width); |
| } |
| |
| public int getColor() { |
| return mDrawable.getPaint().getColor(); |
| } |
| } |
| |
| public static class MarqueeSpan extends CharacterStyle { |
| public static final int SCROLL = 0; |
| public static final int ALTERNATE = 1; |
| public static final int NOTHING = 2; |
| private int mType; |
| private int mMarqueeColor; |
| |
| public MarqueeSpan(int type, int bgc) { |
| mType = type; |
| checkType(type); |
| mMarqueeColor = getMarqueeColor(type, bgc); |
| } |
| |
| public MarqueeSpan(int type) { |
| this(type, EditStyledText.DEFAULT_TRANSPARENT_COLOR); |
| } |
| |
| public int getType() { |
| return mType; |
| } |
| |
| public void resetColor(int bgc) { |
| mMarqueeColor = getMarqueeColor(mType, bgc); |
| } |
| |
| private int getMarqueeColor(int type, int bgc) { |
| int THRESHOLD = 128; |
| int a = Color.alpha(bgc); |
| int r = Color.red(bgc); |
| int g = Color.green(bgc); |
| int b = Color.blue(bgc); |
| if (a == 0) { |
| a = 0x80; |
| } |
| switch (type) { |
| case SCROLL: |
| if (r > THRESHOLD) { |
| r = r / 2; |
| } else { |
| r = (0XFF - r) / 2; |
| } |
| break; |
| case ALTERNATE: |
| if (g > THRESHOLD) { |
| g = g / 2; |
| } else { |
| g = (0XFF - g) / 2; |
| } |
| break; |
| case NOTHING: |
| return DEFAULT_TRANSPARENT_COLOR; |
| default: |
| Log.e(TAG, "--- getMarqueeColor: got illigal marquee ID."); |
| return DEFAULT_TRANSPARENT_COLOR; |
| } |
| return Color.argb(a, r, g, b); |
| } |
| |
| private boolean checkType(int type) { |
| if (type == SCROLL || type == ALTERNATE) { |
| return true; |
| } else { |
| Log.e(LOG_TAG, "--- Invalid type of MarqueeSpan"); |
| return false; |
| } |
| } |
| |
| @Override |
| public void updateDrawState(TextPaint tp) { |
| tp.bgColor = mMarqueeColor; |
| } |
| } |
| |
| public static class RescalableImageSpan extends ImageSpan { |
| Uri mContentUri; |
| private Drawable mDrawable; |
| private Context mContext; |
| public int mIntrinsicWidth = -1; |
| public int mIntrinsicHeight = -1; |
| private final int MAXWIDTH; |
| |
| public RescalableImageSpan(Context context, Uri uri, int maxwidth) { |
| super(context, uri); |
| mContext = context; |
| mContentUri = uri; |
| MAXWIDTH = maxwidth; |
| } |
| |
| public RescalableImageSpan(Context context, int resourceId, int maxwidth) { |
| super(context, resourceId); |
| mContext = context; |
| MAXWIDTH = maxwidth; |
| } |
| |
| @Override |
| public Drawable getDrawable() { |
| if (mDrawable != null) { |
| return mDrawable; |
| } else if (mContentUri != null) { |
| Bitmap bitmap = null; |
| System.gc(); |
| try { |
| InputStream is = |
| mContext.getContentResolver().openInputStream(mContentUri); |
| BitmapFactory.Options opt = new BitmapFactory.Options(); |
| opt.inJustDecodeBounds = true; |
| BitmapFactory.decodeStream(is, null, opt); |
| is.close(); |
| is = mContext.getContentResolver().openInputStream(mContentUri); |
| int width, height; |
| width = opt.outWidth; |
| height = opt.outHeight; |
| mIntrinsicWidth = width; |
| mIntrinsicHeight = height; |
| if (opt.outWidth > MAXWIDTH) { |
| width = MAXWIDTH; |
| height = height * MAXWIDTH / opt.outWidth; |
| Rect padding = new Rect(0, 0, width, height); |
| bitmap = BitmapFactory.decodeStream(is, padding, null); |
| } else { |
| bitmap = BitmapFactory.decodeStream(is); |
| } |
| mDrawable = new BitmapDrawable(mContext.getResources(), bitmap); |
| mDrawable.setBounds(0, 0, width, height); |
| is.close(); |
| } catch (Exception e) { |
| Log.e(LOG_TAG, "Failed to loaded content " + mContentUri, e); |
| return null; |
| } catch (OutOfMemoryError e) { |
| Log.e(LOG_TAG, "OutOfMemoryError"); |
| return null; |
| } |
| } else { |
| mDrawable = super.getDrawable(); |
| rescaleBigImage(mDrawable); |
| mIntrinsicWidth = mDrawable.getIntrinsicWidth(); |
| mIntrinsicHeight = mDrawable.getIntrinsicHeight(); |
| } |
| return mDrawable; |
| } |
| |
| public boolean isOverSize() { |
| return (getDrawable().getIntrinsicWidth() > MAXWIDTH); |
| } |
| |
| public Uri getContentUri() { |
| return mContentUri; |
| } |
| |
| private void rescaleBigImage(Drawable image) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- rescaleBigImage:"); |
| } |
| if (MAXWIDTH < 0) { |
| return; |
| } |
| int image_width = image.getIntrinsicWidth(); |
| int image_height = image.getIntrinsicHeight(); |
| if (DBG) { |
| Log.d(LOG_TAG, "--- rescaleBigImage:" + image_width + "," + image_height |
| + "," + MAXWIDTH); |
| } |
| if (image_width > MAXWIDTH) { |
| image_width = MAXWIDTH; |
| image_height = image_height * MAXWIDTH / image_width; |
| } |
| image.setBounds(0, 0, image_width, image_height); |
| } |
| } |
| |
| public static class HorizontalLineDrawable extends ShapeDrawable { |
| private Spannable mSpannable; |
| private int mWidth; |
| private static boolean DBG_HL = false; |
| |
| public HorizontalLineDrawable(int color, int width, Spannable spannable) { |
| super(new RectShape()); |
| mSpannable = spannable; |
| mWidth = width; |
| renewColor(color); |
| renewBounds(width); |
| } |
| |
| @Override |
| public void draw(Canvas canvas) { |
| renewColor(); |
| Rect rect = new Rect(0, 9, mWidth, 11); |
| canvas.drawRect(rect, getPaint()); |
| } |
| |
| public void renewBounds(int width) { |
| int MARGIN = 20; |
| int HEIGHT = 20; |
| if (DBG_HL) { |
| Log.d(LOG_TAG, "--- renewBounds:" + width); |
| } |
| if (width > MARGIN) { |
| width -= MARGIN; |
| } |
| mWidth = width; |
| setBounds(0, 0, width, HEIGHT); |
| } |
| |
| private void renewColor(int color) { |
| if (DBG_HL) { |
| Log.d(LOG_TAG, "--- renewColor:" + color); |
| } |
| getPaint().setColor(color); |
| } |
| |
| private void renewColor() { |
| HorizontalLineSpan parent = getParentSpan(); |
| Spannable text = mSpannable; |
| int start = text.getSpanStart(parent); |
| int end = text.getSpanEnd(parent); |
| ForegroundColorSpan[] spans = |
| text.getSpans(start, end, ForegroundColorSpan.class); |
| if (DBG_HL) { |
| Log.d(LOG_TAG, "--- renewColor:" + spans.length); |
| } |
| if (spans.length > 0) { |
| renewColor(spans[spans.length - 1].getForegroundColor()); |
| } |
| } |
| |
| private HorizontalLineSpan getParentSpan() { |
| Spannable text = mSpannable; |
| HorizontalLineSpan[] images = |
| text.getSpans(0, text.length(), HorizontalLineSpan.class); |
| if (images.length > 0) { |
| for (HorizontalLineSpan image : images) { |
| if (image.getDrawable() == this) { |
| return image; |
| } |
| } |
| } |
| Log.e(LOG_TAG, "---renewBounds: Couldn't find"); |
| return null; |
| } |
| } |
| } |
| |
| public static class ColorPaletteDrawable extends ShapeDrawable { |
| private Rect mRect; |
| |
| public ColorPaletteDrawable(int color, int width, int height, int mergin) { |
| super(new RectShape()); |
| mRect = new Rect(mergin, mergin, width - mergin, height - mergin); |
| getPaint().setColor(color); |
| } |
| |
| @Override |
| public void draw(Canvas canvas) { |
| canvas.drawRect(mRect, getPaint()); |
| } |
| } |
| |
| public class EditModeActions { |
| |
| private static final String TAG = "EditModeActions"; |
| private static final boolean DBG = true; |
| private EditStyledText mEST; |
| private EditorManager mManager; |
| private StyledTextDialog mDialog; |
| |
| private int mMode = EditStyledText.MODE_NOTHING; |
| |
| private HashMap<Integer, EditModeActionBase> mActionMap = |
| new HashMap<Integer, EditModeActionBase>(); |
| |
| private NothingAction mNothingAction = new NothingAction(); |
| private CopyAction mCopyAction = new CopyAction(); |
| private PasteAction mPasteAction = new PasteAction(); |
| private SelectAction mSelectAction = new SelectAction(); |
| private CutAction mCutAction = new CutAction(); |
| private SelectAllAction mSelectAllAction = new SelectAllAction(); |
| private HorizontalLineAction mHorizontalLineAction = new HorizontalLineAction(); |
| private StopSelectionAction mStopSelectionAction = new StopSelectionAction(); |
| private ClearStylesAction mClearStylesAction = new ClearStylesAction(); |
| private ImageAction mImageAction = new ImageAction(); |
| private BackgroundColorAction mBackgroundColorAction = new BackgroundColorAction(); |
| private PreviewAction mPreviewAction = new PreviewAction(); |
| private CancelAction mCancelEditAction = new CancelAction(); |
| private TextViewAction mTextViewAction = new TextViewAction(); |
| private StartEditAction mStartEditAction = new StartEditAction(); |
| private EndEditAction mEndEditAction = new EndEditAction(); |
| private ResetAction mResetAction = new ResetAction(); |
| private ShowMenuAction mShowMenuAction = new ShowMenuAction(); |
| private AlignAction mAlignAction = new AlignAction(); |
| private TelopAction mTelopAction = new TelopAction(); |
| private SwingAction mSwingAction = new SwingAction(); |
| private MarqueeDialogAction mMarqueeDialogAction = new MarqueeDialogAction(); |
| private ColorAction mColorAction = new ColorAction(); |
| private SizeAction mSizeAction = new SizeAction(); |
| |
| EditModeActions(EditStyledText est, EditorManager manager, StyledTextDialog dialog) { |
| mEST = est; |
| mManager = manager; |
| mDialog = dialog; |
| mActionMap.put(EditStyledText.MODE_NOTHING, mNothingAction); |
| mActionMap.put(EditStyledText.MODE_COPY, mCopyAction); |
| mActionMap.put(EditStyledText.MODE_PASTE, mPasteAction); |
| mActionMap.put(EditStyledText.MODE_SELECT, mSelectAction); |
| mActionMap.put(EditStyledText.MODE_CUT, mCutAction); |
| mActionMap.put(EditStyledText.MODE_SELECTALL, mSelectAllAction); |
| mActionMap.put(EditStyledText.MODE_HORIZONTALLINE, mHorizontalLineAction); |
| mActionMap.put(EditStyledText.MODE_STOP_SELECT, mStopSelectionAction); |
| mActionMap.put(EditStyledText.MODE_CLEARSTYLES, mClearStylesAction); |
| mActionMap.put(EditStyledText.MODE_IMAGE, mImageAction); |
| mActionMap.put(EditStyledText.MODE_BGCOLOR, mBackgroundColorAction); |
| mActionMap.put(EditStyledText.MODE_PREVIEW, mPreviewAction); |
| mActionMap.put(EditStyledText.MODE_CANCEL, mCancelEditAction); |
| mActionMap.put(EditStyledText.MODE_TEXTVIEWFUNCTION, mTextViewAction); |
| mActionMap.put(EditStyledText.MODE_START_EDIT, mStartEditAction); |
| mActionMap.put(EditStyledText.MODE_END_EDIT, mEndEditAction); |
| mActionMap.put(EditStyledText.MODE_RESET, mResetAction); |
| mActionMap.put(EditStyledText.MODE_SHOW_MENU, mShowMenuAction); |
| mActionMap.put(EditStyledText.MODE_ALIGN, mAlignAction); |
| mActionMap.put(EditStyledText.MODE_TELOP, mTelopAction); |
| mActionMap.put(EditStyledText.MODE_SWING, mSwingAction); |
| mActionMap.put(EditStyledText.MODE_MARQUEE, mMarqueeDialogAction); |
| mActionMap.put(EditStyledText.MODE_COLOR, mColorAction); |
| mActionMap.put(EditStyledText.MODE_SIZE, mSizeAction); |
| } |
| |
| public void addAction(int modeId, EditModeActionBase action) { |
| mActionMap.put(modeId, action); |
| } |
| |
| public void onAction(int newMode, Object[] params) { |
| getAction(newMode).addParams(params); |
| mMode = newMode; |
| doNext(newMode); |
| } |
| |
| public void onAction(int newMode, Object param) { |
| onAction(newMode, new Object[] { param }); |
| } |
| |
| public void onAction(int newMode) { |
| onAction(newMode, null); |
| } |
| |
| public void onSelectAction() { |
| doNext(EditStyledText.MODE_SELECT); |
| } |
| |
| private EditModeActionBase getAction(int mode) { |
| if (mActionMap.containsKey(mode)) { |
| return mActionMap.get(mode); |
| } |
| return null; |
| } |
| |
| public boolean doNext() { |
| return doNext(mMode); |
| } |
| |
| public boolean doNext(int mode) { |
| if (DBG) { |
| Log.d(TAG, "--- do the next action: " + mode + "," + mManager.getSelectState()); |
| } |
| EditModeActionBase action = getAction(mode); |
| if (action == null) { |
| Log.e(TAG, "--- invalid action error."); |
| return false; |
| } |
| switch (mManager.getSelectState()) { |
| case EditStyledText.STATE_SELECT_OFF: |
| return action.doNotSelected(); |
| case EditStyledText.STATE_SELECT_ON: |
| return action.doStartPosIsSelected(); |
| case EditStyledText.STATE_SELECTED: |
| return action.doEndPosIsSelected(); |
| case EditStyledText.STATE_SELECT_FIX: |
| if (mManager.isWaitInput()) { |
| return action.doSelectionIsFixedAndWaitingInput(); |
| } else { |
| return action.doSelectionIsFixed(); |
| } |
| default: |
| return false; |
| } |
| } |
| |
| public class EditModeActionBase { |
| private Object[] mParams; |
| |
| protected boolean canOverWrap() { |
| return false; |
| } |
| |
| protected boolean canSelect() { |
| return false; |
| } |
| |
| protected boolean canWaitInput() { |
| return false; |
| } |
| |
| protected boolean needSelection() { |
| return false; |
| } |
| |
| protected boolean isLine() { |
| return false; |
| } |
| |
| protected boolean doNotSelected() { |
| return false; |
| } |
| |
| protected boolean doStartPosIsSelected() { |
| return doNotSelected(); |
| } |
| |
| protected boolean doEndPosIsSelected() { |
| return doStartPosIsSelected(); |
| } |
| |
| protected boolean doSelectionIsFixed() { |
| return doEndPosIsSelected(); |
| } |
| |
| protected boolean doSelectionIsFixedAndWaitingInput() { |
| return doEndPosIsSelected(); |
| } |
| |
| protected boolean fixSelection() { |
| mEST.finishComposingText(); |
| mManager.setSelectState(EditStyledText.STATE_SELECT_FIX); |
| return true; |
| } |
| |
| protected void addParams(Object[] o) { |
| mParams = o; |
| } |
| |
| protected Object getParam(int num) { |
| if (mParams == null || num > mParams.length) { |
| if (DBG) { |
| Log.d(TAG, "--- Number of the parameter is out of bound."); |
| } |
| return null; |
| } else { |
| return mParams[num]; |
| } |
| } |
| } |
| |
| public class NothingAction extends EditModeActionBase { |
| } |
| |
| public class TextViewActionBase extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| if (mManager.getEditMode() == EditStyledText.MODE_NOTHING |
| || mManager.getEditMode() == EditStyledText.MODE_SELECT) { |
| mManager.setEditMode(mMode); |
| onSelectAction(); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| protected boolean doEndPosIsSelected() { |
| if (mManager.getEditMode() == EditStyledText.MODE_NOTHING |
| || mManager.getEditMode() == EditStyledText.MODE_SELECT) { |
| mManager.setEditMode(mMode); |
| fixSelection(); |
| doNext(); |
| return true; |
| } else if (mManager.getEditMode() != mMode) { |
| mManager.resetEdit(); |
| mManager.setEditMode(mMode); |
| doNext(); |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| public class TextViewAction extends TextViewActionBase { |
| @Override |
| protected boolean doEndPosIsSelected() { |
| if (super.doEndPosIsSelected()) { |
| return true; |
| } |
| Object param = getParam(0); |
| if (param != null && param instanceof Integer) { |
| mEST.onTextContextMenuItem((Integer) param); |
| } |
| mManager.resetEdit(); |
| return true; |
| } |
| } |
| |
| public class CopyAction extends TextViewActionBase { |
| @Override |
| protected boolean doEndPosIsSelected() { |
| if (super.doEndPosIsSelected()) { |
| return true; |
| } |
| mManager.copyToClipBoard(); |
| mManager.resetEdit(); |
| return true; |
| } |
| } |
| |
| public class CutAction extends TextViewActionBase { |
| @Override |
| protected boolean doEndPosIsSelected() { |
| if (super.doEndPosIsSelected()) { |
| return true; |
| } |
| mManager.cutToClipBoard(); |
| mManager.resetEdit(); |
| return true; |
| } |
| } |
| |
| public class SelectAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| if (mManager.isTextSelected()) { |
| Log.e(TAG, "Selection is off, but selected"); |
| } |
| mManager.setSelectStartPos(); |
| mEST.sendHintMessage(EditStyledText.HINT_MSG_SELECT_END); |
| return true; |
| } |
| |
| @Override |
| protected boolean doStartPosIsSelected() { |
| if (mManager.isTextSelected()) { |
| Log.e(TAG, "Selection now start, but selected"); |
| } |
| mManager.setSelectEndPos(); |
| mEST.sendHintMessage(EditStyledText.HINT_MSG_PUSH_COMPETE); |
| if (mManager.getEditMode() != EditStyledText.MODE_SELECT) { |
| doNext(mManager.getEditMode()); // doNextHandle needs edit mode in editor. |
| } |
| return true; |
| } |
| |
| @Override |
| protected boolean doSelectionIsFixed() { |
| return false; |
| } |
| } |
| |
| public class PasteAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.pasteFromClipboard(); |
| mManager.resetEdit(); |
| return true; |
| } |
| } |
| |
| public class SelectAllAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.selectAll(); |
| return true; |
| } |
| } |
| |
| public class HorizontalLineAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.insertHorizontalLine(); |
| return true; |
| } |
| } |
| |
| public class ClearStylesAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.clearStyles(); |
| return true; |
| } |
| } |
| |
| public class StopSelectionAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.fixSelectionAndDoNextAction(); |
| return true; |
| } |
| } |
| |
| public class CancelAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mEST.cancelViewManagers(); |
| return true; |
| } |
| } |
| |
| public class ImageAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| Object param = getParam(0); |
| if (param != null) { |
| if (param instanceof Uri) { |
| mManager.insertImageFromUri((Uri) param); |
| } else if (param instanceof Integer) { |
| mManager.insertImageFromResId((Integer) param); |
| } |
| } else { |
| mEST.showInsertImageSelectAlertDialog(); |
| } |
| return true; |
| } |
| } |
| |
| public class BackgroundColorAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mDialog.onShowBackgroundColorAlertDialog(); |
| return true; |
| } |
| } |
| |
| public class PreviewAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mEST.showPreview(); |
| return true; |
| } |
| } |
| |
| public class StartEditAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.startEdit(); |
| return true; |
| } |
| } |
| |
| public class EndEditAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.endEdit(); |
| return true; |
| } |
| } |
| |
| public class ResetAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mManager.resetEdit(); |
| return true; |
| } |
| } |
| |
| public class ShowMenuAction extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| mEST.showMenuAlertDialog(); |
| return true; |
| } |
| } |
| |
| public class SetSpanActionBase extends EditModeActionBase { |
| @Override |
| protected boolean doNotSelected() { |
| if (mManager.getEditMode() == EditStyledText.MODE_NOTHING |
| || mManager.getEditMode() == EditStyledText.MODE_SELECT) { |
| mManager.setEditMode(mMode); |
| mManager.setInternalSelection(mEST.getSelectionStart(), |
| mEST.getSelectionEnd()); |
| fixSelection(); |
| doNext(); |
| return true; |
| } else if (mManager.getEditMode() != mMode) { |
| Log.d(TAG, "--- setspanactionbase" + mManager.getEditMode() + "," + mMode); |
| if (!mManager.isWaitInput()) { |
| mManager.resetEdit(); |
| mManager.setEditMode(mMode); |
| } else { |
| mManager.setEditMode(EditStyledText.MODE_NOTHING); |
| mManager.setSelectState(EditStyledText.STATE_SELECT_OFF); |
| } |
| doNext(); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| protected boolean doStartPosIsSelected() { |
| if (mManager.getEditMode() == EditStyledText.MODE_NOTHING |
| || mManager.getEditMode() == EditStyledText.MODE_SELECT) { |
| mManager.setEditMode(mMode); |
| onSelectAction(); |
| return true; |
| } |
| return doNotSelected(); |
| } |
| |
| @Override |
| protected boolean doEndPosIsSelected() { |
| if (mManager.getEditMode() == EditStyledText.MODE_NOTHING |
| || mManager.getEditMode() == EditStyledText.MODE_SELECT) { |
| mManager.setEditMode(mMode); |
| fixSelection(); |
| doNext(); |
| return true; |
| } |
| return doStartPosIsSelected(); |
| } |
| |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (doEndPosIsSelected()) { |
| return true; |
| } |
| mEST.sendHintMessage(EditStyledText.HINT_MSG_NULL); |
| |
| return false; |
| } |
| } |
| |
| public class AlignAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mDialog.onShowAlignAlertDialog(); |
| return true; |
| } |
| } |
| |
| public class TelopAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mManager.setTelop(); |
| return true; |
| } |
| } |
| |
| public class SwingAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mManager.setSwing(); |
| return true; |
| } |
| } |
| |
| public class MarqueeDialogAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mDialog.onShowMarqueeAlertDialog(); |
| return true; |
| } |
| } |
| |
| public class ColorAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mDialog.onShowForegroundColorAlertDialog(); |
| return true; |
| } |
| |
| @Override |
| protected boolean doSelectionIsFixedAndWaitingInput() { |
| if (super.doSelectionIsFixedAndWaitingInput()) { |
| return true; |
| } |
| int size = mManager.getSizeWaitInput(); |
| mManager.setItemColor(mManager.getColorWaitInput(), false); |
| // selection was resumed |
| if (!mManager.isWaitInput()) { |
| mManager.setItemSize(size, false); |
| mManager.resetEdit(); |
| } else { |
| fixSelection(); |
| mDialog.onShowForegroundColorAlertDialog(); |
| } |
| return true; |
| } |
| } |
| |
| public class SizeAction extends SetSpanActionBase { |
| @Override |
| protected boolean doSelectionIsFixed() { |
| if (super.doSelectionIsFixed()) { |
| return true; |
| } |
| mDialog.onShowSizeAlertDialog(); |
| return true; |
| } |
| |
| @Override |
| protected boolean doSelectionIsFixedAndWaitingInput() { |
| if (super.doSelectionIsFixedAndWaitingInput()) { |
| return true; |
| } |
| int color = mManager.getColorWaitInput(); |
| mManager.setItemSize(mManager.getSizeWaitInput(), false); |
| if (!mManager.isWaitInput()) { |
| mManager.setItemColor(color, false); |
| mManager.resetEdit(); |
| } else { |
| fixSelection(); |
| mDialog.onShowSizeAlertDialog(); |
| } |
| return true; |
| } |
| } |
| } |
| } |