From a141cba76606c7dcc4965f0a25cc9a4ff2d8879e Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 5 Aug 2016 18:01:06 +0200 Subject: gtktiledviewer: expose undo/redo info in a repair document dialog This shows the full undo and redo stack, with all the metadata available via the LOK API. Also fix SfxUndoManager::GetRedoActionsInfo(), so it's easy to show the undo/redo stack in linear time; and fix a use-after-free in lokdocview. Change-Id: I66625ed453efa61b5738d99d7d1ad8f468908240 Reviewed-on: https://gerrit.libreoffice.org/27913 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- .../qa/gtktiledviewer/gtktiledviewer.cxx | 108 ++++++++++++++++++++- libreofficekit/source/gtk/lokdocview.cxx | 2 +- 2 files changed, 108 insertions(+), 2 deletions(-) (limited to 'libreofficekit') diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx index 37cf7e2dff42..eaf1555d68e5 100644 --- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx +++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx @@ -441,6 +441,106 @@ static void addMoreUnoParam(GtkWidget* /*pWidget*/, gpointer userdata) gtk_widget_show_all(pUnoParamAreaBox); } +static void documentRepair(GtkWidget* pButton, gpointer /*pItem*/) +{ + TiledWindow& rWindow = lcl_getTiledWindow(pButton); + LOKDocView* pDocView = LOK_DOC_VIEW(rWindow.m_pDocView); + // Get the data. + LibreOfficeKitDocument* pDocument = lok_doc_view_get_document(pDocView); + // How it in linear time, so first redo in reverse order, then undo. + std::vector aTypes = {".uno:Redo", ".uno:Undo"}; + std::vector aTrees; + for (size_t nType = 0; nType < aTypes.size(); ++nType) + { + const std::string& rType = aTypes[nType]; + char* pValues = pDocument->pClass->getCommandValues(pDocument, rType.c_str()); + std::stringstream aInfo; + aInfo << "lok::Document::getCommandValues('" << rType << "') returned '" << pValues << "'" << std::endl; + g_info("%s", aInfo.str().c_str()); + std::stringstream aStream(pValues); + free(pValues); + assert(!aStream.str().empty()); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + aTrees.push_back(aTree); + } + + // Create the dialog. + GtkWidget* pDialog = gtk_dialog_new_with_buttons("Repair document", + GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET(pDocView))), + GTK_DIALOG_MODAL, + "Jump to state", + GTK_RESPONSE_OK, + nullptr); + GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG (pDialog)); + + // Build the table. + GtkTreeStore* pTreeStore = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + for (size_t nTree = 0; nTree < aTrees.size(); ++nTree) + { + const auto& rTree = aTrees[nTree]; + for (const auto& rValue : rTree.get_child("actions")) + { + GtkTreeIter aTreeIter; + gtk_tree_store_append(pTreeStore, &aTreeIter, nullptr); + gtk_tree_store_set(pTreeStore, &aTreeIter, + 0, aTypes[nTree].c_str(), + 1, rValue.second.get("index"), + 2, rValue.second.get("comment").c_str(), + 3, rValue.second.get("viewId").c_str(), + 4, rValue.second.get("dateTime").c_str(), + -1); + } + } + GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore)); + std::vector aColumns = {"Type", "Index", "Comment", "View ID", "Timestamp"}; + for (size_t nColumn = 0; nColumn < aColumns.size(); ++nColumn) + { + GtkCellRenderer* pRenderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* pColumn = gtk_tree_view_column_new_with_attributes(aColumns[nColumn].c_str(), + pRenderer, + "text", nColumn, + nullptr); + gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pColumn); + } + gtk_box_pack_start(GTK_BOX(pContentArea), pTreeView, TRUE, TRUE, 2); + + // Show the dialog. + gtk_widget_show_all(pDialog); + gint res = gtk_dialog_run(GTK_DIALOG(pDialog)); + + // Dispatch the matching command, if necessary. + if (res == GTK_RESPONSE_OK) + { + GtkTreeSelection* pSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pTreeView)); + GtkTreeIter aTreeIter; + GtkTreeModel* pTreeModel; + if (gtk_tree_selection_get_selected(pSelection, &pTreeModel, &aTreeIter)) + { + gchar* pType = nullptr; + gint nIndex = 0; + // 0: type, 1: index + gtk_tree_model_get(pTreeModel, &aTreeIter, 0, &pType, 1, &nIndex, -1); + // '.uno:Undo' or '.uno:Redo' + const std::string aType(pType); + // Without the '.uno:' prefix. + std::string aKey = aType.substr(strlen(".uno:")); + g_free(pType); + + // Post the command. + boost::property_tree::ptree aTree; + aTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short"); + aTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex + 1); + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + std::string aArguments = aStream.str(); + lok_doc_view_post_command(pDocView, aType.c_str(), aArguments.c_str(), false); + } + } + + gtk_widget_destroy(pDialog); +} + static void unoCommandDebugger(GtkWidget* pButton, gpointer /* pItem */) { TiledWindow& rWindow = lcl_getTiledWindow(pButton); @@ -1267,7 +1367,7 @@ static GtkWidget* createWindow(TiledWindow& rWindow) gtk_toolbar_insert( GTK_TOOLBAR(pUpperToolbar), gtk_separator_tool_item_new(), -1); - // Undo and redo. + // Undo, redo and document repair. rWindow.m_pUndo = gtk_tool_button_new(nullptr, nullptr); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(rWindow.m_pUndo), "edit-undo-symbolic"); gtk_tool_item_set_tooltip_text(rWindow.m_pUndo, "Undo"); @@ -1284,6 +1384,12 @@ static GtkWidget* createWindow(TiledWindow& rWindow) lcl_registerToolItem(rWindow, rWindow.m_pRedo, ".uno:Redo"); gtk_widget_set_sensitive(GTK_WIDGET(rWindow.m_pRedo), false); + GtkToolItem* pDocumentRepair = gtk_tool_button_new(nullptr, nullptr); + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(pDocumentRepair), "document-properties"); + gtk_tool_item_set_tooltip_text(pDocumentRepair, "Document repair"); + gtk_toolbar_insert(GTK_TOOLBAR(pUpperToolbar), pDocumentRepair, -1); + g_signal_connect(G_OBJECT(pDocumentRepair), "clicked", G_CALLBACK(documentRepair), nullptr); + gtk_toolbar_insert(GTK_TOOLBAR(pUpperToolbar), gtk_separator_tool_item_new(), -1); // Find. diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 3201ad38ad2e..34cbd27bedd8 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -436,7 +436,7 @@ LOKPostCommand (LOKDocView* pDocView, GTask* task = g_task_new(pDocView, nullptr, nullptr, nullptr); LOEvent* pLOEvent = new LOEvent(LOK_POST_COMMAND); GError* error = nullptr; - pLOEvent->m_pCommand = pCommand; + pLOEvent->m_pCommand = g_strdup(pCommand); pLOEvent->m_pArguments = g_strdup(pArguments); pLOEvent->m_bNotifyWhenFinished = bNotifyWhenFinished; -- cgit