Avoid potential negative array index access to cached text.
[LibreOffice.git] / android / source / src / java / org / libreoffice / LOKitTileProvider.java
blob5d1cf12209dc773f2f50aa14b6daa78672378dd7
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9 package org.libreoffice;
11 import android.content.Context;
12 import android.graphics.Bitmap;
13 import android.graphics.PointF;
14 import android.os.Build;
15 import android.print.PrintAttributes;
16 import android.print.PrintDocumentAdapter;
17 import android.print.PrintManager;
18 import android.util.Log;
19 import android.view.KeyEvent;
20 import android.widget.Toast;
22 import org.json.JSONException;
23 import org.json.JSONObject;
24 import org.libreoffice.kit.DirectBufferAllocator;
25 import org.libreoffice.kit.Document;
26 import org.libreoffice.kit.LibreOfficeKit;
27 import org.libreoffice.kit.Office;
28 import org.mozilla.gecko.gfx.BufferedCairoImage;
29 import org.mozilla.gecko.gfx.CairoImage;
30 import org.mozilla.gecko.gfx.IntSize;
32 import java.io.File;
33 import java.nio.ByteBuffer;
35 /**
36 * LOKit implementation of TileProvider.
38 class LOKitTileProvider implements TileProvider {
39 private static final String LOGTAG = LOKitTileProvider.class.getSimpleName();
40 private static final int TILE_SIZE = 256;
41 private final float mTileWidth;
42 private final float mTileHeight;
43 private String mInputFile;
44 private Office mOffice;
45 private Document mDocument;
46 private final boolean mIsReady;
47 private final LibreOfficeMainActivity mContext;
49 private final float mDPI;
50 private float mWidthTwip;
51 private float mHeightTwip;
53 private final Document.MessageCallback mMessageCallback;
55 private final long objectCreationTime = System.currentTimeMillis();
57 /**
58 * Initialize LOKit and load the document.
59 * @param messageCallback - callback for messages retrieved from LOKit
60 * @param input - input path of the document
62 LOKitTileProvider(LibreOfficeMainActivity context, InvalidationHandler messageCallback, String input) {
63 mContext = context;
64 mMessageCallback = messageCallback;
66 LibreOfficeKit.putenv("SAL_LOG=+WARN+INFO");
67 LibreOfficeKit.init(mContext);
69 mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle());
70 mOffice.setMessageCallback(messageCallback);
71 mOffice.setOptionalFeatures(Document.LOK_FEATURE_DOCUMENT_PASSWORD);
72 mContext.setTileProvider(this);
73 mInputFile = input;
75 Log.i(LOGTAG, "====> Loading file '" + input + "'");
77 File fileToBeEncoded = new File(input);
78 String encodedFileName = android.net.Uri.encode(fileToBeEncoded.getName());
80 mDocument = mOffice.documentLoad(
81 (new File(fileToBeEncoded.getParent(),encodedFileName)).getPath()
84 if (mDocument == null && !mContext.isPasswordProtected()) {
85 Log.i(LOGTAG, "====> mOffice.documentLoad() returned null, trying to restart 'Office' and loading again");
86 mOffice.destroy();
87 Log.i(LOGTAG, "====> mOffice.destroy() done");
88 ByteBuffer handle = LibreOfficeKit.getLibreOfficeKitHandle();
89 Log.i(LOGTAG, "====> getLibreOfficeKitHandle() = " + handle);
90 mOffice = new Office(handle);
91 Log.i(LOGTAG, "====> new Office created");
92 mOffice.setMessageCallback(messageCallback);
93 mOffice.setOptionalFeatures(Document.LOK_FEATURE_DOCUMENT_PASSWORD);
94 Log.i(LOGTAG, "====> setup Lokit callback and optional features (password support)");
95 mDocument = mOffice.documentLoad(
96 (new File(fileToBeEncoded.getParent(),encodedFileName)).getPath()
100 Log.i(LOGTAG, "====> mDocument = " + mDocument);
102 mDPI = LOKitShell.getDpi(mContext);
103 mTileWidth = pixelToTwip(TILE_SIZE, mDPI);
104 mTileHeight = pixelToTwip(TILE_SIZE, mDPI);
106 if (mDocument != null)
107 mDocument.initializeForRendering();
109 if (checkDocument()) {
110 postLoad();
111 mIsReady = true;
112 } else {
113 mIsReady = false;
118 * Triggered after the document is loaded.
120 private void postLoad() {
121 mDocument.setMessageCallback(mMessageCallback);
123 resetParts();
124 // Writer documents always have one part, so hide the navigation drawer.
125 if (mDocument.getDocumentType() == Document.DOCTYPE_TEXT) {
126 mContext.disableNavigationDrawer();
127 mContext.getToolbarController().hideItem(R.id.action_parts);
130 // Enable headers for Calc documents
131 if (mDocument.getDocumentType() == Document.DOCTYPE_SPREADSHEET) {
132 mContext.initializeCalcHeaders();
135 mDocument.setPart(0);
137 setupDocumentFonts();
139 LOKitShell.getMainHandler().post(new Runnable() {
140 @Override
141 public void run() {
142 mContext.getDocumentPartViewListAdapter().notifyDataSetChanged();
147 public void addPart(){
148 int parts = mDocument.getParts();
149 if(mDocument.getDocumentType() == Document.DOCTYPE_SPREADSHEET){
150 try{
151 JSONObject jsonObject = new JSONObject();
152 JSONObject values = new JSONObject();
153 JSONObject values2 = new JSONObject();
154 values.put("type", "long");
155 values.put("value", 0); //add to the last
156 values2.put("type", "string");
157 values2.put("value", "");
158 jsonObject.put("Name", values2);
159 jsonObject.put("Index", values);
160 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:Insert", jsonObject.toString()));
161 }catch (JSONException e) {
162 e.printStackTrace();
164 } else if (mDocument.getDocumentType() == Document.DOCTYPE_PRESENTATION){
165 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:InsertPage"));
168 String partName = mDocument.getPartName(parts);
169 if (partName.isEmpty()) {
170 partName = getGenericPartName(parts);
172 mDocument.setPart(parts);
173 resetDocumentSize();
174 final DocumentPartView partView = new DocumentPartView(parts, partName);
175 mContext.getDocumentPartView().add(partView);
178 public void resetParts(){
179 mContext.getDocumentPartView().clear();
180 if (mDocument.getDocumentType() != Document.DOCTYPE_TEXT) {
181 int parts = mDocument.getParts();
182 for (int i = 0; i < parts; i++) {
183 String partName = mDocument.getPartName(i);
185 if (partName.isEmpty()) {
186 partName = getGenericPartName(i);
188 Log.i(LOGTAG, "resetParts: " + partName);
189 mDocument.setPart(i);
190 resetDocumentSize();
191 final DocumentPartView partView = new DocumentPartView(i, partName);
192 mContext.getDocumentPartView().add(partView);
197 public void renamePart(String partName) {
198 try{
199 for(int i=0; i<mDocument.getParts(); i++){
200 if(mContext.getDocumentPartView().get(i).partName.equals(partName)){
201 //part name must be unique
202 Toast.makeText(mContext, mContext.getString(R.string.name_already_used), Toast.LENGTH_SHORT).show();
203 return;
206 JSONObject parameter = new JSONObject();
207 JSONObject name = new JSONObject();
208 name.put("type", "string");
209 name.put("value", partName);
210 parameter.put("Name", name);
211 if(isPresentation()){
212 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND_NOTIFY, ".uno:RenamePage", parameter.toString(),true));
213 }else {
214 JSONObject index = new JSONObject();
215 index.put("type","long");
216 index.put("value", getCurrentPartNumber()+1);
217 parameter.put("Index", index);
218 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND_NOTIFY, ".uno:Name", parameter.toString(),true));
220 }catch (JSONException e){
221 e.printStackTrace();
225 public void removePart() {
226 try{
227 if (!isSpreadsheet() && !isPresentation()) {
228 //document must be spreadsheet or presentation
229 return;
232 if(isPresentation()){
233 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND_NOTIFY, ".uno:DeletePage", true));
234 return;
237 if(getPartsCount() < 2){
238 return;
241 JSONObject parameter = new JSONObject();
242 JSONObject index = new JSONObject();
243 index.put("type","long");
244 index.put("value", getCurrentPartNumber()+1);
245 parameter.put("Index", index);
246 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND_NOTIFY, ".uno:Remove", parameter.toString(),true));
247 }catch (JSONException e){
248 e.printStackTrace();
252 @Override
253 public boolean saveDocumentAs(final String filePath, String format, boolean takeOwnership) {
254 String options = "";
255 if (takeOwnership) {
256 options = "TakeOwnership";
259 final String newFilePath = "file://" + filePath;
260 Log.d("saveFilePathURL", newFilePath);
261 LOKitShell.showProgressSpinner(mContext);
262 mDocument.saveAs(newFilePath, format, options);
263 final boolean ok;
264 if (!mOffice.getError().isEmpty()){
265 ok = true;
266 Log.e("Save Error", mOffice.getError());
267 if (format.equals("svg")) {
268 // error in creating temp slideshow svg file
269 Log.d(LOGTAG, "Error in creating temp slideshow svg file");
270 } else if(format.equals("pdf")){
271 Log.d(LOGTAG, "Error in creating pdf file");
272 } else {
273 LOKitShell.getMainHandler().post(new Runnable() {
274 @Override
275 public void run() {
276 // There was some error
277 mContext.showCustomStatusMessage(mContext.getString(R.string.unable_to_save));
281 } else {
282 ok = false;
283 if (format.equals("svg")) {
284 // successfully created temp slideshow svg file
285 LOKitShell.getMainHandler().post(new Runnable() {
286 @Override
287 public void run() {
288 mContext.startPresentation(newFilePath);
291 } else if (takeOwnership) {
292 mInputFile = filePath;
295 LOKitShell.hideProgressSpinner(mContext);
296 return ok;
299 @Override
300 public boolean saveDocumentAs(final String filePath, boolean takeOwnership) {
301 final int docType = mDocument.getDocumentType();
302 if (docType == Document.DOCTYPE_TEXT)
303 return saveDocumentAs(filePath, "odt", takeOwnership);
304 else if (docType == Document.DOCTYPE_SPREADSHEET)
305 return saveDocumentAs(filePath, "ods", takeOwnership);
306 else if (docType == Document.DOCTYPE_PRESENTATION)
307 return saveDocumentAs(filePath, "odp", takeOwnership);
308 else if (docType == Document.DOCTYPE_DRAWING)
309 return saveDocumentAs(filePath, "odg", takeOwnership);
311 Log.w(LOGTAG, "Cannot determine file format from document. Not saving.");
312 return false;
315 public void printDocument() {
316 String mInputFileName = (new File(mInputFile)).getName();
317 String file = mInputFileName.substring(0,(mInputFileName.length()-3))+"pdf";
318 String cacheFile = mContext.getExternalCacheDir().getAbsolutePath() + "/" + file;
319 mDocument.saveAs("file://"+cacheFile,"pdf","");
320 try {
321 PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
322 PrintDocumentAdapter printAdapter = new PDFDocumentAdapter(mContext, cacheFile);
323 printManager.print("Document", printAdapter, new PrintAttributes.Builder().build());
325 } catch (Exception e) {
326 e.printStackTrace();
330 public void saveDocument(){
331 mContext.saveDocument();
334 private void setupDocumentFonts() {
335 String values = mDocument.getCommandValues(".uno:CharFontName");
336 if (values == null || values.isEmpty())
337 return;
339 mContext.getFontController().parseJson(values);
340 mContext.getFontController().setupFontViews();
343 private String getGenericPartName(int i) {
344 if (mDocument == null) {
345 return "";
347 switch (mDocument.getDocumentType()) {
348 case Document.DOCTYPE_DRAWING:
349 case Document.DOCTYPE_TEXT:
350 return mContext.getString(R.string.page) + " " + (i + 1);
351 case Document.DOCTYPE_SPREADSHEET:
352 return mContext.getString(R.string.sheet) + " " + (i + 1);
353 case Document.DOCTYPE_PRESENTATION:
354 return mContext.getString(R.string.slide) + " " + (i + 1);
355 case Document.DOCTYPE_OTHER:
356 default:
357 return mContext.getString(R.string.part) + " " + (i + 1);
361 static float twipToPixel(float input, float dpi) {
362 return input / 1440.0f * dpi;
365 private static float pixelToTwip(float input, float dpi) {
366 return (input / dpi) * 1440.0f;
371 * @see TileProvider#getPartsCount()
373 @Override
374 public int getPartsCount() {
375 return mDocument.getParts();
379 * Wrapper for getPartPageRectangles() JNI function.
381 public String getPartPageRectangles() {
382 return mDocument.getPartPageRectangles();
386 * Fetch Calc header information.
388 public String getCalcHeaders() {
389 long nX = 0;
390 long nY = 0;
391 long nWidth = mDocument.getDocumentWidth();
392 long nHeight = mDocument.getDocumentHeight();
393 return mDocument.getCommandValues(".uno:ViewRowColumnHeaders?x=" + nX + "&y=" + nY
394 + "&width=" + nWidth + "&height=" + nHeight);
398 * @see TileProvider#onSwipeLeft()
400 @Override
401 public void onSwipeLeft() {
402 if (mDocument.getDocumentType() == Document.DOCTYPE_PRESENTATION &&
403 getCurrentPartNumber() < getPartsCount()-1) {
404 LOKitShell.sendChangePartEvent(getCurrentPartNumber()+1);
409 * @see TileProvider#onSwipeRight()
411 @Override
412 public void onSwipeRight() {
413 if (mDocument.getDocumentType() == Document.DOCTYPE_PRESENTATION &&
414 getCurrentPartNumber() > 0) {
415 LOKitShell.sendChangePartEvent(getCurrentPartNumber()-1);
419 private boolean checkDocument() {
420 String error = null;
421 boolean ret;
423 if (mDocument == null || !mOffice.getError().isEmpty()) {
424 error = "Cannot open " + mInputFile + ": " + mOffice.getError();
425 ret = false;
426 } else {
427 ret = resetDocumentSize();
428 if (!ret) {
429 error = "Document returned an invalid size or the document is empty.";
433 if (!ret && !mContext.isPasswordProtected()) {
434 final String message = error;
435 LOKitShell.getMainHandler().post(new Runnable() {
436 @Override
437 public void run() {
438 mContext.showAlertDialog(message);
441 } else if (!ret && mContext.isPasswordProtected()) {
442 mContext.finish();
445 return ret;
448 private boolean resetDocumentSize() {
449 mWidthTwip = mDocument.getDocumentWidth();
450 mHeightTwip = mDocument.getDocumentHeight();
452 if (mWidthTwip == 0 || mHeightTwip == 0) {
453 Log.e(LOGTAG, "Document size zero - last error: " + mOffice.getError());
454 return false;
455 } else {
456 Log.i(LOGTAG, "Reset document size: " + mDocument.getDocumentWidth() + " x " + mDocument.getDocumentHeight());
459 return true;
462 @Override
463 public void setDocumentSize(int pageWidth, int pageHeight){
464 mWidthTwip = pageWidth;
465 mHeightTwip = pageHeight;
469 * @see TileProvider#getPageWidth()
471 @Override
472 public int getPageWidth() {
473 return (int) twipToPixel(mWidthTwip, mDPI);
477 * @see TileProvider#getPageHeight()
479 @Override
480 public int getPageHeight() {
481 return (int) twipToPixel(mHeightTwip, mDPI);
485 * @see TileProvider#isReady()
487 @Override
488 public boolean isReady() {
489 return mIsReady;
493 * @see TileProvider#createTile(float, float, org.mozilla.gecko.gfx.IntSize, float)
495 @Override
496 public CairoImage createTile(float x, float y, IntSize tileSize, float zoom) {
497 ByteBuffer buffer = DirectBufferAllocator.guardedAllocate(tileSize.width * tileSize.height * 4);
498 if (buffer == null)
499 return null;
501 CairoImage image = new BufferedCairoImage(buffer, tileSize.width, tileSize.height, CairoImage.FORMAT_ARGB32);
502 rerenderTile(image, x, y, tileSize, zoom);
503 return image;
507 * @see TileProvider#rerenderTile(org.mozilla.gecko.gfx.CairoImage, float, float, org.mozilla.gecko.gfx.IntSize, float)
509 @Override
510 public void rerenderTile(CairoImage image, float x, float y, IntSize tileSize, float zoom) {
511 if (mDocument != null && image.getBuffer() != null) {
512 float twipX = pixelToTwip(x, mDPI) / zoom;
513 float twipY = pixelToTwip(y, mDPI) / zoom;
514 float twipWidth = mTileWidth / zoom;
515 float twipHeight = mTileHeight / zoom;
516 long start = System.currentTimeMillis() - objectCreationTime;
518 //Log.i(LOGTAG, "paintTile >> @" + start + " (" + tileSize.width + " " + tileSize.height + " " + (int) twipX + " " + (int) twipY + " " + (int) twipWidth + " " + (int) twipHeight + ")");
519 mDocument.paintTile(image.getBuffer(), tileSize.width, tileSize.height, (int) twipX, (int) twipY, (int) twipWidth, (int) twipHeight);
521 long stop = System.currentTimeMillis() - objectCreationTime;
522 //Log.i(LOGTAG, "paintTile << @" + stop + " elapsed: " + (stop - start));
523 } else {
524 if (mDocument == null) {
525 Log.e(LOGTAG, "Document is null!!");
531 * @see TileProvider#thumbnail(int)
533 @Override
534 public Bitmap thumbnail(int size) {
535 int widthPixel = getPageWidth();
536 int heightPixel = getPageHeight();
538 if (widthPixel > heightPixel) {
539 double ratio = heightPixel / (double) widthPixel;
540 widthPixel = size;
541 heightPixel = (int) (widthPixel * ratio);
542 } else {
543 double ratio = widthPixel / (double) heightPixel;
544 heightPixel = size;
545 widthPixel = (int) (heightPixel * ratio);
548 Log.w(LOGTAG, "Thumbnail size: " + getPageWidth() + " " + getPageHeight() + " " + widthPixel + " " + heightPixel);
550 ByteBuffer buffer = ByteBuffer.allocateDirect(widthPixel * heightPixel * 4);
551 if (mDocument != null)
552 mDocument.paintTile(buffer, widthPixel, heightPixel, 0, 0, (int) mWidthTwip, (int) mHeightTwip);
554 Bitmap bitmap = null;
555 try {
556 bitmap = Bitmap.createBitmap(widthPixel, heightPixel, Bitmap.Config.ARGB_8888);
557 bitmap.copyPixelsFromBuffer(buffer);
558 } catch (IllegalArgumentException e) {
559 Log.e(LOGTAG, "width (" + widthPixel + ") and height (" + heightPixel + ") must not be 0! (ToDo: likely timing issue)");
561 if (bitmap == null) {
562 Log.w(LOGTAG, "Thumbnail not created!");
564 return bitmap;
568 * @see TileProvider#close()
570 @Override
571 public void close() {
572 Log.i(LOGTAG, "Document destroyed: " + mInputFile);
573 if (mDocument != null) {
574 mDocument.destroy();
575 mDocument = null;
580 * @see TileProvider#isDrawing()
582 @Override
583 public boolean isDrawing() {
584 return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_DRAWING;
588 * @see TileProvider#isTextDocument()
590 @Override
591 public boolean isTextDocument() {
592 return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_TEXT;
596 * @see TileProvider#isSpreadsheet()
598 @Override
599 public boolean isSpreadsheet() {
600 return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_SPREADSHEET;
604 * @see TileProvider#isPresentation()
606 @Override
607 public boolean isPresentation(){
608 return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_PRESENTATION;
612 * Returns the Unicode character generated by this event or 0.
614 private int getCharCode(KeyEvent keyEvent) {
615 switch (keyEvent.getKeyCode())
617 case KeyEvent.KEYCODE_DEL:
618 case KeyEvent.KEYCODE_ENTER:
619 return 0;
621 return keyEvent.getUnicodeChar();
625 * Returns the integer code representing the key of the event (non-zero for
626 * control keys).
628 private int getKeyCode(KeyEvent keyEvent) {
629 switch (keyEvent.getKeyCode()) {
630 case KeyEvent.KEYCODE_DEL:
631 return com.sun.star.awt.Key.BACKSPACE;
632 case KeyEvent.KEYCODE_ENTER:
633 return com.sun.star.awt.Key.RETURN;
635 return 0;
639 * @see TileProvider#sendKeyEvent(android.view.KeyEvent)
641 @Override
642 public void sendKeyEvent(KeyEvent keyEvent) {
643 switch (keyEvent.getAction()) {
644 case KeyEvent.ACTION_MULTIPLE:
645 String keyString = keyEvent.getCharacters();
646 for (int i = 0; i < keyString.length(); i++) {
647 int codePoint = keyString.codePointAt(i);
648 mDocument.postKeyEvent(Document.KEY_EVENT_PRESS, codePoint, getKeyCode(keyEvent));
650 break;
651 case KeyEvent.ACTION_DOWN:
652 mDocument.postKeyEvent(Document.KEY_EVENT_PRESS, getCharCode(keyEvent), getKeyCode(keyEvent));
653 break;
654 case KeyEvent.ACTION_UP:
655 mDocument.postKeyEvent(Document.KEY_EVENT_RELEASE, getCharCode(keyEvent), getKeyCode(keyEvent));
656 break;
660 private void mouseButton(int type, PointF inDocument, int numberOfClicks, float zoomFactor) {
661 int x = (int) pixelToTwip(inDocument.x, mDPI);
662 int y = (int) pixelToTwip(inDocument.y, mDPI);
664 mDocument.setClientZoom(TILE_SIZE, TILE_SIZE, (int) (mTileWidth / zoomFactor), (int) (mTileHeight / zoomFactor));
665 mDocument.postMouseEvent(type, x, y, numberOfClicks, Document.MOUSE_BUTTON_LEFT, Document.KEYBOARD_MODIFIER_NONE);
669 * @see TileProvider#mouseButtonDown(android.graphics.PointF, int, float)
671 @Override
672 public void mouseButtonDown(PointF documentCoordinate, int numberOfClicks, float zoomFactor) {
673 mouseButton(Document.MOUSE_EVENT_BUTTON_DOWN, documentCoordinate, numberOfClicks, zoomFactor);
677 * @see TileProvider#mouseButtonUp(android.graphics.PointF, int, float)
679 @Override
680 public void mouseButtonUp(PointF documentCoordinate, int numberOfClicks, float zoomFactor) {
681 mouseButton(Document.MOUSE_EVENT_BUTTON_UP, documentCoordinate, numberOfClicks, zoomFactor);
685 * @param command UNO command string
686 * @param arguments Arguments to UNO command
688 @Override
689 public void postUnoCommand(String command, String arguments) {
690 postUnoCommand(command, arguments, false);
694 * @param command
695 * @param arguments
696 * @param notifyWhenFinished
698 @Override
699 public void postUnoCommand(String command, String arguments, boolean notifyWhenFinished) {
700 mDocument.postUnoCommand(command, arguments, notifyWhenFinished);
703 private void setTextSelection(int type, PointF documentCoordinate) {
704 int x = (int) pixelToTwip(documentCoordinate.x, mDPI);
705 int y = (int) pixelToTwip(documentCoordinate.y, mDPI);
706 mDocument.setTextSelection(type, x, y);
710 * @see TileProvider#setTextSelectionStart(android.graphics.PointF)
712 @Override
713 public void setTextSelectionStart(PointF documentCoordinate) {
714 setTextSelection(Document.SET_TEXT_SELECTION_START, documentCoordinate);
718 * @see TileProvider#setTextSelectionEnd(android.graphics.PointF)
720 @Override
721 public void setTextSelectionEnd(PointF documentCoordinate) {
722 setTextSelection(Document.SET_TEXT_SELECTION_END, documentCoordinate);
726 * @see TileProvider#setTextSelectionReset(android.graphics.PointF)
728 @Override
729 public void setTextSelectionReset(PointF documentCoordinate) {
730 setTextSelection(Document.SET_TEXT_SELECTION_RESET, documentCoordinate);
734 * @param mimeType
735 * @return
737 @Override
738 public String getTextSelection(String mimeType) {
739 return mDocument.getTextSelection(mimeType);
743 * paste
744 * @param mimeType
745 * @param data
746 * @return
748 @Override
749 public boolean paste(String mimeType, String data) {
750 return mDocument.paste(mimeType, data);
755 * @see org.libreoffice.TileProvider#setGraphicSelectionStart(android.graphics.PointF)
757 @Override
758 public void setGraphicSelectionStart(PointF documentCoordinate) {
759 setGraphicSelection(Document.SET_GRAPHIC_SELECTION_START, documentCoordinate);
763 * @see org.libreoffice.TileProvider#setGraphicSelectionEnd(android.graphics.PointF)
765 @Override
766 public void setGraphicSelectionEnd(PointF documentCoordinate) {
767 setGraphicSelection(Document.SET_GRAPHIC_SELECTION_END, documentCoordinate);
770 private void setGraphicSelection(int type, PointF documentCoordinate) {
771 int x = (int) pixelToTwip(documentCoordinate.x, mDPI);
772 int y = (int) pixelToTwip(documentCoordinate.y, mDPI);
773 LibreOfficeMainActivity.setDocumentChanged(true);
774 mDocument.setGraphicSelection(type, x, y);
777 @Override
778 protected void finalize() throws Throwable {
779 close();
780 super.finalize();
784 * @see TileProvider#changePart(int)
786 @Override
787 public void changePart(int partIndex) {
788 if (mDocument == null)
789 return;
791 mDocument.setPart(partIndex);
792 resetDocumentSize();
796 * @see TileProvider#getCurrentPartNumber()
798 @Override
799 public int getCurrentPartNumber() {
800 if (mDocument == null)
801 return 0;
803 return mDocument.getPart();
806 public void setDocumentPassword(String url, String password) {
807 mOffice.setDocumentPassword(url, password);
810 public Document.MessageCallback getMessageCallback() {
811 return mMessageCallback;
815 // vim:set shiftwidth=4 softtabstop=4 expandtab: