bump product version to 6.4.0.3
[LibreOffice.git] / libreofficekit / qa / gtktiledviewer / gtv-signal-handlers.cxx
blob708d4d44045365cba7847f1546180269d1ea69d7
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-lokdocview-signal-handlers.hxx"
15 #include "gtv-lok-dialog.hxx"
17 #include <sal/types.h>
19 #include <map>
20 #include <vector>
22 #include <boost/property_tree/json_parser.hpp>
23 #include <boost/optional.hpp>
25 void btn_clicked(GtkWidget* pButton, gpointer)
27 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
28 GtkToolButton* pItem = GTK_TOOL_BUTTON(pButton);
29 const gchar* label = gtk_tool_button_get_label(pItem);
30 if (gtv_application_window_get_toolbar_broadcast(window) && g_str_has_prefix(label, ".uno:"))
32 std::string aArguments;
33 if (g_strcmp0(label, ".uno:InsertAnnotation") == 0)
35 std::map<std::string, std::string> aEntries;
36 aEntries["Text"] = "";
37 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Insert Comment", aEntries);
39 boost::property_tree::ptree aTree;
40 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "type", nullptr), '/'), "string");
41 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "value", nullptr), '/'), aEntries["Text"]);
43 std::stringstream aStream;
44 boost::property_tree::write_json(aStream, aTree);
45 aArguments = aStream.str();
48 bool bNotify = g_strcmp0(label, ".uno:Save") == 0;
49 if (window->lokdocview)
50 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), label, aArguments.c_str(), bNotify);
54 void doCopy(GtkWidget* pButton, gpointer /*pItem*/)
56 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
57 char* pUsedFormat = nullptr;
58 // TODO: Should check `text-selection` signal before trying to copy
59 char* pSelection = lok_doc_view_copy_selection(LOK_DOC_VIEW(window->lokdocview), "text/html", &pUsedFormat);
60 if (!pSelection)
61 return;
63 GtkClipboard* pClipboard = gtk_clipboard_get_for_display(gtk_widget_get_display(pButton), GDK_SELECTION_CLIPBOARD);
64 std::string aUsedFormat(pUsedFormat);
65 if (aUsedFormat == "text/plain;charset=utf-8")
66 gtk_clipboard_set_text(pClipboard, pSelection, -1);
67 else
68 GtvHelpers::clipboardSetHtml(pClipboard, pSelection);
70 free(pSelection);
71 free(pUsedFormat);
74 void doPaste(GtkWidget* pButton, gpointer /*pItem*/)
76 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
77 GtkClipboard* pClipboard = gtk_clipboard_get_for_display(gtk_widget_get_display(pButton), GDK_SELECTION_CLIPBOARD);
78 GdkAtom* pTargets;
79 gint nTargets;
80 std::map<std::string, GdkAtom> aTargets;
81 if (gtk_clipboard_wait_for_targets(pClipboard, &pTargets, &nTargets))
83 for (gint i = 0; i < nTargets; ++i)
85 gchar* pName = gdk_atom_name(pTargets[i]);
86 aTargets[pName] = pTargets[i];
87 g_free(pName);
89 g_free(pTargets);
92 boost::optional<GdkAtom> oTarget;
93 std::string aTargetName;
95 std::vector<std::string> aPreferredNames =
97 std::string("image/png"),
98 std::string("text/html")
100 for (const std::string& rName : aPreferredNames)
102 std::map<std::string, GdkAtom>::iterator it = aTargets.find(rName);
103 if (it != aTargets.end())
105 aTargetName = it->first;
106 oTarget = it->second;
107 break;
111 if (oTarget)
113 GtkSelectionData* pSelectionData = gtk_clipboard_wait_for_contents(pClipboard, *oTarget);
114 if (!pSelectionData)
116 return;
118 gint nLength;
119 const guchar* pData = gtk_selection_data_get_data_with_length(pSelectionData, &nLength);
120 bool bSuccess = lok_doc_view_paste(LOK_DOC_VIEW(window->lokdocview), aTargetName.c_str(), reinterpret_cast<const char*>(pData), nLength);
121 gtk_selection_data_free(pSelectionData);
122 if (bSuccess)
123 return;
126 gchar* pText = gtk_clipboard_wait_for_text(pClipboard);
127 if (pText)
128 lok_doc_view_paste(LOK_DOC_VIEW(window->lokdocview), "text/plain;charset=utf-8", pText, strlen(pText));
131 void createView(GtkWidget* pButton, gpointer /*pItem*/)
133 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
134 gtv_application_window_create_view_from_window(GTV_APPLICATION_WINDOW(window));
137 void getRulerState(GtkWidget* pButton, gpointer /*pItem*/)
139 const std::string type = ".uno:RulerState";
140 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
141 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
142 pDocument->pClass->getCommandValues(pDocument, type.c_str());
145 static void removeUnoParam(GtkWidget* pWidget, gpointer userdata)
147 GtkWidget* pParamAreaBox = GTK_WIDGET(userdata);
148 GtkWidget* pParamContainer = gtk_widget_get_parent(pWidget);
150 gtk_container_remove(GTK_CONTAINER(pParamAreaBox), pParamContainer);
153 static void addMoreUnoParam(GtkWidget* /*pWidget*/, gpointer userdata)
155 GtkWidget* pUnoParamAreaBox = GTK_WIDGET(userdata);
157 GtkWidget* pParamContainer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
158 gtk_box_pack_start(GTK_BOX(pUnoParamAreaBox), pParamContainer, TRUE, TRUE, 2);
160 GtkWidget* pTypeEntry = gtk_entry_new();
161 gtk_box_pack_start(GTK_BOX(pParamContainer), pTypeEntry, TRUE, TRUE, 2);
162 gtk_entry_set_placeholder_text(GTK_ENTRY(pTypeEntry), "Param type (Eg. boolean, string etc.)");
164 GtkWidget* pNameEntry = gtk_entry_new();
165 gtk_box_pack_start(GTK_BOX(pParamContainer), pNameEntry, TRUE, TRUE, 2);
166 gtk_entry_set_placeholder_text(GTK_ENTRY(pNameEntry), "Param name");
168 GtkWidget* pValueEntry = gtk_entry_new();
169 gtk_box_pack_start(GTK_BOX(pParamContainer), pValueEntry, TRUE, TRUE, 2);
170 gtk_entry_set_placeholder_text(GTK_ENTRY(pValueEntry), "Param value");
172 GtkWidget* pRemoveButton = gtk_button_new_from_icon_name("list-remove-symbolic", GTK_ICON_SIZE_BUTTON);
173 g_signal_connect(pRemoveButton, "clicked", G_CALLBACK(removeUnoParam), pUnoParamAreaBox);
174 gtk_box_pack_start(GTK_BOX(pParamContainer), pRemoveButton, TRUE, TRUE, 2);
176 gtk_widget_show_all(pUnoParamAreaBox);
179 static void iterateUnoParams(GtkWidget* pWidget, gpointer userdata)
181 boost::property_tree::ptree *pTree = static_cast<boost::property_tree::ptree*>(userdata);
182 GtvGtkWrapper<GList> pChildren(gtk_container_get_children(GTK_CONTAINER(pWidget)),
183 [](GList* pList) {
184 g_list_free(pList);
186 GList* pIt = nullptr;
187 guint i = 0;
188 const gchar* unoParam[3];
189 for (pIt = pChildren.get(), i = 0; pIt != nullptr && i < 3; pIt = pIt->next, i++)
191 unoParam[i] = gtk_entry_get_text(GTK_ENTRY(pIt->data));
194 pTree->put(boost::property_tree::ptree::path_type(g_strconcat(unoParam[1], "/", "type", nullptr), '/'), unoParam[0]);
195 pTree->put(boost::property_tree::ptree::path_type(g_strconcat(unoParam[1], "/", "value", nullptr), '/'), unoParam[2]);
198 void recentUnoChanged( GtkWidget* pSelector, gpointer /* pItem */ )
200 GtvApplicationWindow* pWindow = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
201 gchar* pUnoCmd = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(pSelector));
203 GtvMainToolbar* pToolbar = gtv_application_window_get_main_toolbar(pWindow);
204 const std::string aUnoArgs = gtv_main_toolbar_get_recent_uno_args(pToolbar, pUnoCmd);
205 // this will also discard our default placeholder string, "Recent UNO"
206 if (aUnoArgs.empty())
207 return;
209 lok_doc_view_post_command(LOK_DOC_VIEW(pWindow->lokdocview), pUnoCmd, (aUnoArgs.empty() ? nullptr : aUnoArgs.c_str()), false);
210 g_free(pUnoCmd);
213 static void addToRecentUnoCommands(GtvApplicationWindow* pWindow, const std::string& rUnoCmd, std::string rArgs)
215 GtvMainToolbar* pToolbar = gtv_application_window_get_main_toolbar(pWindow);
216 rArgs.erase(std::find(rArgs.begin(), rArgs.end(), '\n'));
217 const std::string rUnoCmdStr = rUnoCmd + " | " + rArgs;
220 // add to file
221 std::ofstream outfile("/tmp/gtv-recentunos.txt", std::ios_base::app | std::ios_base::out);
222 if (outfile.good())
223 outfile << rUnoCmdStr << '\n';
225 // add to combo box
226 gtv_main_toolbar_add_recent_uno(pToolbar, rUnoCmdStr);
229 void unoCommandDebugger(GtkWidget* pButton, gpointer /* pItem */)
231 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
232 GtkWidget* pUnoCmdDialog = gtk_dialog_new_with_buttons ("Execute UNO command",
233 GTK_WINDOW (window),
234 GTK_DIALOG_MODAL,
235 "Execute",
236 GTK_RESPONSE_OK,
237 nullptr);
238 g_object_set(G_OBJECT(pUnoCmdDialog), "resizable", FALSE, nullptr);
239 GtkWidget* pDialogMessageArea = gtk_dialog_get_content_area (GTK_DIALOG (pUnoCmdDialog));
240 GtkWidget* pUnoCmdAreaBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
241 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pUnoCmdAreaBox, TRUE, TRUE, 2);
243 GtkWidget* pUnoCmdLabel = gtk_label_new("Enter UNO command");
244 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdLabel, TRUE, TRUE, 2);
246 GtkWidget* pUnoCmdEntry = gtk_entry_new ();
247 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdEntry, TRUE, TRUE, 2);
248 gtk_entry_set_placeholder_text(GTK_ENTRY(pUnoCmdEntry), "UNO command (Eg. Bold, Italic etc.)");
249 GtkWidget* pUnoParamAreaBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
250 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pUnoParamAreaBox, TRUE, TRUE, 2);
252 GtkWidget* pAddMoreButton = gtk_button_new_with_label("Add UNO parameter");
253 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pAddMoreButton, TRUE, TRUE, 2);
254 g_signal_connect(G_OBJECT(pAddMoreButton), "clicked", G_CALLBACK(addMoreUnoParam), pUnoParamAreaBox);
256 gtk_widget_show_all(pUnoCmdDialog);
258 gint res = gtk_dialog_run (GTK_DIALOG(pUnoCmdDialog));
259 switch (res)
261 case GTK_RESPONSE_OK:
263 const gchar* sUnoCmd = g_strconcat(".uno:", gtk_entry_get_text(GTK_ENTRY(pUnoCmdEntry)), nullptr);
265 boost::property_tree::ptree aTree;
266 gtk_container_foreach(GTK_CONTAINER(pUnoParamAreaBox), iterateUnoParams, &aTree);
268 std::stringstream aStream;
269 boost::property_tree::write_json(aStream, aTree, false);
270 std::string aArguments = aStream.str();
272 g_info("Generated UNO command: %s %s", sUnoCmd, aArguments.c_str());
274 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), sUnoCmd, (aArguments.empty() ? nullptr : aArguments.c_str()), false);
275 addToRecentUnoCommands(window, sUnoCmd, aArguments);
277 break;
280 gtk_widget_destroy(pUnoCmdDialog);
283 void toggleEditing(GtkWidget* pButton, gpointer /*pItem*/)
285 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
286 bool bActive = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(pButton));
287 if (bool(lok_doc_view_get_edit(LOK_DOC_VIEW(window->lokdocview))) != bActive)
288 lok_doc_view_set_edit(LOK_DOC_VIEW(window->lokdocview), bActive);
291 void changePart( GtkWidget* pSelector, gpointer /* pItem */ )
293 int nPart = gtk_combo_box_get_active( GTK_COMBO_BOX(pSelector) );
294 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
296 if (gtv_application_window_get_part_broadcast(window) && window->lokdocview)
298 lok_doc_view_set_part( LOK_DOC_VIEW(window->lokdocview), nPart );
299 lok_doc_view_reset_view(LOK_DOC_VIEW(window->lokdocview));
303 void changePartMode( GtkWidget* pSelector, gpointer /* pItem */ )
305 // Just convert directly back to the LibreOfficeKitPartMode enum.
306 // I.e. the ordering above should match the enum member ordering.
307 LibreOfficeKitPartMode ePartMode =
308 LibreOfficeKitPartMode( gtk_combo_box_get_active( GTK_COMBO_BOX(pSelector) ) );
309 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
311 if ( window->lokdocview )
313 lok_doc_view_set_partmode( LOK_DOC_VIEW(window->lokdocview), ePartMode );
317 void changeZoom( GtkWidget* pButton, gpointer /* pItem */ )
319 static const float fZooms[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0 };
320 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
321 const char *sName = gtk_tool_button_get_icon_name( GTK_TOOL_BUTTON(pButton) );
323 float fZoom = 0;
324 float fCurrentZoom = 0;
326 if ( window->lokdocview )
328 fCurrentZoom = lok_doc_view_get_zoom( LOK_DOC_VIEW(window->lokdocview) );
331 if ( strcmp(sName, "zoom-in-symbolic") == 0)
333 for ( size_t i = 0; i < SAL_N_ELEMENTS( fZooms ); i++ )
335 if ( fCurrentZoom < fZooms[i] )
337 fZoom = fZooms[i];
338 break;
342 else if ( strcmp(sName, "zoom-original-symbolic") == 0)
344 fZoom = 1;
346 else if ( strcmp(sName, "zoom-out-symbolic") == 0)
348 for ( size_t i = 0; i < SAL_N_ELEMENTS( fZooms ); i++ )
350 if ( fCurrentZoom > fZooms[i] )
352 fZoom = fZooms[i];
357 if ( fZoom != 0 && window->lokdocview )
359 lok_doc_view_set_zoom( LOK_DOC_VIEW(window->lokdocview), fZoom );
360 GdkRectangle aVisibleArea;
361 gtv_application_window_get_visible_area(window, &aVisibleArea);
362 lok_doc_view_set_visible_area(LOK_DOC_VIEW(window->lokdocview), &aVisibleArea);
364 const std::string aZoom = std::string("Zoom: ") + std::to_string(int(fZoom * 100)) + std::string("%");
365 gtk_label_set_text(GTK_LABEL(window->zoomlabel), aZoom.c_str());
368 void documentRedline(GtkWidget* pButton, gpointer /*pItem*/)
370 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
371 // Get the data.
372 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
373 char* pValues = pDocument->pClass->getCommandValues(pDocument, ".uno:AcceptTrackedChanges");
374 if (!pValues)
375 return;
377 std::stringstream aInfo;
378 aInfo << "lok::Document::getCommandValues('.uno:AcceptTrackedChanges') returned '" << pValues << "'" << std::endl;
379 g_info("%s", aInfo.str().c_str());
380 std::stringstream aStream(pValues);
381 free(pValues);
382 assert(!aStream.str().empty());
383 boost::property_tree::ptree aTree;
384 boost::property_tree::read_json(aStream, aTree);
386 // Create the dialog.
387 GtkWidget* pDialog = gtk_dialog_new_with_buttons("Manage Changes",
388 GTK_WINDOW (window),
389 GTK_DIALOG_MODAL,
390 "Accept",
391 GTK_RESPONSE_YES,
392 "Reject",
393 GTK_RESPONSE_NO,
394 "Jump",
395 GTK_RESPONSE_APPLY,
396 nullptr);
397 gtk_window_set_default_size(GTK_WINDOW(pDialog), 800, 600);
398 GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG (pDialog));
399 GtkWidget* pScrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
401 // Build the table.
402 GtkTreeStore* pTreeStore = gtk_tree_store_new(6, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
403 for (const auto& rValue : aTree.get_child("redlines"))
405 GtkTreeIter aTreeIter;
406 gtk_tree_store_append(pTreeStore, &aTreeIter, nullptr);
407 gtk_tree_store_set(pTreeStore, &aTreeIter,
408 0, rValue.second.get<int>("index"),
409 1, rValue.second.get<std::string>("author").c_str(),
410 2, rValue.second.get<std::string>("type").c_str(),
411 3, rValue.second.get<std::string>("comment").c_str(),
412 4, rValue.second.get<std::string>("description").c_str(),
413 5, rValue.second.get<std::string>("dateTime").c_str(),
414 -1);
416 GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore));
417 std::vector<std::string> aColumns = {"Index", "Author", "Type", "Comment", "Description", "Timestamp"};
418 for (size_t nColumn = 0; nColumn < aColumns.size(); ++nColumn)
420 GtkCellRenderer* pRenderer = gtk_cell_renderer_text_new();
421 GtkTreeViewColumn* pColumn = gtk_tree_view_column_new_with_attributes(aColumns[nColumn].c_str(),
422 pRenderer,
423 "text", nColumn,
424 nullptr);
425 gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pColumn);
427 gtk_container_add(GTK_CONTAINER(pScrolledWindow), pTreeView);
428 gtk_box_pack_start(GTK_BOX(pContentArea), pScrolledWindow, TRUE, TRUE, 2);
430 // Show the dialog.
431 gtk_widget_show_all(pDialog);
432 gint res = gtk_dialog_run(GTK_DIALOG(pDialog));
434 // Dispatch the matching command, if necessary.
435 if (res == GTK_RESPONSE_YES || res == GTK_RESPONSE_NO || res == GTK_RESPONSE_APPLY)
437 GtkTreeSelection* pSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pTreeView));
438 GtkTreeIter aTreeIter;
439 GtkTreeModel* pTreeModel;
440 if (gtk_tree_selection_get_selected(pSelection, &pTreeModel, &aTreeIter))
442 gint nIndex = 0;
443 // 0: index
444 gtk_tree_model_get(pTreeModel, &aTreeIter, 0, &nIndex, -1);
445 std::string aCommand;
446 if (res == GTK_RESPONSE_YES)
447 aCommand = ".uno:AcceptTrackedChange";
448 else if (res == GTK_RESPONSE_NO)
449 aCommand = ".uno:RejectTrackedChange";
450 else
451 // Just select the given redline, don't accept or reject it.
452 aCommand = ".uno:NextTrackedChange";
453 // Without the '.uno:' prefix.
454 std::string aKey = aCommand.substr(strlen(".uno:"));
456 // Post the command.
457 boost::property_tree::ptree aCommandTree;
458 aCommandTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short");
459 aCommandTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex);
461 aStream.str(std::string());
462 boost::property_tree::write_json(aStream, aCommandTree);
463 std::string aArguments = aStream.str();
464 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), aCommand.c_str(), aArguments.c_str(), false);
468 gtk_widget_destroy(pDialog);
471 void documentRepair(GtkWidget* pButton, gpointer /*pItem*/)
473 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
474 // Get the data.
475 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
476 // Show it in linear time, so first redo in reverse order, then undo.
477 std::vector<std::string> aTypes = {".uno:Redo", ".uno:Undo"};
478 std::vector<boost::property_tree::ptree> aTrees;
479 for (size_t nType = 0; nType < aTypes.size(); ++nType)
481 const std::string& rType = aTypes[nType];
482 char* pValues = pDocument->pClass->getCommandValues(pDocument, rType.c_str());
483 std::stringstream aInfo;
484 aInfo << "lok::Document::getCommandValues('" << rType << "') returned '" << pValues << "'" << std::endl;
485 g_info("%s", aInfo.str().c_str());
486 std::stringstream aStream(pValues);
487 free(pValues);
488 assert(!aStream.str().empty());
489 boost::property_tree::ptree aTree;
490 boost::property_tree::read_json(aStream, aTree);
491 aTrees.push_back(aTree);
494 // Create the dialog.
495 GtkWidget* pDialog = gtk_dialog_new_with_buttons("Repair document",
496 GTK_WINDOW (window),
497 GTK_DIALOG_MODAL,
498 "Jump to state",
499 GTK_RESPONSE_OK,
500 nullptr);
501 gtk_window_set_default_size(GTK_WINDOW(pDialog), 800, 600);
502 GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG (pDialog));
503 GtkWidget* pScrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
505 // Build the table.
506 GtkTreeStore* pTreeStore = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
507 for (size_t nTree = 0; nTree < aTrees.size(); ++nTree)
509 const auto& rTree = aTrees[nTree];
510 for (const auto& rValue : rTree.get_child("actions"))
512 GtkTreeIter aTreeIter;
513 gtk_tree_store_append(pTreeStore, &aTreeIter, nullptr);
514 gtk_tree_store_set(pTreeStore, &aTreeIter,
515 0, aTypes[nTree].c_str(),
516 1, rValue.second.get<int>("index"),
517 2, rValue.second.get<std::string>("comment").c_str(),
518 3, rValue.second.get<std::string>("viewId").c_str(),
519 4, rValue.second.get<std::string>("dateTime").c_str(),
520 -1);
523 GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore));
524 std::vector<std::string> aColumns = {"Type", "Index", "Comment", "View ID", "Timestamp"};
525 for (size_t nColumn = 0; nColumn < aColumns.size(); ++nColumn)
527 GtkCellRenderer* pRenderer = gtk_cell_renderer_text_new();
528 GtkTreeViewColumn* pColumn = gtk_tree_view_column_new_with_attributes(aColumns[nColumn].c_str(),
529 pRenderer,
530 "text", nColumn,
531 nullptr);
532 gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pColumn);
534 gtk_container_add(GTK_CONTAINER(pScrolledWindow), pTreeView);
535 gtk_box_pack_start(GTK_BOX(pContentArea), pScrolledWindow, TRUE, TRUE, 2);
537 // Show the dialog.
538 gtk_widget_show_all(pDialog);
539 gint res = gtk_dialog_run(GTK_DIALOG(pDialog));
541 // Dispatch the matching command, if necessary.
542 if (res == GTK_RESPONSE_OK)
544 GtkTreeSelection* pSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pTreeView));
545 GtkTreeIter aTreeIter;
546 GtkTreeModel* pTreeModel;
547 if (gtk_tree_selection_get_selected(pSelection, &pTreeModel, &aTreeIter))
549 gchar* pType = nullptr;
550 gint nIndex = 0;
551 // 0: type, 1: index
552 gtk_tree_model_get(pTreeModel, &aTreeIter, 0, &pType, 1, &nIndex, -1);
553 // '.uno:Undo' or '.uno:Redo'
554 const std::string aType(pType);
555 // Without the '.uno:' prefix.
556 std::string aKey = aType.substr(strlen(".uno:"));
557 g_free(pType);
559 // Post the command.
560 boost::property_tree::ptree aTree;
561 aTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short");
562 aTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex + 1);
564 // Without this, we could only undo our own commands.
565 aTree.put(boost::property_tree::ptree::path_type("Repair/type", '/'), "boolean");
566 aTree.put(boost::property_tree::ptree::path_type("Repair/value", '/'), true);
568 std::stringstream aStream;
569 boost::property_tree::write_json(aStream, aTree);
570 std::string aArguments = aStream.str();
571 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), aType.c_str(), aArguments.c_str(), false);
575 gtk_widget_destroy(pDialog);
578 void toggleFindbar(GtkWidget* pButton, gpointer /*pItem*/)
580 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
581 gtv_application_window_toggle_findbar(window);
584 void docAdjustmentChanged(GtkAdjustment*, gpointer pData)
586 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(pData);
587 if (window->lokdocview)
588 LOKDocViewSigHandlers::configureEvent(window->lokdocview, nullptr, nullptr);
591 void signalSearchNext(GtkWidget* pButton, gpointer /*pItem*/)
593 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
594 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
595 const char* pText = gtk_entry_get_text(pEntry);
596 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
597 lok_doc_view_find_next(LOK_DOC_VIEW(window->lokdocview), pText, findAll);
600 void signalSearchPrev(GtkWidget* pButton, gpointer /*pItem*/)
602 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
603 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
604 const char* pText = gtk_entry_get_text(pEntry);
605 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
606 lok_doc_view_find_prev(LOK_DOC_VIEW(window->lokdocview), pText, findAll);
609 gboolean signalFindbar(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer /*pData*/)
611 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
612 gtk_label_set_text(GTK_LABEL(window->findbarlabel), "");
613 switch(pEvent->keyval)
615 case GDK_KEY_Return:
617 // Search forward.
618 signalSearchNext(pWidget, nullptr);
619 return TRUE;
621 case GDK_KEY_Escape:
623 // Hide the findbar.
624 gtk_widget_hide(GTK_WIDGET(window->findtoolbar));
625 return TRUE;
628 return FALSE;
631 void toggleFindAll(GtkWidget* pButton, gpointer /*pItem*/)
633 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
634 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
635 const char* pText = gtk_entry_get_text(pEntry);
636 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
637 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll), !findAll);
638 lok_doc_view_highlight_all(LOK_DOC_VIEW(window->lokdocview), pText);
641 void editButtonClicked(GtkWidget* pWidget, gpointer userdata)
643 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
644 std::map<std::string, std::string> aEntries;
645 aEntries["Text"] = "";
647 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Edit comment", aEntries);
649 gchar *commentId = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
651 boost::property_tree::ptree aTree;
652 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "type", nullptr), '/'), "string");
653 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "value", nullptr), '/'), std::string(commentId));
655 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "type", nullptr), '/'), "string");
656 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "value", nullptr), '/'), aEntries["Text"]);
658 std::stringstream aStream;
659 boost::property_tree::write_json(aStream, aTree);
660 std::string aArguments = aStream.str();
662 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:EditAnnotation", aArguments.c_str(), false);
665 void replyButtonClicked(GtkWidget* pWidget, gpointer userdata)
667 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
668 std::map<std::string, std::string> aEntries;
669 aEntries["Text"] = "";
671 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Reply comment", aEntries);
673 gchar *commentId = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
675 boost::property_tree::ptree aTree;
676 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "type", nullptr), '/'), "string");
677 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "value", nullptr), '/'), std::string(commentId));
679 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "type", nullptr), '/'), "string");
680 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Text", "/", "value", nullptr), '/'), aEntries["Text"]);
682 std::stringstream aStream;
683 boost::property_tree::write_json(aStream, aTree);
684 std::string aArguments = aStream.str();
686 // Different reply UNO command for impress
687 std::string replyCommand = ".uno:ReplyComment";
688 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
689 if (pDocument && pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_PRESENTATION)
690 replyCommand = ".uno:ReplyToAnnotation";
691 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), replyCommand.c_str(), aArguments.c_str(), false);
694 void deleteCommentButtonClicked(GtkWidget* pWidget, gpointer userdata)
696 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
697 gchar *commentid = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
699 boost::property_tree::ptree aTree;
700 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "type", nullptr), '/'), "string");
701 aTree.put(boost::property_tree::ptree::path_type(g_strconcat("Id", "/", "value", nullptr), '/'), std::string(commentid));
703 std::stringstream aStream;
704 boost::property_tree::write_json(aStream, aTree);
705 std::string aArguments = aStream.str();
707 // Different reply UNO command for impress
708 std::string deleteCommand = ".uno:DeleteComment";
709 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
710 if (pDocument)
712 if (pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_PRESENTATION)
713 deleteCommand = ".uno:DeleteAnnotation";
714 else if (pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_SPREADSHEET)
715 deleteCommand = ".uno:DeleteNote";
718 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), deleteCommand.c_str(), aArguments.c_str(), false);
721 /// Handles the key-press-event of the address entry widget.
722 gboolean signalAddressbar(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer /*pData*/)
724 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
725 switch(pEvent->keyval)
727 case GDK_KEY_Return:
729 GtkEntry* pEntry = GTK_ENTRY(pWidget);
730 const char* pText = gtk_entry_get_text(pEntry);
732 boost::property_tree::ptree aTree;
733 aTree.put(boost::property_tree::ptree::path_type("ToPoint/type", '/'), "string");
734 aTree.put(boost::property_tree::ptree::path_type("ToPoint/value", '/'), pText);
735 std::stringstream aStream;
736 boost::property_tree::write_json(aStream, aTree);
737 std::string aArguments = aStream.str();
739 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:GoToCell", aArguments.c_str(), false);
740 gtk_widget_grab_focus(window->lokdocview);
741 return TRUE;
743 case GDK_KEY_Escape:
745 std::string aArguments;
746 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:Cancel", aArguments.c_str(), false);
747 gtk_widget_grab_focus(window->lokdocview);
748 return TRUE;
751 return FALSE;
754 /// Handles the key-press-event of the formula entry widget.
755 gboolean signalFormulabar(GtkWidget* /*pWidget*/, GdkEventKey* /*pEvent*/, gpointer /*pData*/)
757 // for now it just displays the callback
758 // TODO - submit the edited formula
759 return TRUE;
762 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */