You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

453 lines
11 KiB

#include "SidebarIndexPage.h"
#include "control/Control.h"
#include "model/LinkDestination.h"
#include "model/XojPage.h"
#include <config.h>
#include <i18n.h>
#include <Util.h>
SidebarIndexPage::SidebarIndexPage(Control* control) : AbstractSidebarPage(control)
{
XOJ_INIT_TYPE(SidebarIndexPage);
this->searchTimeout = 0;
this->hasContents = false;
this->treeViewBookmarks = gtk_tree_view_new();
g_object_ref(this->treeViewBookmarks);
gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeViewBookmarks), true);
gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeViewBookmarks), DOCUMENT_LINKS_COLUMN_NAME);
gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeViewBookmarks),
(GtkTreeViewSearchEqualFunc) treeSearchFunction, this, NULL);
this->scrollBookmarks = gtk_scrolled_window_new(NULL, NULL);
g_object_ref(this->scrollBookmarks);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollBookmarks), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollBookmarks), GTK_SHADOW_IN);
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeViewBookmarks), FALSE);
gtk_container_add(GTK_CONTAINER(scrollBookmarks), treeViewBookmarks);
GtkTreeViewColumn* column = gtk_tree_view_column_new();
gtk_tree_view_column_set_expand(GTK_TREE_VIEW_COLUMN(column), TRUE);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeViewBookmarks), column);
GtkCellRenderer* renderer = (GtkCellRenderer*) g_object_new(GTK_TYPE_CELL_RENDERER_TEXT, "ellipsize",
PANGO_ELLIPSIZE_END, NULL);
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, TRUE);
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "markup", DOCUMENT_LINKS_COLUMN_NAME, NULL);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_end(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer,
"text", DOCUMENT_LINKS_COLUMN_PAGE_NUMBER, NULL);
g_object_set(G_OBJECT(renderer), "style", PANGO_STYLE_ITALIC, NULL);
g_signal_connect(treeViewBookmarks, "cursor-changed", G_CALLBACK(treeBookmarkSelected), this);
gtk_widget_show(this->treeViewBookmarks);
registerListener(control);
}
SidebarIndexPage::~SidebarIndexPage()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
if (this->searchTimeout)
{
g_source_remove(this->searchTimeout);
this->searchTimeout = 0;
}
g_object_unref(this->treeViewBookmarks);
g_object_unref(this->scrollBookmarks);
XOJ_RELEASE_TYPE(SidebarIndexPage);
}
void SidebarIndexPage::enableSidebar()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
// Nothing to do at the moment
}
void SidebarIndexPage::disableSidebar()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
// Nothing to do at the moment
}
void SidebarIndexPage::askInsertPdfPage(size_t pdfPage)
{
XOJ_CHECK_TYPE(SidebarIndexPage);
GtkWidget* dialog = gtk_message_dialog_new(control->getGtkWindow(), GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
FC(_F("Your current document does not contain PDF Page no {1}\n"
"Would you like to insert this page?\n\n"
"Tip: You can select Journal → Paper Background → PDF Background "
"to insert a PDF page.") % (pdfPage + 1)));
gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", 1);
gtk_dialog_add_button(GTK_DIALOG(dialog), "Insert after", 2);
gtk_dialog_add_button(GTK_DIALOG(dialog), "Insert at end", 3);
gtk_window_set_transient_for(GTK_WINDOW(dialog), control->getGtkWindow());
int res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (res == 1)
{
return;
}
int position = 0;
Document* doc = control->getDocument();
if (res == 2)
{
position = control->getCurrentPageNo() + 1;
}
else if (res == 3)
{
position = doc->getPageCount();
}
doc->lock();
XojPdfPageSPtr pdf = doc->getPdfPage(pdfPage);
doc->unlock();
if (pdf)
{
PageRef page = new XojPage(pdf->getWidth(), pdf->getHeight());
page->setBackgroundPdfPageNr(pdfPage);
control->insertPage(page, position);
}
}
bool SidebarIndexPage::treeBookmarkSelected(GtkWidget* treeview, SidebarIndexPage* sidebar)
{
XOJ_CHECK_TYPE_OBJ(sidebar, SidebarIndexPage);
if (sidebar->searchTimeout)
{
return false;
}
gtk_widget_grab_focus(GTK_WIDGET(treeview));
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
if (selection)
{
GtkTreeModel* model = NULL;
GtkTreeIter iter = { 0 };
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
XojLinkDest* link = NULL;
gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1);
if (link && link->dest)
{
LinkDestination* dest = link->dest;
size_t pdfPage = dest->getPdfPage();
if (pdfPage != size_t_npos)
{
Document* doc = sidebar->control->getDocument();
doc->lock();
size_t page = doc->findPdfPage(pdfPage);
doc->unlock();
if (page == size_t_npos)
{
sidebar->askInsertPdfPage(pdfPage);
}
else
{
if (dest->shouldChangeTop())
{
sidebar->control->getScrollHandler()->scrollToPage(page, dest->getTop() * sidebar->control->getZoomControl()->getZoom());
}
else
{
if (sidebar->control->getCurrentPageNo() != page)
{
sidebar->control->getScrollHandler()->scrollToPage(page);
}
}
}
}
}
g_object_unref(link);
return true;
}
}
return false;
}
bool SidebarIndexPage::searchTimeoutFunc(SidebarIndexPage* sidebar)
{
XOJ_CHECK_TYPE_OBJ(sidebar, SidebarIndexPage);
sidebar->searchTimeout = 0;
treeBookmarkSelected(sidebar->treeViewBookmarks, sidebar);
return false;
}
gboolean SidebarIndexPage::treeSearchFunction(GtkTreeModel* model, gint column, const gchar* key,
GtkTreeIter* iter, SidebarIndexPage* sidebar)
{
XOJ_CHECK_TYPE_OBJ(sidebar, SidebarIndexPage);
if (sidebar->searchTimeout)
{
g_source_remove(sidebar->searchTimeout);
sidebar->searchTimeout = 0;
}
sidebar->searchTimeout = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE, 2,
(GSourceFunc) searchTimeoutFunc, sidebar, NULL);
// Source: Pidgin
gchar* text;
gtk_tree_model_get(model, iter, DOCUMENT_LINKS_COLUMN_NAME, &text, -1);
if (text == NULL)
{
return TRUE;
}
gchar* tmp = g_utf8_normalize(key, -1, G_NORMALIZE_DEFAULT);
gchar* enteredstring = g_utf8_casefold(tmp, -1);
g_free(tmp);
tmp = g_utf8_normalize(text, -1, G_NORMALIZE_DEFAULT);
gchar* normalized = g_utf8_casefold(tmp, -1);
g_free(tmp);
if (g_str_has_prefix(normalized, enteredstring))
{
g_free(enteredstring);
g_free(normalized);
return FALSE;
}
/* Use Pango to separate by words. */
size_t len = g_utf8_strlen(normalized, -1);
PangoLogAttr* log_attrs = g_new(PangoLogAttr, len + 1);
pango_get_log_attrs(normalized, strlen(normalized), -1, NULL, log_attrs, len + 1);
gchar* word = normalized;
gboolean result = TRUE;
for (size_t i = 0; i < (len - 1); i++)
{
if (log_attrs[i].is_word_start && g_str_has_prefix(word, enteredstring))
{
result = FALSE;
break;
}
word = g_utf8_next_char(word);
}
g_free(log_attrs);
g_free(enteredstring);
g_free(normalized);
return result;
}
string SidebarIndexPage::getName()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
return _("Contents");
}
string SidebarIndexPage::getIconName()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
return "sidebar_index.svg";
}
bool SidebarIndexPage::hasData()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
return this->hasContents;
}
GtkWidget* SidebarIndexPage::getWidget()
{
XOJ_CHECK_TYPE(SidebarIndexPage);
return this->scrollBookmarks;
}
int SidebarIndexPage::expandOpenLinks(GtkTreeModel* model, GtkTreeIter* parent)
{
XOJ_CHECK_TYPE(SidebarIndexPage);
GtkTreeIter iter = { 0 };
XojLinkDest* link = NULL;
if (model == NULL)
{
return 0;
}
int count = 0;
if (gtk_tree_model_iter_children(model, &iter, parent))
{
do
{
gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1);
if (link->dest->getExpand())
{
GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
gtk_tree_view_expand_row(GTK_TREE_VIEW(treeViewBookmarks), path, FALSE);
gtk_tree_path_free(path);
}
g_object_unref(link);
count++;
count += expandOpenLinks(model, &iter);
}
while (gtk_tree_model_iter_next(model, &iter));
}
return count;
}
void SidebarIndexPage::selectPageNr(size_t page, size_t pdfPage)
{
XOJ_CHECK_TYPE(SidebarIndexPage);
selectPageNr(page, pdfPage, NULL);
}
bool SidebarIndexPage::selectPageNr(size_t page, size_t pdfPage, GtkTreeIter* parent)
{
XOJ_CHECK_TYPE(SidebarIndexPage);
GtkTreeIter iter;
Document* doc = control->getDocument();
doc->lock();
GtkTreeModel* model = doc->getContentsModel();
if (model == NULL)
{
doc->unlock();
return false;
}
g_object_ref(model);
doc->unlock();
if (parent == NULL)
{
// check if there is already the current page selected
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks));
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
XojLinkDest* link = NULL;
gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1);
if (link && link->dest)
{
LinkDestination* dest = link->dest;
if (dest->getPdfPage() == pdfPage)
{
g_object_unref(model);
g_object_unref(link);
// already a bookmark from this page selected
return true;
}
}
g_object_unref(link);
}
}
gboolean valid = gtk_tree_model_iter_children(model, &iter, parent);
while (valid)
{
XojLinkDest* link = NULL;
gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1);
if (link->dest->getPdfPage() == pdfPage)
{
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks));
gtk_tree_selection_select_iter(selection, &iter);
g_object_unref(link);
g_object_unref(model);
return true;
}
else
{
g_object_unref(link);
if (selectPageNr(page, pdfPage, &iter))
{
g_object_unref(model);
return true;
}
else
{
valid = gtk_tree_model_iter_next(model, &iter);
}
}
}
g_object_unref(model);
return false;
}
void SidebarIndexPage::documentChanged(DocumentChangeType type)
{
XOJ_CHECK_TYPE(SidebarIndexPage);
if (type == DOCUMENT_CHANGE_CLEARED)
{
gtk_tree_view_set_model(GTK_TREE_VIEW(this->treeViewBookmarks), NULL);
}
else if (type == DOCUMENT_CHANGE_PDF_BOOKMARKS || type == DOCUMENT_CHANGE_COMPLETE)
{
Document* doc = this->control->getDocument();
doc->lock();
GtkTreeModel* model = doc->getContentsModel();
gtk_tree_view_set_model(GTK_TREE_VIEW(this->treeViewBookmarks), model);
int count = expandOpenLinks(model, NULL);
doc->unlock();
hasContents = (count != 0);
}
}