Kaydet (Commit) 02f3c484 authored tarafından Ximeng Zu's avatar Ximeng Zu Kaydeden (comit) Tomaž Vajngerl

Calc UI on Android Viewer

Adding Calc UI. Two blank views are added as
row and column headers. CommonCanvasElement
is used to draw header cells on the views. [WIP]

Change-Id: I37eaa82805045ab650fd127e54c8421c61a4ea27
Reviewed-on: https://gerrit.libreoffice.org/38936Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
Tested-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
üst fadf31b3
......@@ -36,22 +36,53 @@
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:id="@+id/gecko_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="match_parent">
<org.mozilla.gecko.gfx.LayerView
android:id="@+id/layer_view"
<View
android:id="@+id/calc_header_top_left"
android:layout_width="@dimen/calc_header_width"
android:layout_height="@dimen/calc_header_height"
android:visibility="gone"/>
<org.libreoffice.overlay.CalcHeadersView
android:id="@+id/calc_header_column"
android:layout_width="match_parent"
android:layout_height="@dimen/calc_header_height"
android:layout_toRightOf="@+id/calc_header_top_left"
android:layout_toEndOf="@+id/calc_header_top_left"
android:visibility="gone"/>
<org.libreoffice.overlay.CalcHeadersView
android:id="@+id/calc_header_row"
android:layout_width="@dimen/calc_header_width"
android:layout_height="match_parent"
android:layout_below="@+id/calc_header_top_left"
android:visibility="gone"/>
<RelativeLayout
android:id="@+id/gecko_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_toRightOf="@+id/calc_header_row"
android:layout_toEndOf="@+id/calc_header_row"
android:layout_below="@+id/calc_header_column">
<org.mozilla.gecko.gfx.LayerView
android:id="@+id/layer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<org.libreoffice.overlay.DocumentOverlayView
android:id="@+id/text_cursor_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<org.libreoffice.overlay.DocumentOverlayView
android:id="@+id/text_cursor_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
<include layout="@layout/toolbar_bottom"/>
......
......@@ -9,4 +9,6 @@
<dimen name="list_item_margin">8dp</dimen>
<dimen name="file_icon_width">32dp</dimen>
<dimen name="toolbar_height">256dp</dimen>
<dimen name="calc_header_width">48dp</dimen>
<dimen name="calc_header_height">24dp</dimen>
</resources>
......@@ -38,6 +38,7 @@ public class LOEvent implements Comparable<LOEvent> {
public static final int SAVE_AS = 17;
public static final int UPDATE_PART_PAGE_RECT = 18;
public static final int UPDATE_ZOOM_CONSTRAINTS = 19;
public static final int UPDATE_CALC_HEADERS = 20;
public final int mType;
public int mPriority = 0;
......
......@@ -156,6 +156,9 @@ class LOKitThread extends Thread {
mLayerClient.clearAndResetlayers();
redraw();
updatePartPageRectangles();
if (mTileProvider.isSpreadsheet()) {
updateCalcHeaders();
}
}
/**
......@@ -170,11 +173,15 @@ class LOKitThread extends Thread {
private void updateZoomConstraints() {
mLayerClient = mContext.getLayerClient();
// Set min zoom to the page width so that you cannot zoom below page width
// applies to all types of document; in the future spreadsheets may be singled out
float minZoom = mLayerClient.getViewportMetrics().getWidth()/mTileProvider.getPageWidth();
mLayerClient.setZoomConstraints(new ZoomConstraints(true, 0.0f, minZoom, 0.0f));
if (mTileProvider.isSpreadsheet()) {
// Calc has a fixed zoom at 1x and doesn't allow zooming for now
mLayerClient.setZoomConstraints(new ZoomConstraints(false, 1f, 0f, 0f));
} else {
// Set min zoom to the page width so that you cannot zoom below page width
// applies to all types of document; in the future spreadsheets may be singled out
float minZoom = mLayerClient.getViewportMetrics().getWidth()/mTileProvider.getPageWidth();
mLayerClient.setZoomConstraints(new ZoomConstraints(true, 1f, minZoom, 0f));
}
}
......@@ -343,9 +350,19 @@ class LOKitThread extends Thread {
case LOEvent.UPDATE_ZOOM_CONSTRAINTS:
updateZoomConstraints();
break;
case LOEvent.UPDATE_CALC_HEADERS:
updateCalcHeaders();
break;
}
}
private void updateCalcHeaders() {
LOKitTileProvider tileProvider = (LOKitTileProvider)mTileProvider;
String values = tileProvider.getCalcHeaders();
mContext.getCalcHeadersController().setHeaders(values);
}
/**
* Request a change of the handle position.
*/
......
......@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
*/
class LOKitTileProvider implements TileProvider {
private static final String LOGTAG = LOKitTileProvider.class.getSimpleName();
private static final float DPI_1X_ZOOM = 96f; // for use in Calc at fixed zoom 1x
private static int TILE_SIZE = 256;
private final float mTileWidth;
private final float mTileHeight;
......@@ -53,9 +54,6 @@ class LOKitTileProvider implements TileProvider {
LOKitTileProvider(LibreOfficeMainActivity context, Document.MessageCallback messageCallback, String input) {
mContext = context;
mMessageCallback = messageCallback;
mDPI = LOKitShell.getDpi(mContext);
mTileWidth = pixelToTwip(TILE_SIZE, mDPI);
mTileHeight = pixelToTwip(TILE_SIZE, mDPI);
LibreOfficeKit.putenv("SAL_LOG=+WARN+INFO");
LibreOfficeKit.init(mContext);
......@@ -80,6 +78,15 @@ class LOKitTileProvider implements TileProvider {
Log.i(LOGTAG, "====> mDocument = " + mDocument);
if(isSpreadsheet()) {
mDPI = DPI_1X_ZOOM; // Calc has a fixed zoom at 1x
} else {
mDPI = LOKitShell.getDpi(mContext);
}
mTileWidth = pixelToTwip(TILE_SIZE, mDPI);
mTileHeight = pixelToTwip(TILE_SIZE, mDPI);
if (mDocument != null)
mDocument.initializeForRendering();
......@@ -124,6 +131,11 @@ class LOKitTileProvider implements TileProvider {
mContext.getToolbarController().disableMenuItem(R.id.action_parts, true);
}
// Enable headers for Calc documents
if (mDocument.getDocumentType() == Document.DOCTYPE_SPREADSHEET) {
mContext.initializeCalcHeaders();
}
mDocument.setPart(0);
setupDocumentFonts();
......@@ -229,6 +241,18 @@ class LOKitTileProvider implements TileProvider {
return mDocument.getPartPageRectangles();
}
/**
* Fetch Calc header information.
*/
public String getCalcHeaders() {
long nX = 0;
long nY = 0;
long nWidth = mDocument.getDocumentWidth();
long nHeight = mDocument.getDocumentHeight();
return mDocument.getCommandValues(".uno:ViewRowColumnHeaders?x=" + nX + "&y=" + nY
+ "&width=" + nWidth + "&height=" + nHeight);
}
/**
* @see TileProvider#onSwipeLeft()
*/
......
......@@ -33,6 +33,7 @@ import android.widget.ListView;
import android.widget.TabHost;
import android.widget.Toast;
import org.libreoffice.overlay.CalcHeadersController;
import org.libreoffice.overlay.DocumentOverlay;
import org.libreoffice.storage.DocumentProviderFactory;
import org.libreoffice.storage.IFile;
......@@ -91,6 +92,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
private ToolbarController mToolbarController;
private FontController mFontController;
private SearchController mSearchController;
private CalcHeadersController mCalcHeadersController;
public GeckoLayerClient getLayerClient() {
return mLayerClient;
......@@ -645,6 +647,10 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
return mDocumentOverlay;
}
public CalcHeadersController getCalcHeadersController() {
return mCalcHeadersController;
}
public ToolbarController getToolbarController() {
return mToolbarController;
}
......@@ -685,6 +691,18 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
}
}
public void initializeCalcHeaders() {
mCalcHeadersController = new CalcHeadersController(this, mLayerClient.getView());
LOKitShell.getMainHandler().post(new Runnable() {
@Override
public void run() {
findViewById(R.id.calc_header_top_left).setVisibility(View.VISIBLE);
findViewById(R.id.calc_header_row).setVisibility(View.VISIBLE);
findViewById(R.id.calc_header_column).setVisibility(View.VISIBLE);
}
});
}
private class DocumentPartClickListener implements android.widget.AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
......
package org.libreoffice.canvas;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.text.TextPaint;
public class CalcHeaderCell extends CommonCanvasElement {
private TextPaint mTextPaint = new TextPaint();
private Paint mBgPaint = new Paint();
private RectF mBounds;
private String mText;
public CalcHeaderCell(float left, float top, float width, float height, String text) {
mBounds = new RectF(left, top, left + width, top + height);
mBgPaint.setStyle(Style.STROKE);
mBgPaint.setColor(Color.GRAY);
mBgPaint.setAlpha(100); // hard coded for now
mTextPaint.setColor(Color.GRAY);
mTextPaint.setTextSize(24f); // hard coded for now
mText = text;
}
/**
* Implement hit test here
*
* @param x - x coordinate of the
* @param y - y coordinate of the
*/
@Override
public boolean onHitTest(float x, float y) {
return false;
}
/**
* Called inside draw if the element is visible. Override this method to
* draw the element on the canvas.
*
* @param canvas - the canvas
*/
@Override
public void onDraw(Canvas canvas) {
canvas.drawRect(mBounds, mBgPaint);
canvas.drawText(mText, mBounds.left, mBounds.bottom, mTextPaint);
}
}
\ No newline at end of file
package org.libreoffice.overlay;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.libreoffice.LOEvent;
import org.libreoffice.LOKitShell;
import org.libreoffice.LibreOfficeMainActivity;
import org.libreoffice.R;
import org.mozilla.gecko.gfx.LayerView;
import java.util.ArrayList;
public class CalcHeadersController {
private static final String LOGTAG = CalcHeadersController.class.getSimpleName();
private static final float DPI_1X_ZOOM = 96f; // Calc uses a fixed zoom a 1x which is 96 dpi
private final CalcHeadersView mCalcRowHeadersView;
private final CalcHeadersView mCalcColumnHeadersView;
private LibreOfficeMainActivity mContext;
public CalcHeadersController(LibreOfficeMainActivity context, LayerView layerView) {
mContext = context;
mContext.getDocumentOverlay().setCalcHeadersController(this);
mCalcRowHeadersView = (CalcHeadersView) context.findViewById(R.id.calc_header_row);
mCalcColumnHeadersView = (CalcHeadersView) context.findViewById(R.id.calc_header_column);
if (mCalcColumnHeadersView == null || mCalcRowHeadersView == null) {
Log.e(LOGTAG, "Failed to initialize Calc headers - View is null");
} else {
mCalcRowHeadersView.initialize(layerView, true);
mCalcColumnHeadersView.initialize(layerView, false);
}
LOKitShell.sendEvent(new LOEvent(LOEvent.UPDATE_CALC_HEADERS));
}
public void setHeaders(String headers) {
HeaderInfo parsedHeaders = parseHeaderInfo(headers);
if (parsedHeaders != null) {
mCalcRowHeadersView.setHeaders(parsedHeaders.rowLabels, parsedHeaders.rowDimens);
mCalcColumnHeadersView.setHeaders(parsedHeaders.columnLabels, parsedHeaders.columnDimens);
showHeaders();
} else {
Log.e(LOGTAG, "Parse header info JSON failed.");
}
}
public void showHeaders() {
LOKitShell.getMainHandler().post(new Runnable() {
@Override
public void run() {
mCalcColumnHeadersView.invalidate();
mCalcRowHeadersView.invalidate();
}
});
}
private HeaderInfo parseHeaderInfo(String headers) {
HeaderInfo headerInfo = new HeaderInfo();
try {
JSONObject collectiveResult = new JSONObject(headers);
JSONArray rowResult = collectiveResult.getJSONArray("rows");
for (int i = 0; i < rowResult.length(); i++) {
headerInfo.rowLabels.add(rowResult.getJSONObject(i).getString("text"));
headerInfo.rowDimens.add(twipToPixel(rowResult.getJSONObject(i).getLong("size"), DPI_1X_ZOOM));
}
JSONArray columnResult = collectiveResult.getJSONArray("columns");
for (int i = 0; i < columnResult.length(); i++) {
headerInfo.columnLabels.add(columnResult.getJSONObject(i).getString("text"));
headerInfo.columnDimens.add(twipToPixel(columnResult.getJSONObject(i).getLong("size"), DPI_1X_ZOOM));
}
return headerInfo;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private float twipToPixel(float input, float dpi) {
return input / 1440.0f * dpi;
}
private class HeaderInfo {
ArrayList<String> rowLabels;
ArrayList<Float> rowDimens;
ArrayList<String> columnLabels;
ArrayList<Float> columnDimens;
private HeaderInfo() {
rowLabels = new ArrayList<String>();
rowDimens = new ArrayList<Float>();
columnDimens = new ArrayList<Float>();
columnLabels = new ArrayList<String>();
}
}
}
package org.libreoffice.overlay;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import org.libreoffice.canvas.CalcHeaderCell;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import java.util.ArrayList;
public class CalcHeadersView extends View implements View.OnTouchListener {
private boolean mInitialized;
private LayerView mLayerView;
private boolean mIsRow; // true if this is for row headers, false for column
private ArrayList<String> mLabels;
private ArrayList<Float> mDimens;
public CalcHeadersView(Context context) {
super(context);
}
public CalcHeadersView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CalcHeadersView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void initialize(LayerView layerView, boolean isRow) {
if (!mInitialized) {
setOnTouchListener(this);
mLayerView = layerView;
mIsRow = isRow;
mInitialized = true;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mInitialized && mDimens != null && mLabels != null) {
updateHeaders(canvas);
}
}
private void updateHeaders(Canvas canvas) {
ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics();
float zoom = metrics.getZoomFactor();
PointF origin = metrics.getOrigin();
boolean inRangeOfVisibleHeaders = false; // a helper variable for skipping unnecessary onDraw()'s
float top,bottom,left,right;
for (int i = 1; i < mLabels.size(); i++) {
if (mIsRow) {
top = -origin.y + zoom*mDimens.get(i-1);
bottom = -origin.y + zoom*mDimens.get(i);
if (top <= getHeight() && bottom >= 0) {
inRangeOfVisibleHeaders = true;
new CalcHeaderCell(0f, top, getWidth(), bottom - top, mLabels.get(i)).onDraw(canvas);
} else {
if (inRangeOfVisibleHeaders) {
break;
}
}
} else {
left = -origin.x + zoom*mDimens.get(i-1);
right = -origin.x + zoom*mDimens.get(i);
if (left <= getWidth() && right >= 0) {
new CalcHeaderCell(left, 0f, right - left, getHeight(), mLabels.get(i)).onDraw(canvas);
} else {
if (inRangeOfVisibleHeaders) {
break;
}
}
}
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
public void setHeaders(ArrayList<String> labels, ArrayList<Float> dimens) {
mLabels = labels;
mDimens = dimens;
}
}
......@@ -8,11 +8,11 @@
*/
package org.libreoffice.overlay;
import org.libreoffice.LibreOfficeMainActivity;
import android.graphics.RectF;
import android.util.Log;
import org.libreoffice.LOKitShell;
import org.libreoffice.LibreOfficeMainActivity;
import org.libreoffice.R;
import org.libreoffice.canvas.SelectionHandle;
import org.mozilla.gecko.gfx.Layer;
......@@ -237,6 +237,11 @@ public class DocumentOverlay {
public RectF getCurrentCursorPosition() {
return mDocumentOverlayView.getCurrentCursorPosition();
}
public void setCalcHeadersController(CalcHeadersController calcHeadersController) {
mDocumentOverlayView.setCalcHeadersController(calcHeadersController);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -67,6 +67,7 @@ public class DocumentOverlayView extends View implements View.OnTouchListener {
private PageNumberRect mPageNumberRect;
private boolean mPageNumberAvailable = false;
private int previousIndex = 0; // previous page number, used to compare with the current
private CalcHeadersController mCalcHeadersController;
public DocumentOverlayView(Context context) {
super(context);
......@@ -217,6 +218,9 @@ public class DocumentOverlayView extends View implements View.OnTouchListener {
mGraphicSelection.draw(canvas);
if (mCalcHeadersController != null) {
mCalcHeadersController.showHeaders();
}
}
/**
......@@ -450,6 +454,10 @@ public class DocumentOverlayView extends View implements View.OnTouchListener {
public RectF getCurrentCursorPosition() {
return mCursor.mPosition;
}
public void setCalcHeadersController(CalcHeadersController calcHeadersController) {
mCalcHeadersController = calcHeadersController;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -984,6 +984,9 @@ class JavaPanZoomController
@Override
public boolean onDoubleTap(MotionEvent motionEvent) {
if (!mTarget.getZoomConstraints().getAllowDoubleTapZoom()) {
return true;
}
// Double tap zooms in or out depending on the current zoom factor
PointF pointOfTap = getMotionInDocumentCoordinates(motionEvent);
ImmutableViewportMetrics metrics = getMetrics();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment