diff --git a/toys/mug/Makefile.am b/toys/mug/Makefile.am index f9b34915..5787c713 100644 --- a/toys/mug/Makefile.am +++ b/toys/mug/Makefile.am @@ -35,7 +35,7 @@ AM_CFLAGS= \ -Wno-deprecated-declarations \ -Wno-switch-enum -AM_CXXFLAGS=$(WARN_CXXFLAGS) +AM_CXXFLAGS=$(AM_CFLAGS) $(WARN_CXXFLAGS) # # Distributors: this is a _toy_, not for distribution. the "noinst_" says enough @@ -43,11 +43,9 @@ AM_CXXFLAGS=$(WARN_CXXFLAGS) noinst_PROGRAMS= \ mug -# note, mug.cc is '.cc' only because libmu must explicitly -# be linked as c++, not c. mug_SOURCES= \ mug.c \ - mug-msg-list-view.c \ + mug-msg-list-view.cc \ mug-msg-list-view.h \ mug-msg-view.h \ mug-msg-view.c \ @@ -57,12 +55,6 @@ mug_SOURCES= \ mug-shortcuts.h \ dummy.cc -# we need to use dummy.cc to enforce c++ linking... -BUILT_SOURCES= \ - dummy.cc - -dummy.cc: - touch dummy.cc DISTCLEANFILES= \ $(BUILT_SOURCES) @@ -70,6 +62,7 @@ DISTCLEANFILES= \ mug_LDADD= \ $(ASAN_LDFLAGS) \ ${top_builddir}/lib/libmu.la \ + ${top_builddir}/lib/utils/libmu-utils.la \ libmuwidgets.la \ ${GTK_LIBS} diff --git a/toys/mug/mug-msg-list-view.c b/toys/mug/mug-msg-list-view.c deleted file mode 100644 index c265a15b..00000000 --- a/toys/mug/mug-msg-list-view.c +++ /dev/null @@ -1,473 +0,0 @@ -/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/ -/* -** Copyright (C) 2008-2019 Dirk-Jan C. Binnema -** -** This program is free software; you can redistribute it and/or modify it -** under the terms of the GNU General Public License as published by the -** Free Software Foundation; either version 3, or (at your option) any -** later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software Foundation, -** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -** -*/ - -#include "mug-msg-list-view.h" -#include "mu-query.h" -#include "utils/mu-str.h" -#include "utils/mu-date.h" -#include "mu-threader.h" - -/* 'private'/'protected' functions */ -static void mug_msg_list_view_class_init (MugMsgListViewClass * klass); -static void mug_msg_list_view_init (MugMsgListView * obj); -static void mug_msg_list_view_finalize (GObject * obj); - -/* list my signals */ -enum { - MUG_MSG_SELECTED, - MUG_ERROR_OCCURED, - LAST_SIGNAL -}; - -enum { - MUG_COL_DATESTR, - MUG_COL_MAILDIR, - MUG_COL_FLAGSSTR, - MUG_COL_FROM, - MUG_COL_TO, - MUG_COL_SUBJECT, - MUG_COL_PATH, - MUG_COL_PRIO, - MUG_COL_FLAGS, - MUG_COL_TIME, - MUG_N_COLS -}; - -typedef struct _MugMsgListViewPrivate MugMsgListViewPrivate; -struct _MugMsgListViewPrivate { - GtkTreeStore *_store; - char *_xpath; - char *_query; -}; -#define MUG_MSG_LIST_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ - MUG_TYPE_MSG_LIST_VIEW, \ - MugMsgListViewPrivate)) -/* globals */ -static GtkTreeViewClass *parent_class = NULL; - -/* uncomment the following if you have defined any signals */ -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (MugMsgListView, mug_msg_list_view, GTK_TYPE_TREE_VIEW); - -static void -mug_msg_list_view_class_init (MugMsgListViewClass * klass) -{ - GObjectClass *gobject_class; - gobject_class = (GObjectClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - gobject_class->finalize = mug_msg_list_view_finalize; - - g_type_class_add_private (gobject_class, - sizeof (MugMsgListViewPrivate)); - - signals[MUG_MSG_SELECTED] = - g_signal_new ("msg-selected", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MugMsgListViewClass, - msg_selected), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); - signals[MUG_ERROR_OCCURED] = - g_signal_new ("error-occured", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MugMsgListViewClass, - error_occured), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); -} - -static void -on_cursor_changed (GtkTreeView * tview, MugMsgListView * lst) -{ - GtkTreeSelection *sel; - GtkTreeIter iter; - MugMsgListViewPrivate *priv; - - priv = MUG_MSG_LIST_VIEW_GET_PRIVATE (tview); - - sel = gtk_tree_view_get_selection (tview); - if (!sel) - return; /* hmmm */ - if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { - char *path; - gtk_tree_model_get (GTK_TREE_MODEL (priv->_store), &iter, - MUG_COL_PATH, &path, -1); - g_signal_emit (G_OBJECT (lst), - signals[MUG_MSG_SELECTED], 0, path); - g_free (path); - } -} - -static void -treecell_func (GtkTreeViewColumn * tree_column, GtkCellRenderer * renderer, - GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data) -{ - MuFlags flags; - MuMsgPrio prio; - - gtk_tree_model_get (tree_model, iter, - MUG_COL_FLAGS, &flags, MUG_COL_PRIO, &prio, -1); - - g_object_set (G_OBJECT (renderer), - "weight", (flags & MU_FLAG_NEW) ? 800 : 400, - "weight", (flags & MU_FLAG_SEEN) ? 400 : 800, - "foreground", prio == MU_MSG_PRIO_HIGH ? "red" : NULL, - NULL); -} - -/* sortcolidx == -1 means 'sortcolidx = colidx' */ -static void -append_col (GtkTreeView * treeview, const char *label, int colidx, - int sortcolidx, gint maxwidth) -{ - GtkTreeViewColumn *col; - GtkCellRenderer *renderer; - - renderer = gtk_cell_renderer_text_new (); - g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - - col = gtk_tree_view_column_new_with_attributes (label, renderer, "text", - colidx, NULL); - g_object_set (G_OBJECT (col), "resizable", TRUE, NULL); - - gtk_tree_view_column_set_sort_indicator (col, TRUE); - - if (sortcolidx == -1) - sortcolidx = colidx; - gtk_tree_view_column_set_sort_column_id (col, sortcolidx); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); - - if (maxwidth) { - gtk_tree_view_column_set_fixed_width (col, maxwidth); - gtk_tree_view_column_set_expand (col, FALSE); - } else - gtk_tree_view_column_set_expand (col, TRUE); - - gtk_tree_view_column_set_cell_data_func (col, renderer, - (GtkTreeCellDataFunc) - treecell_func, NULL, NULL); - - gtk_tree_view_append_column (treeview, col); - - gtk_tree_view_columns_autosize (treeview); - gtk_tree_view_set_fixed_height_mode (treeview, TRUE); -} - -static void -mug_msg_list_view_init (MugMsgListView * obj) -{ - MugMsgListViewPrivate *priv; - GtkTreeView *tview; - - priv = MUG_MSG_LIST_VIEW_GET_PRIVATE (obj); - - priv->_xpath = priv->_query = NULL; - priv->_store = gtk_tree_store_new (MUG_N_COLS, G_TYPE_STRING, /* date */ - G_TYPE_STRING,/* folder */ - G_TYPE_STRING,/* flagstr */ - G_TYPE_STRING, /* from */ - G_TYPE_STRING,/* to */ - G_TYPE_STRING,/* subject */ - G_TYPE_STRING, /* path */ - G_TYPE_UINT, /* prio */ - G_TYPE_UINT, /* flags */ - G_TYPE_INT); /* timeval */ - - tview = GTK_TREE_VIEW (obj); - gtk_tree_view_set_model (tview, GTK_TREE_MODEL (priv->_store)); - gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (obj), TRUE); - gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (obj), - GTK_TREE_VIEW_GRID_LINES_VERTICAL); - gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (obj), TRUE); - - append_col (tview, "Date", MUG_COL_DATESTR, MUG_COL_TIME, 80); - append_col (tview, "Folder", MUG_COL_MAILDIR, -1, 60); - append_col (tview, "F", MUG_COL_FLAGSSTR, -1, 25); - append_col (tview, "From", MUG_COL_FROM, -1, 0); - append_col (tview, "To", MUG_COL_TO, -1, 0); - append_col (tview, "Subject", MUG_COL_SUBJECT, -1, 0); - - g_signal_connect (G_OBJECT (obj), "cursor-changed", - G_CALLBACK (on_cursor_changed), obj); -} - -static void -mug_msg_list_view_finalize (GObject * obj) -{ - MugMsgListViewPrivate *priv; - priv = MUG_MSG_LIST_VIEW_GET_PRIVATE (obj); - - if (priv->_store) - g_object_unref (priv->_store); - - g_free (priv->_xpath); - g_free (priv->_query); - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -void -mug_msg_list_view_move_first (MugMsgListView * self) -{ - GtkTreePath *path; - - g_return_if_fail (MUG_IS_MSG_LIST_VIEW (self)); - - path = gtk_tree_path_new_first (); - gtk_tree_view_set_cursor (GTK_TREE_VIEW (self), path, NULL, FALSE); - - gtk_tree_path_free (path); -} - -static gboolean -msg_list_view_move (MugMsgListView * self, gboolean next) -{ - GtkTreePath *path; - - gtk_tree_view_get_cursor (GTK_TREE_VIEW (self), &path, NULL); - if (!path) - return FALSE; - - if (next) - gtk_tree_path_next (path); - else - gtk_tree_path_prev (path); - - gtk_tree_view_set_cursor (GTK_TREE_VIEW (self), path, NULL, FALSE); - gtk_tree_path_free (path); - - return TRUE; -} - -gboolean -mug_msg_list_view_move_next (MugMsgListView * self) -{ - g_return_val_if_fail (MUG_IS_MSG_LIST_VIEW (self), FALSE); - - return msg_list_view_move (self, TRUE); -} - -gboolean -mug_msg_list_view_move_prev (MugMsgListView * self) -{ - g_return_val_if_fail (MUG_IS_MSG_LIST_VIEW (self), FALSE); - - return msg_list_view_move (self, FALSE); -} - -GtkWidget * -mug_msg_list_view_new (const char *xpath) -{ - GtkWidget *w; - MugMsgListViewPrivate *priv; - - g_return_val_if_fail (xpath, NULL); - - w = GTK_WIDGET (g_object_new (MUG_TYPE_MSG_LIST_VIEW, NULL)); - - priv = MUG_MSG_LIST_VIEW_GET_PRIVATE (w); - priv->_xpath = g_strdup (xpath); - - return w; -} - -static gchar * -empty_or_display_contact (const gchar * str) -{ - if (!str || *str == '\0') - return g_strdup ("-"); - else - return mu_str_display_contact (str); - -} - -static MugError -mu_result_to_mug_error (MuError r) -{ - switch (r) { - /* case MU_ERROR_XAPIAN_DIR_NOT_ACCESSIBLE: */ - /* return MUG_ERROR_XAPIAN_DIR; */ - /* case MU_ERROR_XAPIAN_VERSION_MISMATCH: */ - /* return MUG_ERROR_XAPIAN_NOT_UPTODATE; */ - case MU_ERROR_XAPIAN_QUERY: - return MUG_ERROR_QUERY; - default: - return MUG_ERROR_OTHER; - } -} - -static MuMsgIter * -run_query (const char *xpath, const char *query, MugMsgListView * self) -{ - GError *err; - MuQuery *xapian; - MuMsgIter *iter; - MuStore *store; - MuQueryFlags qflags; - - err = NULL; - if (! (store = mu_store_new_readable (xpath, &err)) || - ! (xapian = mu_query_new (store, &err))) { - if (store) - mu_store_unref (store); - g_warning ("Error: %s", err->message); - g_signal_emit (G_OBJECT (self), - signals[MUG_ERROR_OCCURED], 0, - mu_result_to_mug_error (err->code)); - g_error_free (err); - return NULL; - } - mu_store_unref (store); - - qflags = - MU_QUERY_FLAG_DESCENDING | - MU_QUERY_FLAG_SKIP_UNREADABLE | - MU_QUERY_FLAG_SKIP_DUPS | - MU_QUERY_FLAG_THREADS; - - iter = mu_query_run (xapian, query, MU_MSG_FIELD_ID_DATE, - -1, qflags, &err); - mu_query_destroy (xapian); - if (!iter) { - g_warning ("Error: %s", err->message); - g_signal_emit (G_OBJECT (self), - signals[MUG_ERROR_OCCURED], 0, - mu_result_to_mug_error (err->code)); - g_error_free (err); - return NULL; - } - - return iter; -} - -static void -add_row (GtkTreeStore * store, MuMsg *msg, GtkTreeIter *treeiter) -{ - const gchar *datestr, *flagstr; - gchar *from, *to; - time_t timeval; - - timeval = mu_msg_get_date (msg); - datestr = timeval == 0 ? "-" : mu_date_display_s (timeval); - from = empty_or_display_contact (mu_msg_get_from (msg)); - to = empty_or_display_contact (mu_msg_get_to (msg)); - flagstr = mu_flags_to_str_s (mu_msg_get_flags (msg), MU_FLAG_TYPE_ANY); - - /* if (0) { */ - /* GtkTreeIter myiter; */ - /* if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(store), */ - /* &myiter, path)) */ - /* g_warning ("%s: cannot get iter for %s", - * __func__, path); */ - /* } */ - - gtk_tree_store_set (store, treeiter, - MUG_COL_DATESTR, datestr, - MUG_COL_MAILDIR, mu_msg_get_maildir (msg), - MUG_COL_FLAGSSTR, flagstr, - MUG_COL_FROM, from, - MUG_COL_TO, to, - MUG_COL_SUBJECT, mu_msg_get_subject (msg), - MUG_COL_PATH, mu_msg_get_path (msg), - MUG_COL_PRIO, mu_msg_get_prio (msg), - MUG_COL_FLAGS, mu_msg_get_flags (msg), - MUG_COL_TIME, timeval, -1); - g_free (from); - g_free (to); -} - -static int -update_model (GtkTreeStore *store, const char *xpath, const char *query, - MugMsgListView *self) -{ - MuMsgIter *iter; - int count; - const MuMsgIterThreadInfo *prev_ti = NULL; - - iter = run_query (xpath, query, self); - if (!iter) { - g_warning ("error: running query failed\n"); - return -1; - } - - for (count = 0; !mu_msg_iter_is_done (iter); - mu_msg_iter_next (iter), ++count) { - - GtkTreeIter treeiter, prev_treeiter; - const MuMsgIterThreadInfo *ti; - - ti = mu_msg_iter_get_thread_info (iter); - - if (!prev_ti || !g_str_has_prefix (ti->threadpath, - prev_ti->threadpath)) - gtk_tree_store_append (store, &treeiter, NULL); - else - gtk_tree_store_append (store, &treeiter, &prev_treeiter); - - /* don't unref msg */ - add_row (store, mu_msg_iter_get_msg_floating (iter), &treeiter); - - prev_ti = ti; - prev_treeiter = treeiter; - } - - mu_msg_iter_destroy (iter); - - return count; -} - -int -mug_msg_list_view_query (MugMsgListView * self, const char *query) -{ - MugMsgListViewPrivate *priv; - gboolean rv; - - g_return_val_if_fail (MUG_IS_MSG_LIST_VIEW (self), FALSE); - - priv = MUG_MSG_LIST_VIEW_GET_PRIVATE (self); - gtk_tree_store_clear (priv->_store); - - g_free (priv->_query); - priv->_query = query ? g_strdup (query) : NULL; - - if (!query) - return TRUE; - - rv = update_model (priv->_store, priv->_xpath, query, self); - - gtk_tree_view_expand_all (GTK_TREE_VIEW(self)); - - return rv; -} - -const gchar * -mug_msg_list_view_get_query (MugMsgListView * self) -{ - g_return_val_if_fail (MUG_IS_MSG_LIST_VIEW (self), NULL); - - return MUG_MSG_LIST_VIEW_GET_PRIVATE (self)->_query; -}