1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
12 #include "gtv-application-window.hxx"
13 #include "gtv-helpers.hxx"
14 #include "gtv-calc-header-bar.hxx"
15 #include "gtv-comments-sidebar.hxx"
16 #include "gtv-lokdocview-signal-handlers.hxx"
17 #include "gtv-lok-dialog.hxx"
19 #include <boost/property_tree/json_parser.hpp>
21 static gboolean
deleteLokDialog(GtkWidget
* pWidget
, GdkEvent
* /*event*/, gpointer userdata
)
23 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(userdata
);
24 g_info("deleteLokDialog");
25 gtv_application_window_unregister_child_window(window
, GTK_WINDOW(pWidget
));
30 static gboolean
destroyLokDialog(GtkWidget
* pWidget
, gpointer userdata
)
32 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(userdata
);
33 g_info("destroyLokDialog");
34 gtv_application_window_unregister_child_window(window
, GTK_WINDOW(pWidget
));
39 void LOKDocViewSigHandlers::editChanged(LOKDocView
* pDocView
, gboolean bWasEdit
, gpointer
)
41 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
42 bool bEdit
= lok_doc_view_get_edit(LOK_DOC_VIEW(window
->lokdocview
));
43 g_info("signalEdit: %d -> %d", bWasEdit
, bEdit
);
45 // Let the main toolbar know, so that it can enable disable the button
46 GtvMainToolbar
* pMainToolbar
= gtv_application_window_get_main_toolbar(GTV_APPLICATION_WINDOW(window
));
47 gtv_main_toolbar_set_edit(pMainToolbar
, bEdit
);
50 void LOKDocViewSigHandlers::commandChanged(LOKDocView
* pDocView
, char* pPayload
, gpointer
)
52 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
53 std::string
aPayload(pPayload
);
54 size_t nPosition
= aPayload
.find('=');
55 if (nPosition
== std::string::npos
)
58 const std::string aKey
= aPayload
.substr(0, nPosition
);
59 const std::string aValue
= aPayload
.substr(nPosition
+ 1);
60 GtkToolItem
* pItem
= gtv_application_window_find_tool_by_unocommand(window
, aKey
);
63 if (aValue
== "true" || aValue
== "false") {
64 bool bEdit
= aValue
== "true";
65 if (bool(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(pItem
))) != bEdit
)
67 // Avoid invoking lok_doc_view_post_command().
68 // FIXME: maybe block/unblock the signal (see
69 // g_signal_handlers_block_by_func) ?
70 gtv_application_window_set_toolbar_broadcast(window
, false);
71 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(pItem
), bEdit
);
72 gtv_application_window_set_toolbar_broadcast(window
, true);
75 } else if (aValue
== "enabled" || aValue
== "disabled") {
76 bool bSensitive
= aValue
== "enabled";
77 gtk_widget_set_sensitive(GTK_WIDGET(pItem
), bSensitive
);
79 // Remember state, so in case edit is disable and enabled
80 // later, the correct sensitivity can be restored.
81 GtvMainToolbar
* pMainToolbar
= gtv_application_window_get_main_toolbar(window
);
82 gtv_main_toolbar_set_sensitive_internal(pMainToolbar
, pItem
, bSensitive
);
85 else if (aKey
== ".uno:TrackedChangeIndex")
87 std::string
aText("Current redline: ");
92 gtk_label_set_text(GTK_LABEL(window
->redlinelabel
), aText
.c_str());
96 void LOKDocViewSigHandlers::commandResult(LOKDocView
*, char* pPayload
, gpointer
)
98 fprintf(stderr
, "Command finished: %s\n", pPayload
);
101 void LOKDocViewSigHandlers::searchNotFound(LOKDocView
* pDocView
, char* , gpointer
)
103 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
104 gtk_label_set_text(GTK_LABEL(window
->findbarlabel
), "Search key not found");
107 void LOKDocViewSigHandlers::searchResultCount(LOKDocView
* pDocView
, char* pPayload
, gpointer
)
109 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
110 std::stringstream ss
;
111 ss
<< pPayload
<< " match(es)";
112 gtk_label_set_text(GTK_LABEL(window
->findbarlabel
), ss
.str().c_str());
115 void LOKDocViewSigHandlers::partChanged(LOKDocView
* /*pDocView*/, int, gpointer
)
117 // GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView)));
118 //rWindow.m_bPartSelectorBroadcast = false;
119 // gtk_combo_box_set_active(GTK_COMBO_BOX(rWindow.m_pPartSelector), nPart);
120 // rWindow.m_bPartSelectorBroadcast = true;
123 void LOKDocViewSigHandlers::hyperlinkClicked(LOKDocView
* pDocView
, char* pPayload
, gpointer
)
125 GError
* pError
= nullptr;
126 #if GTK_CHECK_VERSION(3,22,0)
127 gtk_show_uri_on_window(
128 GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET(pDocView
))),
129 pPayload
, GDK_CURRENT_TIME
, &pError
);
132 gtk_show_uri(nullptr, pPayload
, GDK_CURRENT_TIME
, &pError
);
134 if (pError
!= nullptr)
136 g_warning("Unable to show URI %s : %s", pPayload
, pError
->message
);
137 g_error_free(pError
);
141 void LOKDocViewSigHandlers::cursorChanged(LOKDocView
* pDocView
, gint nX
, gint nY
,
142 gint
/*nWidth*/, gint
/*nHeight*/, gpointer
/*pData*/)
144 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
145 GtkAdjustment
* vadj
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window
->scrolledwindow
));
146 GtkAdjustment
* hadj
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window
->scrolledwindow
));
147 GdkRectangle visArea
;
151 gtv_application_window_get_visible_area(window
, &visArea
);
156 y
= nY
- visArea
.height
/2;
158 y
= gtk_adjustment_get_lower(vadj
);
160 else if (nY
> visArea
.y
+ visArea
.height
)
162 y
= nY
- visArea
.height
/2;
163 upper
= lok_doc_view_pixel_to_twip(pDocView
, gtk_adjustment_get_upper(vadj
));
171 x
= nX
- visArea
.width
/2;
173 x
= gtk_adjustment_get_lower(hadj
);
175 else if (nX
> visArea
.x
+ visArea
.width
)
177 x
= nX
- visArea
.width
/2;
178 upper
= lok_doc_view_pixel_to_twip(pDocView
, gtk_adjustment_get_upper(hadj
));
184 gtk_adjustment_set_value(vadj
, lok_doc_view_twip_to_pixel(pDocView
, y
));
186 gtk_adjustment_set_value(hadj
, lok_doc_view_twip_to_pixel(pDocView
, x
));
189 void LOKDocViewSigHandlers::addressChanged(LOKDocView
* pDocView
, char* pPayload
, gpointer
)
191 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
192 GtvMainToolbar
* toolbar
= gtv_application_window_get_main_toolbar(window
);
193 GtkEntry
* pAddressbar
= GTK_ENTRY(toolbar
->m_pAddressbar
);
194 gtk_entry_set_text(pAddressbar
, pPayload
);
197 void LOKDocViewSigHandlers::formulaChanged(LOKDocView
* pDocView
, char* pPayload
, gpointer
)
199 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
200 GtvMainToolbar
* toolbar
= gtv_application_window_get_main_toolbar(window
);
201 GtkEntry
* pFormulabar
= GTK_ENTRY(toolbar
->m_pFormulabar
);
202 gtk_entry_set_text(pFormulabar
, pPayload
);
205 void LOKDocViewSigHandlers::passwordRequired(LOKDocView
* pDocView
, char* pUrl
, gboolean bModify
, gpointer
)
207 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
208 GtkWidget
* pPasswordDialog
= gtk_dialog_new_with_buttons ("Password required",
214 g_object_set(G_OBJECT(pPasswordDialog
), "resizable", FALSE
, nullptr);
215 GtkWidget
* pDialogMessageArea
= gtk_dialog_get_content_area (GTK_DIALOG (pPasswordDialog
));
216 GtkWidget
* pPasswordEntry
= gtk_entry_new ();
217 gtk_entry_set_visibility (GTK_ENTRY(pPasswordEntry
), FALSE
);
218 gtk_entry_set_invisible_char (GTK_ENTRY(pPasswordEntry
), '*');
219 gtk_box_pack_end(GTK_BOX(pDialogMessageArea
), pPasswordEntry
, true, true, 2);
222 GtkWidget
* pSecondaryLabel
= gtk_label_new ("Document requires password to edit");
223 gtk_box_pack_end(GTK_BOX(pDialogMessageArea
), pSecondaryLabel
, true, true, 2);
224 gtk_dialog_add_button (GTK_DIALOG (pPasswordDialog
), "Open as read-only", GTK_RESPONSE_ACCEPT
);
226 gtk_widget_show_all(pPasswordDialog
);
228 gint res
= gtk_dialog_run (GTK_DIALOG(pPasswordDialog
));
231 case GTK_RESPONSE_OK
:
232 lok_doc_view_set_document_password (LOK_DOC_VIEW(window
->lokdocview
), pUrl
, gtk_entry_get_text(GTK_ENTRY(pPasswordEntry
)));
234 case GTK_RESPONSE_ACCEPT
:
235 // User accepts to open this document as read-only
236 case GTK_RESPONSE_DELETE_EVENT
:
237 lok_doc_view_set_document_password (LOK_DOC_VIEW(window
->lokdocview
), pUrl
, nullptr);
241 gtk_widget_destroy(pPasswordDialog
);
244 void LOKDocViewSigHandlers::comment(LOKDocView
* pDocView
, gchar
* pComment
, gpointer
)
246 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView
)));
248 std::stringstream
aStream(pComment
);
249 boost::property_tree::ptree aRoot
;
250 boost::property_tree::read_json(aStream
, aRoot
);
251 boost::property_tree::ptree aComment
= aRoot
.get_child("comment");
252 GtvCommentsSidebar
* sidebar
= GTV_COMMENTS_SIDEBAR(window
->commentssidebar
);
253 GtkWidget
* pCommentsGrid
= sidebar
->commentsgrid
;
254 GtvGtkWrapper
<GList
> pChildren(gtk_container_get_children(GTK_CONTAINER(pCommentsGrid
)),
259 GtkWidget
* pSelf
= nullptr;
260 GtkWidget
* pParent
= nullptr;
261 for (GList
* l
= pChildren
.get(); l
!= nullptr; l
= l
->next
)
263 gchar
*id
= static_cast<gchar
*>(g_object_get_data(G_OBJECT(l
->data
), "id"));
265 if (g_strcmp0(id
, aComment
.get
<std::string
>("id").c_str()) == 0)
266 pSelf
= GTK_WIDGET(l
->data
);
268 // There is no 'parent' in Remove callbacks
269 if (g_strcmp0(id
, aComment
.get("parent", std::string("0")).c_str()) == 0)
270 pParent
= GTK_WIDGET(l
->data
);
273 if (aComment
.get
<std::string
>("action") == "Remove")
276 gtk_widget_destroy(pSelf
);
278 g_warning("Can't find the comment to remove in the list !!");
280 else if (aComment
.get
<std::string
>("action") == "Add" || aComment
.get
<std::string
>("action") == "Modify")
282 GtkWidget
* pCommentBox
= GtvHelpers::createCommentBox(aComment
);
283 if (pSelf
!= nullptr || pParent
!= nullptr)
285 gtk_grid_insert_next_to(GTK_GRID(pCommentsGrid
), pSelf
!= nullptr ? pSelf
: pParent
, GTK_POS_BOTTOM
);
286 gtk_grid_attach_next_to(GTK_GRID(pCommentsGrid
), pCommentBox
, pSelf
!= nullptr ? pSelf
: pParent
, GTK_POS_BOTTOM
, 1, 1);
289 gtk_container_add(GTK_CONTAINER(pCommentsGrid
), pCommentBox
);
291 gtk_widget_show_all(pCommentBox
);
293 // We added the widget already below the existing one, so destroy the
294 // already existing one now
296 gtk_widget_destroy(pSelf
);
300 void LOKDocViewSigHandlers::window(LOKDocView
* pDocView
, gchar
* pPayload
, gpointer pData
)
302 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(pData
);
304 std::stringstream
aStream(pPayload
);
305 boost::property_tree::ptree aRoot
;
306 boost::property_tree::read_json(aStream
, aRoot
);
307 const unsigned nWinId
= aRoot
.get
<unsigned>("id");
308 const std::string aAction
= aRoot
.get
<std::string
>("action");
310 if (aAction
== "created")
312 const std::string aType
= aRoot
.get
<std::string
>("type");
313 const std::string aSize
= aRoot
.get
<std::string
>("size");
314 const std::string aTitle
= aRoot
.get
<std::string
>("title", "");
315 std::vector
<int> aSizePoints
= GtvHelpers::split
<int>(aSize
, ", ", 2);
317 if (aType
== "dialog")
319 GtkWidget
* pDialog
= gtv_lok_dialog_new(pDocView
, nWinId
, aSizePoints
[0], aSizePoints
[1]);
320 g_info("created dialog, for dialogid: %d with size: %s", nWinId
, aSize
.c_str());
322 gtv_application_window_register_child_window(window
, GTK_WINDOW(pDialog
));
323 g_signal_connect(pDialog
, "destroy", G_CALLBACK(destroyLokDialog
), window
);
324 g_signal_connect(pDialog
, "delete-event", G_CALLBACK(deleteLokDialog
), window
);
327 gtk_window_set_title(GTK_WINDOW(pDialog
), aTitle
.c_str());
329 gtk_window_set_resizable(GTK_WINDOW(pDialog
), false);
330 gtk_widget_show_all(GTK_WIDGET(pDialog
));
331 gtk_window_present(GTK_WINDOW(pDialog
));
333 else if (aType
== "child")
335 const unsigned nParentId
= std::atoi(aRoot
.get
<std::string
>("parentId").c_str());
336 GtkWindow
* pDialog
= gtv_application_window_get_child_window_by_id(window
, nParentId
);
337 const std::string aPos
= aRoot
.get
<std::string
>("position");
338 std::vector
<int> aPosPoints
= GtvHelpers::split
<int>(aPos
, ", ", 2);
339 gtv_lok_dialog_child_create(GTV_LOK_DIALOG(pDialog
), nWinId
, aPosPoints
[0], aPosPoints
[1], aSizePoints
[0], aSizePoints
[1]);
344 // check if it's a child window
345 GtkWidget
* pParent
= gtv_application_window_get_parent(window
, nWinId
);
346 if (pParent
) // it's a floating window in the dialog
348 if (aAction
== "invalidate")
349 gtv_lok_dialog_child_invalidate(GTV_LOK_DIALOG(pParent
));
350 else if (aAction
== "close")
351 gtv_lok_dialog_child_close(GTV_LOK_DIALOG(pParent
));
353 else if (GtkWindow
* pDialog
= gtv_application_window_get_child_window_by_id(window
, nWinId
))
354 { // it's the dialog window itself
355 if (aAction
== "close")
356 gtk_widget_destroy(GTK_WIDGET(pDialog
));
357 else if (aAction
== "size_changed")
359 const std::string aSize
= aRoot
.get
<std::string
>("size");
360 std::vector
<int> aSizePoints
= GtvHelpers::split
<int>(aSize
, ", ", 2);
361 if (aSizePoints
.size() != 2)
363 g_error("Malformed size_changed callback");
367 g_object_set(G_OBJECT(pDialog
),
368 "width", aSizePoints
[0],
369 "height", aSizePoints
[1],
372 GdkRectangle aGdkRectangle
= {0, 0, 0, 0};
373 gtv_lok_dialog_invalidate(GTV_LOK_DIALOG(pDialog
), aGdkRectangle
);
375 else if (aAction
== "invalidate")
377 GdkRectangle aGdkRectangle
= {0, 0, 0, 0};
380 const std::string aRectangle
= aRoot
.get
<std::string
>("rectangle");
381 std::vector
<int> aRectPoints
= GtvHelpers::split
<int>(aRectangle
, ", ", 4);
382 if (aRectPoints
.size() == 4)
383 aGdkRectangle
= {aRectPoints
[0], aRectPoints
[1], aRectPoints
[2], aRectPoints
[3]};
385 catch(const std::exception
&)
388 gtv_lok_dialog_invalidate(GTV_LOK_DIALOG(pDialog
), aGdkRectangle
);
390 else if (aAction
== "title_changed")
392 const std::string aTitle
= aRoot
.get
<std::string
>("title", "");
393 gtk_window_set_title(pDialog
, aTitle
.c_str());
399 gboolean
LOKDocViewSigHandlers::configureEvent(GtkWidget
* pWidget
, GdkEventConfigure
* /*pEvent*/, gpointer
/*pData*/)
401 GtvApplicationWindow
* window
= GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pWidget
)));
403 gboolean isInit
= false;
404 g_object_get(G_OBJECT(window
->lokdocview
), "is-initialized", &isInit
, nullptr);
407 g_info("Ignoring configure event; document not yet ready");
411 LibreOfficeKitDocument
* pDocument
= lok_doc_view_get_document(LOK_DOC_VIEW(window
->lokdocview
));
412 if (pDocument
&& pDocument
->pClass
->getDocumentType(pDocument
) == LOK_DOCTYPE_SPREADSHEET
)
414 GtkAdjustment
* pVAdjustment
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window
->scrolledwindow
));
415 int rowSizePixel
= GTV_CALC_HEADER_BAR(window
->rowbar
)->m_nSizePixel
= gtk_adjustment_get_page_size(pVAdjustment
);
416 int rowPosPixel
= GTV_CALC_HEADER_BAR(window
->rowbar
)->m_nPositionPixel
= gtk_adjustment_get_value(pVAdjustment
);
417 GtkAdjustment
* pHAdjustment
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window
->scrolledwindow
));
418 int colSizePixel
= GTV_CALC_HEADER_BAR(window
->columnbar
)->m_nSizePixel
= gtk_adjustment_get_page_size(pHAdjustment
);
419 int colPosPixel
= GTV_CALC_HEADER_BAR(window
->columnbar
)->m_nPositionPixel
= gtk_adjustment_get_value(pHAdjustment
);
421 std::stringstream aCommand
;
422 aCommand
<< ".uno:ViewRowColumnHeaders";
423 aCommand
<< "?x=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window
->lokdocview
), colPosPixel
));
424 aCommand
<< "&width=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window
->lokdocview
), colSizePixel
));
425 aCommand
<< "&y=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window
->lokdocview
), rowPosPixel
));
426 aCommand
<< "&height=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window
->lokdocview
), rowSizePixel
));
427 std::stringstream ss
;
428 ss
<< "lok::Document::getCommandValues(" << aCommand
.str() << ")";
429 g_info("%s", ss
.str().c_str());
430 char* pValues
= pDocument
->pClass
->getCommandValues(pDocument
, aCommand
.str().c_str());
431 g_info("lok::Document::getCommandValues() returned '%s'", pValues
);
432 std::stringstream
aStream(pValues
);
434 assert(!aStream
.str().empty());
435 boost::property_tree::ptree aTree
;
436 boost::property_tree::read_json(aStream
, aTree
);
438 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window
->rowbar
), &aTree
.get_child("rows"));
439 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window
->columnbar
), &aTree
.get_child("columns"));
440 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window
->cornerarea
), nullptr);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */