android/experimental/LOAndroid3/res/drawable-hdpi/handle_end.png |binary android/experimental/LOAndroid3/res/drawable-hdpi/handle_middle.png |binary android/experimental/LOAndroid3/res/drawable-hdpi/handle_start.png |binary android/experimental/LOAndroid3/res/drawable-xhdpi/handle_end.png |binary android/experimental/LOAndroid3/res/drawable-xhdpi/handle_middle.png |binary android/experimental/LOAndroid3/res/drawable-xhdpi/handle_start.png |binary android/experimental/LOAndroid3/res/drawable/handle_end.png |binary android/experimental/LOAndroid3/res/drawable/handle_middle.png |binary android/experimental/LOAndroid3/res/drawable/handle_start.png |binary android/experimental/LOAndroid3/res/layout/activity_main.xml | 3 android/experimental/LOAndroid3/res/layout/text_selection_handles.xml | 29 + android/experimental/LOAndroid3/res/values/attrs.xml | 17 android/experimental/LOAndroid3/res/values/dimens.xml | 3 android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java | 27 - android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java | 16 android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java | 15 android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java | 5 android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java | 5 android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java | 32 - android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java | 191 ++++++++++ android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java | 170 ++++++++ sw/inc/crsrsh.hxx | 6 sw/source/core/crsr/crsrsh.cxx | 21 - 23 files changed, 482 insertions(+), 58 deletions(-)
New commits: commit 0266b4ab4464998bea7bc29b6289f193040523d3 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jan 29 19:03:07 2015 +0900 tdf#87098 don't adjust zoom/position for spreadsheets Change-Id: Ieb908980a931b123e2c48fe3ecdc7830b48810ed diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java index 5cb8f31..354404c 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java @@ -63,16 +63,27 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation mViewportMetrics = mLayerClient.getViewportMetrics(); mLayerClient.setViewportMetrics(mViewportMetrics); - if (mTileProvider.isTextDocument()) { + zoomAndRepositionTheDocument(); + + mLayerClient.forceRedraw(); + } + + private void zoomAndRepositionTheDocument() { + if (mTileProvider.isSpreadsheet()) { + // Don't do anything for spreadsheets - show at 100% + } else if (mTileProvider.isTextDocument()) { + // Always zoom text document to the beginning of the document and centered by width float centerY = mViewportMetrics.getCssViewport().centerY(); - mLayerClient.zoomTo(new RectF (0, centerY, mTileProvider.getPageWidth(), centerY)); - } else if (mViewportMetrics.getViewport().width() < mViewportMetrics.getViewport().height()) { - mLayerClient.zoomTo(mTileProvider.getPageWidth(), 0); + mLayerClient.zoomTo(new RectF(0, centerY, mTileProvider.getPageWidth(), centerY)); } else { - mLayerClient.zoomTo(0, mTileProvider.getPageHeight()); + // Other documents - always show the whole document on the screen, + // regardless of document shape and orientation. + if (mViewportMetrics.getViewport().width() < mViewportMetrics.getViewport().height()) { + mLayerClient.zoomTo(mTileProvider.getPageWidth(), 0); + } else { + mLayerClient.zoomTo(0, mTileProvider.getPageHeight()); + } } - - mLayerClient.forceRedraw(); } /** Invalidate everything + handle the geometry change */ diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java index 5539450..c5f31b3 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java @@ -270,6 +270,11 @@ public class LOKitTileProvider implements TileProvider, Document.MessageCallback return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_TEXT; } + @Override + public boolean isSpreadsheet() { + return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_SPREADSHEET; + } + /** * Register the tile invalidation callback. */ diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java index 006ae90..34347bb 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java @@ -85,6 +85,11 @@ public class MockTileProvider implements TileProvider { } @Override + public boolean isSpreadsheet() { + return false; + } + + @Override public void registerInvalidationCallback(TileInvalidationCallback tileInvalidationCallback) { } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java index 759ecad..c983c62 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java @@ -54,6 +54,11 @@ public interface TileProvider { boolean isTextDocument(); /** + * Returns true if the current open document is a spreadsheet. + */ + boolean isSpreadsheet(); + + /** * Register a callback that is invoked when a tile invalidation is * required. * commit 5b97fb635f160e5a2f8ee88adbb488174acec9c3 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jan 29 18:07:06 2015 +0900 Don't hide cursor for Android anymore - makes cursor events work Change-Id: I97caadf079c9a5e38c00c80fdc8185aee997f632 diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 7e61c7d4..220bb8c 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -63,7 +63,7 @@ #include <comcore.hrc> #include <IDocumentLayoutAccess.hxx> -#if defined(ANDROID) || defined(IOS) +#if defined(IOS) #include <touch/touch.h> #endif @@ -2119,7 +2119,7 @@ void SwCrsrShell::ShowCrsr() { m_bSVCrsrVis = true; m_pCurCrsr->SetShowTxtInputFldOverlay( true ); -#if defined(ANDROID) || defined(IOS) +#if defined(IOS) touch_ui_show_keyboard(); #endif UpdateCrsr(); @@ -2135,7 +2135,7 @@ void SwCrsrShell::HideCrsr() SET_CURR_SHELL( this ); m_pCurCrsr->SetShowTxtInputFldOverlay( false ); m_pVisCrsr->Hide(); -#if defined(ANDROID) || defined(IOS) +#if defined(IOS) touch_ui_hide_keyboard(); #endif } @@ -2628,7 +2628,7 @@ SwCrsrShell::SwCrsrShell( SwCrsrShell& rShell, vcl::Window *pInitWin ) m_pVisCrsr = new SwVisCrsr( this ); m_bMacroExecAllowed = rShell.IsMacroExecAllowed(); -#if defined(ANDROID) || defined(IOS) +#if defined(IOS) HideCrsr(); #endif } @@ -2679,7 +2679,7 @@ SwCrsrShell::SwCrsrShell( SwDoc& rDoc, vcl::Window *pInitWin, m_pVisCrsr = new SwVisCrsr( this ); m_bMacroExecAllowed = true; -#if defined(ANDROID) || defined(IOS) +#if defined(IOS) HideCrsr(); #endif } commit e1372059d04ff07300d418747766c7f2326d243f Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jan 29 17:46:23 2015 +0900 Combine DBG_UTIL and header version of Stt{End}CrsrMove Having 2 versions (debug and release) of one method (on top of that in different places - one implemented in header) which are mostly the same is a recipe for disaster. Change-Id: Ia38f900ac076d1c1765fea2c7326147b115e343d diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index d57520c..13489ce 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -447,14 +447,8 @@ public: */ void Combine(); -#ifdef DBG_UTIL void SttCrsrMove(); void EndCrsrMove( const bool bIdleEnd = false ); -#else - void SttCrsrMove() { ++m_nCrsrMove; StartAction(); } - void EndCrsrMove( const bool bIdleEnd = false ) - { EndAction( bIdleEnd, true ); --m_nCrsrMove; } -#endif /* * When the focus is lost the selected ranges are not displayed anymore. diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 980c278..7e61c7d4 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -314,22 +314,27 @@ void SwCrsrShell::EndAction( const bool bIdleEnd, const bool DoSetPosX ) } } -#ifdef DBG_UTIL void SwCrsrShell::SttCrsrMove() { +#ifdef DBG_UTIL OSL_ENSURE( m_nCrsrMove < USHRT_MAX, "To many nested CrsrMoves." ); +#endif ++m_nCrsrMove; StartAction(); } void SwCrsrShell::EndCrsrMove( const bool bIdleEnd ) { +#ifdef DBG_UTIL OSL_ENSURE( m_nCrsrMove, "EndCrsrMove() without SttCrsrMove()." ); +#endif EndAction( bIdleEnd, true ); - if( !--m_nCrsrMove ) + --m_nCrsrMove; +#ifdef DBG_UTIL + if( !m_nCrsrMove ) m_bInCMvVisportChgd = false; -} #endif +} bool SwCrsrShell::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode, bool bVisualAllowed ) commit 9bdf428d99eb6eb78882eff9f176bfde0f7cb01e Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jan 29 14:40:29 2015 +0900 android: Actually we don't need ViewFactory Change-Id: I2d1ccafefe9c52d0536601ba7ff219e6547ceb20 diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java index 362fb78..f1eb759 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -96,8 +96,6 @@ public class LibreOfficeMainActivity extends LOAbout { mMainHandler = new Handler(); - LayoutInflater.from(this).setFactory(ViewFactory.getInstance()); - if (getIntent().getData() != null) { mInputFile = getIntent().getData().getPath(); } else { diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java deleted file mode 100644 index 68f88d9..0000000 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.libreoffice; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; - -import org.mozilla.gecko.TextSelectionHandle; -import org.mozilla.gecko.gfx.LayerView; - -public class ViewFactory implements LayoutInflater.Factory { - private static final String LOGTAG = ViewFactory.class.getSimpleName(); - private static final String LAYER_VIEW_ID = "org.mozilla.gecko.gfx.LayerView"; - private static final String TEXT_SELECTION_HANDLE_ID = "org.mozilla.gecko.TextSelectionHandle"; - private static final ViewFactory INSTANCE = new ViewFactory(); - - private ViewFactory() { - } - - public static LayoutInflater.Factory getInstance() { - return INSTANCE; - } - - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - if (name.equals(LAYER_VIEW_ID)) { - Log.i(LOGTAG, "Creating custom Gecko view: " + name); - return new LayerView(context, attrs); - } else if (name.equals(TEXT_SELECTION_HANDLE_ID)) { - Log.i(LOGTAG, "Creating custom Gecko view: " + name); - return new TextSelectionHandle(context, attrs); - } - return null; - } -} \ No newline at end of file commit bdb25ebb9e0b38838cd5e174774443f75b316433 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jan 29 11:26:24 2015 +0900 android: integrate text selection handles from Fennec Integrate text selection handles from Fennec and insert middle handle when a cursor invalidation event is recieved from LO. Change-Id: I6ba31d46bf89555bdbca9ce4be666039e8bc9041 diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/handle_end.png b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_end.png new file mode 100644 index 0000000..d5e2044 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_end.png differ diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/handle_middle.png b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_middle.png new file mode 100644 index 0000000..5dcee14 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_middle.png differ diff --git a/android/experimental/LOAndroid3/res/drawable-hdpi/handle_start.png b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_start.png new file mode 100644 index 0000000..b6a8ce7 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-hdpi/handle_start.png differ diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_end.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_end.png new file mode 100644 index 0000000..c83b7b6 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_end.png differ diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_middle.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_middle.png new file mode 100644 index 0000000..2a1774f Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_middle.png differ diff --git a/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_start.png b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_start.png new file mode 100644 index 0000000..9af7654 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable-xhdpi/handle_start.png differ diff --git a/android/experimental/LOAndroid3/res/drawable/handle_end.png b/android/experimental/LOAndroid3/res/drawable/handle_end.png new file mode 100644 index 0000000..32b77df Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable/handle_end.png differ diff --git a/android/experimental/LOAndroid3/res/drawable/handle_middle.png b/android/experimental/LOAndroid3/res/drawable/handle_middle.png new file mode 100644 index 0000000..751eb89 Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable/handle_middle.png differ diff --git a/android/experimental/LOAndroid3/res/drawable/handle_start.png b/android/experimental/LOAndroid3/res/drawable/handle_start.png new file mode 100644 index 0000000..cf12a0d Binary files /dev/null and b/android/experimental/LOAndroid3/res/drawable/handle_start.png differ diff --git a/android/experimental/LOAndroid3/res/layout/activity_main.xml b/android/experimental/LOAndroid3/res/layout/activity_main.xml index 1b1bb07..e9a946f 100644 --- a/android/experimental/LOAndroid3/res/layout/activity_main.xml +++ b/android/experimental/LOAndroid3/res/layout/activity_main.xml @@ -22,6 +22,9 @@ android:id="@+id/layer_view" android:layout_width="fill_parent" android:layout_height="fill_parent"/> + + <include layout="@layout/text_selection_handles"/> + </RelativeLayout> <RelativeLayout diff --git a/android/experimental/LOAndroid3/res/layout/text_selection_handles.xml b/android/experimental/LOAndroid3/res/layout/text_selection_handles.xml new file mode 100644 index 0000000..1f0d816 --- /dev/null +++ b/android/experimental/LOAndroid3/res/layout/text_selection_handles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:gecko="http://schemas.android.com/apk/res-auto"> + + <org.mozilla.gecko.TextSelectionHandle android:id="@+id/start_handle" + android:layout_width="@dimen/text_selection_handle_width" + android:layout_height="@dimen/text_selection_handle_height" + android:src="@drawable/handle_start" + android:visibility="gone" + gecko:handleType="start"/> + + <org.mozilla.gecko.TextSelectionHandle android:id="@+id/middle_handle" + android:layout_width="@dimen/text_selection_handle_width" + android:layout_height="@dimen/text_selection_handle_height" + android:src="@drawable/handle_middle" + android:visibility="gone" + gecko:handleType="middle"/> + + <org.mozilla.gecko.TextSelectionHandle android:id="@+id/end_handle" + android:layout_width="@dimen/text_selection_handle_width" + android:layout_height="@dimen/text_selection_handle_height" + android:src="@drawable/handle_end" + android:visibility="gone" + gecko:handleType="end"/> +</merge> diff --git a/android/experimental/LOAndroid3/res/values/attrs.xml b/android/experimental/LOAndroid3/res/values/attrs.xml new file mode 100644 index 0000000..ed73978 --- /dev/null +++ b/android/experimental/LOAndroid3/res/values/attrs.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<resources> + + <declare-styleable name="TextSelectionHandle"> + <attr name="handleType"> + <flag name="start" value="0x01"/> + <flag name="middle" value="0x02"/> + <flag name="end" value="0x03"/> + </attr> + </declare-styleable> + +</resources> + diff --git a/android/experimental/LOAndroid3/res/values/dimens.xml b/android/experimental/LOAndroid3/res/values/dimens.xml index 47c8224..1e5d771 100644 --- a/android/experimental/LOAndroid3/res/values/dimens.xml +++ b/android/experimental/LOAndroid3/res/values/dimens.xml @@ -2,4 +2,7 @@ <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> + <dimen name="text_selection_handle_width">30dp</dimen> + <dimen name="text_selection_handle_height">44dp</dimen> + <dimen name="text_selection_handle_shadow">2dp</dimen> </resources> diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java index c8bcc23..5cb8f31 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java @@ -168,8 +168,6 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation private void touch(String touchType, MotionEvent motionEvent, PointF mDocumentTouchCoordinate) { LibreOfficeMainActivity.mAppContext.showSoftKeyboard(); - float x = motionEvent.getX(); - float y = motionEvent.getY(); mTileProvider.mouseButtonDown(mDocumentTouchCoordinate); } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java index 3e3412a7..5539450 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java @@ -10,6 +10,7 @@ import org.libreoffice.kit.DirectBufferAllocator; import org.libreoffice.kit.Document; import org.libreoffice.kit.LibreOfficeKit; import org.libreoffice.kit.Office; +import org.mozilla.gecko.TextSelection; import org.mozilla.gecko.gfx.BufferedCairoImage; import org.mozilla.gecko.gfx.CairoImage; import org.mozilla.gecko.gfx.GeckoLayerClient; @@ -303,6 +304,11 @@ public class LOKitTileProvider implements TileProvider, Document.MessageCallback private void mouseButton(int type, PointF inDocument) { int x = (int) pixelToTwip(inDocument.x, mDPI); int y = (int) pixelToTwip(inDocument.y, mDPI); + + TextSelection textSelection = LibreOfficeMainActivity.mAppContext.getTextSelection(); + textSelection.positionHandle("MIDDLE", new RectF(inDocument.x, inDocument.y, inDocument.x, inDocument.y)); + textSelection.showHandle("MIDDLE"); + mDocument.postMouseEvent(type, x, y); } @@ -376,9 +382,12 @@ public class LOKitTileProvider implements TileProvider, Document.MessageCallback break; } case Document.CALLBACK_INVALIDATE_VISIBLE_CURSOR: { + Log.i(LOGTAG, "Invalidate visible cursor: " + payload); RectF rect = convertCallbackMessageStringToRectF(payload); if (rect != null) { - //tileInvalidationCallback.invalidate(rect); + TextSelection textSelection = LibreOfficeMainActivity.mAppContext.getTextSelection(); + textSelection.positionHandle("MIDDLE", rect); + textSelection.showHandle("MIDDLE"); } break; } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java index bca8230..362fb78 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -20,6 +20,8 @@ import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; +import org.mozilla.gecko.TextSelection; +import org.mozilla.gecko.TextSelectionHandle; import org.mozilla.gecko.ZoomConstraints; import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.LayerView; @@ -45,6 +47,7 @@ public class LibreOfficeMainActivity extends LOAbout { private List<DocumentPartView> mDocumentPartView = new ArrayList<DocumentPartView>(); private DocumentPartViewListAdapter mDocumentPartViewListAdapter; private String mInputFile; + private TextSelection mTextSelection; public LibreOfficeMainActivity() { super(/*newActivity=*/false); @@ -124,6 +127,12 @@ public class LibreOfficeMainActivity extends LOAbout { sLOKitThread.clearQueue(); } + TextSelectionHandle startHandle = (TextSelectionHandle) findViewById(R.id.start_handle); + TextSelectionHandle middleHandle = (TextSelectionHandle) findViewById(R.id.middle_handle); + TextSelectionHandle endHandle = (TextSelectionHandle) findViewById(R.id.end_handle); + + mTextSelection = new TextSelection(startHandle, middleHandle, endHandle); + mLayerClient = new GeckoLayerClient(this); mLayerClient.setZoomConstraints(new ZoomConstraints(true)); LayerView layerView = (LayerView) findViewById(R.id.layer_view); @@ -231,6 +240,10 @@ public class LibreOfficeMainActivity extends LOAbout { alertDialog.show(); } + public TextSelection getTextSelection() { + return mTextSelection; + } + private class DocumentPartClickListener implements android.widget.AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java index c26ad22..68f88d9 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/ViewFactory.java @@ -6,11 +6,13 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import org.mozilla.gecko.TextSelectionHandle; import org.mozilla.gecko.gfx.LayerView; public class ViewFactory implements LayoutInflater.Factory { private static final String LOGTAG = ViewFactory.class.getSimpleName(); private static final String LAYER_VIEW_ID = "org.mozilla.gecko.gfx.LayerView"; + private static final String TEXT_SELECTION_HANDLE_ID = "org.mozilla.gecko.TextSelectionHandle"; private static final ViewFactory INSTANCE = new ViewFactory(); private ViewFactory() { @@ -25,8 +27,10 @@ public class ViewFactory implements LayoutInflater.Factory { if (name.equals(LAYER_VIEW_ID)) { Log.i(LOGTAG, "Creating custom Gecko view: " + name); return new LayerView(context, attrs); + } else if (name.equals(TEXT_SELECTION_HANDLE_ID)) { + Log.i(LOGTAG, "Creating custom Gecko view: " + name); + return new TextSelectionHandle(context, attrs); } - return null; } } \ No newline at end of file diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java new file mode 100644 index 0000000..f09e93a --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java @@ -0,0 +1,191 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.graphics.RectF; +import android.util.Log; +import android.view.View; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.libreoffice.LOKitShell; +import org.libreoffice.LibreOfficeMainActivity; +import org.mozilla.gecko.gfx.Layer; +import org.mozilla.gecko.gfx.LayerView; +import org.mozilla.gecko.util.FloatUtils; + +public class TextSelection extends Layer { + private static final String LOGTAG = "GeckoTextSelection"; + + private final TextSelectionHandle mStartHandle; + private final TextSelectionHandle mMiddleHandle; + private final TextSelectionHandle mEndHandle; + + private float mViewLeft; + private float mViewTop; + private float mViewZoom; + + public TextSelection(TextSelectionHandle startHandle, + TextSelectionHandle middleHandle, + TextSelectionHandle endHandle) { + mStartHandle = startHandle; + mMiddleHandle = middleHandle; + mEndHandle = endHandle; + + // Only register listeners if we have valid start/middle/end handles + if (mStartHandle == null || mMiddleHandle == null || mEndHandle == null) { + Log.e(LOGTAG, "Failed to initialize text selection because at least one handle is null"); + } + } + + void destroy() { + } + + public void handleMessage(String event, JSONObject message) { + try { + if (event.equals("TextSelection:ShowHandles")) { + final JSONArray handles = message.getJSONArray("handles"); + LibreOfficeMainActivity.mAppContext.mMainHandler.post(new Runnable() { + public void run() { + try { + for (int i=0; i < handles.length(); i++) { + String handle = handles.getString(i); + + if (handle.equals("START")) + mStartHandle.setVisibility(View.VISIBLE); + else if (handle.equals("MIDDLE")) + mMiddleHandle.setVisibility(View.VISIBLE); + else + mEndHandle.setVisibility(View.VISIBLE); + } + + mViewLeft = 0.0f; + mViewTop = 0.0f; + mViewZoom = 0.0f; + LayerView layerView = LOKitShell.getLayerView(); + if (layerView != null) { + layerView.addLayer(TextSelection.this); + } + } catch(Exception e) {} + } + }); + } else if (event.equals("TextSelection:HideHandles")) { + final JSONArray handles = message.getJSONArray("handles"); + LibreOfficeMainActivity.mAppContext.mMainHandler.post(new Runnable() { + public void run() { + try { + LayerView layerView = LOKitShell.getLayerView(); + if (layerView != null) { + layerView.removeLayer(TextSelection.this); + } + + for (int i=0; i < handles.length(); i++) { + String handle = handles.getString(i); + if (handle.equals("START")) + mStartHandle.setVisibility(View.GONE); + else if (handle.equals("MIDDLE")) + mMiddleHandle.setVisibility(View.GONE); + else + mEndHandle.setVisibility(View.GONE); + } + + } catch(Exception e) {} + } + }); + } else if (event.equals("TextSelection:PositionHandles")) { + final JSONArray positions = message.getJSONArray("positions"); + LibreOfficeMainActivity.mAppContext.mMainHandler.post(new Runnable() { + public void run() { + try { + for (int i=0; i < positions.length(); i++) { + JSONObject position = positions.getJSONObject(i); + String handle = position.getString("handle"); + int left = position.getInt("left"); + int top = position.getInt("top"); + + if (handle.equals("START")) + mStartHandle.positionFromGecko(left, top); + else if (handle.equals("MIDDLE")) + mMiddleHandle.positionFromGecko(left, top); + else + mEndHandle.positionFromGecko(left, top); + } + } catch (Exception e) { } + } + }); + } + } catch (Exception e) { + Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); + } + } + + @Override + public void draw(final RenderContext context) { + // cache the relevant values from the context and bail out if they are the same. we do this + // because this draw function gets called a lot (once per compositor frame) and we want to + // avoid doing a lot of extra work in cases where it's not needed. + if (FloatUtils.fuzzyEquals(mViewLeft, context.viewport.left) + && FloatUtils.fuzzyEquals(mViewTop, context.viewport.top) + && FloatUtils.fuzzyEquals(mViewZoom, context.zoomFactor)) { + return; + } + mViewLeft = context.viewport.left; + mViewTop = context.viewport.top; + mViewZoom = context.zoomFactor; + + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + mStartHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); + mMiddleHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); + mEndHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); + } + }); + } + + public void showHandle(final String handleType) { + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + try { + TextSelectionHandle handle; + if (handleType.equals("START")) + handle = mStartHandle; + else if (handleType.equals("MIDDLE")) + handle = mMiddleHandle; + else + handle = mEndHandle; + + handle.setVisibility(View.VISIBLE); + + mViewLeft = 0.0f; + mViewTop = 0.0f; + mViewZoom = 0.0f; + LayerView layerView = LOKitShell.getLayerView(); + if (layerView != null) { + layerView.addLayer(TextSelection.this); + } + } catch (Exception e) { + } + } + }); + } + + public void positionHandle(final String handleType, final RectF position) { + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + try { + TextSelectionHandle handle; + if (handleType.equals("START")) + handle = mStartHandle; + else if (handleType.equals("MIDDLE")) + handle = mMiddleHandle; + else + handle = mEndHandle; + + handle.positionFromGecko((int) position.left, (int) position.top); + } catch (Exception e) { } + } + }); + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java new file mode 100644 index 0000000..92ca9d4 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java @@ -0,0 +1,170 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.libreoffice.LOKitShell; +import org.libreoffice.R; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; +import org.mozilla.gecko.gfx.LayerView; + +import org.json.JSONObject; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.PointF; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +public class TextSelectionHandle extends ImageView implements View.OnTouchListener { + private static final String LOGTAG = "GeckoTextSelectionHandle"; + + private enum HandleType { START, MIDDLE, END }; + + private final HandleType mHandleType; + private final int mWidth; + private final int mHeight; + private final int mShadow; + + private int mLeft; + private int mTop; + private PointF mGeckoPoint; + private int mTouchStartX; + private int mTouchStartY; + + private RelativeLayout.LayoutParams mLayoutParams; + + public TextSelectionHandle(Context context, AttributeSet attrs) { + super(context, attrs); + setOnTouchListener(this); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextSelectionHandle); + int handleType = a.getInt(R.styleable.TextSelectionHandle_handleType, 0x01); + + if (handleType == 0x01) + mHandleType = HandleType.START; + else if (handleType == 0x02) + mHandleType = HandleType.MIDDLE; + else + mHandleType = HandleType.END; + + mGeckoPoint = new PointF(0.0f, 0.0f); + + mWidth = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_width); + mHeight = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_height); + mShadow = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_shadow); + } + + public boolean onTouch(View v, MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + mTouchStartX = Math.round(event.getX()); + mTouchStartY = Math.round(event.getY()); + break; + } + case MotionEvent.ACTION_UP: { + mTouchStartX = 0; + mTouchStartY = 0; + + // Reposition handles to line up with ends of selection + JSONObject args = new JSONObject(); + try { + args.put("handleType", mHandleType.toString()); + } catch (Exception e) { + Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Position"); + } + //GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Position", args.toString())); + break; + } + case MotionEvent.ACTION_MOVE: { + move(Math.round(event.getX()), Math.round(event.getY())); + break; + } + } + return true; + } + + private void move(int newX, int newY) { + mLeft = mLeft + newX - mTouchStartX; + mTop = mTop + newY - mTouchStartY; + + LayerView layerView = LOKitShell.getLayerView(); + if (layerView == null) { + Log.e(LOGTAG, "Can't move selection because layerView is null"); + return; + } + // Send x coordinate on the right side of the start handle, left side of the end handle. + float left = (float) mLeft; + if (mHandleType.equals(HandleType.START)) + left += mWidth - mShadow; + else if (mHandleType.equals(HandleType.MIDDLE)) + left += (float) ((mWidth - mShadow) / 2); + else + left += mShadow; + + PointF geckoPoint = new PointF(left, (float) mTop); + geckoPoint = layerView.getLayerClient().convertViewPointToLayerPoint(geckoPoint); + + JSONObject args = new JSONObject(); + try { + args.put("handleType", mHandleType.toString()); + args.put("x", Math.round(geckoPoint.x)); + args.put("y", Math.round(geckoPoint.y)); + } catch (Exception e) { + Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Move"); + } + //GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Move", args.toString())); + + setLayoutPosition(); + } + + void positionFromGecko(int left, int top) { + Log.i(LOGTAG, "positionFromGecko: " + left + " " + top); + LayerView layerView = LOKitShell.getLayerView(); + if (layerView == null) { + Log.e(LOGTAG, "Can't position handle because layerView is null"); + return; + } + + mGeckoPoint = new PointF((float) left, (float) top); + ImmutableViewportMetrics metrics = layerView.getViewportMetrics(); + repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); + } + + void repositionWithViewport(float x, float y, float zoom) { + PointF viewPoint = new PointF((mGeckoPoint.x * zoom) - x, + (mGeckoPoint.y * zoom) - y); + + mLeft = Math.round(viewPoint.x); + if (mHandleType.equals(HandleType.START)) + mLeft -= mWidth - mShadow; + else if (mHandleType.equals(HandleType.MIDDLE)) + mLeft -= (float) ((mWidth - mShadow) / 2); + else + mLeft -= mShadow; + + mTop = Math.round(viewPoint.y); + + setLayoutPosition(); + } + + private void setLayoutPosition() { + if (mLayoutParams == null) { + mLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams(); + // Set negative right/bottom margins so that the handles can be dragged outside of + // the content area (if they are dragged to the left/top, the dyanmic margins set + // below will take care of that). + mLayoutParams.rightMargin = 0 - mWidth; + mLayoutParams.bottomMargin = 0 - mHeight; + } + + mLayoutParams.leftMargin = mLeft; + mLayoutParams.topMargin = mTop; + setLayoutParams(mLayoutParams); + } +}
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits