2015-06-04 22:09:57 +05:30
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2014-06-12 17:38:10 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* 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/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sal/types.h>
|
2015-01-14 17:57:47 +01:00
|
|
|
#include <math.h>
|
2015-01-16 15:47:51 +01:00
|
|
|
#include <string.h>
|
2015-03-31 12:50:36 +02:00
|
|
|
#include <vector>
|
2015-04-02 16:47:01 +02:00
|
|
|
#include <string>
|
2014-06-12 17:38:10 +01:00
|
|
|
|
2015-03-25 17:54:11 +01:00
|
|
|
#include <com/sun/star/awt/Key.hpp>
|
2014-06-12 17:38:10 +01:00
|
|
|
#define LOK_USE_UNSTABLE_API
|
|
|
|
#include <LibreOfficeKit/LibreOfficeKit.h>
|
2015-06-10 16:10:19 +05:30
|
|
|
#include <LibreOfficeKit/LibreOfficeKitInit.h>
|
2015-02-20 16:21:06 +01:00
|
|
|
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
|
2014-06-12 17:38:10 +01:00
|
|
|
#include <LibreOfficeKit/LibreOfficeKitGtk.h>
|
2015-03-25 17:54:11 +01:00
|
|
|
#include <rsc/rsc-vcl-shared-types.hxx>
|
2014-06-12 17:38:10 +01:00
|
|
|
|
2015-06-04 00:06:46 +05:30
|
|
|
#include "tilebuffer.hxx"
|
|
|
|
|
2015-01-27 14:36:12 +01:00
|
|
|
#if !GLIB_CHECK_VERSION(2,32,0)
|
2015-01-12 11:58:18 +00:00
|
|
|
#define G_SOURCE_REMOVE FALSE
|
2015-01-27 14:36:12 +01:00
|
|
|
#define G_SOURCE_CONTINUE TRUE
|
2015-01-12 11:58:18 +00:00
|
|
|
#endif
|
2015-04-03 10:19:16 +02:00
|
|
|
#if !GLIB_CHECK_VERSION(2,40,0)
|
2015-01-26 10:57:10 +01:00
|
|
|
#define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
|
|
|
|
#endif
|
2015-01-12 11:58:18 +00:00
|
|
|
|
2015-02-09 14:22:01 +01:00
|
|
|
// Cursor bitmaps from the Android app.
|
2015-06-11 22:00:11 +05:30
|
|
|
#define CURSOR_HANDLE_DIR "/android/source/res/drawable/"
|
2015-03-10 10:12:02 +01:00
|
|
|
// Number of handles around a graphic selection.
|
|
|
|
#define GRAPHIC_HANDLE_COUNT 8
|
2015-02-09 14:22:01 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
struct _LOKDocViewPrivate
|
2015-03-20 10:16:07 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
gchar* m_aLOPath;
|
|
|
|
gchar* m_aDocPath;
|
|
|
|
guint m_nLoadProgress;
|
|
|
|
gboolean m_bIsLoading;
|
|
|
|
gboolean m_bCanZoomIn;
|
|
|
|
gboolean m_bCanZoomOut;
|
2015-03-20 10:16:07 +01:00
|
|
|
LibreOfficeKit* m_pOffice;
|
|
|
|
LibreOfficeKitDocument* m_pDocument;
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
TileBuffer m_aTileBuffer;
|
|
|
|
|
|
|
|
gfloat m_fZoom;
|
|
|
|
glong m_nDocumentWidthTwips;
|
|
|
|
glong m_nDocumentHeightTwips;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// View or edit mode.
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bEdit;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Position and size of the visible cursor.
|
|
|
|
GdkRectangle m_aVisibleCursor;
|
|
|
|
/// Cursor overlay is visible or hidden (for blinking).
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bCursorOverlayVisible;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Cursor is visible or hidden (e.g. for graphic selection).
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bCursorVisible;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Time of the last button press.
|
|
|
|
guint32 m_nLastButtonPressTime;
|
|
|
|
/// Time of the last button release.
|
|
|
|
guint32 m_nLastButtonReleaseTime;
|
|
|
|
/// Rectangles of the current text selection.
|
2015-03-31 12:50:36 +02:00
|
|
|
std::vector<GdkRectangle> m_aTextSelectionRectangles;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Position and size of the selection start (as if there would be a cursor caret there).
|
|
|
|
GdkRectangle m_aTextSelectionStart;
|
|
|
|
/// Position and size of the selection end.
|
|
|
|
GdkRectangle m_aTextSelectionEnd;
|
|
|
|
GdkRectangle m_aGraphicSelection;
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bInDragGraphicSelection;
|
2015-03-20 10:16:07 +01:00
|
|
|
|
|
|
|
/// @name Start/middle/end handle.
|
|
|
|
///@{
|
|
|
|
/// Bitmap of the text selection start handle.
|
|
|
|
cairo_surface_t* m_pHandleStart;
|
|
|
|
/// Rectangle of the text selection start handle, to know if the user clicked on it or not
|
|
|
|
GdkRectangle m_aHandleStartRect;
|
|
|
|
/// If we are in the middle of a drag of the text selection end handle.
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bInDragStartHandle;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Bitmap of the text selection middle handle.
|
|
|
|
cairo_surface_t* m_pHandleMiddle;
|
|
|
|
/// Rectangle of the text selection middle handle, to know if the user clicked on it or not
|
|
|
|
GdkRectangle m_aHandleMiddleRect;
|
|
|
|
/// If we are in the middle of a drag of the text selection middle handle.
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bInDragMiddleHandle;
|
2015-03-20 10:16:07 +01:00
|
|
|
/// Bitmap of the text selection end handle.
|
|
|
|
cairo_surface_t* m_pHandleEnd;
|
|
|
|
/// Rectangle of the text selection end handle, to know if the user clicked on it or not
|
|
|
|
GdkRectangle m_aHandleEndRect;
|
|
|
|
/// If we are in the middle of a drag of the text selection end handle.
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bInDragEndHandle;
|
2015-03-20 10:16:07 +01:00
|
|
|
///@}
|
|
|
|
|
|
|
|
/// @name Graphic handles.
|
|
|
|
///@{
|
|
|
|
/// Bitmap of a graphic selection handle.
|
|
|
|
cairo_surface_t* m_pGraphicHandle;
|
|
|
|
/// Rectangle of a graphic selection handle, to know if the user clicked on it or not.
|
|
|
|
GdkRectangle m_aGraphicHandleRects[8];
|
|
|
|
/// If we are in the middle of a drag of a graphic selection handle.
|
2015-06-11 22:00:11 +05:30
|
|
|
gboolean m_bInDragGraphicHandles[8];
|
2015-03-20 10:16:07 +01:00
|
|
|
///@}
|
|
|
|
};
|
|
|
|
|
2015-06-06 03:10:31 +05:30
|
|
|
enum
|
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOAD_CHANGED,
|
|
|
|
LOAD_FAILED,
|
2015-06-06 03:10:31 +05:30
|
|
|
EDIT_CHANGED,
|
|
|
|
COMMAND_CHANGED,
|
|
|
|
SEARCH_NOT_FOUND,
|
|
|
|
PART_CHANGED,
|
2015-06-11 22:00:11 +05:30
|
|
|
HYPERLINK_CLICKED,
|
|
|
|
|
2015-06-06 03:10:31 +05:30
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_LO_PATH,
|
|
|
|
PROP_DOC_PATH,
|
|
|
|
PROP_EDITABLE,
|
|
|
|
PROP_LOAD_PROGRESS,
|
|
|
|
PROP_ZOOM,
|
|
|
|
PROP_IS_LOADING,
|
|
|
|
PROP_DOC_WIDTH,
|
|
|
|
PROP_DOC_HEIGHT,
|
|
|
|
PROP_CAN_ZOOM_IN,
|
|
|
|
PROP_CAN_ZOOM_OUT
|
|
|
|
};
|
2015-06-06 03:10:31 +05:30
|
|
|
|
|
|
|
static guint doc_view_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
2015-06-18 21:52:22 +05:30
|
|
|
static void lok_doc_view_initable_iface_init (GInitableIface *iface);
|
|
|
|
|
2015-06-09 11:58:24 +02:00
|
|
|
SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
|
2015-06-09 11:57:56 +02:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
|
|
|
#endif
|
2015-06-18 21:52:22 +05:30
|
|
|
G_DEFINE_TYPE_WITH_CODE (LOKDocView, lok_doc_view, GTK_TYPE_DRAWING_AREA,
|
|
|
|
G_ADD_PRIVATE (LOKDocView)
|
|
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, lok_doc_view_initable_iface_init));
|
2015-06-09 11:57:56 +02:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
2015-06-06 03:10:31 +05:30
|
|
|
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
struct CallbackData
|
|
|
|
{
|
|
|
|
int m_nType;
|
|
|
|
std::string m_aPayload;
|
|
|
|
LOKDocView* m_pDocView;
|
|
|
|
|
|
|
|
CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView)
|
|
|
|
: m_nType(nType),
|
|
|
|
m_aPayload(rPayload),
|
|
|
|
m_pDocView(pDocView) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
|
2015-06-06 03:10:31 +05:30
|
|
|
{
|
|
|
|
rWidth = rHeight = 0;
|
|
|
|
gchar** ppCoordinates = g_strsplit(pPayload, ", ", 2);
|
|
|
|
gchar** ppCoordinate = ppCoordinates;
|
|
|
|
if (!*ppCoordinate)
|
|
|
|
return;
|
|
|
|
rWidth = atoi(*ppCoordinate);
|
|
|
|
++ppCoordinate;
|
|
|
|
if (!*ppCoordinate)
|
|
|
|
return;
|
|
|
|
rHeight = atoi(*ppCoordinate);
|
|
|
|
g_strfreev(ppCoordinates);
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
/// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
|
|
|
|
static const char*
|
|
|
|
callbackTypeToString (int nType)
|
2015-05-18 09:33:53 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
switch (nType)
|
2015-05-18 09:33:53 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
case LOK_CALLBACK_INVALIDATE_TILES:
|
|
|
|
return "LOK_CALLBACK_INVALIDATE_TILES";
|
|
|
|
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
|
|
|
|
return "LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR";
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION:
|
|
|
|
return "LOK_CALLBACK_TEXT_SELECTION";
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION_START:
|
|
|
|
return "LOK_CALLBACK_TEXT_SELECTION_START";
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION_END:
|
|
|
|
return "LOK_CALLBACK_TEXT_SELECTION_END";
|
|
|
|
case LOK_CALLBACK_CURSOR_VISIBLE:
|
|
|
|
return "LOK_CALLBACK_CURSOR_VISIBLE";
|
|
|
|
case LOK_CALLBACK_GRAPHIC_SELECTION:
|
|
|
|
return "LOK_CALLBACK_GRAPHIC_SELECTION";
|
|
|
|
case LOK_CALLBACK_HYPERLINK_CLICKED:
|
|
|
|
return "LOK_CALLBACK_HYPERLINK_CLICKED";
|
|
|
|
case LOK_CALLBACK_STATE_CHANGED:
|
|
|
|
return "LOK_CALLBACK_STATE_CHANGED";
|
2015-05-18 09:33:53 +02:00
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_START:
|
2015-06-11 22:00:11 +05:30
|
|
|
return "LOK_CALLBACK_STATUS_INDICATOR_START";
|
2015-05-18 09:33:53 +02:00
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
|
2015-06-11 22:00:11 +05:30
|
|
|
return "LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE";
|
2015-05-18 09:33:53 +02:00
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
|
2015-06-11 22:00:11 +05:30
|
|
|
return "LOK_CALLBACK_STATUS_INDICATOR_FINISH";
|
|
|
|
case LOK_CALLBACK_SEARCH_NOT_FOUND:
|
|
|
|
return "LOK_CALLBACK_SEARCH_NOT_FOUND";
|
|
|
|
case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
|
|
|
|
return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
|
|
|
|
case LOK_CALLBACK_SET_PART:
|
|
|
|
return "LOK_CALLBACK_SET_PART";
|
2015-05-18 09:33:53 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
return 0;
|
2015-06-09 16:27:37 +05:30
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static bool
|
|
|
|
isEmptyRectangle(const GdkRectangle& rRectangle)
|
2015-06-09 16:27:37 +05:30
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
|
2015-06-03 20:52:49 +05:30
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
signalKey (LOKDocView* pDocView, const GdkEvent* pEvent)
|
2015-03-25 17:54:11 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-03-25 17:54:11 +01:00
|
|
|
int nCharCode = 0;
|
|
|
|
int nKeyCode = 0;
|
2015-06-11 22:00:11 +05:30
|
|
|
guint keyval;
|
|
|
|
GdkModifierType state;
|
|
|
|
gdk_event_get_keyval (pEvent, &keyval);
|
|
|
|
gdk_event_get_state (pEvent, &state);
|
2015-03-25 17:54:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (!priv->m_bEdit)
|
2015-03-25 17:54:11 +01:00
|
|
|
{
|
|
|
|
g_info("signalKey: not in edit mode, ignore");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
switch (keyval)
|
2015-03-25 17:54:11 +01:00
|
|
|
{
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_BackSpace:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::BACKSPACE;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Return:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::RETURN;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Escape:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::ESCAPE;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Tab:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::TAB;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Down:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::DOWN;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Up:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::UP;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Left:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::LEFT;
|
|
|
|
break;
|
2015-06-10 16:18:06 +05:30
|
|
|
case GDK_KEY_Right:
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode = com::sun::star::awt::Key::RIGHT;
|
|
|
|
break;
|
|
|
|
default:
|
2015-06-11 22:00:11 +05:30
|
|
|
if (keyval >= GDK_KEY_F1 && keyval <= GDK_KEY_F26)
|
|
|
|
nKeyCode = com::sun::star::awt::Key::F1 + (keyval - GDK_KEY_F1);
|
2015-03-25 17:54:11 +01:00
|
|
|
else
|
2015-06-11 22:00:11 +05:30
|
|
|
nCharCode = gdk_keyval_to_unicode(keyval);
|
2015-03-25 17:54:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// rsc is not public API, but should be good enough for debugging purposes.
|
|
|
|
// If this is needed for real, then probably a new param of type
|
|
|
|
// css::awt::KeyModifier is needed in postKeyEvent().
|
2015-06-11 22:00:11 +05:30
|
|
|
if (state & GDK_SHIFT_MASK)
|
2015-03-25 17:54:11 +01:00
|
|
|
nKeyCode |= KEY_SHIFT;
|
|
|
|
|
|
|
|
if (pEvent->type == GDK_KEY_RELEASE)
|
2015-06-11 22:00:11 +05:30
|
|
|
priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYUP, nCharCode, nKeyCode);
|
2015-03-25 17:54:11 +01:00
|
|
|
else
|
2015-06-11 22:00:11 +05:30
|
|
|
priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYINPUT, nCharCode, nKeyCode);
|
2015-03-12 17:21:44 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean
|
|
|
|
handleTimeout (gpointer pData)
|
2015-01-20 10:20:24 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pData);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-01-20 10:20:24 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bEdit)
|
2015-02-10 18:19:32 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bCursorOverlayVisible)
|
|
|
|
priv->m_bCursorOverlayVisible = false;
|
|
|
|
else
|
|
|
|
priv->m_bCursorOverlayVisible = true;
|
|
|
|
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
|
|
|
|
}
|
2015-03-10 10:12:02 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
2015-03-10 10:53:28 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
commandChanged(LOKDocView* pDocView, const std::string& rString)
|
|
|
|
{
|
|
|
|
g_signal_emit(pDocView, doc_view_signals[COMMAND_CHANGED], 0, rString.c_str());
|
|
|
|
}
|
2015-02-10 14:15:42 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
searchNotFound(LOKDocView* pDocView, const std::string& rString)
|
|
|
|
{
|
|
|
|
g_signal_emit(pDocView, doc_view_signals[SEARCH_NOT_FOUND], 0, rString.c_str());
|
|
|
|
}
|
2015-03-10 10:12:02 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
setPart(LOKDocView* pDocView, const std::string& rString)
|
|
|
|
{
|
|
|
|
g_signal_emit(pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
|
|
|
|
}
|
2015-02-10 14:15:42 +01:00
|
|
|
|
2015-06-23 01:52:44 +05:30
|
|
|
static void
|
|
|
|
hyperlinkClicked(LOKDocView* pDocView, const std::string& rString)
|
|
|
|
{
|
|
|
|
g_signal_emit(pDocView, doc_view_signals[HYPERLINK_CLICKED], 0, rString.c_str());
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
/// Implementation of the global callback handler, invoked by globalCallback();
|
|
|
|
static gboolean
|
|
|
|
globalCallback (gpointer pData)
|
|
|
|
{
|
|
|
|
CallbackData* pCallback = static_cast<CallbackData*>(pData);
|
2015-01-20 10:20:24 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
switch (pCallback->m_nType)
|
2015-01-20 10:20:24 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_START:
|
2015-02-05 14:19:35 +01:00
|
|
|
{
|
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
|
2015-02-05 14:19:35 +01:00
|
|
|
{
|
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
|
|
|
|
{
|
|
|
|
}
|
|
|
|
break;
|
2015-01-20 10:20:24 +01:00
|
|
|
default:
|
2015-06-11 22:00:11 +05:30
|
|
|
g_assert(false);
|
2015-01-20 10:20:24 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
delete pCallback;
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
2015-01-20 10:20:24 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
globalCallbackWorker(int nType, const char* pPayload, void* pData)
|
2015-03-25 18:19:11 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pData);
|
2015-03-25 18:19:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
CallbackData* pCallback = new CallbackData(nType, pPayload ? pPayload : "(nil)", pDocView);
|
|
|
|
g_info("LOKDocView_Impl::globalCallbackWorkerImpl: %s, '%s'", callbackTypeToString(nType), pPayload);
|
|
|
|
gdk_threads_add_idle(globalCallback, pCallback);
|
2015-03-25 18:19:11 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static GdkRectangle
|
|
|
|
payloadToRectangle (LOKDocView* pDocView, const char* pPayload)
|
2015-03-26 09:45:41 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkRectangle aRet;
|
|
|
|
gchar** ppCoordinates = g_strsplit(pPayload, ", ", 4);
|
|
|
|
gchar** ppCoordinate = ppCoordinates;
|
2015-03-25 18:19:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
aRet.width = aRet.height = aRet.x = aRet.y = 0;
|
2015-03-25 18:19:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (!*ppCoordinate)
|
|
|
|
return aRet;
|
|
|
|
aRet.x = atoi(*ppCoordinate);
|
|
|
|
if (aRet.x < 0)
|
|
|
|
aRet.x = 0;
|
|
|
|
++ppCoordinate;
|
|
|
|
if (!*ppCoordinate)
|
|
|
|
return aRet;
|
|
|
|
aRet.y = atoi(*ppCoordinate);
|
|
|
|
if (aRet.y < 0)
|
|
|
|
aRet.y = 0;
|
|
|
|
++ppCoordinate;
|
|
|
|
if (!*ppCoordinate)
|
|
|
|
return aRet;
|
|
|
|
aRet.width = atoi(*ppCoordinate);
|
|
|
|
if (aRet.x + aRet.width > priv->m_nDocumentWidthTwips)
|
|
|
|
aRet.width = priv->m_nDocumentWidthTwips - aRet.x;
|
|
|
|
++ppCoordinate;
|
|
|
|
if (!*ppCoordinate)
|
|
|
|
return aRet;
|
|
|
|
aRet.height = atoi(*ppCoordinate);
|
|
|
|
if (aRet.y + aRet.height > priv->m_nDocumentHeightTwips)
|
|
|
|
aRet.height = priv->m_nDocumentHeightTwips - aRet.y;
|
|
|
|
g_strfreev(ppCoordinates);
|
2015-03-25 18:19:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
return aRet;
|
|
|
|
}
|
2015-03-25 18:19:11 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static const std::vector<GdkRectangle>
|
|
|
|
payloadToRectangles(LOKDocView* pDocView, const char* pPayload)
|
|
|
|
{
|
|
|
|
std::vector<GdkRectangle> aRet;
|
2015-05-15 10:13:53 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
gchar** ppRectangles = g_strsplit(pPayload, "; ", 0);
|
|
|
|
for (gchar** ppRectangle = ppRectangles; *ppRectangle; ++ppRectangle)
|
|
|
|
aRet.push_back(payloadToRectangle(pDocView, *ppRectangle));
|
|
|
|
g_strfreev(ppRectangles);
|
|
|
|
|
|
|
|
return aRet;
|
2015-03-25 18:19:11 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
static void
|
|
|
|
setTilesInvalid (LOKDocView* pDocView, const GdkRectangle& rRectangle)
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkRectangle aRectanglePixels;
|
|
|
|
GdkPoint aStart, aEnd;
|
|
|
|
|
|
|
|
aRectanglePixels.x = twipToPixel(rRectangle.x, priv->m_fZoom);
|
|
|
|
aRectanglePixels.y = twipToPixel(rRectangle.y, priv->m_fZoom);
|
|
|
|
aRectanglePixels.width = twipToPixel(rRectangle.width, priv->m_fZoom);
|
|
|
|
aRectanglePixels.height = twipToPixel(rRectangle.height, priv->m_fZoom);
|
|
|
|
|
|
|
|
aStart.x = aRectanglePixels.y / nTileSizePixels;
|
|
|
|
aStart.y = aRectanglePixels.x / nTileSizePixels;
|
|
|
|
aEnd.x = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
|
|
|
|
aEnd.y = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
|
|
|
|
|
|
|
|
for (int i = aStart.x; i < aEnd.x; i++)
|
|
|
|
for (int j = aStart.y; j < aEnd.y; j++)
|
|
|
|
priv->m_aTileBuffer.setInvalid(i, j);
|
2015-03-27 09:17:26 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean
|
|
|
|
callback (gpointer pData)
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
CallbackData* pCallback = static_cast<CallbackData*>(pData);
|
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pCallback->m_pDocView);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-03-27 09:17:26 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
switch (pCallback->m_nType)
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
case LOK_CALLBACK_INVALIDATE_TILES:
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
if (pCallback->m_aPayload != "EMPTY")
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkRectangle aRectangle = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
|
|
|
|
setTilesInvalid(pDocView, aRectangle);
|
2015-03-27 09:17:26 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
else
|
|
|
|
priv->m_aTileBuffer.resetAllTiles();
|
2015-03-27 09:17:26 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
|
|
|
|
{
|
|
|
|
priv->m_aVisibleCursor = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
|
|
|
|
priv->m_bCursorOverlayVisible = true;
|
|
|
|
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION:
|
|
|
|
{
|
|
|
|
priv->m_aTextSelectionRectangles = payloadToRectangles(pDocView, pCallback->m_aPayload.c_str());
|
|
|
|
// In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
|
|
|
|
if (priv->m_aTextSelectionRectangles.empty())
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
memset(&priv->m_aTextSelectionStart, 0, sizeof(priv->m_aTextSelectionStart));
|
|
|
|
memset(&priv->m_aHandleStartRect, 0, sizeof(priv->m_aHandleStartRect));
|
|
|
|
memset(&priv->m_aTextSelectionEnd, 0, sizeof(priv->m_aTextSelectionEnd));
|
|
|
|
memset(&priv->m_aHandleEndRect, 0, sizeof(priv->m_aHandleEndRect));
|
2015-03-27 09:17:26 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
else
|
|
|
|
memset(&priv->m_aHandleMiddleRect, 0, sizeof(priv->m_aHandleMiddleRect));
|
2015-03-27 09:17:26 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION_START:
|
2015-03-27 09:17:26 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
priv->m_aTextSelectionStart = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
|
2015-03-27 09:17:26 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_TEXT_SELECTION_END:
|
|
|
|
{
|
|
|
|
priv->m_aTextSelectionEnd = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_CURSOR_VISIBLE:
|
|
|
|
{
|
|
|
|
priv->m_bCursorVisible = pCallback->m_aPayload == "true";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_GRAPHIC_SELECTION:
|
|
|
|
{
|
|
|
|
if (pCallback->m_aPayload != "EMPTY")
|
|
|
|
priv->m_aGraphicSelection = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
|
|
|
|
else
|
|
|
|
memset(&priv->m_aGraphicSelection, 0, sizeof(priv->m_aGraphicSelection));
|
|
|
|
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_HYPERLINK_CLICKED:
|
|
|
|
{
|
2015-06-23 01:52:44 +05:30
|
|
|
hyperlinkClicked(pDocView, pCallback->m_aPayload);
|
2015-06-11 22:00:11 +05:30
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_STATE_CHANGED:
|
|
|
|
{
|
|
|
|
commandChanged(pDocView, pCallback->m_aPayload);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_SEARCH_NOT_FOUND:
|
|
|
|
{
|
|
|
|
searchNotFound(pDocView, pCallback->m_aPayload);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
|
|
|
|
{
|
|
|
|
payloadToSize(pCallback->m_aPayload.c_str(), priv->m_nDocumentWidthTwips, priv->m_nDocumentHeightTwips);
|
|
|
|
gtk_widget_set_size_request(GTK_WIDGET(pDocView),
|
|
|
|
twipToPixel(priv->m_nDocumentWidthTwips, priv->m_fZoom),
|
|
|
|
twipToPixel(priv->m_nDocumentHeightTwips, priv->m_fZoom));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOK_CALLBACK_SET_PART:
|
|
|
|
{
|
|
|
|
setPart(pDocView, pCallback->m_aPayload);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
delete pCallback;
|
2015-03-27 09:17:26 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
return G_SOURCE_REMOVE;
|
2015-03-27 16:11:40 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
callbackWorker (int nType, const char* pPayload, void* pData)
|
2015-06-04 14:15:58 +05:30
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pData);
|
2015-06-04 14:15:58 +05:30
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
CallbackData* pCallback = new CallbackData(nType, pPayload ? pPayload : "(nil)", pDocView);
|
|
|
|
g_info("lok_doc_view_callbackWorker: %s, '%s'", callbackTypeToString(nType), pPayload);
|
|
|
|
gdk_threads_add_idle(callback, pCallback);
|
2015-06-04 14:15:58 +05:30
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
renderHandle(LOKDocView* pDocView,
|
|
|
|
cairo_t* pCairo,
|
|
|
|
const GdkRectangle& rCursor,
|
|
|
|
cairo_surface_t* pHandle,
|
|
|
|
GdkRectangle& rRectangle)
|
2015-03-27 16:11:40 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-03-27 16:11:40 +01:00
|
|
|
GdkPoint aCursorBottom;
|
|
|
|
int nHandleWidth, nHandleHeight;
|
|
|
|
double fHandleScale;
|
|
|
|
|
|
|
|
nHandleWidth = cairo_image_surface_get_width(pHandle);
|
|
|
|
nHandleHeight = cairo_image_surface_get_height(pHandle);
|
|
|
|
// We want to scale down the handle, so that its height is the same as the cursor caret.
|
2015-06-11 22:00:11 +05:30
|
|
|
fHandleScale = twipToPixel(rCursor.height, priv->m_fZoom) / nHandleHeight;
|
2015-03-27 16:11:40 +01:00
|
|
|
// We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
|
2015-06-11 22:00:11 +05:30
|
|
|
aCursorBottom.x = twipToPixel(rCursor.x, priv->m_fZoom) + twipToPixel(rCursor.width, priv->m_fZoom) / 2 - (nHandleWidth * fHandleScale) / 2;
|
|
|
|
aCursorBottom.y = twipToPixel(rCursor.y, priv->m_fZoom) + twipToPixel(rCursor.height, priv->m_fZoom);
|
|
|
|
|
|
|
|
cairo_save (pCairo);
|
2015-03-27 16:11:40 +01:00
|
|
|
cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
|
|
|
|
cairo_scale(pCairo, fHandleScale, fHandleScale);
|
|
|
|
cairo_set_source_surface(pCairo, pHandle, 0, 0);
|
|
|
|
cairo_paint(pCairo);
|
2015-06-11 22:00:11 +05:30
|
|
|
cairo_restore (pCairo);
|
2015-03-27 16:11:40 +01:00
|
|
|
|
|
|
|
rRectangle.x = aCursorBottom.x;
|
|
|
|
rRectangle.y = aCursorBottom.y;
|
|
|
|
rRectangle.width = nHandleWidth * fHandleScale;
|
|
|
|
rRectangle.height = nHandleHeight * fHandleScale;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Renders pHandle around an rSelection rectangle on pCairo.
|
2015-06-11 22:00:11 +05:30
|
|
|
static void
|
|
|
|
renderGraphicHandle(LOKDocView* pDocView,
|
|
|
|
cairo_t* pCairo,
|
|
|
|
const GdkRectangle& rSelection,
|
|
|
|
cairo_surface_t* pHandle)
|
2015-03-27 16:11:40 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-03-27 16:11:40 +01:00
|
|
|
int nHandleWidth, nHandleHeight;
|
|
|
|
GdkRectangle aSelection;
|
|
|
|
|
|
|
|
nHandleWidth = cairo_image_surface_get_width(pHandle);
|
|
|
|
nHandleHeight = cairo_image_surface_get_height(pHandle);
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
aSelection.x = twipToPixel(rSelection.x, priv->m_fZoom);
|
|
|
|
aSelection.y = twipToPixel(rSelection.y, priv->m_fZoom);
|
|
|
|
aSelection.width = twipToPixel(rSelection.width, priv->m_fZoom);
|
|
|
|
aSelection.height = twipToPixel(rSelection.height, priv->m_fZoom);
|
2015-03-27 16:11:40 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
|
|
|
|
{
|
|
|
|
int x = aSelection.x, y = aSelection.y;
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0: // top-left
|
|
|
|
break;
|
|
|
|
case 1: // top-middle
|
|
|
|
x += aSelection.width / 2;
|
|
|
|
break;
|
|
|
|
case 2: // top-right
|
|
|
|
x += aSelection.width;
|
|
|
|
break;
|
|
|
|
case 3: // middle-left
|
|
|
|
y += aSelection.height / 2;
|
|
|
|
break;
|
|
|
|
case 4: // middle-right
|
|
|
|
x += aSelection.width;
|
|
|
|
y += aSelection.height / 2;
|
|
|
|
break;
|
|
|
|
case 5: // bottom-left
|
|
|
|
y += aSelection.height;
|
|
|
|
break;
|
|
|
|
case 6: // bottom-middle
|
|
|
|
x += aSelection.width / 2;
|
|
|
|
y += aSelection.height;
|
|
|
|
break;
|
|
|
|
case 7: // bottom-right
|
|
|
|
x += aSelection.width;
|
|
|
|
y += aSelection.height;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Center the handle.
|
|
|
|
x -= nHandleWidth / 2;
|
|
|
|
y -= nHandleHeight / 2;
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
priv->m_aGraphicHandleRects[i].x = x;
|
|
|
|
priv->m_aGraphicHandleRects[i].y = y;
|
|
|
|
priv->m_aGraphicHandleRects[i].width = nHandleWidth;
|
|
|
|
priv->m_aGraphicHandleRects[i].height = nHandleHeight;
|
2015-03-27 16:11:40 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
cairo_save (pCairo);
|
2015-03-27 16:11:40 +01:00
|
|
|
cairo_translate(pCairo, x, y);
|
|
|
|
cairo_set_source_surface(pCairo, pHandle, 0, 0);
|
|
|
|
cairo_paint(pCairo);
|
2015-06-11 22:00:11 +05:30
|
|
|
cairo_restore (pCairo);
|
2015-03-27 16:11:40 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-27 09:17:26 +01:00
|
|
|
|
2014-06-12 17:38:10 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean
|
|
|
|
renderDocument(LOKDocView* pDocView, cairo_t* pCairo)
|
2015-03-30 09:09:01 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkRectangle aVisibleArea;
|
|
|
|
long nDocumentWidthPixels = twipToPixel(priv->m_nDocumentWidthTwips, priv->m_fZoom);
|
|
|
|
long nDocumentHeightPixels = twipToPixel(priv->m_nDocumentHeightTwips, priv->m_fZoom);
|
|
|
|
// Total number of rows / columns in this document.
|
|
|
|
guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
|
|
|
|
guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
|
|
|
|
|
|
|
|
gdk_cairo_get_clip_rectangle (pCairo, &aVisibleArea);
|
|
|
|
aVisibleArea.x = pixelToTwip (aVisibleArea.x, priv->m_fZoom);
|
|
|
|
aVisibleArea.y = pixelToTwip (aVisibleArea.y, priv->m_fZoom);
|
|
|
|
aVisibleArea.width = pixelToTwip (aVisibleArea.width, priv->m_fZoom);
|
|
|
|
aVisibleArea.height = pixelToTwip (aVisibleArea.height, priv->m_fZoom);
|
|
|
|
|
|
|
|
// Render the tiles.
|
|
|
|
for (guint nRow = 0; nRow < nRows; ++nRow)
|
2014-06-12 17:38:10 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
for (guint nColumn = 0; nColumn < nColumns; ++nColumn)
|
|
|
|
{
|
|
|
|
GdkRectangle aTileRectangleTwips, aTileRectanglePixels;
|
|
|
|
bool bPaint = true;
|
2015-03-30 09:09:01 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
// Determine size of the tile: the rightmost/bottommost tiles may
|
|
|
|
// be smaller, and we need the size to decide if we need to repaint.
|
|
|
|
if (nColumn == nColumns - 1)
|
|
|
|
aTileRectanglePixels.width = nDocumentWidthPixels - nColumn * nTileSizePixels;
|
|
|
|
else
|
|
|
|
aTileRectanglePixels.width = nTileSizePixels;
|
|
|
|
if (nRow == nRows - 1)
|
|
|
|
aTileRectanglePixels.height = nDocumentHeightPixels - nRow * nTileSizePixels;
|
|
|
|
else
|
|
|
|
aTileRectanglePixels.height = nTileSizePixels;
|
2014-06-12 17:38:10 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
// Determine size and position of the tile in document coordinates,
|
|
|
|
// so we can decide if we can skip painting for partial rendering.
|
|
|
|
aTileRectangleTwips.x = pixelToTwip(nTileSizePixels, priv->m_fZoom) * nColumn;
|
|
|
|
aTileRectangleTwips.y = pixelToTwip(nTileSizePixels, priv->m_fZoom) * nRow;
|
|
|
|
aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width, priv->m_fZoom);
|
|
|
|
aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height, priv->m_fZoom);
|
2015-03-31 12:50:36 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (!gdk_rectangle_intersect(&aVisibleArea, &aTileRectangleTwips, 0))
|
|
|
|
bPaint = false;
|
|
|
|
|
|
|
|
if (bPaint)
|
|
|
|
{
|
|
|
|
Tile& currentTile = priv->m_aTileBuffer.getTile(nRow, nColumn, priv->m_fZoom);
|
|
|
|
GdkPixbuf* pPixBuf = currentTile.getBuffer();
|
|
|
|
gdk_cairo_set_source_pixbuf (pCairo, pPixBuf,
|
|
|
|
twipToPixel(aTileRectangleTwips.x, priv->m_fZoom),
|
|
|
|
twipToPixel(aTileRectangleTwips.y, priv->m_fZoom));
|
|
|
|
cairo_paint(pCairo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2015-03-31 12:50:36 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean
|
|
|
|
renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
|
2015-03-31 12:50:36 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-03-31 12:50:36 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bEdit && priv->m_bCursorVisible && priv->m_bCursorOverlayVisible && !isEmptyRectangle(priv->m_aVisibleCursor))
|
|
|
|
{
|
|
|
|
if (priv->m_aVisibleCursor.width < 30)
|
|
|
|
// Set a minimal width if it would be 0.
|
|
|
|
priv->m_aVisibleCursor.width = 30;
|
2015-03-31 12:50:36 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
cairo_set_source_rgb(pCairo, 0, 0, 0);
|
|
|
|
cairo_rectangle(pCairo,
|
|
|
|
twipToPixel(priv->m_aVisibleCursor.x, priv->m_fZoom),
|
|
|
|
twipToPixel(priv->m_aVisibleCursor.y, priv->m_fZoom),
|
|
|
|
twipToPixel(priv->m_aVisibleCursor.width, priv->m_fZoom),
|
|
|
|
twipToPixel(priv->m_aVisibleCursor.height, priv->m_fZoom));
|
|
|
|
cairo_fill(pCairo);
|
|
|
|
}
|
2015-03-31 12:50:36 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bEdit && priv->m_bCursorVisible && !isEmptyRectangle(priv->m_aVisibleCursor) && priv->m_aTextSelectionRectangles.empty())
|
2015-04-02 16:47:01 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
// Have a cursor, but no selection: we need the middle handle.
|
|
|
|
gchar* handleMiddlePath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_middle.png", NULL);
|
|
|
|
if (!priv->m_pHandleMiddle)
|
|
|
|
priv->m_pHandleMiddle = cairo_image_surface_create_from_png(handleMiddlePath);
|
|
|
|
g_free (handleMiddlePath);
|
|
|
|
renderHandle(pDocView, pCairo, priv->m_aVisibleCursor, priv->m_pHandleMiddle, priv->m_aHandleMiddleRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!priv->m_aTextSelectionRectangles.empty())
|
|
|
|
{
|
|
|
|
for (GdkRectangle& rRectangle : priv->m_aTextSelectionRectangles)
|
|
|
|
{
|
|
|
|
// Blue with 75% transparency.
|
|
|
|
cairo_set_source_rgba(pCairo, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
|
|
|
|
cairo_rectangle(pCairo,
|
|
|
|
twipToPixel(rRectangle.x, priv->m_fZoom),
|
|
|
|
twipToPixel(rRectangle.y, priv->m_fZoom),
|
|
|
|
twipToPixel(rRectangle.width, priv->m_fZoom),
|
|
|
|
twipToPixel(rRectangle.height, priv->m_fZoom));
|
|
|
|
cairo_fill(pCairo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handles
|
|
|
|
if (!isEmptyRectangle(priv->m_aTextSelectionStart))
|
|
|
|
{
|
|
|
|
// Have a start position: we need a start handle.
|
|
|
|
gchar* handleStartPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_start.png", NULL);
|
|
|
|
if (!priv->m_pHandleStart)
|
|
|
|
priv->m_pHandleStart = cairo_image_surface_create_from_png(handleStartPath);
|
|
|
|
renderHandle(pDocView, pCairo, priv->m_aTextSelectionStart, priv->m_pHandleStart, priv->m_aHandleStartRect);
|
|
|
|
g_free (handleStartPath);
|
|
|
|
}
|
|
|
|
if (!isEmptyRectangle(priv->m_aTextSelectionEnd))
|
|
|
|
{
|
|
|
|
// Have a start position: we need an end handle.
|
|
|
|
gchar* handleEndPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_end.png", NULL);
|
|
|
|
if (!priv->m_pHandleEnd)
|
|
|
|
priv->m_pHandleEnd = cairo_image_surface_create_from_png(handleEndPath);
|
|
|
|
renderHandle(pDocView, pCairo, priv->m_aTextSelectionEnd, priv->m_pHandleEnd, priv->m_aHandleEndRect);
|
|
|
|
g_free (handleEndPath);
|
|
|
|
}
|
2015-04-02 16:47:01 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (!isEmptyRectangle(priv->m_aGraphicSelection))
|
|
|
|
{
|
|
|
|
gchar* handleGraphicPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_graphic.png", NULL);
|
|
|
|
if (!priv->m_pGraphicHandle)
|
|
|
|
priv->m_pGraphicHandle = cairo_image_surface_create_from_png(handleGraphicPath);
|
|
|
|
renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection, priv->m_pGraphicHandle);
|
|
|
|
g_free (handleGraphicPath);
|
|
|
|
}
|
2015-04-03 10:19:16 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
return FALSE;
|
2015-05-18 07:41:04 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean
|
|
|
|
lok_doc_view_signal_button(GtkWidget* pWidget, GdkEventButton* pEvent)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pWidget);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)",
|
|
|
|
(int)pEvent->x, (int)pEvent->y,
|
|
|
|
(int)pixelToTwip(pEvent->x, priv->m_fZoom),
|
|
|
|
(int)pixelToTwip(pEvent->y, priv->m_fZoom));
|
|
|
|
|
|
|
|
if (pEvent->type == GDK_BUTTON_RELEASE)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragStartHandle)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("LOKDocView_Impl::signalButton: end of drag start handle");
|
|
|
|
priv->m_bInDragStartHandle = false;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (priv->m_bInDragMiddleHandle)
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: end of drag middle handle");
|
|
|
|
priv->m_bInDragMiddleHandle = false;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (priv->m_bInDragEndHandle)
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: end of drag end handle");
|
|
|
|
priv->m_bInDragEndHandle = false;
|
|
|
|
return FALSE;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-06-06 00:36:54 +05:30
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
|
|
|
|
{
|
|
|
|
if (priv->m_bInDragGraphicHandles[i])
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i);
|
|
|
|
priv->m_bInDragGraphicHandles[i] = false;
|
|
|
|
priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2015-04-03 10:19:16 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragGraphicSelection)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
|
|
|
|
priv->m_bInDragGraphicSelection = false;
|
|
|
|
priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
if (priv->m_bEdit)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkRectangle aClick;
|
|
|
|
aClick.x = pEvent->x;
|
|
|
|
aClick.y = pEvent->y;
|
|
|
|
aClick.width = 1;
|
|
|
|
aClick.height = 1;
|
|
|
|
if (pEvent->type == GDK_BUTTON_PRESS)
|
|
|
|
{
|
|
|
|
if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleStartRect, NULL))
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: start of drag start handle");
|
|
|
|
priv->m_bInDragStartHandle = true;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleMiddleRect, NULL))
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: start of drag middle handle");
|
|
|
|
priv->m_bInDragMiddleHandle = true;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleEndRect, NULL))
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: start of drag end handle");
|
|
|
|
priv->m_bInDragEndHandle = true;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
|
|
|
|
{
|
|
|
|
if (gdk_rectangle_intersect(&aClick, &priv->m_aGraphicHandleRects[i], NULL))
|
|
|
|
{
|
|
|
|
g_info("LOKDocView_Impl::signalButton: start of drag graphic handle #%d", i);
|
|
|
|
priv->m_bInDragGraphicHandles[i] = true;
|
|
|
|
priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument,
|
|
|
|
LOK_SETGRAPHICSELECTION_START,
|
|
|
|
pixelToTwip(priv->m_aGraphicHandleRects[i].x + priv->m_aGraphicHandleRects[i].width / 2, priv->m_fZoom),
|
|
|
|
pixelToTwip(priv->m_aGraphicHandleRects[i].y + priv->m_aGraphicHandleRects[i].height / 2, priv->m_fZoom));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
if (!priv->m_bEdit)
|
|
|
|
lok_doc_view_set_edit(pDocView, TRUE);
|
|
|
|
|
|
|
|
switch (pEvent->type)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
case GDK_BUTTON_PRESS:
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
int nCount = 1;
|
|
|
|
if ((pEvent->time - priv->m_nLastButtonPressTime) < 250)
|
|
|
|
nCount++;
|
|
|
|
priv->m_nLastButtonPressTime = pEvent->time;
|
|
|
|
priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), nCount);
|
|
|
|
break;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
case GDK_BUTTON_RELEASE:
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
int nCount = 1;
|
|
|
|
if ((pEvent->time - priv->m_nLastButtonReleaseTime) < 250)
|
|
|
|
nCount++;
|
|
|
|
priv->m_nLastButtonReleaseTime = pEvent->time;
|
|
|
|
priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), nCount);
|
|
|
|
break;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
getDragPoint(GdkRectangle* pHandle,
|
|
|
|
GdkEventMotion* pEvent,
|
|
|
|
GdkPoint* pPoint)
|
|
|
|
{
|
|
|
|
GdkPoint aCursor, aHandle;
|
|
|
|
|
|
|
|
// Center of the cursor rectangle: we know that it's above the handle.
|
|
|
|
aCursor.x = pHandle->x + pHandle->width / 2;
|
|
|
|
aCursor.y = pHandle->y - pHandle->height / 2;
|
|
|
|
// Center of the handle rectangle.
|
|
|
|
aHandle.x = pHandle->x + pHandle->width / 2;
|
|
|
|
aHandle.y = pHandle->y + pHandle->height / 2;
|
|
|
|
// Our target is the original cursor position + the dragged offset.
|
|
|
|
pPoint->x = aCursor.x + (pEvent->x - aHandle.x);
|
|
|
|
pPoint->y = aCursor.y + (pEvent->y - aHandle.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
lok_doc_view_signal_motion (GtkWidget* pWidget, GdkEventMotion* pEvent)
|
|
|
|
{
|
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (pWidget);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
GdkPoint aPoint;
|
|
|
|
|
|
|
|
if (priv->m_bInDragMiddleHandle)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("lcl_signalMotion: dragging the middle handle");
|
|
|
|
getDragPoint(&priv->m_aHandleMiddleRect, pEvent, &aPoint);
|
|
|
|
priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragStartHandle)
|
2015-04-13 16:23:32 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("lcl_signalMotion: dragging the start handle");
|
|
|
|
getDragPoint(&priv->m_aHandleStartRect, pEvent, &aPoint);
|
|
|
|
priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
2015-04-13 16:23:32 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragEndHandle)
|
2015-05-21 13:17:18 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("lcl_signalMotion: dragging the end handle");
|
|
|
|
getDragPoint(&priv->m_aHandleEndRect, pEvent, &aPoint);
|
|
|
|
priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
2015-05-21 13:17:18 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
|
2015-05-23 10:44:07 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragGraphicHandles[i])
|
|
|
|
{
|
|
|
|
g_info("lcl_signalMotion: dragging the graphic handle #%d", i);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-05-23 10:44:07 +01:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
if (priv->m_bInDragGraphicSelection)
|
2015-05-26 17:00:20 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
g_info("lcl_signalMotion: dragging the graphic selection");
|
|
|
|
return FALSE;
|
2015-05-26 17:00:20 +02:00
|
|
|
}
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
GdkRectangle aMotionInTwipsInTwips;
|
|
|
|
aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x, priv->m_fZoom);
|
|
|
|
aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y, priv->m_fZoom);
|
|
|
|
aMotionInTwipsInTwips.width = 1;
|
|
|
|
aMotionInTwipsInTwips.height = 1;
|
|
|
|
if (gdk_rectangle_intersect(&aMotionInTwipsInTwips, &priv->m_aGraphicSelection, 0))
|
|
|
|
{
|
|
|
|
g_info("lcl_signalMotion: start of drag graphic selection");
|
|
|
|
priv->m_bInDragGraphicSelection = true;
|
|
|
|
priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
|
|
|
|
return FALSE;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
// Otherwise a mouse move, as on the desktop.
|
|
|
|
priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), 1);
|
2015-04-03 10:19:16 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
return FALSE;
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void lok_doc_view_init (LOKDocView* pDocView)
|
2015-05-18 07:41:04 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
priv->m_bCursorVisible = true;
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
gtk_widget_add_events(GTK_WIDGET(pDocView),
|
|
|
|
GDK_BUTTON_PRESS_MASK
|
|
|
|
|GDK_BUTTON_RELEASE_MASK
|
|
|
|
|GDK_BUTTON_MOTION_MASK
|
|
|
|
|GDK_KEY_PRESS_MASK
|
|
|
|
|GDK_KEY_RELEASE_MASK);
|
2015-05-18 07:41:04 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void lok_doc_view_set_property (GObject* object, guint propId, const GValue *value, GParamSpec *pspec)
|
2015-04-03 10:19:16 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (object);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
switch (propId)
|
|
|
|
{
|
|
|
|
case PROP_LO_PATH:
|
|
|
|
priv->m_aLOPath = g_value_dup_string (value);
|
|
|
|
break;
|
|
|
|
case PROP_DOC_PATH:
|
|
|
|
priv->m_aDocPath = g_value_dup_string (value);
|
|
|
|
break;
|
|
|
|
case PROP_EDITABLE:
|
|
|
|
lok_doc_view_set_edit (pDocView, g_value_get_boolean (value));
|
|
|
|
break;
|
|
|
|
case PROP_ZOOM:
|
|
|
|
lok_doc_view_set_zoom (pDocView, g_value_get_float (value));
|
|
|
|
break;
|
|
|
|
case PROP_DOC_WIDTH:
|
|
|
|
priv->m_nDocumentWidthTwips = g_value_get_long (value);
|
|
|
|
break;
|
|
|
|
case PROP_DOC_HEIGHT:
|
|
|
|
priv->m_nDocumentHeightTwips = g_value_get_long (value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec);
|
|
|
|
}
|
2015-04-03 10:19:16 +02:00
|
|
|
}
|
2015-04-02 16:47:01 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void lok_doc_view_get_property (GObject* object, guint propId, GValue *value, GParamSpec *pspec)
|
2015-05-18 07:41:04 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (object);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
switch (propId)
|
|
|
|
{
|
|
|
|
case PROP_LO_PATH:
|
|
|
|
g_value_set_string (value, priv->m_aLOPath);
|
|
|
|
break;
|
|
|
|
case PROP_DOC_PATH:
|
|
|
|
g_value_set_string (value, priv->m_aDocPath);
|
|
|
|
break;
|
|
|
|
case PROP_EDITABLE:
|
|
|
|
g_value_set_boolean (value, priv->m_bEdit);
|
|
|
|
break;
|
|
|
|
case PROP_LOAD_PROGRESS:
|
|
|
|
g_value_set_uint (value, priv->m_nLoadProgress);
|
|
|
|
break;
|
|
|
|
case PROP_ZOOM:
|
|
|
|
g_value_set_float (value, priv->m_fZoom);
|
|
|
|
break;
|
|
|
|
case PROP_IS_LOADING:
|
|
|
|
g_value_set_boolean (value, priv->m_bIsLoading);
|
|
|
|
break;
|
|
|
|
case PROP_DOC_WIDTH:
|
|
|
|
g_value_set_long (value, priv->m_nDocumentWidthTwips);
|
|
|
|
break;
|
|
|
|
case PROP_DOC_HEIGHT:
|
|
|
|
g_value_set_long (value, priv->m_nDocumentHeightTwips);
|
|
|
|
break;
|
|
|
|
case PROP_CAN_ZOOM_IN:
|
|
|
|
g_value_set_boolean (value, priv->m_bCanZoomIn);
|
|
|
|
break;
|
|
|
|
case PROP_CAN_ZOOM_OUT:
|
|
|
|
g_value_set_boolean (value, priv->m_bCanZoomOut);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec);
|
|
|
|
}
|
2015-05-18 07:41:04 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static gboolean lok_doc_view_draw (GtkWidget* pWidget, cairo_t* pCairo)
|
2015-04-14 11:00:11 +02:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView *pDocView = LOK_DOC_VIEW (pWidget);
|
|
|
|
|
|
|
|
renderDocument (pDocView, pCairo);
|
|
|
|
renderOverlay (pDocView, pCairo);
|
|
|
|
|
|
|
|
return FALSE;
|
2015-04-14 11:00:11 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
static void lok_doc_view_finalize (GObject* object)
|
2015-05-21 13:17:18 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
LOKDocView* pDocView = LOK_DOC_VIEW (object);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
if (priv->m_pDocument)
|
|
|
|
priv->m_pDocument->pClass->destroy (priv->m_pDocument);
|
|
|
|
if (priv->m_pOffice)
|
|
|
|
priv->m_pOffice->pClass->destroy (priv->m_pOffice);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (lok_doc_view_parent_class)->finalize (object);
|
2015-05-21 13:17:18 +01:00
|
|
|
}
|
|
|
|
|
2015-06-18 21:52:22 +05:30
|
|
|
static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* /*cancellable*/, GError **error)
|
2015-05-27 11:30:04 +02:00
|
|
|
{
|
2015-06-18 21:52:22 +05:30
|
|
|
LOKDocView *pDocView = LOK_DOC_VIEW (initable);
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
2015-06-18 21:52:22 +05:30
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
if (priv->m_pOffice != NULL)
|
2015-06-18 21:52:22 +05:30
|
|
|
return TRUE;
|
2015-06-11 22:00:11 +05:30
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_pOffice = lok_init (priv->m_aLOPath);
|
2015-06-11 22:00:11 +05:30
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
if (priv->m_pOffice == NULL)
|
2015-06-18 21:52:22 +05:30
|
|
|
{
|
|
|
|
g_set_error (error,
|
|
|
|
g_quark_from_static_string ("LOK initialization error"), 0,
|
|
|
|
"Failed to get LibreOfficeKit context. Make sure path (%s) is correct",
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_aLOPath);
|
2015-06-18 21:52:22 +05:30
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lok_doc_view_initable_iface_init (GInitableIface *iface)
|
|
|
|
{
|
|
|
|
iface->init = lok_doc_view_initable_init;
|
2015-05-27 11:30:04 +02:00
|
|
|
}
|
|
|
|
|
2015-06-06 03:10:31 +05:30
|
|
|
static void lok_doc_view_class_init (LOKDocViewClass* pClass)
|
2014-06-12 17:38:10 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
GObjectClass *pGObjectClass = G_OBJECT_CLASS(pClass);
|
|
|
|
GtkWidgetClass *pWidgetClass = GTK_WIDGET_CLASS(pClass);
|
|
|
|
|
|
|
|
pGObjectClass->get_property = lok_doc_view_get_property;
|
|
|
|
pGObjectClass->set_property = lok_doc_view_set_property;
|
|
|
|
pGObjectClass->finalize = lok_doc_view_finalize;
|
|
|
|
|
|
|
|
pWidgetClass->draw = lok_doc_view_draw;
|
|
|
|
pWidgetClass->button_press_event = lok_doc_view_signal_button;
|
|
|
|
pWidgetClass->button_release_event = lok_doc_view_signal_button;
|
|
|
|
pWidgetClass->motion_notify_event = lok_doc_view_signal_motion;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:lopath:
|
|
|
|
*
|
|
|
|
* The absolute path of the LibreOffice install.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_LO_PATH,
|
|
|
|
g_param_spec_string("lopath",
|
|
|
|
"LO Path",
|
|
|
|
"LibreOffice Install Path",
|
|
|
|
0,
|
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE
|
|
|
|
| G_PARAM_CONSTRUCT_ONLY)));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:docpath:
|
|
|
|
*
|
|
|
|
* The path of the document that is currently being viewed.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_DOC_PATH,
|
|
|
|
g_param_spec_string("docpath",
|
|
|
|
"Document Path",
|
|
|
|
"The URI of the document to open",
|
|
|
|
0,
|
2015-06-16 11:34:36 +02:00
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE)));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:editable:
|
|
|
|
*
|
|
|
|
* Whether the document loaded inside of #LOKDocView is editable or not.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_EDITABLE,
|
|
|
|
g_param_spec_boolean("editable",
|
|
|
|
"Editable",
|
|
|
|
"Whether the content is in edit mode or not",
|
|
|
|
FALSE,
|
2015-06-16 11:34:36 +02:00
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE)));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:load-progress:
|
|
|
|
*
|
|
|
|
* The percent completion of the current loading operation of the
|
|
|
|
* document. This can be used for progress bars. Note that this is not a
|
|
|
|
* very accurate progress indicator, and its value might reset it couple of
|
|
|
|
* times to 0 and start again. You should not rely on its numbers.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_LOAD_PROGRESS,
|
|
|
|
g_param_spec_int("load-progress",
|
|
|
|
"Estimated Load Progress",
|
|
|
|
"Whether the content is in edit mode or not",
|
|
|
|
0, 100, 0,
|
|
|
|
G_PARAM_READABLE));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:zoom-level:
|
|
|
|
*
|
|
|
|
* The current zoom level of the document loaded inside #LOKDocView. The
|
|
|
|
* default value is 1.0.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_ZOOM,
|
|
|
|
g_param_spec_float("zoom-level",
|
|
|
|
"Zoom Level",
|
|
|
|
"The current zoom level of the content",
|
|
|
|
0, 5.0, 1.0,
|
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT)));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:is-loading:
|
|
|
|
*
|
|
|
|
* Whether the requested document is being loaded or not. %TRUE if it is
|
|
|
|
* being loaded, otherwise %FALSE.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_IS_LOADING,
|
|
|
|
g_param_spec_boolean("is-loading",
|
|
|
|
"Is Loading",
|
|
|
|
"Whether the view is loading a document",
|
|
|
|
FALSE,
|
2015-06-16 11:34:36 +02:00
|
|
|
static_cast<GParamFlags>(G_PARAM_READABLE)));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:doc-width:
|
|
|
|
*
|
|
|
|
* The width of the currently loaded document in #LOKDocView in twips.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_DOC_WIDTH,
|
|
|
|
g_param_spec_long("doc-width",
|
|
|
|
"Document Width",
|
|
|
|
"Width of the document in twips",
|
|
|
|
0, G_MAXLONG, 0,
|
2015-06-16 11:34:36 +02:00
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE)));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:doc-height:
|
|
|
|
*
|
|
|
|
* The height of the currently loaded document in #LOKDocView in twips.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_DOC_HEIGHT,
|
|
|
|
g_param_spec_long("doc-height",
|
|
|
|
"Document Height",
|
|
|
|
"Height of the document in twips",
|
|
|
|
0, G_MAXLONG, 0,
|
2015-06-16 11:34:36 +02:00
|
|
|
static_cast<GParamFlags>(G_PARAM_READWRITE)));
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:can-zoom-in:
|
|
|
|
*
|
|
|
|
* It tells whether the view can further be zoomed in or not.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_CAN_ZOOM_IN,
|
|
|
|
g_param_spec_boolean("can-zoom-in",
|
|
|
|
"Can Zoom In",
|
|
|
|
"Whether the view can be zoomed in further",
|
|
|
|
TRUE,
|
|
|
|
static_cast<GParamFlags>(G_PARAM_READABLE
|
|
|
|
| G_PARAM_STATIC_STRINGS)));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView:can-zoom-out:
|
|
|
|
*
|
|
|
|
* It tells whether the view can further be zoomed out or not.
|
|
|
|
*/
|
|
|
|
g_object_class_install_property (pGObjectClass,
|
|
|
|
PROP_CAN_ZOOM_OUT,
|
|
|
|
g_param_spec_boolean("can-zoom-out",
|
|
|
|
"Can Zoom Out",
|
|
|
|
"Whether the view can be zoomed out further",
|
|
|
|
TRUE,
|
|
|
|
static_cast<GParamFlags>(G_PARAM_READABLE
|
|
|
|
| G_PARAM_STATIC_STRINGS)));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView::edit-changed:
|
|
|
|
* @pDocView: the #LOKDocView on which the signal is emitted
|
|
|
|
* @bEdit: the new edit value of the view
|
|
|
|
*/
|
2015-06-06 02:32:54 +05:30
|
|
|
doc_view_signals[EDIT_CHANGED] =
|
2015-03-10 12:50:59 +01:00
|
|
|
g_signal_new("edit-changed",
|
2015-06-11 22:00:11 +05:30
|
|
|
G_TYPE_FROM_CLASS (pGObjectClass),
|
2015-03-10 12:50:59 +01:00
|
|
|
G_SIGNAL_RUN_FIRST,
|
2015-06-11 22:00:11 +05:30
|
|
|
0,
|
2015-03-10 12:50:59 +01:00
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOOLEAN,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_BOOLEAN);
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView::command-changed:
|
|
|
|
* @pDocView: the #LOKDocView on which the signal is emitted
|
|
|
|
* @aCommand: the command that was changed
|
|
|
|
*/
|
2015-06-06 02:32:54 +05:30
|
|
|
doc_view_signals[COMMAND_CHANGED] =
|
2015-04-14 11:00:11 +02:00
|
|
|
g_signal_new("command-changed",
|
2015-06-11 22:00:11 +05:30
|
|
|
G_TYPE_FROM_CLASS(pGObjectClass),
|
2015-04-14 11:00:11 +02:00
|
|
|
G_SIGNAL_RUN_FIRST,
|
2015-06-11 22:00:11 +05:30
|
|
|
0,
|
2015-04-14 11:00:11 +02:00
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_STRING);
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView::search-not-found:
|
|
|
|
* @pDocView: the #LOKDocView on which the signal is emitted
|
|
|
|
* @aCommand: the string for which the search was not found.
|
|
|
|
*/
|
2015-06-06 02:32:54 +05:30
|
|
|
doc_view_signals[SEARCH_NOT_FOUND] =
|
2015-05-21 13:17:18 +01:00
|
|
|
g_signal_new("search-not-found",
|
2015-06-11 22:00:11 +05:30
|
|
|
G_TYPE_FROM_CLASS(pGObjectClass),
|
2015-05-21 13:17:18 +01:00
|
|
|
G_SIGNAL_RUN_FIRST,
|
2015-06-11 22:00:11 +05:30
|
|
|
0,
|
2015-05-21 13:17:18 +01:00
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_STRING);
|
2015-06-11 22:00:11 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* LOKDocView::part-changed:
|
|
|
|
* @pDocView: the #LOKDocView on which the signal is emitted
|
|
|
|
* @aCommand: the part number which the view changed to
|
|
|
|
*/
|
2015-06-06 02:32:54 +05:30
|
|
|
doc_view_signals[PART_CHANGED] =
|
2015-05-27 11:30:04 +02:00
|
|
|
g_signal_new("part-changed",
|
2015-06-11 22:00:11 +05:30
|
|
|
G_TYPE_FROM_CLASS(pGObjectClass),
|
2015-05-27 11:30:04 +02:00
|
|
|
G_SIGNAL_RUN_FIRST,
|
2015-06-11 22:00:11 +05:30
|
|
|
0,
|
2015-05-27 11:30:04 +02:00
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__INT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_INT);
|
2014-06-12 17:38:10 +01:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
/**
|
|
|
|
* LOKDocView::hyperlinked-clicked:
|
|
|
|
* @pDocView: the #LOKDocView on which the signal is emitted
|
|
|
|
* @aHyperlink: the URI which the application should handle
|
|
|
|
*/
|
2015-06-22 15:27:24 +05:30
|
|
|
doc_view_signals[HYPERLINK_CLICKED] =
|
2015-06-23 01:52:44 +05:30
|
|
|
g_signal_new("hyperlink-clicked",
|
2015-06-11 22:00:11 +05:30
|
|
|
G_TYPE_FROM_CLASS(pGObjectClass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_STRING);
|
2014-06-12 17:38:10 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_new:
|
2015-06-10 16:10:19 +05:30
|
|
|
* @pPath: LibreOffice install path.
|
2015-06-18 21:52:22 +05:30
|
|
|
* @cancellable: The cancellable object that you can use to cancel this
|
|
|
|
* operation.
|
|
|
|
* @error: The error that will be set if the object fails to initialize.
|
2015-06-09 18:08:59 +05:30
|
|
|
*
|
2015-06-18 21:52:22 +05:30
|
|
|
* Returns: (transfer none): The #LOKDocView widget instance.
|
2015-06-09 18:08:59 +05:30
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT GtkWidget*
|
2015-06-18 21:52:22 +05:30
|
|
|
lok_doc_view_new (const gchar* pPath, GCancellable *cancellable, GError **error)
|
2015-03-30 09:09:01 +02:00
|
|
|
{
|
2015-06-18 21:52:22 +05:30
|
|
|
return GTK_WIDGET (g_initable_new (LOK_TYPE_DOC_VIEW, cancellable, error, "lopath", pPath, NULL));
|
2015-01-27 14:36:12 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_open_document:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
* @pPath: The path of the document that #LOKDocView widget should try to open
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the document is loaded succesfully, %FALSE otherwise
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT gboolean
|
2015-06-18 21:52:22 +05:30
|
|
|
lok_doc_view_open_document (LOKDocView* pDocView, const gchar* pPath)
|
2014-06-23 15:13:25 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
|
|
|
|
if ( priv->m_pDocument )
|
2014-06-23 15:13:25 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_pDocument->pClass->destroy( priv->m_pDocument );
|
|
|
|
priv->m_pDocument = 0;
|
2014-06-23 15:13:25 +01:00
|
|
|
}
|
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_pOffice->pClass->registerCallback(priv->m_pOffice, globalCallbackWorker, pDocView);
|
|
|
|
priv->m_pDocument = priv->m_pOffice->pClass->documentLoad( priv->m_pOffice, pPath );
|
|
|
|
if ( !priv->m_pDocument )
|
2014-06-26 11:14:50 +01:00
|
|
|
{
|
|
|
|
// FIXME: should have a GError parameter and populate it.
|
2015-06-19 01:06:50 +05:30
|
|
|
char *pError = priv->m_pOffice->pClass->getError( priv->m_pOffice );
|
2014-06-26 11:14:50 +01:00
|
|
|
fprintf( stderr, "Error opening document '%s'\n", pError );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
2015-01-06 15:56:23 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_pDocument->pClass->initializeForRendering(priv->m_pDocument);
|
|
|
|
priv->m_pDocument->pClass->registerCallback(priv->m_pDocument, callbackWorker, pDocView);
|
|
|
|
priv->m_pDocument->pClass->getDocumentSize(priv->m_pDocument, &priv->m_nDocumentWidthTwips, &priv->m_nDocumentHeightTwips);
|
2015-06-11 22:00:11 +05:30
|
|
|
g_timeout_add(600, handleTimeout, pDocView);
|
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
float zoom = priv->m_fZoom;
|
|
|
|
long nDocumentWidthTwips = priv->m_nDocumentWidthTwips;
|
|
|
|
long nDocumentHeightTwips = priv->m_nDocumentHeightTwips;
|
2015-06-04 13:56:46 +05:30
|
|
|
long nDocumentWidthPixels = twipToPixel(nDocumentWidthTwips, zoom);
|
|
|
|
long nDocumentHeightPixels = twipToPixel(nDocumentHeightTwips, zoom);
|
2015-06-09 11:42:41 +02:00
|
|
|
// Total number of columns in this document.
|
2015-06-04 00:06:46 +05:30
|
|
|
guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
|
2015-06-08 14:17:17 +05:30
|
|
|
|
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_aTileBuffer = TileBuffer(priv->m_pDocument,
|
|
|
|
nColumns);
|
2015-06-09 16:27:37 +05:30
|
|
|
gtk_widget_set_size_request(GTK_WIDGET(pDocView),
|
2015-06-05 20:38:55 +05:30
|
|
|
nDocumentWidthPixels,
|
|
|
|
nDocumentHeightPixels);
|
2015-01-06 15:56:23 +01:00
|
|
|
}
|
2014-06-26 11:14:50 +01:00
|
|
|
return TRUE;
|
2014-06-12 17:38:10 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_get_document:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
*
|
|
|
|
* Returns: The #LibreOfficeKitDocument instance the widget is currently showing
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument*
|
|
|
|
lok_doc_view_get_document (LOKDocView* pDocView)
|
2015-03-20 10:16:07 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_pDocument;
|
2015-03-20 10:16:07 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_set_zoom:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
* @fZoom: The new zoom level that pDocView must set it into.
|
|
|
|
*
|
|
|
|
* Sets the new zoom level for the widget.
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_set_zoom (LOKDocView* pDocView, float fZoom)
|
2014-06-23 15:13:25 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
|
|
|
|
priv->m_fZoom = fZoom;
|
|
|
|
long nDocumentWidthPixels = twipToPixel(priv->m_nDocumentWidthTwips, fZoom);
|
|
|
|
long nDocumentHeightPixels = twipToPixel(priv->m_nDocumentHeightTwips, fZoom);
|
2015-06-09 11:42:41 +02:00
|
|
|
// Total number of columns in this document.
|
2015-06-04 00:06:46 +05:30
|
|
|
guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
|
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_aTileBuffer = TileBuffer(priv->m_pDocument,
|
|
|
|
nColumns);
|
2015-06-09 16:27:37 +05:30
|
|
|
gtk_widget_set_size_request(GTK_WIDGET(pDocView),
|
2015-06-05 20:38:55 +05:30
|
|
|
nDocumentWidthPixels,
|
|
|
|
nDocumentHeightPixels);
|
2014-06-23 15:13:25 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_get_zoom:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
*
|
|
|
|
* Returns: The current zoom factor value in float for pDocView
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT float
|
|
|
|
lok_doc_view_get_zoom (LOKDocView* pDocView)
|
2014-06-23 15:13:25 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_fZoom;
|
2014-06-23 15:13:25 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT int
|
|
|
|
lok_doc_view_get_parts (LOKDocView* pDocView)
|
2014-07-08 15:32:20 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_pDocument->pClass->getParts( priv->m_pDocument );
|
2014-07-08 15:32:20 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT int
|
|
|
|
lok_doc_view_get_part (LOKDocView* pDocView)
|
2014-07-08 15:32:20 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_pDocument->pClass->getPart( priv->m_pDocument );
|
2014-07-08 15:32:20 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_set_part (LOKDocView* pDocView, int nPart)
|
2014-07-08 15:32:20 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
priv->m_pDocument->pClass->setPart( priv->m_pDocument, nPart );
|
2014-07-08 15:32:20 +02:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT char*
|
|
|
|
lok_doc_view_get_part_name (LOKDocView* pDocView, int nPart)
|
2014-07-29 13:17:30 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_pDocument->pClass->getPartName( priv->m_pDocument, nPart );
|
2014-07-29 13:17:30 +02:00
|
|
|
}
|
2014-07-29 17:00:33 +02:00
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_set_partmode(LOKDocView* pDocView,
|
|
|
|
int nPartMode)
|
2014-07-29 17:00:33 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
priv->m_pDocument->pClass->setPartMode( priv->m_pDocument, nPartMode );
|
2014-07-29 17:00:33 +02:00
|
|
|
}
|
2015-01-13 16:47:23 +01:00
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_set_edit:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
* @bEdit: %TRUE if the pDocView should go in edit mode, %FALSE otherwise
|
|
|
|
*
|
|
|
|
* Sets the edit-mode for pDocView
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_set_edit(LOKDocView* pDocView,
|
|
|
|
gboolean bEdit)
|
2015-01-13 16:47:23 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
gboolean bWasEdit = priv->m_bEdit;
|
2015-03-10 12:50:59 +01:00
|
|
|
|
2015-06-19 01:06:50 +05:30
|
|
|
if (!priv->m_bEdit && bEdit)
|
2015-06-06 02:32:54 +05:30
|
|
|
g_info("lok_doc_view_set_edit: entering edit mode");
|
2015-06-19 01:06:50 +05:30
|
|
|
else if (priv->m_bEdit && !bEdit)
|
2015-03-10 16:13:53 +01:00
|
|
|
{
|
2015-06-06 02:32:54 +05:30
|
|
|
g_info("lok_doc_view_set_edit: leaving edit mode");
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_pDocument->pClass->resetSelection(priv->m_pDocument);
|
2015-03-10 16:13:53 +01:00
|
|
|
}
|
2015-06-19 01:06:50 +05:30
|
|
|
priv->m_bEdit = bEdit;
|
2015-06-06 02:32:54 +05:30
|
|
|
g_signal_emit(pDocView, doc_view_signals[EDIT_CHANGED], 0, bWasEdit);
|
2015-06-09 16:27:37 +05:30
|
|
|
gtk_widget_queue_draw(GTK_WIDGET(pDocView));
|
2015-01-13 16:47:23 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_get_edit:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the given pDocView is in edit mode.
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT gboolean
|
|
|
|
lok_doc_view_get_edit (LOKDocView* pDocView)
|
2015-03-10 11:18:25 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return priv->m_bEdit;
|
2015-03-10 11:18:25 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_post_command:
|
|
|
|
* @pDocView: the #LOKDocView instance
|
|
|
|
* @pCommand: the command to issue to LO core
|
|
|
|
* @pArguments: the arguments to the given command
|
|
|
|
*
|
|
|
|
* This methods forwards your command to LO core.
|
|
|
|
*/
|
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_post_command (LOKDocView* pDocView,
|
|
|
|
const char* pCommand,
|
|
|
|
const char* pArguments)
|
2015-03-12 14:59:59 +01:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
priv->m_pDocument->pClass->postUnoCommand(priv->m_pDocument, pCommand, pArguments);
|
2015-03-12 14:59:59 +01:00
|
|
|
}
|
|
|
|
|
2015-06-11 22:00:11 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_post_key:
|
|
|
|
* @pDocView: the #LOKDocView instance
|
|
|
|
* @pEvent: the #GdkEventKey containing information about the event
|
|
|
|
*
|
|
|
|
* This methods forwards your key events to the LO core.
|
|
|
|
*/
|
|
|
|
SAL_DLLPUBLIC_EXPORT void
|
|
|
|
lok_doc_view_post_key (LOKDocView* pDocView, GdkEvent* pEvent)
|
2015-03-25 17:54:11 +01:00
|
|
|
{
|
2015-06-11 22:00:11 +05:30
|
|
|
signalKey(pDocView, pEvent);
|
2015-03-25 17:54:11 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_pixel_to_twip:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
* @fInput: The value in pixels to convert to twips
|
|
|
|
*
|
|
|
|
* Converts the value in pixels to twips according to zoom level.
|
|
|
|
*
|
|
|
|
* Returns: The corresponding value in twips
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT float
|
|
|
|
lok_doc_view_pixel_to_twip (LOKDocView* pDocView, float fInput)
|
2015-05-28 17:21:50 +02:00
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return pixelToTwip(fInput, priv->m_fZoom);
|
2015-05-28 17:21:50 +02:00
|
|
|
}
|
|
|
|
|
2015-06-09 18:08:59 +05:30
|
|
|
/**
|
|
|
|
* lok_doc_view_twip_to_pixel:
|
|
|
|
* @pDocView: The #LOKDocView instance
|
|
|
|
* @fInput: The value in twips to convert to pixels
|
|
|
|
*
|
|
|
|
* Converts the value in twips to pixels according to zoom level.
|
|
|
|
*
|
|
|
|
* Returns: The corresponding value in pixels
|
|
|
|
*/
|
2015-06-11 22:00:11 +05:30
|
|
|
SAL_DLLPUBLIC_EXPORT float
|
|
|
|
lok_doc_view_twip_to_pixel (LOKDocView* pDocView, float fInput)
|
2015-06-09 16:27:37 +05:30
|
|
|
{
|
2015-06-19 01:06:50 +05:30
|
|
|
LOKDocViewPrivate *priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
|
|
|
|
return twipToPixel(fInput, priv->m_fZoom);
|
2015-06-09 16:27:37 +05:30
|
|
|
}
|
|
|
|
|
2014-06-12 17:38:10 +01:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|