tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / libreofficekit / qa / gtktiledviewer / gtv-lokdocview-signal-handlers.cxx
blob520472f201e5d2cf222978cd2eeeb9ee3af69153
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <gtk/gtk.h>
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));
27 return FALSE;
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));
36 return FALSE;
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)
56 return;
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);
61 if (pItem != nullptr)
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: ");
88 if (aValue.empty())
89 aText += "none";
90 else
91 aText += aValue;
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);
130 #else
131 (void) pDocView;
132 gtk_show_uri(nullptr, pPayload, GDK_CURRENT_TIME, &pError);
133 #endif
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;
148 gdouble upper;
149 gint x = -1, y = -1;
151 gtv_application_window_get_visible_area(window, &visArea);
153 // check vertically
154 if (nY < visArea.y)
156 y = nY - visArea.height/2;
157 if (y < 0)
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));
164 if (y > upper)
165 y = upper;
169 if (nX < visArea.x)
171 x = nX - visArea.width/2;
172 if (x < 0)
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));
179 if (x > upper)
180 x = upper;
183 if (y!=-1)
184 gtk_adjustment_set_value(vadj, lok_doc_view_twip_to_pixel(pDocView, y));
185 if (x!=-1)
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::contentControl(LOKDocView* pDocView, gchar* pJson, gpointer)
207 GtvApplicationWindow* window
208 = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView)));
209 GtvMainToolbar* toolbar = gtv_application_window_get_main_toolbar(window);
210 gtv_application_window_set_part_broadcast(window, false);
211 gtk_list_store_clear(
212 GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(toolbar->m_pContentControlSelector))));
213 if (!window->lokdocview)
215 return;
218 std::stringstream aStream(pJson);
219 boost::property_tree::ptree aTree;
220 boost::property_tree::read_json(aStream, aTree);
221 boost::optional<boost::property_tree::ptree&> oItems = aTree.get_child_optional("items");
222 if (oItems)
224 for (const auto& rItem : *oItems)
226 std::string aValue = rItem.second.get_value<std::string>();
227 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toolbar->m_pContentControlSelector),
228 aValue.c_str());
232 boost::optional<boost::property_tree::ptree&> oDate = aTree.get_child_optional("date");
233 gtk_widget_set_sensitive(GTK_WIDGET(toolbar->m_pContentControlDateSelector), bool(oDate));
235 gtv_application_window_set_part_broadcast(window, true);
238 void LOKDocViewSigHandlers::passwordRequired(LOKDocView* pDocView, char* pUrl, gboolean bModify, gpointer)
240 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView)));
241 GtkWidget* pPasswordDialog = gtk_dialog_new_with_buttons ("Password required",
242 GTK_WINDOW (window),
243 GTK_DIALOG_MODAL,
244 "OK",
245 GTK_RESPONSE_OK,
246 nullptr);
247 g_object_set(G_OBJECT(pPasswordDialog), "resizable", FALSE, nullptr);
248 GtkWidget* pDialogMessageArea = gtk_dialog_get_content_area (GTK_DIALOG (pPasswordDialog));
249 GtkWidget* pPasswordEntry = gtk_entry_new ();
250 gtk_entry_set_visibility (GTK_ENTRY(pPasswordEntry), FALSE);
251 gtk_entry_set_invisible_char (GTK_ENTRY(pPasswordEntry), '*');
252 gtk_box_pack_end(GTK_BOX(pDialogMessageArea), pPasswordEntry, true, true, 2);
253 if (bModify)
255 GtkWidget* pSecondaryLabel = gtk_label_new ("Document requires password to edit");
256 gtk_box_pack_end(GTK_BOX(pDialogMessageArea), pSecondaryLabel, true, true, 2);
257 gtk_dialog_add_button (GTK_DIALOG (pPasswordDialog), "Open as read-only", GTK_RESPONSE_ACCEPT);
259 gtk_widget_show_all(pPasswordDialog);
261 gint res = gtk_dialog_run (GTK_DIALOG(pPasswordDialog));
262 switch (res)
264 case GTK_RESPONSE_OK:
265 lok_doc_view_set_document_password (LOK_DOC_VIEW(window->lokdocview), pUrl, gtk_entry_get_text(GTK_ENTRY(pPasswordEntry)));
266 break;
267 case GTK_RESPONSE_ACCEPT:
268 // User accepts to open this document as read-only
269 case GTK_RESPONSE_DELETE_EVENT:
270 lok_doc_view_set_document_password (LOK_DOC_VIEW(window->lokdocview), pUrl, nullptr);
271 break;
274 gtk_widget_destroy(pPasswordDialog);
277 void LOKDocViewSigHandlers::comment(LOKDocView* pDocView, gchar* pComment, gpointer)
279 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pDocView)));
281 std::stringstream aStream(pComment);
282 boost::property_tree::ptree aRoot;
283 boost::property_tree::read_json(aStream, aRoot);
284 boost::property_tree::ptree aComment = aRoot.get_child("comment");
285 GtvCommentsSidebar* sidebar = GTV_COMMENTS_SIDEBAR(window->commentssidebar);
286 GtkWidget* pCommentsGrid = sidebar->commentsgrid;
287 GtvGtkWrapper<GList> pChildren(gtk_container_get_children(GTK_CONTAINER(pCommentsGrid)),
288 [](GList* l)
290 g_list_free(l);
292 GtkWidget* pSelf = nullptr;
293 GtkWidget* pParent = nullptr;
294 for (GList* l = pChildren.get(); l != nullptr; l = l->next)
296 gchar *id = static_cast<gchar*>(g_object_get_data(G_OBJECT(l->data), "id"));
298 if (g_strcmp0(id, aComment.get<std::string>("id").c_str()) == 0)
299 pSelf = GTK_WIDGET(l->data);
301 // There is no 'parent' in Remove callbacks
302 if (g_strcmp0(id, aComment.get("parent", std::string("0")).c_str()) == 0)
303 pParent = GTK_WIDGET(l->data);
306 if (aComment.get<std::string>("action") == "Remove")
308 if (pSelf)
309 gtk_widget_destroy(pSelf);
310 else
311 g_warning("Can't find the comment to remove in the list !!");
313 else if (aComment.get<std::string>("action") == "Add" || aComment.get<std::string>("action") == "Modify")
315 GtkWidget* pCommentBox = GtvHelpers::createCommentBox(aComment);
316 if (pSelf != nullptr || pParent != nullptr)
318 gtk_grid_insert_next_to(GTK_GRID(pCommentsGrid), pSelf != nullptr ? pSelf : pParent, GTK_POS_BOTTOM);
319 gtk_grid_attach_next_to(GTK_GRID(pCommentsGrid), pCommentBox, pSelf != nullptr ? pSelf : pParent, GTK_POS_BOTTOM, 1, 1);
321 else
322 gtk_container_add(GTK_CONTAINER(pCommentsGrid), pCommentBox);
324 gtk_widget_show_all(pCommentBox);
326 // We added the widget already below the existing one, so destroy the
327 // already existing one now
328 if (pSelf)
329 gtk_widget_destroy(pSelf);
333 void LOKDocViewSigHandlers::window(LOKDocView* pDocView, gchar* pPayload, gpointer pData)
335 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(pData);
337 std::stringstream aStream(pPayload);
338 boost::property_tree::ptree aRoot;
339 boost::property_tree::read_json(aStream, aRoot);
340 const unsigned nWinId = aRoot.get<unsigned>("id");
341 const std::string aAction = aRoot.get<std::string>("action");
343 if (aAction == "created")
345 const std::string aType = aRoot.get<std::string>("type");
346 const std::string aSize = aRoot.get<std::string>("size");
347 const std::string aTitle = aRoot.get<std::string>("title", "");
348 std::vector<int> aSizePoints = GtvHelpers::split<int>(aSize, ", ", 2);
350 if (aType == "dialog")
352 GtkWidget* pDialog = gtv_lok_dialog_new(pDocView, nWinId, aSizePoints[0], aSizePoints[1]);
353 g_info("created dialog, for dialogid: %d with size: %s", nWinId, aSize.c_str());
355 gtv_application_window_register_child_window(window, GTK_WINDOW(pDialog));
356 g_signal_connect(pDialog, "destroy", G_CALLBACK(destroyLokDialog), window);
357 g_signal_connect(pDialog, "delete-event", G_CALLBACK(deleteLokDialog), window);
359 if (!aTitle.empty())
360 gtk_window_set_title(GTK_WINDOW(pDialog), aTitle.c_str());
362 gtk_window_set_resizable(GTK_WINDOW(pDialog), false);
363 gtk_widget_show_all(GTK_WIDGET(pDialog));
364 gtk_window_present(GTK_WINDOW(pDialog));
366 else if (aType == "child")
368 const unsigned nParentId = std::atoi(aRoot.get<std::string>("parentId").c_str());
369 GtkWindow* pDialog = gtv_application_window_get_child_window_by_id(window, nParentId);
370 if (!pDialog)
372 g_warning("no parent dialog (id: %d) for created child; is child a sidebar?", nParentId);
373 return;
375 const std::string aPos = aRoot.get<std::string>("position");
376 std::vector<int> aPosPoints = GtvHelpers::split<int>(aPos, ", ", 2);
377 gtv_lok_dialog_child_create(GTV_LOK_DIALOG(pDialog), nWinId, aPosPoints[0], aPosPoints[1], aSizePoints[0], aSizePoints[1]);
380 else
382 // check if it's a child window
383 GtkWidget* pParent = gtv_application_window_get_parent(window, nWinId);
384 if (pParent) // it's a floating window in the dialog
386 if (aAction == "invalidate")
387 gtv_lok_dialog_child_invalidate(GTV_LOK_DIALOG(pParent));
388 else if (aAction == "close")
389 gtv_lok_dialog_child_close(GTV_LOK_DIALOG(pParent));
391 else if (GtkWindow* pDialog = gtv_application_window_get_child_window_by_id(window, nWinId))
392 { // it's the dialog window itself
393 if (aAction == "close")
394 gtk_widget_destroy(GTK_WIDGET(pDialog));
395 else if (aAction == "size_changed")
397 const std::string aSize = aRoot.get<std::string>("size");
398 std::vector<int> aSizePoints = GtvHelpers::split<int>(aSize, ", ", 2);
399 if (aSizePoints.size() != 2)
401 g_error("Malformed size_changed callback");
402 return;
405 g_object_set(G_OBJECT(pDialog),
406 "width", aSizePoints[0],
407 "height", aSizePoints[1],
408 nullptr);
410 GdkRectangle aGdkRectangle = {0, 0, 0, 0};
411 gtv_lok_dialog_invalidate(GTV_LOK_DIALOG(pDialog), aGdkRectangle);
413 else if (aAction == "invalidate")
415 GdkRectangle aGdkRectangle = {0, 0, 0, 0};
418 const std::string aRectangle = aRoot.get<std::string>("rectangle");
419 std::vector<int> aRectPoints = GtvHelpers::split<int>(aRectangle, ", ", 4);
420 if (aRectPoints.size() == 4)
421 aGdkRectangle = {aRectPoints[0], aRectPoints[1], aRectPoints[2], aRectPoints[3]};
423 catch(const std::exception&)
426 gtv_lok_dialog_invalidate(GTV_LOK_DIALOG(pDialog), aGdkRectangle);
428 else if (aAction == "title_changed")
430 const std::string aTitle = aRoot.get<std::string>("title", "");
431 gtk_window_set_title(pDialog, aTitle.c_str());
437 gboolean LOKDocViewSigHandlers::configureEvent(GtkWidget* pWidget, GdkEventConfigure* /*pEvent*/, gpointer /*pData*/)
439 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(pWidget)));
441 gboolean isInit = false;
442 g_object_get(G_OBJECT(window->lokdocview), "is-initialized", &isInit, nullptr);
443 if (!isInit)
445 g_info("Ignoring configure event; document not yet ready");
446 return false;
449 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
450 if (!pDocument || pDocument->pClass->getDocumentType(pDocument) != LOK_DOCTYPE_SPREADSHEET)
451 return true;
453 GtkAdjustment* pVAdjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window->scrolledwindow));
454 int rowSizePixel = GTV_CALC_HEADER_BAR(window->rowbar)->m_nSizePixel = gtk_adjustment_get_page_size(pVAdjustment);
455 int rowPosPixel = GTV_CALC_HEADER_BAR(window->rowbar)->m_nPositionPixel = gtk_adjustment_get_value(pVAdjustment);
456 GtkAdjustment* pHAdjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window->scrolledwindow));
457 int colSizePixel = GTV_CALC_HEADER_BAR(window->columnbar)->m_nSizePixel = gtk_adjustment_get_page_size(pHAdjustment);
458 int colPosPixel = GTV_CALC_HEADER_BAR(window->columnbar)->m_nPositionPixel = gtk_adjustment_get_value(pHAdjustment);
460 std::stringstream aCommand;
461 aCommand << ".uno:ViewRowColumnHeaders";
462 aCommand << "?x=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window->lokdocview), colPosPixel));
463 aCommand << "&width=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window->lokdocview), colSizePixel));
464 aCommand << "&y=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window->lokdocview), rowPosPixel));
465 aCommand << "&height=" << int(lok_doc_view_pixel_to_twip(LOK_DOC_VIEW(window->lokdocview), rowSizePixel));
466 std::stringstream ss;
467 ss << "lok::Document::getCommandValues(" << aCommand.str() << ")";
468 g_info("%s", ss.str().c_str());
469 char* pValues = pDocument->pClass->getCommandValues(pDocument, aCommand.str().c_str());
470 g_info("lok::Document::getCommandValues() returned '%s'", pValues);
471 std::stringstream aStream(pValues);
472 free(pValues);
473 assert(!aStream.str().empty());
474 boost::property_tree::ptree aTree;
475 boost::property_tree::read_json(aStream, aTree);
477 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window->rowbar), &aTree.get_child("rows"));
478 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window->columnbar), &aTree.get_child("columns"));
479 gtv_calc_header_bar_configure(GTV_CALC_HEADER_BAR(window->cornerarea), nullptr);
481 return true;
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */