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-lokdocview-signal-handlers.hxx"
15 #include "gtv-signal-handlers.hxx"
17 #include <sal/macros.h>
23 #include <boost/property_tree/json_parser.hpp>
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:")))
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
);
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);
69 GtvHelpers::clipboardSetHtml(pClipboard
, pSelection
);
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
);
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
];
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
;
114 GtkSelectionData
* pSelectionData
= gtk_clipboard_wait_for_contents(pClipboard
, *oTarget
);
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
);
127 gchar
* pText
= gtk_clipboard_wait_for_text(pClipboard
);
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
)),
187 GList
* pIt
= nullptr;
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]);
199 pPath
= g_strconcat(unoParam
[1], "/", "value", nullptr);
200 pTree
->put(boost::property_tree::ptree::path_type(pPath
, '/'), unoParam
[2]);
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())
215 lok_doc_view_post_command(LOK_DOC_VIEW(pWindow
->lokdocview
), pUnoCmd
, (aUnoArgs
.empty() ? nullptr : aUnoArgs
.c_str()), false);
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
;
227 std::ofstream
outfile("/tmp/gtv-recentunos.txt", std::ios_base::app
| std::ios_base::out
);
229 outfile
<< rUnoCmdStr
<< '\n';
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",
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
);
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",
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
);
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
;
385 aDate
<< std::setfill('0') << std::setw(2) << (nMonth
+ 1);
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
) );
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
] )
424 else if ( strcmp(sName
, "zoom-original-symbolic") == 0)
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
] )
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
));
454 LibreOfficeKitDocument
* pDocument
= lok_doc_view_get_document(LOK_DOC_VIEW(window
->lokdocview
));
455 char* pValues
= pDocument
->pClass
->getCommandValues(pDocument
, ".uno:AcceptTrackedChanges");
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
);
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",
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);
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(),
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(),
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);
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
))
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";
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:"));
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
));
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
);
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",
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);
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(),
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(),
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);
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;
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:"));
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
)
700 signalSearchNext(pWidget
, nullptr);
706 gtk_widget_hide(GTK_WIDGET(window
->findtoolbar
));
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
));
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
)
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
);
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
);
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
844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */