LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / libreofficekit / qa / gtktiledviewer / gtv-signal-handlers.cxx
blobe1dd0347041a48f085ebcf6aeaaff1065179ecc5
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-signal-handlers.hxx"
17 #include <sal/macros.h>
19 #include <cassert>
20 #include <map>
21 #include <vector>
23 #include <boost/property_tree/json_parser.hpp>
24 #include <optional>
26 void btn_clicked(GtkWidget* pButton, gpointer)
28 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
29 GtkToolButton* pItem = GTK_TOOL_BUTTON(pButton);
30 const gchar* label = gtk_tool_button_get_label(pItem);
31 if (!(gtv_application_window_get_toolbar_broadcast(window) && g_str_has_prefix(label, ".uno:")))
32 return;
34 std::string aArguments;
35 if (g_strcmp0(label, ".uno:InsertAnnotation") == 0)
37 std::map<std::string, std::string> aEntries;
38 aEntries["Text"] = "";
39 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Insert Comment", aEntries);
41 boost::property_tree::ptree aTree;
42 aTree.put(boost::property_tree::ptree::path_type("Text/type", '/'), "string");
43 aTree.put(boost::property_tree::ptree::path_type("Text/value", '/'), aEntries["Text"]);
45 std::stringstream aStream;
46 boost::property_tree::write_json(aStream, aTree);
47 aArguments = aStream.str();
50 bool bNotify = g_strcmp0(label, ".uno:Save") == 0;
51 if (window->lokdocview)
52 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), label, aArguments.c_str(), bNotify);
55 void doCopy(GtkWidget* pButton, gpointer /*pItem*/)
57 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
58 char* pUsedFormat = nullptr;
59 // TODO: Should check `text-selection` signal before trying to copy
60 char* pSelection = lok_doc_view_copy_selection(LOK_DOC_VIEW(window->lokdocview), "text/html", &pUsedFormat);
61 if (!pSelection)
62 return;
64 GtkClipboard* pClipboard = gtk_clipboard_get_for_display(gtk_widget_get_display(pButton), GDK_SELECTION_CLIPBOARD);
65 std::string aUsedFormat(pUsedFormat);
66 if (aUsedFormat == "text/plain;charset=utf-8")
67 gtk_clipboard_set_text(pClipboard, pSelection, -1);
68 else
69 GtvHelpers::clipboardSetHtml(pClipboard, pSelection);
71 free(pSelection);
72 free(pUsedFormat);
75 void doPaste(GtkWidget* pButton, gpointer /*pItem*/)
77 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
78 GtkClipboard* pClipboard = gtk_clipboard_get_for_display(gtk_widget_get_display(pButton), GDK_SELECTION_CLIPBOARD);
79 GdkAtom* pTargets;
80 gint nTargets;
81 std::map<std::string, GdkAtom> aTargets;
82 if (gtk_clipboard_wait_for_targets(pClipboard, &pTargets, &nTargets))
84 for (gint i = 0; i < nTargets; ++i)
86 gchar* pName = gdk_atom_name(pTargets[i]);
87 aTargets[pName] = pTargets[i];
88 g_free(pName);
90 g_free(pTargets);
93 std::optional<GdkAtom> oTarget;
94 std::string aTargetName;
96 std::vector<std::string> aPreferredNames =
98 std::string("image/png"),
99 std::string("text/html")
101 for (const std::string& rName : aPreferredNames)
103 std::map<std::string, GdkAtom>::iterator it = aTargets.find(rName);
104 if (it != aTargets.end())
106 aTargetName = it->first;
107 oTarget = it->second;
108 break;
112 if (oTarget)
114 GtkSelectionData* pSelectionData = gtk_clipboard_wait_for_contents(pClipboard, *oTarget);
115 if (!pSelectionData)
117 return;
119 gint nLength;
120 const guchar* pData = gtk_selection_data_get_data_with_length(pSelectionData, &nLength);
121 bool bSuccess = lok_doc_view_paste(LOK_DOC_VIEW(window->lokdocview), aTargetName.c_str(), reinterpret_cast<const char*>(pData), nLength);
122 gtk_selection_data_free(pSelectionData);
123 if (bSuccess)
124 return;
127 gchar* pText = gtk_clipboard_wait_for_text(pClipboard);
128 if (pText)
129 lok_doc_view_paste(LOK_DOC_VIEW(window->lokdocview), "text/plain;charset=utf-8", pText, strlen(pText));
132 void createView(GtkWidget* pButton, gpointer /*pItem*/)
134 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
135 gtv_application_window_create_view_from_window(GTV_APPLICATION_WINDOW(window));
138 void getRulerState(GtkWidget* pButton, gpointer /*pItem*/)
140 const std::string type = ".uno:RulerState";
141 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
142 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
143 pDocument->pClass->getCommandValues(pDocument, type.c_str());
146 static void removeUnoParam(GtkWidget* pWidget, gpointer userdata)
148 GtkWidget* pParamAreaBox = GTK_WIDGET(userdata);
149 GtkWidget* pParamContainer = gtk_widget_get_parent(pWidget);
151 gtk_container_remove(GTK_CONTAINER(pParamAreaBox), pParamContainer);
154 static void addMoreUnoParam(GtkWidget* /*pWidget*/, gpointer userdata)
156 GtkWidget* pUnoParamAreaBox = GTK_WIDGET(userdata);
158 GtkWidget* pParamContainer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
159 gtk_box_pack_start(GTK_BOX(pUnoParamAreaBox), pParamContainer, true, true, 2);
161 GtkWidget* pTypeEntry = gtk_entry_new();
162 gtk_box_pack_start(GTK_BOX(pParamContainer), pTypeEntry, true, true, 2);
163 gtk_entry_set_placeholder_text(GTK_ENTRY(pTypeEntry), "Param type (Eg. boolean, string etc.)");
165 GtkWidget* pNameEntry = gtk_entry_new();
166 gtk_box_pack_start(GTK_BOX(pParamContainer), pNameEntry, true, true, 2);
167 gtk_entry_set_placeholder_text(GTK_ENTRY(pNameEntry), "Param name");
169 GtkWidget* pValueEntry = gtk_entry_new();
170 gtk_box_pack_start(GTK_BOX(pParamContainer), pValueEntry, true, true, 2);
171 gtk_entry_set_placeholder_text(GTK_ENTRY(pValueEntry), "Param value");
173 GtkWidget* pRemoveButton = gtk_button_new_from_icon_name("list-remove-symbolic", GTK_ICON_SIZE_BUTTON);
174 g_signal_connect(pRemoveButton, "clicked", G_CALLBACK(removeUnoParam), pUnoParamAreaBox);
175 gtk_box_pack_start(GTK_BOX(pParamContainer), pRemoveButton, true, true, 2);
177 gtk_widget_show_all(pUnoParamAreaBox);
180 static void iterateUnoParams(GtkWidget* pWidget, gpointer userdata)
182 boost::property_tree::ptree *pTree = static_cast<boost::property_tree::ptree*>(userdata);
183 GtvGtkWrapper<GList> pChildren(gtk_container_get_children(GTK_CONTAINER(pWidget)),
184 [](GList* pList) {
185 g_list_free(pList);
187 GList* pIt = nullptr;
188 guint i = 0;
189 const gchar* unoParam[3];
190 for (pIt = pChildren.get(), i = 0; i < 3; pIt = pIt->next, i++)
192 assert(pIt != nullptr);
193 unoParam[i] = gtk_entry_get_text(GTK_ENTRY(pIt->data));
196 gchar* pPath = g_strconcat(unoParam[1], "/", "type", nullptr);
197 pTree->put(boost::property_tree::ptree::path_type(pPath, '/'), unoParam[0]);
198 g_free(pPath);
199 pPath = g_strconcat(unoParam[1], "/", "value", nullptr);
200 pTree->put(boost::property_tree::ptree::path_type(pPath, '/'), unoParam[2]);
201 g_free(pPath);
204 void recentUnoChanged( GtkWidget* pSelector, gpointer /* pItem */ )
206 GtvApplicationWindow* pWindow = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
207 gchar* pUnoCmd = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(pSelector));
209 GtvMainToolbar* pToolbar = gtv_application_window_get_main_toolbar(pWindow);
210 const std::string aUnoArgs = gtv_main_toolbar_get_recent_uno_args(pToolbar, pUnoCmd);
211 // this will also discard our default placeholder string, "Recent UNO"
212 if (aUnoArgs.empty())
213 return;
215 lok_doc_view_post_command(LOK_DOC_VIEW(pWindow->lokdocview), pUnoCmd, (aUnoArgs.empty() ? nullptr : aUnoArgs.c_str()), false);
216 g_free(pUnoCmd);
219 static void addToRecentUnoCommands(GtvApplicationWindow* pWindow, const std::string& rUnoCmd, std::string rArgs)
221 GtvMainToolbar* pToolbar = gtv_application_window_get_main_toolbar(pWindow);
222 rArgs.erase(std::find(rArgs.begin(), rArgs.end(), '\n'));
223 const std::string rUnoCmdStr = rUnoCmd + " | " + rArgs;
226 // add to file
227 std::ofstream outfile("/tmp/gtv-recentunos.txt", std::ios_base::app | std::ios_base::out);
228 if (outfile.good())
229 outfile << rUnoCmdStr << '\n';
231 // add to combo box
232 gtv_main_toolbar_add_recent_uno(pToolbar, rUnoCmdStr);
235 void unoCommandDebugger(GtkWidget* pButton, gpointer /* pItem */)
237 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
238 GtkWidget* pUnoCmdDialog = gtk_dialog_new_with_buttons ("Execute UNO command",
239 GTK_WINDOW (window),
240 GTK_DIALOG_MODAL,
241 "Execute",
242 GTK_RESPONSE_OK,
243 nullptr);
244 g_object_set(G_OBJECT(pUnoCmdDialog), "resizable", FALSE, nullptr);
245 GtkWidget* pDialogMessageArea = gtk_dialog_get_content_area (GTK_DIALOG (pUnoCmdDialog));
246 GtkWidget* pUnoCmdAreaBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
247 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pUnoCmdAreaBox, true, true, 2);
249 GtkWidget* pUnoCmdLabel = gtk_label_new("Enter UNO command");
250 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdLabel, true, true, 2);
252 GtkWidget* pUnoCmdEntry = gtk_entry_new ();
253 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdEntry, true, true, 2);
254 gtk_entry_set_placeholder_text(GTK_ENTRY(pUnoCmdEntry), "UNO command (Eg. Bold, Italic etc.)");
255 GtkWidget* pUnoParamAreaBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
256 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pUnoParamAreaBox, true, true, 2);
258 GtkWidget* pAddMoreButton = gtk_button_new_with_label("Add UNO parameter");
259 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pAddMoreButton, true, true, 2);
260 g_signal_connect(G_OBJECT(pAddMoreButton), "clicked", G_CALLBACK(addMoreUnoParam), pUnoParamAreaBox);
262 gtk_widget_show_all(pUnoCmdDialog);
264 gint res = gtk_dialog_run (GTK_DIALOG(pUnoCmdDialog));
265 if (res == GTK_RESPONSE_OK)
267 gchar* sUnoCmd = g_strconcat(".uno:", gtk_entry_get_text(GTK_ENTRY(pUnoCmdEntry)), nullptr);
269 boost::property_tree::ptree aTree;
270 gtk_container_foreach(GTK_CONTAINER(pUnoParamAreaBox), iterateUnoParams, &aTree);
272 std::stringstream aStream;
273 boost::property_tree::write_json(aStream, aTree, false);
274 std::string aArguments = aStream.str();
276 g_info("Generated UNO command: %s %s", sUnoCmd, aArguments.c_str());
278 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), sUnoCmd, (aArguments.empty() ? nullptr : aArguments.c_str()), false);
279 addToRecentUnoCommands(window, sUnoCmd, aArguments);
281 g_free(sUnoCmd);
284 gtk_widget_destroy(pUnoCmdDialog);
287 void commandValuesDebugger(GtkWidget* pButton, gpointer /* pItem */)
289 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
290 GtkWidget* pUnoCmdDialog = gtk_dialog_new_with_buttons ("Get command values",
291 GTK_WINDOW (window),
292 GTK_DIALOG_MODAL,
293 "Execute",
294 GTK_RESPONSE_OK,
295 nullptr);
296 g_object_set(G_OBJECT(pUnoCmdDialog), "resizable", FALSE, nullptr);
297 GtkWidget* pDialogMessageArea = gtk_dialog_get_content_area (GTK_DIALOG (pUnoCmdDialog));
298 GtkWidget* pUnoCmdAreaBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
299 gtk_box_pack_start(GTK_BOX(pDialogMessageArea), pUnoCmdAreaBox, true, true, 2);
301 GtkWidget* pUnoCmdLabel = gtk_label_new("Enter UNO command");
302 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdLabel, true, true, 2);
304 GtkWidget* pUnoCmdEntry = gtk_entry_new ();
305 gtk_box_pack_start(GTK_BOX(pUnoCmdAreaBox), pUnoCmdEntry, true, true, 2);
306 gtk_entry_set_placeholder_text(GTK_ENTRY(pUnoCmdEntry), "e.g. .uno:Undo");
308 gtk_widget_show_all(pUnoCmdDialog);
310 gint res = gtk_dialog_run (GTK_DIALOG(pUnoCmdDialog));
311 if (res == GTK_RESPONSE_OK)
313 const gchar* pUnoCmd = gtk_entry_get_text(GTK_ENTRY(pUnoCmdEntry));
314 gchar* pValues = lok_doc_view_get_command_values(LOK_DOC_VIEW(window->lokdocview), pUnoCmd);
315 g_info("lok::Document::getCommandValues(%s) : %s", pUnoCmd, pValues);
316 g_free(pValues);
319 gtk_widget_destroy(pUnoCmdDialog);
322 void toggleEditing(GtkWidget* pButton, gpointer /*pItem*/)
324 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
325 bool bActive = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(pButton));
326 if (bool(lok_doc_view_get_edit(LOK_DOC_VIEW(window->lokdocview))) != bActive)
327 lok_doc_view_set_edit(LOK_DOC_VIEW(window->lokdocview), bActive);
330 void changePart( GtkWidget* pSelector, gpointer /* pItem */ )
332 int nPart = gtk_combo_box_get_active( GTK_COMBO_BOX(pSelector) );
333 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
335 if (gtv_application_window_get_part_broadcast(window) && window->lokdocview)
337 lok_doc_view_set_part( LOK_DOC_VIEW(window->lokdocview), nPart );
338 lok_doc_view_reset_view(LOK_DOC_VIEW(window->lokdocview));
342 void changePartMode( GtkWidget* pSelector, gpointer /* pItem */ )
344 // Just convert directly back to the LibreOfficeKitPartMode enum.
345 // I.e. the ordering above should match the enum member ordering.
346 LibreOfficeKitPartMode ePartMode =
347 LibreOfficeKitPartMode( gtk_combo_box_get_active( GTK_COMBO_BOX(pSelector) ) );
348 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
350 if ( window->lokdocview )
352 lok_doc_view_set_partmode( LOK_DOC_VIEW(window->lokdocview), ePartMode );
356 void changeContentControl(GtkWidget* pSelector, gpointer /*pItem*/)
358 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
359 if (gtv_application_window_get_part_broadcast(window) && window->lokdocview)
361 int nItem = gtk_combo_box_get_active(GTK_COMBO_BOX(pSelector));
362 boost::property_tree::ptree aValues;
363 aValues.put("type", "drop-down");
364 aValues.put("selected", std::to_string(nItem));
365 std::stringstream aStream;
366 boost::property_tree::write_json(aStream, aValues);
367 std::string aJson = aStream.str();
368 lok_doc_view_send_content_control_event(LOK_DOC_VIEW(window->lokdocview), aJson.c_str());
372 void changeDateContentControl(GtkWidget* pSelector, gpointer /*pItem*/)
374 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pSelector));
375 if (gtv_application_window_get_part_broadcast(window) && window->lokdocview)
377 GtkPopover* pPopover = GTK_POPOVER(gtk_widget_get_parent(gtk_widget_get_parent(pSelector)));
378 guint nYear, nMonth, nDay;
379 gtk_calendar_get_date(GTK_CALENDAR(pSelector), &nYear, &nMonth, &nDay);
380 gtk_popover_popdown(pPopover);
382 std::stringstream aDate;
383 aDate << std::setfill('0') << std::setw(4) << nYear;
384 aDate << "-";
385 aDate << std::setfill('0') << std::setw(2) << (nMonth + 1);
386 aDate << "-";
387 aDate << std::setfill('0') << std::setw(2) << nDay;
388 aDate << "T00:00:00Z";
389 boost::property_tree::ptree aValues;
390 aValues.put("type", "date");
391 aValues.put("selected", aDate.str());
392 std::stringstream aStream;
393 boost::property_tree::write_json(aStream, aValues);
394 std::string aJson = aStream.str();
395 lok_doc_view_send_content_control_event(LOK_DOC_VIEW(window->lokdocview), aJson.c_str());
399 void changeZoom( GtkWidget* pButton, gpointer /* pItem */ )
401 static const float fZooms[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0 };
402 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
403 const char *sName = gtk_tool_button_get_icon_name( GTK_TOOL_BUTTON(pButton) );
405 float fZoom = 0;
406 float fCurrentZoom = 0;
408 if ( window->lokdocview )
410 fCurrentZoom = lok_doc_view_get_zoom( LOK_DOC_VIEW(window->lokdocview) );
413 if ( strcmp(sName, "zoom-in-symbolic") == 0)
415 for ( size_t i = 0; i < SAL_N_ELEMENTS( fZooms ); i++ )
417 if ( fCurrentZoom < fZooms[i] )
419 fZoom = fZooms[i];
420 break;
424 else if ( strcmp(sName, "zoom-original-symbolic") == 0)
426 fZoom = 1;
428 else if ( strcmp(sName, "zoom-out-symbolic") == 0)
430 for ( size_t i = 0; i < SAL_N_ELEMENTS( fZooms ); i++ )
432 if ( fCurrentZoom > fZooms[i] )
434 fZoom = fZooms[i];
439 if ( fZoom != 0 && window->lokdocview )
441 lok_doc_view_set_zoom( LOK_DOC_VIEW(window->lokdocview), fZoom );
442 GdkRectangle aVisibleArea;
443 gtv_application_window_get_visible_area(window, &aVisibleArea);
444 lok_doc_view_set_visible_area(LOK_DOC_VIEW(window->lokdocview), &aVisibleArea);
446 const std::string aZoom = std::string("Zoom: ") + std::to_string(int(fZoom * 100)) + std::string("%");
447 gtk_label_set_text(GTK_LABEL(window->zoomlabel), aZoom.c_str());
450 void documentRedline(GtkWidget* pButton, gpointer /*pItem*/)
452 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
453 // Get the data.
454 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
455 char* pValues = pDocument->pClass->getCommandValues(pDocument, ".uno:AcceptTrackedChanges");
456 if (!pValues)
457 return;
459 std::stringstream aInfo;
460 aInfo << "lok::Document::getCommandValues('.uno:AcceptTrackedChanges') returned '" << pValues << "'" << std::endl;
461 g_info("%s", aInfo.str().c_str());
462 std::stringstream aStream(pValues);
463 free(pValues);
464 assert(!aStream.str().empty());
465 boost::property_tree::ptree aTree;
466 boost::property_tree::read_json(aStream, aTree);
468 // Create the dialog.
469 GtkWidget* pDialog = gtk_dialog_new_with_buttons("Manage Changes",
470 GTK_WINDOW (window),
471 GTK_DIALOG_MODAL,
472 "Accept",
473 GTK_RESPONSE_YES,
474 "Reject",
475 GTK_RESPONSE_NO,
476 "Jump",
477 GTK_RESPONSE_APPLY,
478 nullptr);
479 gtk_window_set_default_size(GTK_WINDOW(pDialog), 800, 600);
480 GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG (pDialog));
481 GtkWidget* pScrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
483 // Build the table.
484 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);
485 for (const auto& rValue : aTree.get_child("redlines"))
487 GtkTreeIter aTreeIter;
488 gtk_tree_store_append(pTreeStore, &aTreeIter, nullptr);
489 gtk_tree_store_set(pTreeStore, &aTreeIter,
490 0, rValue.second.get<int>("index"),
491 1, rValue.second.get<std::string>("author").c_str(),
492 2, rValue.second.get<std::string>("type").c_str(),
493 3, rValue.second.get<std::string>("comment").c_str(),
494 4, rValue.second.get<std::string>("description").c_str(),
495 5, rValue.second.get<std::string>("dateTime").c_str(),
496 -1);
498 GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore));
499 std::vector<std::string> aColumns = {"Index", "Author", "Type", "Comment", "Description", "Timestamp"};
500 for (size_t nColumn = 0; nColumn < aColumns.size(); ++nColumn)
502 GtkCellRenderer* pRenderer = gtk_cell_renderer_text_new();
503 GtkTreeViewColumn* pColumn = gtk_tree_view_column_new_with_attributes(aColumns[nColumn].c_str(),
504 pRenderer,
505 "text", nColumn,
506 nullptr);
507 gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pColumn);
509 gtk_container_add(GTK_CONTAINER(pScrolledWindow), pTreeView);
510 gtk_box_pack_start(GTK_BOX(pContentArea), pScrolledWindow, true, true, 2);
512 // Show the dialog.
513 gtk_widget_show_all(pDialog);
514 gint res = gtk_dialog_run(GTK_DIALOG(pDialog));
516 // Dispatch the matching command, if necessary.
517 if (res == GTK_RESPONSE_YES || res == GTK_RESPONSE_NO || res == GTK_RESPONSE_APPLY)
519 GtkTreeSelection* pSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pTreeView));
520 GtkTreeIter aTreeIter;
521 GtkTreeModel* pTreeModel;
522 if (gtk_tree_selection_get_selected(pSelection, &pTreeModel, &aTreeIter))
524 gint nIndex = 0;
525 // 0: index
526 gtk_tree_model_get(pTreeModel, &aTreeIter, 0, &nIndex, -1);
527 std::string aCommand;
528 if (res == GTK_RESPONSE_YES)
529 aCommand = ".uno:AcceptTrackedChange";
530 else if (res == GTK_RESPONSE_NO)
531 aCommand = ".uno:RejectTrackedChange";
532 else
533 // Just select the given redline, don't accept or reject it.
534 aCommand = ".uno:NextTrackedChange";
535 // Without the '.uno:' prefix.
536 std::string aKey = aCommand.substr(strlen(".uno:"));
538 // Post the command.
539 boost::property_tree::ptree aCommandTree;
540 aCommandTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short");
541 aCommandTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex);
543 aStream.str(std::string());
544 boost::property_tree::write_json(aStream, aCommandTree);
545 std::string aArguments = aStream.str();
546 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), aCommand.c_str(), aArguments.c_str(), false);
550 gtk_widget_destroy(pDialog);
553 void documentRepair(GtkWidget* pButton, gpointer /*pItem*/)
555 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
556 // Get the data.
557 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
558 // Show it in linear time, so first redo in reverse order, then undo.
559 std::vector<std::string> aTypes = {".uno:Redo", ".uno:Undo"};
560 std::vector<boost::property_tree::ptree> aTrees;
561 for (size_t nType = 0; nType < aTypes.size(); ++nType)
563 const std::string& rType = aTypes[nType];
564 char* pValues = pDocument->pClass->getCommandValues(pDocument, rType.c_str());
565 std::stringstream aInfo;
566 aInfo << "lok::Document::getCommandValues('" << rType << "') returned '" << pValues << "'" << std::endl;
567 g_info("%s", aInfo.str().c_str());
568 std::stringstream aStream(pValues);
569 free(pValues);
570 assert(!aStream.str().empty());
571 boost::property_tree::ptree aTree;
572 boost::property_tree::read_json(aStream, aTree);
573 aTrees.push_back(aTree);
576 // Create the dialog.
577 GtkWidget* pDialog = gtk_dialog_new_with_buttons("Repair document",
578 GTK_WINDOW (window),
579 GTK_DIALOG_MODAL,
580 "Jump to state",
581 GTK_RESPONSE_OK,
582 nullptr);
583 gtk_window_set_default_size(GTK_WINDOW(pDialog), 800, 600);
584 GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG (pDialog));
585 GtkWidget* pScrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
587 // Build the table.
588 GtkTreeStore* pTreeStore = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
589 for (size_t nTree = 0; nTree < aTrees.size(); ++nTree)
591 const auto& rTree = aTrees[nTree];
592 for (const auto& rValue : rTree.get_child("actions"))
594 GtkTreeIter aTreeIter;
595 gtk_tree_store_append(pTreeStore, &aTreeIter, nullptr);
596 gtk_tree_store_set(pTreeStore, &aTreeIter,
597 0, aTypes[nTree].c_str(),
598 1, rValue.second.get<int>("index"),
599 2, rValue.second.get<std::string>("comment").c_str(),
600 3, rValue.second.get<std::string>("viewId").c_str(),
601 4, rValue.second.get<std::string>("dateTime").c_str(),
602 -1);
605 GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore));
606 std::vector<std::string> aColumns = {"Type", "Index", "Comment", "View ID", "Timestamp"};
607 for (size_t nColumn = 0; nColumn < aColumns.size(); ++nColumn)
609 GtkCellRenderer* pRenderer = gtk_cell_renderer_text_new();
610 GtkTreeViewColumn* pColumn = gtk_tree_view_column_new_with_attributes(aColumns[nColumn].c_str(),
611 pRenderer,
612 "text", nColumn,
613 nullptr);
614 gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pColumn);
616 gtk_container_add(GTK_CONTAINER(pScrolledWindow), pTreeView);
617 gtk_box_pack_start(GTK_BOX(pContentArea), pScrolledWindow, true, true, 2);
619 // Show the dialog.
620 gtk_widget_show_all(pDialog);
621 gint res = gtk_dialog_run(GTK_DIALOG(pDialog));
623 // Dispatch the matching command, if necessary.
624 if (res == GTK_RESPONSE_OK)
626 GtkTreeSelection* pSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pTreeView));
627 GtkTreeIter aTreeIter;
628 GtkTreeModel* pTreeModel;
629 if (gtk_tree_selection_get_selected(pSelection, &pTreeModel, &aTreeIter))
631 gchar* pType = nullptr;
632 gint nIndex = 0;
633 // 0: type, 1: index
634 gtk_tree_model_get(pTreeModel, &aTreeIter, 0, &pType, 1, &nIndex, -1);
635 // '.uno:Undo' or '.uno:Redo'
636 const std::string aType(pType);
637 // Without the '.uno:' prefix.
638 std::string aKey = aType.substr(strlen(".uno:"));
639 g_free(pType);
641 // Post the command.
642 boost::property_tree::ptree aTree;
643 aTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short");
644 aTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex + 1);
646 // Without this, we could only undo our own commands.
647 aTree.put(boost::property_tree::ptree::path_type("Repair/type", '/'), "boolean");
648 aTree.put(boost::property_tree::ptree::path_type("Repair/value", '/'), true);
650 std::stringstream aStream;
651 boost::property_tree::write_json(aStream, aTree);
652 std::string aArguments = aStream.str();
653 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), aType.c_str(), aArguments.c_str(), false);
657 gtk_widget_destroy(pDialog);
660 void toggleFindbar(GtkWidget* pButton, gpointer /*pItem*/)
662 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
663 gtv_application_window_toggle_findbar(window);
666 void docAdjustmentChanged(GtkAdjustment*, gpointer pData)
668 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(pData);
669 if (window->lokdocview)
670 LOKDocViewSigHandlers::configureEvent(window->lokdocview, nullptr, nullptr);
673 void signalSearchNext(GtkWidget* pButton, gpointer /*pItem*/)
675 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
676 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
677 const char* pText = gtk_entry_get_text(pEntry);
678 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
679 lok_doc_view_find_next(LOK_DOC_VIEW(window->lokdocview), pText, findAll);
682 void signalSearchPrev(GtkWidget* pButton, gpointer /*pItem*/)
684 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
685 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
686 const char* pText = gtk_entry_get_text(pEntry);
687 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
688 lok_doc_view_find_prev(LOK_DOC_VIEW(window->lokdocview), pText, findAll);
691 gboolean signalFindbar(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer /*pData*/)
693 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
694 gtk_label_set_text(GTK_LABEL(window->findbarlabel), "");
695 switch(pEvent->keyval)
697 case GDK_KEY_Return:
699 // Search forward.
700 signalSearchNext(pWidget, nullptr);
701 return true;
703 case GDK_KEY_Escape:
705 // Hide the findbar.
706 gtk_widget_hide(GTK_WIDGET(window->findtoolbar));
707 return true;
710 return FALSE;
713 void toggleFindAll(GtkWidget* pButton, gpointer /*pItem*/)
715 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pButton));
716 GtkEntry* pEntry = GTK_ENTRY(window->findbarEntry);
717 const char* pText = gtk_entry_get_text(pEntry);
718 bool findAll = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll));
719 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(window->findAll), !findAll);
720 lok_doc_view_highlight_all(LOK_DOC_VIEW(window->lokdocview), pText);
723 void editButtonClicked(GtkWidget* pWidget, gpointer userdata)
725 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
726 std::map<std::string, std::string> aEntries;
727 aEntries["Text"] = "";
729 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Edit comment", aEntries);
731 gchar *commentId = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
733 boost::property_tree::ptree aTree;
734 aTree.put(boost::property_tree::ptree::path_type("Id/type", '/'), "string");
735 aTree.put(boost::property_tree::ptree::path_type("Id/value", '/'), std::string(commentId));
737 aTree.put(boost::property_tree::ptree::path_type("Text/type", '/'), "string");
738 aTree.put(boost::property_tree::ptree::path_type("Text/value", '/'), aEntries["Text"]);
740 std::stringstream aStream;
741 boost::property_tree::write_json(aStream, aTree);
742 std::string aArguments = aStream.str();
744 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:EditAnnotation", aArguments.c_str(), false);
747 void replyButtonClicked(GtkWidget* pWidget, gpointer userdata)
749 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
750 std::map<std::string, std::string> aEntries;
751 aEntries["Text"] = "";
753 GtvHelpers::userPromptDialog(GTK_WINDOW(window), "Reply comment", aEntries);
755 gchar *commentId = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
757 boost::property_tree::ptree aTree;
758 aTree.put(boost::property_tree::ptree::path_type("Id/type", '/'), "string");
759 aTree.put(boost::property_tree::ptree::path_type("Id/value", '/'), std::string(commentId));
761 aTree.put(boost::property_tree::ptree::path_type("Text/type", '/'), "string");
762 aTree.put(boost::property_tree::ptree::path_type("Text/value", '/'), aEntries["Text"]);
764 std::stringstream aStream;
765 boost::property_tree::write_json(aStream, aTree);
766 std::string aArguments = aStream.str();
768 // Different reply UNO command for impress
769 std::string replyCommand = ".uno:ReplyComment";
770 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
771 if (pDocument && pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_PRESENTATION)
772 replyCommand = ".uno:ReplyToAnnotation";
773 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), replyCommand.c_str(), aArguments.c_str(), false);
776 void deleteCommentButtonClicked(GtkWidget* pWidget, gpointer userdata)
778 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
779 gchar *commentid = static_cast<gchar*>(g_object_get_data(G_OBJECT(userdata), "id"));
781 boost::property_tree::ptree aTree;
782 aTree.put(boost::property_tree::ptree::path_type("Id/type", '/'), "string");
783 aTree.put(boost::property_tree::ptree::path_type("Id/value", '/'), std::string(commentid));
785 std::stringstream aStream;
786 boost::property_tree::write_json(aStream, aTree);
787 std::string aArguments = aStream.str();
789 // Different reply UNO command for impress
790 std::string deleteCommand = ".uno:DeleteComment";
791 LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(LOK_DOC_VIEW(window->lokdocview));
792 if (pDocument)
794 if (pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_PRESENTATION)
795 deleteCommand = ".uno:DeleteAnnotation";
796 else if (pDocument->pClass->getDocumentType(pDocument) == LOK_DOCTYPE_SPREADSHEET)
797 deleteCommand = ".uno:DeleteNote";
800 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), deleteCommand.c_str(), aArguments.c_str(), false);
803 /// Handles the key-press-event of the address entry widget.
804 gboolean signalAddressbar(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer /*pData*/)
806 GtvApplicationWindow* window = GTV_APPLICATION_WINDOW(gtk_widget_get_toplevel(pWidget));
807 switch(pEvent->keyval)
809 case GDK_KEY_Return:
811 GtkEntry* pEntry = GTK_ENTRY(pWidget);
812 const char* pText = gtk_entry_get_text(pEntry);
814 boost::property_tree::ptree aTree;
815 aTree.put(boost::property_tree::ptree::path_type("ToPoint/type", '/'), "string");
816 aTree.put(boost::property_tree::ptree::path_type("ToPoint/value", '/'), pText);
817 std::stringstream aStream;
818 boost::property_tree::write_json(aStream, aTree);
819 std::string aArguments = aStream.str();
821 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:GoToCell", aArguments.c_str(), false);
822 gtk_widget_grab_focus(window->lokdocview);
823 return true;
825 case GDK_KEY_Escape:
827 std::string aArguments;
828 lok_doc_view_post_command(LOK_DOC_VIEW(window->lokdocview), ".uno:Cancel", aArguments.c_str(), false);
829 gtk_widget_grab_focus(window->lokdocview);
830 return true;
833 return FALSE;
836 /// Handles the key-press-event of the formula entry widget.
837 gboolean signalFormulabar(GtkWidget* /*pWidget*/, GdkEventKey* /*pEvent*/, gpointer /*pData*/)
839 // for now it just displays the callback
840 // TODO - submit the edited formula
841 return true;
844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */