Merge pull request #196 from JosephMcc/1.8-dev1

1.8 dev1
This commit is contained in:
Clement Lefebvre 2018-03-09 15:11:24 +00:00 committed by GitHub
commit 87cd264acf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 3462 additions and 7985 deletions

View File

@ -94,49 +94,25 @@ dnl ================================================================
dnl spell plugins checks: enchant and iso-codes dnl spell plugins checks: enchant and iso-codes
dnl ================================================================ dnl ================================================================
ENCHANT_REQUIRED=1.2.0 GSPELL_REQUIRED=0.2.5
ISO_CODES_REQUIRED=0.35
AC_ARG_ENABLE([spell], AC_ARG_ENABLE([spell],
AS_HELP_STRING([--disable-spell],[Disable spell plugin (default: enabled)]), AS_HELP_STRING([--disable-spell],[Disable spell plugin (default: enabled)]),
[enable_enchant=$enableval], [enable_spell=$enableval],
[enable_enchant=yes]) [enable_spell=yes])
if test "x$enable_enchant" = "xyes" ; then if test "x$enable_spell" = "xyes" ; then
PKG_CHECK_MODULES(ENCHANT, enchant >= $ENCHANT_REQUIRED, \ PKG_CHECK_MODULES(GSPELL, gspell-1 >= $GSPELL_REQUIRED, \
have_enchant=yes, have_enchant=no) have_gspell=yes, have_gspell=no)
if test "x$have_enchant" = "xyes"; then if test "x$have_gspell" = "xno"; then
enable_spell=no
PKG_CHECK_EXISTS([iso-codes >= $ISO_CODES_REQUIRED], AC_MSG_ERROR([gspell library not found or too old. Use --disable-spell to build without spell plugin.])
[have_iso_codes=yes],[have_iso_codes=no])
if test "x$have_iso_codes" = "xyes"; then
AC_MSG_CHECKING([whether iso-codes has iso-639 and iso-3166 domains])
if $PKG_CONFIG --variable=domains iso-codes | grep 639 > /dev/null && \
$PKG_CONFIG --variable=domains iso-codes | grep 3166 > /dev/null ; then
result=yes
else
result=no
have_iso_codes=no
fi
AC_MSG_RESULT([$result])
fi
if test "x$have_iso_codes" = "xyes"; then
AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix])
AC_DEFINE([HAVE_ISO_CODES],[1],[Define if you have the iso-codes package])
else
AC_MSG_ERROR([iso-codes is required to build the spell plugin. Use --disable-spell to build without spell plugin.])
fi
else
enable_enchant=no
AC_MSG_ERROR([Enchant library not found or too old. Use --disable-spell to build without spell plugin.])
fi fi
fi fi
AM_CONDITIONAL(ENABLE_ENCHANT, test x"$enable_enchant" = "xyes") AM_CONDITIONAL(ENABLE_SPELL, test x"$enable_spell" = "xyes")
dnl ================================================================ dnl ================================================================
dnl Start of pkg-config checks dnl Start of pkg-config checks
@ -149,10 +125,11 @@ PKG_CHECK_MODULES(XED, [
$GMODULE_ADD $GMODULE_ADD
gthread-2.0 >= 2.13.0 gthread-2.0 >= 2.13.0
gio-2.0 >= 2.40.0 gio-2.0 >= 2.40.0
gtk+-3.0 >= 3.18.0 gtk+-3.0 >= 3.19.3
gtksourceview-3.0 >= 3.18.0 gtksourceview-3.0 >= 3.19.0
libpeas-1.0 >= 1.12.0 libpeas-1.0 >= 1.12.0
libpeas-gtk-1.0 >= 1.12.0 libpeas-gtk-1.0 >= 1.12.0
xapp
]) ])
PKG_CHECK_MODULES(X11, [x11]) PKG_CHECK_MODULES(X11, [x11])
@ -254,7 +231,7 @@ Configuration:
Source code location: ${srcdir} Source code location: ${srcdir}
Compiler: ${CC} Compiler: ${CC}
Spell Plugin enabled: $enable_enchant Spell Plugin enabled: $enable_spell
Gvfs metadata enabled: $enable_gvfs_metadata Gvfs metadata enabled: $enable_gvfs_metadata
GObject Introspection: ${enable_introspection} GObject Introspection: ${enable_introspection}
" "

6
debian/control vendored
View File

@ -7,13 +7,13 @@ Build-Depends: autotools-dev,
gobject-introspection, gobject-introspection,
gtk-doc-tools, gtk-doc-tools,
intltool, intltool,
iso-codes,
libenchant-dev,
libgirepository1.0-dev, libgirepository1.0-dev,
libglib2.0-dev, libglib2.0-dev,
libgspell-1-dev,
libgtk-3-dev, libgtk-3-dev,
libgtksourceview-3.0-dev, libgtksourceview-3.0-dev,
libpeas-dev, libpeas-dev,
libxapp-dev,
libsm-dev, libsm-dev,
libx11-dev, libx11-dev,
libxml2-dev, libxml2-dev,
@ -145,4 +145,4 @@ Description: Text editor (documentation files)
includes support for spell checking, comparing files, viewing CVS includes support for spell checking, comparing files, viewing CVS
ChangeLogs, and adjusting indentation levels. ChangeLogs, and adjusting indentation levels.
. .
This package contains the documentation files. This package contains the documentation files.

2
debian/rules vendored
View File

@ -14,7 +14,7 @@ override_dh_auto_configure:
# upstream tarball is without configure. autogen.sh will create it # upstream tarball is without configure. autogen.sh will create it
NOCONFIGURE=1 ./autogen.sh NOCONFIGURE=1 ./autogen.sh
dh_auto_configure $(DHFLAGS) -- \ dh_auto_configure $(DHFLAGS) -- \
--disable-silent-rules \ --enable-silent-rules \
--libexecdir=/usr/lib/ \ --libexecdir=/usr/lib/ \
--enable-gtk-doc --enable-gtk-doc

View File

@ -19,7 +19,7 @@ SUBDIRS = \
time \ time \
trailsave trailsave
if ENABLE_ENCHANT if ENABLE_SPELL
SUBDIRS += spell SUBDIRS += spell
endif endif

View File

@ -4,7 +4,7 @@ plugindir = $(XED_PLUGINS_LIBS_DIR)
AM_CPPFLAGS = \ AM_CPPFLAGS = \
-I$(top_srcdir) \ -I$(top_srcdir) \
$(XED_CFLAGS) \ $(XED_CFLAGS) \
$(ENCHANT_CFLAGS) \ $(GSPELL_CFLAGS) \
$(WARN_CFLAGS) \ $(WARN_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS) $(DISABLE_DEPRECATED_CFLAGS)
@ -17,25 +17,13 @@ plugin_LTLIBRARIES = libspell.la
libspell_la_SOURCES = \ libspell_la_SOURCES = \
xed-spell-plugin.c \ xed-spell-plugin.c \
xed-spell-plugin.h \ xed-spell-plugin.h \
xed-spell-checker.c \
xed-spell-checker.h \
xed-spell-checker-dialog.c \
xed-spell-checker-dialog.h \
xed-spell-checker-language.c \
xed-spell-checker-language.h \
xed-spell-language-dialog.c \
xed-spell-language-dialog.h \
xed-automatic-spell-checker.c \
xed-automatic-spell-checker.h \
xed-spell-utils.c \
xed-spell-utils.h \
$(BUILT_SOURCES) $(BUILT_SOURCES)
libspell_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) libspell_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
libspell_la_LIBADD = $(XED_LIBS) $(ENCHANT_LIBS) libspell_la_LIBADD = $(XED_LIBS) $(GSPELL_LIBS)
uidir = $(XED_PLUGINS_DATA_DIR)/spell uidir = $(XED_PLUGINS_DATA_DIR)/spell
ui_DATA = spell-checker.ui languages-dialog.ui xed-spell-setup-dialog.ui ui_DATA = xed-spell-setup-dialog.ui
xed-spell-marshal.h: xed-spell-marshal.list $(GLIB_GENMARSHAL) xed-spell-marshal.h: xed-spell-marshal.list $(GLIB_GENMARSHAL)
$(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=xed_marshal > $@ $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=xed_marshal > $@

View File

@ -1,140 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!--*- mode: xml -*-->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Set language</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="helpbutton1">
<property name="label">gtk-help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="closebutton1">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="border_width">5</property>
<property name="orientation">vertical</property>
<property name="spacing">11</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Select the _language of the current document.</property>
<property name="use_underline">True</property>
<property name="wrap">True</property>
<property name="mnemonic_widget">languages_treeview</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">etched-in</property>
<child>
<object class="GtkTreeView" id="languages_treeview">
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-11">helpbutton1</action-widget>
<action-widget response="-6">closebutton1</action-widget>
<action-widget response="-5">button1</action-widget>
</action-widgets>
</object>
</interface>

View File

@ -1,369 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="check_spelling_window">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="startup_id">Check spelling</property>
<child>
<object class="GtkBox" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Misspelled word:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="misspelled_word_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">word</property>
<property name="use_markup">True</property>
<property name="justify">center</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Change _to:</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="spacing">12</property>
<child>
<object class="GtkEntry" id="word_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="check_word_button">
<property name="label" translatable="yes">Check _Word</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Suggestions:</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="suggestions_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkGrid" id="grid3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">12</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkButton" id="ignore_button">
<property name="label" translatable="yes">_Ignore</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ignore_all_button">
<property name="label" translatable="yes">Ignore _All</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_button">
<property name="label" translatable="yes">Cha_nge</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_all_button">
<property name="label" translatable="yes">Change A_ll</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">11</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">User dictionary:</property>
<property name="use_markup">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="add_word_button">
<property name="label" translatable="yes">Add w_ord</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Language:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="language_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Language</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="close_button">
<property name="label" translatable="yes">_Close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
<property name="use_underline">True</property>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -1,967 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-automatic-spell-checker.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */
/* gtkspell - a spell-checking addon for GTK's TextView widget
* Copyright (c) 2002 Evan Martin.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib/gi18n.h>
#include "xed-automatic-spell-checker.h"
#include "xed-spell-utils.h"
struct _XedAutomaticSpellChecker
{
XedDocument *doc;
GSList *views;
GtkTextMark *mark_insert_start;
GtkTextMark *mark_insert_end;
gboolean deferred_check;
GtkTextTag *tag_highlight;
GtkTextMark *mark_click;
XedSpellChecker *spell_checker;
};
static GQuark automatic_spell_checker_id = 0;
static GQuark suggestion_id = 0;
static void xed_automatic_spell_checker_free_internal (XedAutomaticSpellChecker *spell);
static void
view_destroy (XedView *view,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_detach_view (spell, view);
}
static void
check_word (XedAutomaticSpellChecker *spell,
GtkTextIter *start,
GtkTextIter *end)
{
gchar *word;
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE);
/*
g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end));
*/
if (!xed_spell_checker_check_word (spell->spell_checker, word, -1))
{
/*
g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end));
*/
gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, start, end);
}
g_free (word);
}
static void
check_range (XedAutomaticSpellChecker *spell,
GtkTextIter start,
GtkTextIter end,
gboolean force_all)
{
/* we need to "split" on word boundaries.
* luckily, Pango knows what "words" are
* so we don't have to figure it out. */
GtkTextIter wstart;
GtkTextIter wend;
GtkTextIter cursor;
GtkTextIter precursor;
gboolean highlight;
/*
g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start),
gtk_text_iter_get_offset (&end));
*/
if (gtk_text_iter_inside_word (&end))
{
gtk_text_iter_forward_word_end (&end);
}
if (!gtk_text_iter_starts_word (&start))
{
if (gtk_text_iter_inside_word (&start) || gtk_text_iter_ends_word (&start))
{
gtk_text_iter_backward_word_start (&start);
}
else
{
/* if we're neither at the beginning nor inside a word,
* me must be in some spaces.
* skip forward to the beginning of the next word. */
if (gtk_text_iter_forward_word_end (&start))
{
gtk_text_iter_backward_word_start (&start);
}
}
}
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc),
&cursor,
gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc)));
precursor = cursor;
gtk_text_iter_backward_char (&precursor);
highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) ||
gtk_text_iter_has_tag (&precursor, spell->tag_highlight);
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, &start, &end);
/* Fix a corner case when replacement occurs at beginning of buffer:
* An iter at offset 0 seems to always be inside a word,
* even if it's not. Possibly a pango bug.
*/
if (gtk_text_iter_get_offset (&start) == 0)
{
gtk_text_iter_forward_word_end(&start);
gtk_text_iter_backward_word_start(&start);
}
wstart = start;
while (xed_spell_utils_skip_no_spell_check (&wstart, &end) && gtk_text_iter_compare (&wstart, &end) < 0)
{
gboolean inword;
/* move wend to the end of the current word. */
wend = wstart;
gtk_text_iter_forward_word_end (&wend);
inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && (gtk_text_iter_compare (&cursor, &wend) <= 0);
if (inword && !force_all)
{
/* this word is being actively edited,
* only check if it's already highligted,
* otherwise defer this check until later. */
if (highlight)
{
check_word (spell, &wstart, &wend);
}
else
{
spell->deferred_check = TRUE;
}
}
else
{
check_word (spell, &wstart, &wend);
spell->deferred_check = FALSE;
}
/* now move wend to the beginning of the next word, */
gtk_text_iter_forward_word_end (&wend);
gtk_text_iter_backward_word_start (&wend);
/* make sure we've actually advanced
* (we don't advance in some corner cases), */
if (gtk_text_iter_equal (&wstart, &wend))
{
break; /* we're done in these cases.. */
}
/* and then pick this as the new next word beginning. */
wstart = wend;
}
}
static void
check_deferred_range (XedAutomaticSpellChecker *spell,
gboolean force_all)
{
GtkTextIter start, end;
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), &start, spell->mark_insert_start);
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), &end, spell->mark_insert_end);
check_range (spell, start, end, force_all);
}
/* insertion works like this:
* - before the text is inserted, we mark the position in the buffer.
* - after the text is inserted, we see where our mark is and use that and
* the current position to check the entire range of inserted text.
*
* this may be overkill for the common case (inserting one character). */
static void
insert_text_before (GtkTextBuffer *buffer,
GtkTextIter *iter,
gchar *text,
gint len,
XedAutomaticSpellChecker *spell)
{
gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter);
}
static void
insert_text_after (GtkTextBuffer *buffer,
GtkTextIter *iter,
gchar *text,
gint len,
XedAutomaticSpellChecker *spell)
{
GtkTextIter start;
/* we need to check a range of text. */
gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start);
check_range (spell, start, *iter, FALSE);
gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter);
}
/* deleting is more simple: we're given the range of deleted text.
* after deletion, the start and end iters should be at the same position
* (because all of the text between them was deleted!).
* this means we only really check the words immediately bounding the
* deletion.
*/
static void
delete_range_after (GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
XedAutomaticSpellChecker *spell)
{
check_range (spell, *start, *end, FALSE);
}
static void
mark_set (GtkTextBuffer *buffer,
GtkTextIter *iter,
GtkTextMark *mark,
XedAutomaticSpellChecker *spell)
{
/* if the cursor has moved and there is a deferred check so handle it now */
if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check)
{
check_deferred_range (spell, FALSE);
}
}
static void
get_word_extents_from_mark (GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
GtkTextMark *mark)
{
gtk_text_buffer_get_iter_at_mark(buffer, start, mark);
if (!gtk_text_iter_starts_word (start))
{
gtk_text_iter_backward_word_start (start);
}
*end = *start;
if (gtk_text_iter_inside_word (end))
{
gtk_text_iter_forward_word_end (end);
}
}
static void
remove_tag_to_word (XedAutomaticSpellChecker *spell,
const gchar *word)
{
GtkTextIter iter;
GtkTextIter match_start, match_end;
gboolean found;
gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0);
found = TRUE;
while (found)
{
found = gtk_text_iter_forward_search (&iter,
word,
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
&match_start,
&match_end,
NULL);
if (found)
{
if (gtk_text_iter_starts_word (&match_start) && gtk_text_iter_ends_word (&match_end))
{
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc),
spell->tag_highlight,
&match_start,
&match_end);
}
iter = match_end;
}
}
}
static void
add_to_dictionary (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *word;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
xed_spell_checker_add_word_to_personal (spell->spell_checker, word, -1);
g_free (word);
}
static void
ignore_all (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *word;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
xed_spell_checker_add_word_to_session (spell->spell_checker, word, -1);
g_free (word);
}
static void
replace_word (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *oldword;
const gchar *newword;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id);
g_return_if_fail (newword != NULL);
gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc));
gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end);
gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1);
gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc));
xed_spell_checker_set_correction (spell->spell_checker,
oldword, strlen (oldword),
newword, strlen (newword));
g_free (oldword);
}
static GtkWidget *
build_suggestion_menu (XedAutomaticSpellChecker *spell,
const gchar *word)
{
GtkWidget *topmenu, *menu;
GtkWidget *mi;
GSList *suggestions;
GSList *list;
gchar *label_text;
topmenu = menu = gtk_menu_new();
suggestions = xed_spell_checker_get_suggestions (spell->spell_checker, word, -1);
list = suggestions;
if (suggestions == NULL)
{
/* no suggestions. put something in the menu anyway... */
GtkWidget *label;
/* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */
label = gtk_label_new (_("(no suggested words)"));
mi = gtk_menu_item_new ();
gtk_widget_set_sensitive (mi, FALSE);
gtk_container_add (GTK_CONTAINER(mi), label);
gtk_widget_show_all (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
}
else
{
gint count = 0;
/* build a set of menus with suggestions. */
while (suggestions != NULL)
{
GtkWidget *label;
if (count == 10)
{
/* Separator */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
mi = gtk_menu_item_new_with_mnemonic (_("_More..."));
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
count = 0;
}
label_text = g_strdup_printf ("<b>%s</b>", (gchar*) suggestions->data);
label = gtk_label_new (label_text);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_widget_set_halign (label, GTK_ALIGN_START);
mi = gtk_menu_item_new ();
gtk_container_add (GTK_CONTAINER (mi), label);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
g_object_set_qdata_full (G_OBJECT (mi),
suggestion_id,
g_strdup (suggestions->data),
(GDestroyNotify)g_free);
g_free (label_text);
g_signal_connect (mi, "activate",
G_CALLBACK (replace_word), spell);
count++;
suggestions = g_slist_next (suggestions);
}
}
/* free the suggestion list */
suggestions = list;
while (list)
{
g_free (list->data);
list = g_slist_next (list);
}
g_slist_free (suggestions);
/* Separator */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
/* Ignore all */
mi = gtk_menu_item_new_with_mnemonic (_("_Ignore All"));
g_signal_connect (mi, "activate",
G_CALLBACK(ignore_all), spell);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
/* + Add to Dictionary */
mi = gtk_menu_item_new_with_mnemonic (_("_Add"));
g_signal_connect (mi, "activate",
G_CALLBACK (add_to_dictionary), spell);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
return topmenu;
}
static void
populate_popup (GtkTextView *textview,
GtkMenu *menu,
XedAutomaticSpellChecker *spell)
{
GtkWidget *mi;
GtkTextIter start, end;
char *word;
/* we need to figure out if they picked a misspelled word. */
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
/* if our highlight algorithm ever messes up,
* this isn't correct, either. */
if (!gtk_text_iter_has_tag (&start, spell->tag_highlight))
{
return; /* word wasn't misspelled. */
}
/* menu separator comes first. */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
/* then, on top of it, the suggestions menu. */
mi = gtk_menu_item_new_with_mnemonic (_("_Spelling Suggestions..."));
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), build_suggestion_menu (spell, word));
g_free(word);
gtk_widget_show_all (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
}
void
xed_automatic_spell_checker_recheck_all (XedAutomaticSpellChecker *spell)
{
GtkTextIter start, end;
g_return_if_fail (spell != NULL);
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end);
check_range (spell, start, end, TRUE);
}
static void
add_word_signal_cb (XedSpellChecker *checker,
const gchar *word,
gint len,
XedAutomaticSpellChecker *spell)
{
gchar *w;
if (len < 0)
{
w = g_strdup (word);
}
else
{
w = g_strndup (word, len);
}
remove_tag_to_word (spell, w);
g_free (w);
}
static void
set_language_cb (XedSpellChecker *checker,
const XedSpellCheckerLanguage *lang,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_recheck_all (spell);
}
static void
clear_session_cb (XedSpellChecker *checker,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_recheck_all (spell);
}
/* When the user right-clicks on a word, they want to check that word.
* Here, we do NOT move the cursor to the location of the clicked-upon word
* since that prevents the use of edit functions on the context menu.
*/
static gboolean
button_press_event (GtkTextView *view,
GdkEventButton *event,
XedAutomaticSpellChecker *spell)
{
if (event->button == 3)
{
gint x, y;
GtkTextIter iter;
GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
/* handle deferred check if it exists */
if (spell->deferred_check)
{
check_deferred_range (spell, TRUE);
}
gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_TEXT, event->x, event->y, &x, &y);
gtk_text_view_get_iter_at_location (view, &iter, x, y);
gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter);
}
return FALSE; /* false: let gtk process this event, too.
we don't want to eat any events. */
}
/* Move the insert mark before popping up the menu, otherwise it
* will contain the wrong set of suggestions.
*/
static gboolean
popup_menu_event (GtkTextView *view,
XedAutomaticSpellChecker *spell)
{
GtkTextIter iter;
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (view);
/* handle deferred check if it exists */
if (spell->deferred_check)
{
check_deferred_range (spell, TRUE);
}
gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter);
return FALSE;
}
static void
tag_table_changed (GtkTextTagTable *table,
XedAutomaticSpellChecker *spell)
{
g_return_if_fail (spell->tag_highlight != NULL);
gtk_text_tag_set_priority (spell->tag_highlight, gtk_text_tag_table_get_size (table) - 1);
}
static void
tag_added_or_removed (GtkTextTagTable *table,
GtkTextTag *tag,
XedAutomaticSpellChecker *spell)
{
tag_table_changed (table, spell);
}
static void
tag_changed (GtkTextTagTable *table,
GtkTextTag *tag,
gboolean size_changed,
XedAutomaticSpellChecker *spell)
{
tag_table_changed (table, spell);
}
static void
highlight_updated (GtkSourceBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
XedAutomaticSpellChecker *spell)
{
check_range (spell, *start, *end, FALSE);
}
static void
spell_tag_destroyed (XedAutomaticSpellChecker *spell,
GObject *where_the_object_was)
{
spell->tag_highlight = NULL;
}
XedAutomaticSpellChecker *
xed_automatic_spell_checker_new (XedDocument *doc,
XedSpellChecker *checker)
{
XedAutomaticSpellChecker *spell;
GtkTextTagTable *tag_table;
GtkTextIter start, end;
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
g_return_val_if_fail (XED_IS_SPELL_CHECKER (checker), NULL);
g_return_val_if_fail ((spell = xed_automatic_spell_checker_get_from_document (doc)) == NULL, spell);
/* attach to the widget */
spell = g_new0 (XedAutomaticSpellChecker, 1);
spell->doc = doc;
spell->spell_checker = g_object_ref (checker);
if (automatic_spell_checker_id == 0)
{
automatic_spell_checker_id = g_quark_from_string ("XedAutomaticSpellCheckerID");
}
if (suggestion_id == 0)
{
suggestion_id = g_quark_from_string ("XedAutoSuggestionID");
}
g_object_set_qdata_full (G_OBJECT (doc), automatic_spell_checker_id,
spell, (GDestroyNotify)xed_automatic_spell_checker_free_internal);
g_signal_connect (doc, "insert-text",
G_CALLBACK (insert_text_before), spell);
g_signal_connect_after (doc, "insert-text",
G_CALLBACK (insert_text_after), spell);
g_signal_connect_after (doc, "delete-range",
G_CALLBACK (delete_range_after), spell);
g_signal_connect (doc, "mark-set",
G_CALLBACK (mark_set), spell);
g_signal_connect (doc, "highlight-updated",
G_CALLBACK (highlight_updated), spell);
g_signal_connect (spell->spell_checker, "add_word_to_session",
G_CALLBACK (add_word_signal_cb), spell);
g_signal_connect (spell->spell_checker, "add_word_to_personal",
G_CALLBACK (add_word_signal_cb), spell);
g_signal_connect (spell->spell_checker, "clear_session",
G_CALLBACK (clear_session_cb), spell);
g_signal_connect (spell->spell_checker, "set_language",
G_CALLBACK (set_language_cb), spell);
spell->tag_highlight = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (doc),
"gtkspell-misspelled",
"underline", PANGO_UNDERLINE_ERROR,
NULL);
g_object_weak_ref (G_OBJECT (spell->tag_highlight), (GWeakNotify)spell_tag_destroyed, spell);
tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc));
gtk_text_tag_set_priority (spell->tag_highlight, gtk_text_tag_table_get_size (tag_table) - 1);
g_signal_connect (tag_table, "tag-added",
G_CALLBACK (tag_added_or_removed), spell);
g_signal_connect (tag_table, "tag-removed",
G_CALLBACK (tag_added_or_removed), spell);
g_signal_connect (tag_table, "tag-changed",
G_CALLBACK (tag_changed), spell);
/* we create the mark here, but we don't use it until text is
* inserted, so we don't really care where iter points. */
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end);
spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-start");
if (spell->mark_insert_start == NULL)
{
spell->mark_insert_start = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-start",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_insert_start, &start);
}
spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-end");
if (spell->mark_insert_end == NULL)
{
spell->mark_insert_end = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-end",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_insert_end, &start);
}
spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-click");
if (spell->mark_click == NULL)
{
spell->mark_click = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-click",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_click, &start);
}
spell->deferred_check = FALSE;
return spell;
}
XedAutomaticSpellChecker *
xed_automatic_spell_checker_get_from_document (const XedDocument *doc)
{
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
if (automatic_spell_checker_id == 0)
{
return NULL;
}
return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id);
}
void
xed_automatic_spell_checker_free (XedAutomaticSpellChecker *spell)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (xed_automatic_spell_checker_get_from_document (spell->doc) == spell);
if (automatic_spell_checker_id == 0)
{
return;
}
g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL);
}
static void
xed_automatic_spell_checker_free_internal (XedAutomaticSpellChecker *spell)
{
GtkTextTagTable *table;
GtkTextIter start, end;
GSList *list;
g_return_if_fail (spell != NULL);
table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc));
if (table != NULL && spell->tag_highlight != NULL)
{
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end);
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, &start, &end);
g_signal_handlers_disconnect_matched (G_OBJECT (table),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
gtk_text_tag_table_remove (table, spell->tag_highlight);
}
g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_object_unref (spell->spell_checker);
list = spell->views;
while (list != NULL)
{
XedView *view = XED_VIEW (list->data);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
list = g_slist_next (list);
}
g_slist_free (spell->views);
g_free (spell);
}
void
xed_automatic_spell_checker_attach_view (XedAutomaticSpellChecker *spell,
XedView *view)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (XED_IS_VIEW (view));
g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == GTK_TEXT_BUFFER (spell->doc));
g_signal_connect (view, "button-press-event",
G_CALLBACK (button_press_event), spell);
g_signal_connect (view, "popup-menu",
G_CALLBACK (popup_menu_event), spell);
g_signal_connect (view, "populate-popup",
G_CALLBACK (populate_popup), spell);
g_signal_connect (view, "destroy",
G_CALLBACK (view_destroy), spell);
spell->views = g_slist_prepend (spell->views, view);
}
void
xed_automatic_spell_checker_detach_view (XedAutomaticSpellChecker *spell,
XedView *view)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (XED_IS_VIEW (view));
g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == GTK_TEXT_BUFFER (spell->doc));
g_return_if_fail (spell->views != NULL);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
spell->views = g_slist_remove (spell->views, view);
}

View File

@ -1,67 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-automatic-spell-checker.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */
/* gtkspell - a spell-checking addon for GTK's TextView widget
* Copyright (c) 2002 Evan Martin.
*/
#ifndef __XED_AUTOMATIC_SPELL_CHECKER_H__
#define __XED_AUTOMATIC_SPELL_CHECKER_H__
#include <xed/xed-document.h>
#include <xed/xed-view.h>
#include "xed-spell-checker.h"
typedef struct _XedAutomaticSpellChecker XedAutomaticSpellChecker;
XedAutomaticSpellChecker *xed_automatic_spell_checker_new (
XedDocument *doc,
XedSpellChecker *checker);
XedAutomaticSpellChecker *xed_automatic_spell_checker_get_from_document (
const XedDocument *doc);
void xed_automatic_spell_checker_free (
XedAutomaticSpellChecker *spell);
void xed_automatic_spell_checker_attach_view (
XedAutomaticSpellChecker *spell,
XedView *view);
void xed_automatic_spell_checker_detach_view (
XedAutomaticSpellChecker *spell,
XedView *view);
void xed_automatic_spell_checker_recheck_all (
XedAutomaticSpellChecker *spell);
#endif /* __XED_AUTOMATIC_SPELL_CHECKER_H__ */

View File

@ -1,726 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-dialog.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <xed/xed-utils.h>
#include "xed-spell-checker-dialog.h"
#include "xed-spell-marshal.h"
struct _XedSpellCheckerDialog
{
GtkWindow parent_instance;
XedSpellChecker *spell_checker;
gchar *misspelled_word;
GtkWidget *misspelled_word_label;
GtkWidget *word_entry;
GtkWidget *check_word_button;
GtkWidget *ignore_button;
GtkWidget *ignore_all_button;
GtkWidget *change_button;
GtkWidget *change_all_button;
GtkWidget *add_word_button;
GtkWidget *close_button;
GtkWidget *suggestions_list;
GtkWidget *language_label;
GtkTreeModel *suggestions_list_model;
};
enum
{
IGNORE,
IGNORE_ALL,
CHANGE,
CHANGE_ALL,
ADD_WORD_TO_PERSONAL,
LAST_SIGNAL
};
enum
{
COLUMN_SUGGESTIONS,
NUM_COLUMNS
};
static void update_suggestions_list_model (XedSpellCheckerDialog *dlg,
GSList *suggestions);
static void word_entry_changed_handler (GtkEditable *editable,
XedSpellCheckerDialog *dlg);
static void close_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection,
XedSpellCheckerDialog *dlg);
static void check_word_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void add_word_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void ignore_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void ignore_all_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void change_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void change_all_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void suggestions_list_row_activated_handler (GtkTreeView *view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellCheckerDialog *dlg);
static guint signals [LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(XedSpellCheckerDialog, xed_spell_checker_dialog, GTK_TYPE_WINDOW)
static void
xed_spell_checker_dialog_dispose (GObject *object)
{
XedSpellCheckerDialog *dlg = XED_SPELL_CHECKER_DIALOG (object);
if (dlg->spell_checker != NULL)
{
g_object_unref (dlg->spell_checker);
dlg->spell_checker = NULL;
}
if (dlg->misspelled_word != NULL)
{
g_free (dlg->misspelled_word);
dlg->misspelled_word = NULL;
}
G_OBJECT_CLASS (xed_spell_checker_dialog_parent_class)->dispose (object);
}
static void
xed_spell_checker_dialog_class_init (XedSpellCheckerDialogClass * klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = xed_spell_checker_dialog_dispose;
signals[IGNORE] =
g_signal_new ("ignore",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, ignore),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals[IGNORE_ALL] =
g_signal_new ("ignore_all",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, ignore_all),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals[CHANGE] =
g_signal_new ("change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, change),
NULL, NULL,
xed_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_STRING);
signals[CHANGE_ALL] =
g_signal_new ("change_all",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, change_all),
NULL, NULL,
xed_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_STRING);
signals[ADD_WORD_TO_PERSONAL] =
g_signal_new ("add_word_to_personal",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, add_word_to_personal),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
}
static void
create_dialog (XedSpellCheckerDialog *dlg,
const gchar *data_dir)
{
GtkWidget *error_widget;
GtkWidget *content;
GtkTreeViewColumn *column;
GtkCellRenderer *cell;
GtkTreeSelection *selection;
gchar *root_objects[] = {
"content",
"check_word_image",
"add_word_image",
"ignore_image",
"change_image",
"ignore_all_image",
"change_all_image",
NULL
};
gboolean ret;
gchar *ui_file;
g_return_if_fail (dlg != NULL);
dlg->spell_checker = NULL;
dlg->misspelled_word = NULL;
ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL);
ret = xed_utils_get_ui_objects (ui_file,
root_objects,
&error_widget,
"content", &content,
"misspelled_word_label", &dlg->misspelled_word_label,
"word_entry", &dlg->word_entry,
"check_word_button", &dlg->check_word_button,
"ignore_button", &dlg->ignore_button,
"ignore_all_button", &dlg->ignore_all_button,
"change_button", &dlg->change_button,
"change_all_button", &dlg->change_all_button,
"add_word_button", &dlg->add_word_button,
"close_button", &dlg->close_button,
"suggestions_list", &dlg->suggestions_list,
"language_label", &dlg->language_label,
NULL);
g_free (ui_file);
if (!ret)
{
gtk_widget_show (error_widget);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
error_widget, TRUE, TRUE, 0);
return;
}
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), "");
gtk_widget_set_sensitive (dlg->word_entry, FALSE);
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
gtk_label_set_label (GTK_LABEL (dlg->language_label), "");
gtk_container_add (GTK_CONTAINER (dlg), content);
g_object_unref (content);
gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling"));
/* Suggestion list */
dlg->suggestions_list_model = GTK_TREE_MODEL (
gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING));
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list),
dlg->suggestions_list_model);
/* Add the suggestions column */
cell = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell,
"text", COLUMN_SUGGESTIONS, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list),
COLUMN_SUGGESTIONS);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
/* Set default button */
gtk_widget_set_can_default (dlg->change_button, TRUE);
gtk_widget_grab_default (dlg->change_button);
gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE);
/* Connect signals */
g_signal_connect (dlg->word_entry, "changed",
G_CALLBACK (word_entry_changed_handler), dlg);
g_signal_connect (dlg->close_button, "clicked",
G_CALLBACK (close_button_clicked_handler), dlg);
g_signal_connect (selection, "changed",
G_CALLBACK (suggestions_list_selection_changed_handler),
dlg);
g_signal_connect (dlg->check_word_button, "clicked",
G_CALLBACK (check_word_button_clicked_handler), dlg);
g_signal_connect (dlg->add_word_button, "clicked",
G_CALLBACK (add_word_button_clicked_handler), dlg);
g_signal_connect (dlg->ignore_button, "clicked",
G_CALLBACK (ignore_button_clicked_handler), dlg);
g_signal_connect (dlg->ignore_all_button, "clicked",
G_CALLBACK (ignore_all_button_clicked_handler), dlg);
g_signal_connect (dlg->change_button, "clicked",
G_CALLBACK (change_button_clicked_handler), dlg);
g_signal_connect (dlg->change_all_button, "clicked",
G_CALLBACK (change_all_button_clicked_handler), dlg);
g_signal_connect (dlg->suggestions_list, "row-activated",
G_CALLBACK (suggestions_list_row_activated_handler), dlg);
}
static void
xed_spell_checker_dialog_init (XedSpellCheckerDialog *dlg)
{
}
GtkWidget *
xed_spell_checker_dialog_new (const gchar *data_dir)
{
XedSpellCheckerDialog *dlg;
dlg = XED_SPELL_CHECKER_DIALOG (
g_object_new (XED_TYPE_SPELL_CHECKER_DIALOG, NULL));
g_return_val_if_fail (dlg != NULL, NULL);
create_dialog (dlg, data_dir);
return GTK_WIDGET (dlg);
}
GtkWidget *
xed_spell_checker_dialog_new_from_spell_checker (XedSpellChecker *spell,
const gchar *data_dir)
{
XedSpellCheckerDialog *dlg;
g_return_val_if_fail (spell != NULL, NULL);
dlg = XED_SPELL_CHECKER_DIALOG (
g_object_new (XED_TYPE_SPELL_CHECKER_DIALOG, NULL));
g_return_val_if_fail (dlg != NULL, NULL);
create_dialog (dlg, data_dir);
xed_spell_checker_dialog_set_spell_checker (dlg, spell);
return GTK_WIDGET (dlg);
}
void
xed_spell_checker_dialog_set_spell_checker (XedSpellCheckerDialog *dlg, XedSpellChecker *spell)
{
const XedSpellCheckerLanguage* language;
const gchar *lang;
gchar *tmp;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (spell != NULL);
if (dlg->spell_checker != NULL)
g_object_unref (dlg->spell_checker);
dlg->spell_checker = spell;
g_object_ref (dlg->spell_checker);
language = xed_spell_checker_get_language (dlg->spell_checker);
lang = xed_spell_checker_language_to_string (language);
tmp = g_strdup_printf("<b>%s</b>", lang);
gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp);
g_free (tmp);
if (dlg->misspelled_word != NULL)
xed_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1);
else
gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
/* TODO: reset all widgets */
}
void
xed_spell_checker_dialog_set_misspelled_word (XedSpellCheckerDialog *dlg,
const gchar *word,
gint len)
{
gchar *tmp;
GSList *sug;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (word != NULL);
g_return_if_fail (dlg->spell_checker != NULL);
g_return_if_fail (!xed_spell_checker_check_word (dlg->spell_checker, word, -1));
/* build_suggestions_list */
if (dlg->misspelled_word != NULL)
g_free (dlg->misspelled_word);
dlg->misspelled_word = g_strdup (word);
tmp = g_strdup_printf("<b>%s</b>", word);
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp);
g_free (tmp);
sug = xed_spell_checker_get_suggestions (dlg->spell_checker,
dlg->misspelled_word,
-1);
update_suggestions_list_model (dlg, sug);
/* free the suggestion list */
g_slist_foreach (sug, (GFunc)g_free, NULL);
g_slist_free (sug);
gtk_widget_set_sensitive (dlg->ignore_button, TRUE);
gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE);
gtk_widget_set_sensitive (dlg->add_word_button, TRUE);
}
static void
update_suggestions_list_model (XedSpellCheckerDialog *dlg, GSList *suggestions)
{
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *sel;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model));
store = GTK_LIST_STORE (dlg->suggestions_list_model);
gtk_list_store_clear (store);
gtk_widget_set_sensitive (dlg->word_entry, TRUE);
if (suggestions == NULL)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
/* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions
* for the current misspelled word */
COLUMN_SUGGESTIONS, _("(no suggested words)"),
-1);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
return;
}
gtk_widget_set_sensitive (dlg->suggestions_list, TRUE);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data);
while (suggestions != NULL)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_SUGGESTIONS, (gchar*)suggestions->data,
-1);
suggestions = g_slist_next (suggestions);
}
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter);
gtk_tree_selection_select_iter (sel, &iter);
}
static void
word_entry_changed_handler (GtkEditable *editable, XedSpellCheckerDialog *dlg)
{
const gchar *text;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
if (g_utf8_strlen (text, -1) > 0)
{
gtk_widget_set_sensitive (dlg->check_word_button, TRUE);
gtk_widget_set_sensitive (dlg->change_button, TRUE);
gtk_widget_set_sensitive (dlg->change_all_button, TRUE);
}
else
{
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
}
}
static void
close_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
gtk_widget_destroy (GTK_WIDGET (dlg));
}
static void
suggestions_list_selection_changed_handler (GtkTreeSelection *selection,
XedSpellCheckerDialog *dlg)
{
GtkTreeIter iter;
GValue value = {0, };
const gchar *text;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
gtk_tree_model_get_value (dlg->suggestions_list_model, &iter,
COLUMN_SUGGESTIONS,
&value);
text = g_value_get_string (&value);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text);
g_value_unset (&value);
}
static void
check_word_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *word;
gssize len;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
len = strlen (word);
g_return_if_fail (len > 0);
if (xed_spell_checker_check_word (dlg->spell_checker, word, len))
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE (dlg->suggestions_list_model);
gtk_list_store_clear (store);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
/* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */
COLUMN_SUGGESTIONS, _("(correct spelling)"),
-1);
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
}
else
{
GSList *sug;
sug = xed_spell_checker_get_suggestions (dlg->spell_checker,
word,
len);
update_suggestions_list_model (dlg, sug);
/* free the suggestion list */
g_slist_foreach (sug, (GFunc)g_free, NULL);
g_slist_free (sug);
}
}
static void
add_word_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
xed_spell_checker_add_word_to_personal (dlg->spell_checker,
dlg->misspelled_word,
-1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word);
g_free (word);
}
static void
ignore_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word);
g_free (word);
}
static void
ignore_all_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
xed_spell_checker_add_word_to_session (dlg->spell_checker,
dlg->misspelled_word,
-1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word);
g_free (word);
}
static void
change_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *entry_text;
gchar *change;
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
g_return_if_fail (entry_text != NULL);
g_return_if_fail (*entry_text != '\0');
change = g_strdup (entry_text);
xed_spell_checker_set_correction (dlg->spell_checker,
dlg->misspelled_word, -1,
change, -1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change);
g_free (word);
g_free (change);
}
/* double click on one of the suggestions is like clicking on "change" */
static void
suggestions_list_row_activated_handler (GtkTreeView *view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellCheckerDialog *dlg)
{
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg);
}
static void
change_all_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *entry_text;
gchar *change;
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
g_return_if_fail (entry_text != NULL);
g_return_if_fail (*entry_text != '\0');
change = g_strdup (entry_text);
xed_spell_checker_set_correction (dlg->spell_checker,
dlg->misspelled_word, -1,
change, -1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change);
g_free (word);
g_free (change);
}
void
xed_spell_checker_dialog_set_completed (XedSpellCheckerDialog *dlg)
{
gchar *tmp;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
tmp = g_strdup_printf("<b>%s</b>", _("Completed spell checking"));
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label),
tmp);
g_free (tmp);
gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
gtk_widget_set_sensitive (dlg->word_entry, FALSE);
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
}

View File

@ -1,92 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-dialog.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_DIALOG_H__
#define __XED_SPELL_CHECKER_DIALOG_H__
#include <gtk/gtk.h>
#include "xed-spell-checker.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_CHECKER_DIALOG (xed_spell_checker_dialog_get_type ())
#define XED_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
#define XED_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
#define XED_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_SPELL_CHECKER_DIALOG))
#define XED_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_CHECKER_DIALOG))
#define XED_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
typedef struct _XedSpellCheckerDialog XedSpellCheckerDialog;
typedef struct _XedSpellCheckerDialogClass XedSpellCheckerDialogClass;
struct _XedSpellCheckerDialogClass
{
GtkWindowClass parent_class;
/* Signals */
void (*ignore) (XedSpellCheckerDialog *dlg,
const gchar *word);
void (*ignore_all) (XedSpellCheckerDialog *dlg,
const gchar *word);
void (*change) (XedSpellCheckerDialog *dlg,
const gchar *word,
const gchar *change_to);
void (*change_all) (XedSpellCheckerDialog *dlg,
const gchar *word,
const gchar *change_to);
void (*add_word_to_personal) (XedSpellCheckerDialog *dlg,
const gchar *word);
};
GType xed_spell_checker_dialog_get_type (void) G_GNUC_CONST;
/* Constructors */
GtkWidget *xed_spell_checker_dialog_new (const gchar *data_dir);
GtkWidget *xed_spell_checker_dialog_new_from_spell_checker
(XedSpellChecker *spell,
const gchar *data_dir);
void xed_spell_checker_dialog_set_spell_checker
(XedSpellCheckerDialog *dlg,
XedSpellChecker *spell);
void xed_spell_checker_dialog_set_misspelled_word
(XedSpellCheckerDialog *dlg,
const gchar* word,
gint len);
void xed_spell_checker_dialog_set_completed
(XedSpellCheckerDialog *dlg);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_DIALOG_H__ */

View File

@ -1,439 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-language.c
* This file is part of xed
*
* Copyright (C) 2006 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* Part of the code taked from Epiphany.
*
* Copyright (C) 2003, 2004 Christian Persch
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <enchant.h>
#include <glib/gi18n.h>
#include <libxml/xmlreader.h>
#include "xed-spell-checker-language.h"
#include <xed/xed-debug.h>
#define ISO_639_DOMAIN "iso_639"
#define ISO_3166_DOMAIN "iso_3166"
#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
struct _XedSpellCheckerLanguage
{
gchar *abrev;
gchar *name;
};
static gboolean available_languages_initialized = FALSE;
static GSList *available_languages = NULL;
static GHashTable *iso_639_table = NULL;
static GHashTable *iso_3166_table = NULL;
static void
bind_iso_domains (void)
{
static gboolean bound = FALSE;
if (bound == FALSE)
{
bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
bound = TRUE;
}
}
static void
read_iso_639_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
/* Get iso-639-2 code */
if (code == NULL || code[0] == '\0')
{
xmlFree (code);
/* FIXME: use the 2T or 2B code? */
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code");
}
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
g_hash_table_insert (table, code, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
static void
read_iso_3166_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
char *lcode;
lcode = g_ascii_strdown ((char *) code, -1);
xmlFree (code);
/* g_print ("%s -> %s\n", lcode, name); */
g_hash_table_insert (table, lcode, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
typedef enum
{
STATE_START,
STATE_STOP,
STATE_ENTRIES,
} ParserState;
static void
load_iso_entries (int iso,
GFunc read_entry_func,
gpointer user_data)
{
xmlTextReaderPtr reader;
ParserState state = STATE_START;
xmlChar iso_entries[32], iso_entry[32];
char *filename;
int ret = -1;
xed_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso);
filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso);
reader = xmlNewTextReaderFilename (filename);
if (reader == NULL) goto out;
xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso);
xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso);
ret = xmlTextReaderRead (reader);
while (ret == 1)
{
const xmlChar *tag;
xmlReaderTypes type;
tag = xmlTextReaderConstName (reader);
type = xmlTextReaderNodeType (reader);
if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entry))
{
read_entry_func (reader, user_data);
}
else if (state == STATE_START &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_ENTRIES;
}
else if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_END_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_STOP;
}
else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE ||
type == XML_READER_TYPE_WHITESPACE ||
type == XML_READER_TYPE_TEXT ||
type == XML_READER_TYPE_COMMENT)
{
/* eat it */
}
else
{
/* ignore it */
}
ret = xmlTextReaderRead (reader);
}
xmlFreeTextReader (reader);
out:
if (ret < 0 || state != STATE_STOP)
{
g_warning ("Failed to load ISO-%d codes from %s!\n",
iso, filename);
}
g_free (filename);
}
static GHashTable *
create_iso_639_table (void)
{
GHashTable *table;
bind_iso_domains ();
table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) xmlFree,
(GDestroyNotify) xmlFree);
load_iso_entries (639, (GFunc) read_iso_639_entry, table);
return table;
}
static GHashTable *
create_iso_3166_table (void)
{
GHashTable *table;
bind_iso_domains ();
table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) xmlFree);
load_iso_entries (3166, (GFunc) read_iso_3166_entry, table);
return table;
}
static char *
create_name_for_language (const char *code)
{
char **str;
char *name = NULL;
const char *langname, *localename;
int len;
g_return_val_if_fail (iso_639_table != NULL, NULL);
g_return_val_if_fail (iso_3166_table != NULL, NULL);
str = g_strsplit (code, "_", -1);
len = g_strv_length (str);
g_return_val_if_fail (len != 0, NULL);
langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]);
if (len == 1 && langname != NULL)
{
name = g_strdup (dgettext (ISO_639_DOMAIN, langname));
}
else if (len == 2 && langname != NULL)
{
gchar *locale_code = g_ascii_strdown (str[1], -1);
localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code);
g_free (locale_code);
if (localename != NULL)
{
/* Translators: the first %s is the language name, and
* the second %s is the locale name. Example:
* "French (France)"
*/
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname),
dgettext (ISO_3166_DOMAIN, localename));
}
else
{
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname), str[1]);
}
}
else
{
/* Translators: this refers to an unknown language code
* (one which isn't in our built-in list).
*/
name = g_strdup_printf (C_("language", "Unknown (%s)"), code);
}
g_strfreev (str);
return name;
}
static void
enumerate_dicts (const char * const lang_tag,
const char * const provider_name,
const char * const provider_desc,
const char * const provider_file,
void * user_data)
{
gchar *lang_name;
GTree *dicts = (GTree *)user_data;
lang_name = create_name_for_language (lang_tag);
g_return_if_fail (lang_name != NULL);
/* g_print ("%s - %s\n", lang_tag, lang_name); */
g_tree_replace (dicts, g_strdup (lang_tag), lang_name);
}
static gint
key_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
{
return strcmp (a, b);
}
static gint
lang_cmp (const XedSpellCheckerLanguage *a,
const XedSpellCheckerLanguage *b)
{
return g_utf8_collate (a->name, b->name);
}
static gboolean
build_langs_list (const gchar *key,
const gchar *value,
gpointer data)
{
XedSpellCheckerLanguage *lang = g_new (XedSpellCheckerLanguage, 1);
lang->abrev = g_strdup (key);
lang->name = g_strdup (value);
available_languages = g_slist_insert_sorted (available_languages,
lang,
(GCompareFunc)lang_cmp);
return FALSE;
}
const GSList *
xed_spell_checker_get_available_languages (void)
{
EnchantBroker *broker;
GTree *dicts;
if (available_languages_initialized)
return available_languages;
g_return_val_if_fail (available_languages == NULL, NULL);
available_languages_initialized = TRUE;
broker = enchant_broker_init ();
g_return_val_if_fail (broker != NULL, NULL);
/* Use a GTree to efficiently remove duplicates while building the list */
dicts = g_tree_new_full (key_cmp,
NULL,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
iso_639_table = create_iso_639_table ();
iso_3166_table = create_iso_3166_table ();
enchant_broker_list_dicts (broker, enumerate_dicts, dicts);
enchant_broker_free (broker);
g_hash_table_destroy (iso_639_table);
g_hash_table_destroy (iso_3166_table);
iso_639_table = NULL;
iso_3166_table = NULL;
g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL);
g_tree_destroy (dicts);
return available_languages;
}
const gchar *
xed_spell_checker_language_to_string (const XedSpellCheckerLanguage *lang)
{
if (lang == NULL)
/* Translators: this refers the Default language used by the
* spell checker
*/
return C_("language", "Default");
return lang->name;
}
const gchar *
xed_spell_checker_language_to_key (const XedSpellCheckerLanguage *lang)
{
g_return_val_if_fail (lang != NULL, NULL);
return lang->abrev;
}
const XedSpellCheckerLanguage *
xed_spell_checker_language_from_key (const gchar *key)
{
const GSList *langs;
g_return_val_if_fail (key != NULL, NULL);
langs = xed_spell_checker_get_available_languages ();
while (langs != NULL)
{
const XedSpellCheckerLanguage *l = (const XedSpellCheckerLanguage *)langs->data;
if (g_ascii_strcasecmp (key, l->abrev) == 0)
return l;
langs = g_slist_next (langs);
}
return NULL;
}

View File

@ -1,51 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-language.h
* This file is part of xed
*
* Copyright (C) 2006 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_LANGUAGE_H__
#define __XED_SPELL_CHECKER_LANGUAGE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef struct _XedSpellCheckerLanguage XedSpellCheckerLanguage;
const gchar *xed_spell_checker_language_to_string (const XedSpellCheckerLanguage *lang);
const gchar *xed_spell_checker_language_to_key (const XedSpellCheckerLanguage *lang);
const XedSpellCheckerLanguage *xed_spell_checker_language_from_key (const gchar *key);
/* GSList contains "XedSpellCheckerLanguage*" items */
const GSList *xed_spell_checker_get_available_languages
(void);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_LANGUAGE_H__ */

View File

@ -1,520 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker.c
* This file is part of xed
*
* Copyright (C) 2002-2006 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002-2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <enchant.h>
#include <glib/gi18n.h>
#include <glib.h>
#include "xed-spell-checker.h"
#include "xed-spell-utils.h"
#include "xed-spell-marshal.h"
struct _XedSpellChecker
{
GObject parent_instance;
EnchantDict *dict;
EnchantBroker *broker;
const XedSpellCheckerLanguage *active_lang;
};
/* GObject properties */
enum {
PROP_0 = 0,
PROP_LANGUAGE,
LAST_PROP
};
/* Signals */
enum {
ADD_WORD_TO_PERSONAL = 0,
ADD_WORD_TO_SESSION,
SET_LANGUAGE,
CLEAR_SESSION,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(XedSpellChecker, xed_spell_checker, G_TYPE_OBJECT)
static void
xed_spell_checker_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
/*
XedSpellChecker *spell = XED_SPELL_CHECKER (object);
*/
switch (prop_id)
{
case PROP_LANGUAGE:
/* TODO */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
xed_spell_checker_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
/*
XedSpellChecker *spell = XED_SPELL_CHECKER (object);
*/
switch (prop_id)
{
case PROP_LANGUAGE:
/* TODO */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
xed_spell_checker_finalize (GObject *object)
{
XedSpellChecker *spell_checker;
g_return_if_fail (XED_IS_SPELL_CHECKER (object));
spell_checker = XED_SPELL_CHECKER (object);
if (spell_checker->dict != NULL)
enchant_broker_free_dict (spell_checker->broker, spell_checker->dict);
if (spell_checker->broker != NULL)
enchant_broker_free (spell_checker->broker);
G_OBJECT_CLASS (xed_spell_checker_parent_class)->finalize (object);
}
static void
xed_spell_checker_class_init (XedSpellCheckerClass * klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = xed_spell_checker_set_property;
object_class->get_property = xed_spell_checker_get_property;
object_class->finalize = xed_spell_checker_finalize;
g_object_class_install_property (object_class,
PROP_LANGUAGE,
g_param_spec_pointer ("language",
"Language",
"The language used by the spell checker",
G_PARAM_READWRITE));
signals[ADD_WORD_TO_PERSONAL] =
g_signal_new ("add_word_to_personal",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, add_word_to_personal),
NULL, NULL,
xed_marshal_VOID__STRING_INT,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_INT);
signals[ADD_WORD_TO_SESSION] =
g_signal_new ("add_word_to_session",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, add_word_to_session),
NULL, NULL,
xed_marshal_VOID__STRING_INT,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_INT);
signals[SET_LANGUAGE] =
g_signal_new ("set_language",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, set_language),
NULL, NULL,
xed_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
signals[CLEAR_SESSION] =
g_signal_new ("clear_session",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, clear_session),
NULL, NULL,
xed_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
xed_spell_checker_init (XedSpellChecker *spell_checker)
{
spell_checker->broker = enchant_broker_init ();
spell_checker->dict = NULL;
spell_checker->active_lang = NULL;
}
XedSpellChecker *
xed_spell_checker_new (void)
{
XedSpellChecker *spell;
spell = XED_SPELL_CHECKER (
g_object_new (XED_TYPE_SPELL_CHECKER, NULL));
g_return_val_if_fail (spell != NULL, NULL);
return spell;
}
static gboolean
lazy_init (XedSpellChecker *spell,
const XedSpellCheckerLanguage *language)
{
if (spell->dict != NULL)
return TRUE;
g_return_val_if_fail (spell->broker != NULL, FALSE);
spell->active_lang = NULL;
if (language != NULL)
{
spell->active_lang = language;
}
else
{
/* First try to get a default language */
const XedSpellCheckerLanguage *l;
gint i = 0;
const gchar * const *lang_tags = g_get_language_names ();
while (lang_tags [i])
{
l = xed_spell_checker_language_from_key (lang_tags [i]);
if (l != NULL)
{
spell->active_lang = l;
break;
}
i++;
}
}
/* Second try to get a default language */
if (spell->active_lang == NULL)
spell->active_lang = xed_spell_checker_language_from_key ("en_US");
/* Last try to get a default language */
if (spell->active_lang == NULL)
{
const GSList *langs;
langs = xed_spell_checker_get_available_languages ();
if (langs != NULL)
spell->active_lang = (const XedSpellCheckerLanguage *)langs->data;
}
if (spell->active_lang != NULL)
{
const gchar *key;
key = xed_spell_checker_language_to_key (spell->active_lang);
spell->dict = enchant_broker_request_dict (spell->broker,
key);
}
if (spell->dict == NULL)
{
spell->active_lang = NULL;
if (language != NULL)
g_warning ("Spell checker plugin: cannot select a default language.");
return FALSE;
}
return TRUE;
}
gboolean
xed_spell_checker_set_language (XedSpellChecker *spell,
const XedSpellCheckerLanguage *language)
{
gboolean ret;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
if (spell->dict != NULL)
{
enchant_broker_free_dict (spell->broker, spell->dict);
spell->dict = NULL;
}
ret = lazy_init (spell, language);
if (ret)
g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language);
else
g_warning ("Spell checker plugin: cannot use language %s.",
xed_spell_checker_language_to_string (language));
return ret;
}
const XedSpellCheckerLanguage *
xed_spell_checker_get_language (XedSpellChecker *spell)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), NULL);
if (!lazy_init (spell, spell->active_lang))
return NULL;
return spell->active_lang;
}
gboolean
xed_spell_checker_check_word (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
gint enchant_result;
gboolean res = FALSE;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
return FALSE;
if (len < 0)
len = strlen (word);
if (strcmp (word, "xed") == 0)
return TRUE;
if (xed_spell_utils_is_digit (word, len))
return TRUE;
g_return_val_if_fail (spell->dict != NULL, FALSE);
enchant_result = enchant_dict_check (spell->dict, word, len);
switch (enchant_result)
{
case -1:
/* error */
res = FALSE;
g_warning ("Spell checker plugin: error checking word '%s' (%s).",
word, enchant_dict_get_error (spell->dict));
break;
case 1:
/* it is not in the directory */
res = FALSE;
break;
case 0:
/* is is in the directory */
res = TRUE;
break;
default:
g_return_val_if_reached (FALSE);
}
return res;
}
/* return NULL on error or if no suggestions are found */
GSList *
xed_spell_checker_get_suggestions (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
gchar **suggestions;
size_t n_suggestions = 0;
GSList *suggestions_list = NULL;
gint i;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), NULL);
g_return_val_if_fail (word != NULL, NULL);
if (!lazy_init (spell, spell->active_lang))
return NULL;
g_return_val_if_fail (spell->dict != NULL, NULL);
if (len < 0)
len = strlen (word);
suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions);
if (n_suggestions == 0)
return NULL;
g_return_val_if_fail (suggestions != NULL, NULL);
for (i = 0; i < (gint)n_suggestions; i++)
{
suggestions_list = g_slist_prepend (suggestions_list,
suggestions[i]);
}
/* The single suggestions will be freed by the caller */
g_free (suggestions);
suggestions_list = g_slist_reverse (suggestions_list);
return suggestions_list;
}
gboolean
xed_spell_checker_add_word_to_personal (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
return FALSE;
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (len < 0)
len = strlen (word);
enchant_dict_add_to_pwl (spell->dict, word, len);
g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len);
return TRUE;
}
gboolean
xed_spell_checker_add_word_to_session (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
return FALSE;
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (len < 0)
len = strlen (word);
enchant_dict_add_to_session (spell->dict, word, len);
g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len);
return TRUE;
}
gboolean
xed_spell_checker_clear_session (XedSpellChecker *spell)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
/* free and re-request dictionary */
if (spell->dict != NULL)
{
enchant_broker_free_dict (spell->broker, spell->dict);
spell->dict = NULL;
}
if (!lazy_init (spell, spell->active_lang))
return FALSE;
g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0);
return TRUE;
}
/*
* Informs dictionary, that word 'word' will be replaced/corrected by word
* 'replacement'
*/
gboolean
xed_spell_checker_set_correction (XedSpellChecker *spell,
const gchar *word,
gssize w_len,
const gchar *replacement,
gssize r_len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
g_return_val_if_fail (replacement != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
return FALSE;
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (w_len < 0)
w_len = strlen (word);
if (r_len < 0)
r_len = strlen (replacement);
enchant_dict_store_replacement (spell->dict,
word,
w_len,
replacement,
r_len);
return TRUE;
}

View File

@ -1,109 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker.h
* This file is part of xed
*
* Copyright (C) 2002-2006 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_H__
#define __XED_SPELL_CHECKER_H__
#include <glib.h>
#include <glib-object.h>
#include "xed-spell-checker-language.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_CHECKER (xed_spell_checker_get_type ())
#define XED_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
#define XED_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
#define XED_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_SPELL_CHECKER))
#define XED_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_CHECKER))
#define XED_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
typedef struct _XedSpellChecker XedSpellChecker;
typedef struct _XedSpellCheckerClass XedSpellCheckerClass;
struct _XedSpellCheckerClass
{
GObjectClass parent_class;
/* Signals */
void (*add_word_to_personal) (XedSpellChecker *spell,
const gchar *word,
gint len);
void (*add_word_to_session) (XedSpellChecker *spell,
const gchar *word,
gint len);
void (*set_language) (XedSpellChecker *spell,
const XedSpellCheckerLanguage *lang);
void (*clear_session) (XedSpellChecker *spell);
};
GType xed_spell_checker_get_type (void) G_GNUC_CONST;
/* Constructors */
XedSpellChecker *xed_spell_checker_new (void);
gboolean xed_spell_checker_set_language (XedSpellChecker *spell,
const XedSpellCheckerLanguage *lang);
const XedSpellCheckerLanguage
*xed_spell_checker_get_language (XedSpellChecker *spell);
gboolean xed_spell_checker_check_word (XedSpellChecker *spell,
const gchar *word,
gssize len);
GSList *xed_spell_checker_get_suggestions (XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_add_word_to_personal
(XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_add_word_to_session
(XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_clear_session (XedSpellChecker *spell);
gboolean xed_spell_checker_set_correction (XedSpellChecker *spell,
const gchar *word,
gssize w_len,
const gchar *replacement,
gssize r_len);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_H__ */

View File

@ -1,284 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-language-dialog.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <xed/xed-utils.h>
#include <xed/xed-app.h>
#include "xed-spell-language-dialog.h"
#include "xed-spell-checker-language.h"
enum
{
COLUMN_LANGUAGE_NAME = 0,
COLUMN_LANGUAGE_POINTER,
ENCODING_NUM_COLS
};
struct _XedSpellLanguageDialog
{
GtkDialog dialog;
GtkWidget *languages_treeview;
GtkTreeModel *model;
};
G_DEFINE_TYPE (XedSpellLanguageDialog, xed_spell_language_dialog, GTK_TYPE_DIALOG)
static void
xed_spell_language_dialog_class_init (XedSpellLanguageDialogClass *klass)
{
/* GObjectClass *object_class = G_OBJECT_CLASS (klass); */
}
static void
dialog_response_handler (GtkDialog *dlg,
gint res_id)
{
if (res_id == GTK_RESPONSE_HELP)
{
xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dlg), NULL, "xed-spell-checker-plugin");
g_signal_stop_emission_by_name (dlg, "response");
}
}
static void
scroll_to_selected (GtkTreeView *tree_view)
{
GtkTreeModel *model;
GtkTreeSelection *selection;
GtkTreeIter iter;
model = gtk_tree_view_get_model (tree_view);
g_return_if_fail (model != NULL);
/* Scroll to selected */
selection = gtk_tree_view_get_selection (tree_view);
g_return_if_fail (selection != NULL);
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
{
GtkTreePath* path;
path = gtk_tree_model_get_path (model, &iter);
g_return_if_fail (path != NULL);
gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 1.0, 0.0);
gtk_tree_path_free (path);
}
}
static void
language_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellLanguageDialog *dialog)
{
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}
static void
create_dialog (XedSpellLanguageDialog *dlg,
const gchar *data_dir)
{
GtkWidget *error_widget;
GtkWidget *content;
gboolean ret;
GtkCellRenderer *cell;
GtkTreeViewColumn *column;
gchar *ui_file;
gchar *root_objects[] = {
"content",
NULL
};
gtk_dialog_add_buttons (GTK_DIALOG (dlg),
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
_("_Help"), GTK_RESPONSE_HELP,
NULL);
gtk_window_set_title (GTK_WINDOW (dlg), _("Set language"));
gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
/* HIG defaults */
gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), 2);
gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), 5);
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), 6);
g_signal_connect (dlg, "response",
G_CALLBACK (dialog_response_handler), NULL);
ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL);
ret = xed_utils_get_ui_objects (ui_file,
root_objects,
&error_widget,
"content", &content,
"languages_treeview", &dlg->languages_treeview,
NULL);
g_free (ui_file);
if (!ret)
{
gtk_widget_show (error_widget);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), error_widget, TRUE, TRUE, 0);
return;
}
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), content, TRUE, TRUE, 0);
g_object_unref (content);
gtk_container_set_border_width (GTK_CONTAINER (content), 5);
dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER));
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), dlg->model);
g_object_unref (dlg->model);
/* Add the encoding column */
cell = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Languages"),
cell,
"text",
COLUMN_LANGUAGE_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), column);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), COLUMN_LANGUAGE_NAME);
g_signal_connect (dlg->languages_treeview, "realize",
G_CALLBACK (scroll_to_selected), dlg);
g_signal_connect (dlg->languages_treeview, "row-activated",
G_CALLBACK (language_row_activated), dlg);
}
static void
xed_spell_language_dialog_init (XedSpellLanguageDialog *dlg)
{
}
static void
populate_language_list (XedSpellLanguageDialog *dlg,
const XedSpellCheckerLanguage *cur_lang)
{
GtkListStore *store;
GtkTreeIter iter;
const GSList* langs;
/* create list store */
store = GTK_LIST_STORE (dlg->model);
langs = xed_spell_checker_get_available_languages ();
while (langs)
{
const gchar *name;
name = xed_spell_checker_language_to_string ((const XedSpellCheckerLanguage*)langs->data);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_LANGUAGE_NAME, name,
COLUMN_LANGUAGE_POINTER, langs->data,
-1);
if (langs->data == cur_lang)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview));
g_return_if_fail (selection != NULL);
gtk_tree_selection_select_iter (selection, &iter);
}
langs = g_slist_next (langs);
}
}
GtkWidget *
xed_spell_language_dialog_new (GtkWindow *parent,
const XedSpellCheckerLanguage *cur_lang,
const gchar *data_dir)
{
XedSpellLanguageDialog *dlg;
g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
dlg = g_object_new (XED_TYPE_SPELL_LANGUAGE_DIALOG, NULL);
create_dialog (dlg, data_dir);
populate_language_list (dlg, cur_lang);
gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
gtk_widget_grab_focus (dlg->languages_treeview);
return GTK_WIDGET (dlg);
}
const XedSpellCheckerLanguage *
xed_spell_language_get_selected_language (XedSpellLanguageDialog *dlg)
{
GValue value = {0, };
const XedSpellCheckerLanguage* lang;
GtkTreeIter iter;
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview));
g_return_val_if_fail (selection != NULL, NULL);
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
{
return NULL;
}
gtk_tree_model_get_value (dlg->model, &iter, COLUMN_LANGUAGE_POINTER, &value);
lang = (const XedSpellCheckerLanguage* ) g_value_get_pointer (&value);
return lang;
}

View File

@ -1,65 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-language-dialog.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_LANGUAGE_DIALOG_H__
#define __XED_SPELL_LANGUAGE_DIALOG_H__
#include <gtk/gtk.h>
#include "xed-spell-checker-language.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_LANGUAGE_DIALOG (xed_spell_language_dialog_get_type())
#define XED_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialog))
#define XED_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialogClass))
#define XED_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG))
#define XED_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_LANGUAGE_DIALOG))
#define XED_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialogClass))
typedef struct _XedSpellLanguageDialog XedSpellLanguageDialog;
typedef struct _XedSpellLanguageDialogClass XedSpellLanguageDialogClass;
struct _XedSpellLanguageDialogClass
{
GtkDialogClass parent_class;
};
GType xed_spell_language_dialog_get_type (void) G_GNUC_CONST;
GtkWidget *xed_spell_language_dialog_new (GtkWindow *parent,
const XedSpellCheckerLanguage *cur_lang,
const gchar *data_dir);
const XedSpellCheckerLanguage *xed_spell_language_get_selected_language (XedSpellLanguageDialog *dlg);
G_END_DECLS
#endif /* __XED_SPELL_LANGUAGE_DIALOG_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
/*
* xed-spell-utils.c
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "xed-spell-utils.h"
#include <gtksourceview/gtksource.h>
gboolean
xed_spell_utils_is_digit (const char *text, gssize length)
{
gunichar c;
const gchar *p;
const gchar *end;
g_return_val_if_fail (text != NULL, FALSE);
if (length < 0)
length = strlen (text);
p = text;
end = text + length;
while (p != end) {
const gchar *next;
next = g_utf8_next_char (p);
c = g_utf8_get_char (p);
if (!g_unichar_isdigit (c) && c != '.' && c != ',')
return FALSE;
p = next;
}
return TRUE;
}
gboolean
xed_spell_utils_skip_no_spell_check (GtkTextIter *start,
GtkTextIter *end)
{
GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start));
while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check"))
{
GtkTextIter last = *start;
if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check"))
{
return FALSE;
}
if (gtk_text_iter_compare (start, &last) <= 0)
{
return FALSE;
}
gtk_text_iter_forward_word_end (start);
gtk_text_iter_backward_word_start (start);
if (gtk_text_iter_compare (start, &last) <= 0)
{
return FALSE;
}
if (gtk_text_iter_compare (start, end) >= 0)
{
return FALSE;
}
}
return TRUE;
}

View File

@ -1,37 +0,0 @@
/*
* xed-spell-utils.h
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* 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 2 of the License, 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 St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __XED_SPELL_UTILS_H__
#define __XED_SPELL_UTILS_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
gboolean xed_spell_utils_is_digit (const char *text, gssize length);
gboolean xed_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end);
G_END_DECLS
#endif /* __XED_SPELL_UTILS_H__ */

View File

@ -40,10 +40,12 @@ NOINST_H_FILES = \
xed-close-button.h \ xed-close-button.h \
xed-close-confirmation-dialog.h \ xed-close-confirmation-dialog.h \
xed-dirs.h \ xed-dirs.h \
xed-document-private.h \
xed-documents-panel.h \ xed-documents-panel.h \
xed-encodings-dialog.h \ xed-encodings-dialog.h \
xed-history-entry.h \ xed-history-entry.h \
xed-io-error-info-bar.h \ xed-io-error-info-bar.h \
xed-metadata-manager.h \
xed-paned.h \ xed-paned.h \
xed-plugins-engine.h \ xed-plugins-engine.h \
xed-preferences-dialog.h \ xed-preferences-dialog.h \
@ -80,10 +82,6 @@ INST_H_FILES = \
xed-window.h \ xed-window.h \
xed-window-activatable.h xed-window-activatable.h
if !ENABLE_GVFS_METADATA
NOINST_H_FILES += xed-metadata-manager.h
endif
headerdir = $(prefix)/include/xed headerdir = $(prefix)/include/xed
header_DATA = \ header_DATA = \
@ -119,6 +117,7 @@ libxed_c_files = \
xed-message-bus.c \ xed-message-bus.c \
xed-message-type.c \ xed-message-type.c \
xed-message.c \ xed-message.c \
xed-metadata-manager.c \
xed-notebook.c \ xed-notebook.c \
xed-paned.c \ xed-paned.c \
xed-panel.c \ xed-panel.c \
@ -146,10 +145,6 @@ libxed_la_SOURCES = \
$(NOINST_H_FILES) \ $(NOINST_H_FILES) \
$(INST_H_FILES) $(INST_H_FILES)
if !ENABLE_GVFS_METADATA
libxed_la_SOURCES += xed-metadata-manager.c
endif
xed-enum-types.h: xed-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS) xed-enum-types.h: xed-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.h.template $(INST_H_FILES)) > $@ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.h.template $(INST_H_FILES)) > $@

View File

@ -1,7 +1,13 @@
.xed-map-frame:dir(ltr) { .xed-map-frame:dir(ltr) border {
border-width: 0 0 0 1px; border-width: 0 0 0 1px;
} }
.xed-map-frame:dir(rtl) { .xed-map-frame:dir(rtl) border {
border-width: 0 1px 0 0; border-width: 0 1px 0 0;
} }
.xed-searchbar .close-button {
padding: 0;
min-height: 0;
min-width: 0;
}

View File

@ -0,0 +1,17 @@
.xed-window .primary-toolbar {
border: 0px solid @borders;
border-bottom-width: 1px;
}
.xed-statusbar {
border: 0px solid @borders;
border-top-width: 1px;
}
.xed-searchbar {
box-shadow: inset 0 1px @borders;
}
.xed-statusbar button {
padding: 0 4px;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,335 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.17 -->
<object class="GtkShortcutsWindow" id="shortcuts-xed">
<property name="modal">1</property>
<child>
<object class="GtkShortcutsSection">
<property name="visible">1</property>
<property name="section-name">shortcuts</property>
<property name="max-height">12</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Documents</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;N</property>
<property name="title" translatable="yes">Create a new document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;O</property>
<property name="title" translatable="yes">Open a document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;S</property>
<property name="title" translatable="yes">Save the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;S</property>
<property name="title" translatable="yes">Save the document with a new filename</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;L</property>
<property name="title" translatable="yes">Save all the documents</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;W</property>
<property name="title" translatable="yes">Close the document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;W</property>
<property name="title" translatable="yes">Close all the documents</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Down</property>
<property name="title" translatable="yes">Switch to the next document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Up</property>
<property name="title" translatable="yes">Switch to the previous document</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;Alt&gt;1...9</property>
<property name="title" translatable="yes">Switch to the first - ninth document</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Windows and Panes</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F9</property>
<property name="title" translatable="yes">Show side pane</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;F9</property>
<property name="title" translatable="yes">Show bottom pane</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F11</property>
<property name="title" translatable="yes">Fullscreen on / off</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Q</property>
<property name="title" translatable="yes">Quit the application</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Find and Replace</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;F</property>
<property name="title" translatable="yes">Find</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;G</property>
<property name="title" translatable="yes">Find the next match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;Shift&gt;G</property>
<property name="title" translatable="yes">Find the previous match</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;H</property>
<property name="title" translatable="yes">Find and Replace</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;I</property>
<property name="title" translatable="yes">Go to line</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Copy and Paste</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;C</property>
<property name="title" translatable="yes">Copy selected text to clipboard</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;X</property>
<property name="title" translatable="yes">Cut selected text to clipboard</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;V</property>
<property name="title" translatable="yes">Paste text from clipboard</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Undo and Redo</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Z</property>
<property name="title" translatable="yes">Undo previous command</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;Y</property>
<property name="title" translatable="yes">Redo previous command</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Selection</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;A</property>
<property name="title" translatable="yes">Select all text</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Tools</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;shift&gt;F7</property>
<property name="title" translatable="yes">Check spelling</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;P</property>
<property name="title" translatable="yes">Print the document</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Editing</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">Insert</property>
<property name="title" translatable="yes">Toggle insert / overwrite</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;D</property>
<property name="title" translatable="yes">Delete current line</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Up</property>
<property name="title" translatable="yes">Move current line up</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Down</property>
<property name="title" translatable="yes">Move current line down</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Left</property>
<property name="title" translatable="yes">Move current word left</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;alt&gt;Right</property>
<property name="title" translatable="yes">Move current word right</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;U</property>
<property name="title" translatable="yes">Convert to uppercase</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;L</property>
<property name="title" translatable="yes">Convert to lowercase</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;T</property>
<property name="title" translatable="yes">Convert to title case</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;asciitilde</property>
<property name="title" translatable="yes">Invert case</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;a</property>
<property name="title" translatable="yes">Increment number at cursor</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;x</property>
<property name="title" translatable="yes">Decrement number at cursor</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@ -123,6 +123,8 @@
<menu name="HelpMenu" action="Help"> <menu name="HelpMenu" action="Help">
<menuitem name="HelpContentsMenu" action="HelpContents"/> <menuitem name="HelpContentsMenu" action="HelpContents"/>
<menuitem name="HelpAboutMenu" action="HelpAbout"/> <menuitem name="HelpAboutMenu" action="HelpAbout"/>
<menuitem name="HelpAboutMenu" action="HelpAbout"/>
<menuitem name="HelpShortcutsMenu" action="HelpShortcuts"/>
</menu> </menu>
</menubar> </menubar>

View File

@ -6,7 +6,9 @@
<file preprocess="xml-stripblanks">ui/xed-preferences-dialog.ui</file> <file preprocess="xml-stripblanks">ui/xed-preferences-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/xed-print-preferences.ui</file> <file preprocess="xml-stripblanks">ui/xed-print-preferences.ui</file>
<file preprocess="xml-stripblanks">ui/xed-searchbar.ui</file> <file preprocess="xml-stripblanks">ui/xed-searchbar.ui</file>
<file preprocess="xml-stripblanks">ui/xed-shortcuts.ui</file>
<file preprocess="xml-stripblanks">ui/xed-view-frame.ui</file> <file preprocess="xml-stripblanks">ui/xed-view-frame.ui</file>
<file>css/xed-style.css</file> <file>css/xed-style.css</file>
<file>css/xed.adwaita.css</file>
</gresource> </gresource>
</gresources> </gresources>

View File

@ -223,6 +223,54 @@ set_initial_theme_style (XedApp *app)
} }
} }
static void
theme_changed (GtkSettings *settings,
GParamSpec *pspec,
gpointer data)
{
static GtkCssProvider *provider;
gchar *theme;
GdkScreen *screen;
g_object_get (settings, "gtk-theme-name", &theme, NULL);
screen = gdk_screen_get_default ();
if (g_str_equal (theme, "Adwaita"))
{
if (provider == NULL)
{
GFile *file;
provider = gtk_css_provider_new ();
file = g_file_new_for_uri ("resource:///org/x/editor/css/xed.adwaita.css");
gtk_css_provider_load_from_file (provider, file, NULL);
g_object_unref (file);
}
gtk_style_context_add_provider_for_screen (screen,
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
else if (provider != NULL)
{
gtk_style_context_remove_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider));
g_clear_object (&provider);
}
g_free (theme);
}
static void
setup_theme_extensions (void)
{
GtkSettings *settings;
settings = gtk_settings_get_default ();
g_signal_connect (settings, "notify::gtk-theme-name",
G_CALLBACK (theme_changed), NULL);
theme_changed (settings, NULL, NULL);
}
static void static void
xed_app_startup (GApplication *application) xed_app_startup (GApplication *application)
{ {
@ -251,6 +299,8 @@ xed_app_startup (GApplication *application)
gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), icon_dir); gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), icon_dir);
g_free (icon_dir); g_free (icon_dir);
setup_theme_extensions ();
#ifndef ENABLE_GVFS_METADATA #ifndef ENABLE_GVFS_METADATA
/* Setup metadata-manager */ /* Setup metadata-manager */
cache_dir = xed_dirs_get_user_cache_dir (); cache_dir = xed_dirs_get_user_cache_dir ();

View File

@ -32,10 +32,13 @@
#include <config.h> #include <config.h>
#endif #endif
#include "xed-close-confirmation-dialog.h"
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include "xed-close-confirmation-dialog.h"
#include <xed/xed-app.h> #include <xed/xed-app.h>
#include <xed/xed-document.h>
#include <xed/xed-document-private.h>
#include <xed/xed-utils.h> #include <xed/xed-utils.h>
#include <xed/xed-window.h> #include <xed/xed-window.h>

View File

@ -38,31 +38,27 @@
#include <gio/gio.h> #include <gio/gio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-commands.h" #include "xed-commands.h"
#include "xed-window.h" #include "xed-window.h"
#include "xed-window-private.h" #include "xed-window-private.h"
#include "xed-statusbar.h" #include "xed-statusbar.h"
#include "xed-debug.h"
#include "xed-utils.h" #include "xed-utils.h"
#include "xed-file-chooser-dialog.h" #include "xed-file-chooser-dialog.h"
#include "xed-close-confirmation-dialog.h" #include "xed-close-confirmation-dialog.h"
/* Defined constants */ /* Defined constants */
#define XED_OPEN_DIALOG_KEY "xed-open-dialog-key" #define XED_OPEN_DIALOG_KEY "xed-open-dialog-key"
#define XED_TAB_TO_SAVE_AS "xed-tab-to-save-as"
#define XED_LIST_OF_TABS_TO_SAVE_AS "xed-list-of-tabs-to-save-as"
#define XED_IS_CLOSING_ALL "xed-is-closing-all" #define XED_IS_CLOSING_ALL "xed-is-closing-all"
#define XED_IS_QUITTING "xed-is-quitting" #define XED_IS_QUITTING "xed-is-quitting"
#define XED_IS_CLOSING_TAB "xed-is-closing-tab"
#define XED_IS_QUITTING_ALL "xed-is-quitting-all" #define XED_IS_QUITTING_ALL "xed-is-quitting-all"
static void tab_state_changed_while_saving (XedTab *tab, static void tab_state_changed_while_saving (XedTab *tab,
GParamSpec *pspec, GParamSpec *pspec,
XedWindow *window); XedWindow *window);
static void save_as_tab (XedTab *tab,
XedWindow *window);
void void
_xed_cmd_file_new (GtkAction *action, _xed_cmd_file_new (GtkAction *action,
XedWindow *window) XedWindow *window)
@ -521,110 +517,70 @@ replace_read_only_file (GtkWindow *parent,
} }
static void static void
save_finish_cb (XedTab *tab, tab_save_as_ready_cb (XedTab *tab,
GAsyncResult *result, GAsyncResult *result,
gpointer user_data) GTask *task)
{ {
_xed_tab_save_finish (tab, result); gboolean success = _xed_tab_save_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
} }
static void static void
save_dialog_response_cb (XedFileChooserDialog *dialog, save_dialog_response_cb (XedFileChooserDialog *dialog,
gint response_id, gint response_id,
XedWindow *window) GTask *task)
{ {
XedTab *tab; XedTab *tab;
gpointer data; XedWindow *window;
GSList *tabs_to_save_as; GFile *location;
gchar *parse_name;
GtkSourceNewlineType newline_type;
const GtkSourceEncoding *encoding;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = XED_TAB (g_object_get_data (G_OBJECT (dialog), XED_TAB_TO_SAVE_AS)); tab = g_task_get_source_object (task);
window = g_task_get_task_data (task);
if (response_id != GTK_RESPONSE_OK) if (response_id != GTK_RESPONSE_OK)
{ {
gtk_widget_destroy (GTK_WIDGET (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog));
goto save_next_tab; g_task_return_boolean (task, FALSE);
} g_object_unref (task);
if (tab != NULL)
{
GFile *location;
XedDocument *doc;
gchar *parse_name;
GtkSourceNewlineType newline_type;
const GtkSourceEncoding *encoding;
doc = xed_tab_get_document (tab);
location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
g_return_if_fail (location != NULL);
encoding = xed_file_chooser_dialog_get_encoding (dialog);
newline_type = xed_file_chooser_dialog_get_newline_type (dialog);
gtk_widget_destroy (GTK_WIDGET (dialog));
doc = xed_tab_get_document (tab);
g_return_if_fail (XED_IS_DOCUMENT (doc));
parse_name = g_file_get_parse_name (location);
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
window->priv->generic_message_cid,
_("Saving file '%s'\342\200\246"),
parse_name);
g_free (parse_name);
/* let's remember the dir we navigated too,
* even if the saving fails... */
_xed_window_set_default_location (window, location);
_xed_tab_save_as_async (tab,
location,
encoding,
newline_type,
NULL,
(GAsyncReadyCallback) save_finish_cb,
NULL);
g_object_unref (location);
}
save_next_tab:
data = g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS);
if (data == NULL)
{
return; return;
} }
/* Save As the next tab of the list (we are Saving All files) */ location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
tabs_to_save_as = (GSList *)data; g_return_if_fail (location != NULL);
g_return_if_fail (tab == XED_TAB (tabs_to_save_as->data));
/* Remove the first item of the list */ encoding = xed_file_chooser_dialog_get_encoding (dialog);
tabs_to_save_as = g_slist_delete_link (tabs_to_save_as, tabs_to_save_as); newline_type = xed_file_chooser_dialog_get_newline_type (dialog);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as); gtk_widget_destroy (GTK_WIDGET (dialog));
if (tabs_to_save_as != NULL) parse_name = g_file_get_parse_name (location);
{
tab = XED_TAB (tabs_to_save_as->data);
if (GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (tab), XED_IS_CLOSING_TAB)) == TRUE) xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
{ window->priv->generic_message_cid,
g_object_set_data (G_OBJECT (tab), XED_IS_CLOSING_TAB, NULL); _("Saving file '%s'\342\200\246"),
parse_name);
/* Trace tab state changes */ g_free (parse_name);
g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window);
}
xed_window_set_active_tab (window, tab); /* let's remember the dir we navigated too, even if the saving fails... */
save_as_tab (tab, window); _xed_window_set_default_location (window, location);
}
_xed_tab_save_as_async (tab,
location,
encoding,
newline_type,
g_task_get_cancellable (task),
(GAsyncReadyCallback) tab_save_as_ready_cb,
task);
g_object_unref (location);
} }
static GtkFileChooserConfirmation static GtkFileChooserConfirmation
@ -663,16 +619,20 @@ confirm_overwrite_callback (GtkFileChooser *dialog,
return res; return res;
} }
/* Call save_as_tab_finish() in @callback. */
static void static void
save_as_tab (XedTab *tab, save_as_tab_async (XedTab *tab,
XedWindow *window) XedWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{ {
GTask *task;
GtkWidget *save_dialog; GtkWidget *save_dialog;
GtkWindowGroup *wg; GtkWindowGroup *wg;
XedDocument *doc; XedDocument *doc;
GtkSourceFile *file; GtkSourceFile *file;
GFile *location; GFile *location;
gboolean uri_set = FALSE;
const GtkSourceEncoding *encoding; const GtkSourceEncoding *encoding;
GtkSourceNewlineType newline_type; GtkSourceNewlineType newline_type;
@ -681,6 +641,9 @@ save_as_tab (XedTab *tab,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
task = g_task_new (tab, cancellable, callback, user_data);
g_task_set_task_data (task, g_object_ref (window), g_object_unref);
save_dialog = xed_file_chooser_dialog_new (_("Save As\342\200\246"), save_dialog = xed_file_chooser_dialog_new (_("Save As\342\200\246"),
GTK_WINDOW (window), GTK_WINDOW (window),
GTK_FILE_CHOOSER_ACTION_SAVE, GTK_FILE_CHOOSER_ACTION_SAVE,
@ -706,11 +669,11 @@ save_as_tab (XedTab *tab,
if (location != NULL) if (location != NULL)
{ {
uri_set = gtk_file_chooser_set_file (GTK_FILE_CHOOSER (save_dialog), location, NULL); gtk_file_chooser_set_file (GTK_FILE_CHOOSER (save_dialog), location, NULL);
} }
if (!uri_set) else
{ {
GFile *default_path; GFile *default_path;
gchar *docname; gchar *docname;
@ -734,7 +697,7 @@ save_as_tab (XedTab *tab,
g_free (docname); g_free (docname);
} }
/* Set suggested encoding */ /* Set suggested encoding and newline type */
encoding = gtk_source_file_get_encoding (file); encoding = gtk_source_file_get_encoding (file);
if (encoding == NULL) if (encoding == NULL)
@ -748,39 +711,94 @@ save_as_tab (XedTab *tab,
xed_file_chooser_dialog_set_newline_type (XED_FILE_CHOOSER_DIALOG (save_dialog), newline_type); xed_file_chooser_dialog_set_newline_type (XED_FILE_CHOOSER_DIALOG (save_dialog), newline_type);
g_object_set_data (G_OBJECT (save_dialog), XED_TAB_TO_SAVE_AS, tab); g_signal_connect (save_dialog, "response", G_CALLBACK (save_dialog_response_cb), task);
g_signal_connect (save_dialog, "response", G_CALLBACK (save_dialog_response_cb), window);
gtk_widget_show (save_dialog); gtk_widget_show (save_dialog);
} }
static void static gboolean
save_tab (XedTab *tab, save_as_tab_finish (XedTab *tab,
XedWindow *window) GAsyncResult *result)
{ {
XedDocument *doc; g_return_val_if_fail (g_task_is_valid (result, tab), FALSE);
return g_task_propagate_boolean (G_TASK (result), NULL);
}
static void
save_as_tab_ready_cb (XedTab *tab,
GAsyncResult *result,
GTask *task)
{
gboolean success = save_as_tab_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
}
static void
tab_save_ready_cb (XedTab *tab,
GAsyncResult *result,
GTask *task)
{
gboolean success = _xed_tab_save_finish (tab, result);
g_task_return_boolean (task, success);
g_object_unref (task);
}
/**
* xed_commands_save_document_async:
* @document: the #XedDocument to save.
* @window: a #XedWindow.
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @callback: (scope async): a #GAsyncReadyCallback to call when the operation
* is finished.
* @user_data: (closure): the data to pass to the @callback function.
*
* Asynchronously save the @document. @document must belong to @window. The
* source object of the async task is @document (which will be the first
* parameter of the #GAsyncReadyCallback).
*
* When the operation is finished, @callback will be called. You can then call
* xed_commands_save_document_finish() to get the result of the operation.
*/
void
xed_commands_save_document_async (XedDocument *document,
XedWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
XedTab *tab;
gchar *uri_for_display; gchar *uri_for_display;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
g_return_if_fail (XED_IS_TAB (tab)); g_return_if_fail (XED_IS_DOCUMENT (document));
g_return_if_fail (XED_IS_WINDOW (window)); g_return_if_fail (XED_IS_WINDOW (window));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
doc = xed_tab_get_document (tab); task = g_task_new (document, cancellable, callback, user_data);
g_return_if_fail (XED_IS_DOCUMENT (doc));
if (xed_document_is_untitled (doc) || tab = xed_tab_get_from_document (document);
xed_document_get_readonly (doc))
if (xed_document_is_untitled (document) ||
xed_document_get_readonly (document))
{ {
xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly"); xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly");
save_as_tab (tab, window); save_as_tab_async (tab,
window,
cancellable,
(GAsyncReadyCallback) save_as_tab_ready_cb,
task);
return; return;
} }
uri_for_display = xed_document_get_uri_for_display (doc); uri_for_display = xed_document_get_uri_for_display (document);
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar), xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
window->priv->generic_message_cid, window->priv->generic_message_cid,
_("Saving file '%s'\342\200\246"), _("Saving file '%s'\342\200\246"),
@ -789,9 +807,53 @@ save_tab (XedTab *tab,
g_free (uri_for_display); g_free (uri_for_display);
_xed_tab_save_async (tab, _xed_tab_save_async (tab,
NULL, cancellable,
(GAsyncReadyCallback) save_finish_cb, (GAsyncReadyCallback) tab_save_ready_cb,
NULL); task);
}
/**
* xed_commands_save_document_finish:
* @document: a #XedDocument.
* @result: a #GAsyncResult.
*
* Finishes an asynchronous document saving operation started with
* xed_commands_save_document_async().
*
* Note that there is no error parameter because the errors are already handled
* by xed.
*
* Returns: %TRUE if the document has been correctly saved, %FALSE otherwise.
*/
gboolean
xed_commands_save_document_finish (XedDocument *document,
GAsyncResult *result)
{
g_return_val_if_fail (g_task_is_valid (result, document), FALSE);
return g_task_propagate_boolean (G_TASK (result), NULL);
}
static void
save_tab_ready_cb (XedDocument *doc,
GAsyncResult *result,
gpointer user_data)
{
xed_commands_save_document_finish (doc, result);
}
/* Save tab asynchronously, but without results. */
static void
save_tab (XedTab *tab,
XedWindow *window)
{
XedDocument *doc = xed_tab_get_document (tab);
xed_commands_save_document_async (doc,
window,
NULL,
(GAsyncReadyCallback) save_tab_ready_cb,
NULL);
} }
void void
@ -803,12 +865,18 @@ _xed_cmd_file_save (GtkAction *action,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = xed_window_get_active_tab (window); tab = xed_window_get_active_tab (window);
if (tab == NULL) if (tab != NULL)
{ {
return; save_tab (tab, window);
} }
}
save_tab (tab, window); static void
_xed_cmd_file_save_as_cb (XedTab *tab,
GAsyncResult *result,
gpointer user_data)
{
save_as_tab_finish (tab, result);
} }
void void
@ -820,12 +888,149 @@ _xed_cmd_file_save_as (GtkAction *action,
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
tab = xed_window_get_active_tab (window); tab = xed_window_get_active_tab (window);
if (tab == NULL) if (tab != NULL)
{
save_as_tab_async (tab,
window,
NULL,
(GAsyncReadyCallback) _xed_cmd_file_save_as_cb,
NULL);
}
}
static void
quit_if_needed (XedWindow *window)
{
gboolean is_quitting;
gboolean is_quitting_all;
is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
is_quitting_all = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING_ALL));
if (is_quitting)
{
gtk_widget_destroy (GTK_WIDGET (window));
}
if (is_quitting_all)
{
GtkApplication *app;
app = GTK_APPLICATION (g_application_get_default ());
if (gtk_application_get_windows (app) == NULL)
{
g_application_quit (G_APPLICATION (app));
}
}
}
static gboolean
really_close_tab (XedTab *tab)
{
GtkWidget *toplevel;
XedWindow *window;
xed_debug (DEBUG_COMMANDS);
g_return_val_if_fail (xed_tab_get_state (tab) == XED_TAB_STATE_CLOSING, FALSE);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
g_return_val_if_fail (XED_IS_WINDOW (toplevel), FALSE);
window = XED_WINDOW (toplevel);
xed_window_close_tab (window, tab);
if (xed_window_get_active_tab (window) == NULL)
{
quit_if_needed (window);
}
return FALSE;
}
static void
close_tab (XedTab *tab)
{
XedDocument *doc;
doc = xed_tab_get_document (tab);
g_return_if_fail (doc != NULL);
/* If the user has modified again the document, do not close the tab. */
if (_xed_document_needs_saving (doc))
{ {
return; return;
} }
save_as_tab (tab, window); /* Close the document only if it has been succesfully saved.
* Tab state is set to CLOSING (it is a state without exiting
* transitions) and the tab is closed in an idle handler.
*/
_xed_tab_mark_for_closing (tab);
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
(GSourceFunc) really_close_tab,
tab,
NULL);
}
typedef struct _SaveAsData SaveAsData;
struct _SaveAsData
{
/* Reffed */
XedWindow *window;
/* List of reffed GeditTab's */
GSList *tabs_to_save_as;
guint close_tabs : 1;
};
static void save_as_documents_list (SaveAsData *data);
static void
save_as_documents_list_cb (XedTab *tab,
GAsyncResult *result,
SaveAsData *data)
{
gboolean saved = save_as_tab_finish (tab, result);
if (saved && data->close_tabs)
{
close_tab (tab);
}
g_return_if_fail (tab == XED_TAB (data->tabs_to_save_as->data));
g_object_unref (data->tabs_to_save_as->data);
data->tabs_to_save_as = g_slist_delete_link (data->tabs_to_save_as, data->tabs_to_save_as);
if (data->tabs_to_save_as != NULL)
{
save_as_documents_list (data);
}
else
{
g_object_unref (data->window);
g_slice_free (SaveAsData, data);
}
}
static void
save_as_documents_list (SaveAsData *data)
{
XedTab *next_tab = XED_TAB (data->tabs_to_save_as->data);
xed_window_set_active_tab (data->window, next_tab);
save_as_tab_async (next_tab,
data->window,
NULL,
(GAsyncReadyCallback) save_as_documents_list_cb,
data);
} }
/* /*
@ -835,8 +1040,8 @@ static void
save_documents_list (XedWindow *window, save_documents_list (XedWindow *window,
GList *docs) GList *docs)
{ {
SaveAsData *data = NULL;
GList *l; GList *l;
GSList *tabs_to_save_as = NULL;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
@ -868,9 +1073,17 @@ save_documents_list (XedWindow *window,
if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc)) if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
{ {
if (_xed_document_needs_saving (doc)) if (_xed_document_needs_saving (doc))
{
if (data == NULL)
{ {
tabs_to_save_as = g_slist_prepend (tabs_to_save_as, t); data = g_slice_new (SaveAsData);
data->window = g_object_ref (window);
data->tabs_to_save_as = NULL;
data->close_tabs = FALSE;
} }
data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
}
} }
else else
{ {
@ -913,23 +1126,21 @@ save_documents_list (XedWindow *window,
l = g_list_next (l); l = g_list_next (l);
} }
if (tabs_to_save_as != NULL) if (data != NULL)
{ {
XedTab *tab; data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
save_as_documents_list (data);
tabs_to_save_as = g_slist_reverse (tabs_to_save_as );
g_return_if_fail (g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS) == NULL);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as);
tab = XED_TAB (tabs_to_save_as->data);
xed_window_set_active_tab (window, tab);
save_as_tab (tab, window);
} }
} }
/**
* xed_commands_save_all_documents:
* @window: a #XedWindow.
*
* Asynchronously save all documents belonging to @window. The result of the
* operation is not available, so it's difficult to know whether all the
* documents are correctly saved.
*/
void void
xed_commands_save_all_documents (XedWindow *window) xed_commands_save_all_documents (XedWindow *window)
{ {
@ -953,6 +1164,14 @@ _xed_cmd_file_save_all (GtkAction *action,
xed_commands_save_all_documents (window); xed_commands_save_all_documents (window);
} }
/**
* xed_commands_save_document:
* @window: a #XedWindow.
* @document: the #XedDocument to save.
*
* Asynchronously save @document. @document must belong to @window. If you need
* the result of the operation, use xed_commands_save_document_async().
*/
void void
xed_commands_save_document (XedWindow *window, xed_commands_save_document (XedWindow *window,
XedDocument *document) XedDocument *document)
@ -1161,39 +1380,6 @@ _xed_cmd_file_revert (GtkAction *action,
gtk_widget_show (dialog); gtk_widget_show (dialog);
} }
/* Close tab */
static gboolean
really_close_tab (XedTab *tab)
{
GtkWidget *toplevel;
XedWindow *window;
xed_debug (DEBUG_COMMANDS);
g_return_val_if_fail (xed_tab_get_state (tab) == XED_TAB_STATE_CLOSING, FALSE);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
g_return_val_if_fail (XED_IS_WINDOW (toplevel), FALSE);
window = XED_WINDOW (toplevel);
xed_window_close_tab (window, tab);
if (xed_window_get_active_tab (window) == NULL)
{
gboolean is_quitting;
is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
if (is_quitting)
{
gtk_widget_destroy (GTK_WIDGET (window));
}
}
return FALSE;
}
static void static void
tab_state_changed_while_saving (XedTab *tab, tab_state_changed_while_saving (XedTab *tab,
GParamSpec *pspec, GParamSpec *pspec,
@ -1209,26 +1395,9 @@ tab_state_changed_while_saving (XedTab *tab,
finished */ finished */
if (ts == XED_TAB_STATE_NORMAL) if (ts == XED_TAB_STATE_NORMAL)
{ {
XedDocument *doc;
g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (tab_state_changed_while_saving), window); g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (tab_state_changed_while_saving), window);
doc = xed_tab_get_document (tab); close_tab (tab);
g_return_if_fail (doc != NULL);
/* If the saving operation failed or was interrupted, then the
document is still "modified" -> do not close the tab */
if (_xed_document_needs_saving (doc))
{
return;
}
/* Close the document only if it has been succesfully saved.
Tab state is set to CLOSING (it is a state without exiting
transitions) and the tab is closed in a idle handler */
_xed_tab_mark_for_closing (tab);
g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc)really_close_tab, tab, NULL);
} }
} }
@ -1244,21 +1413,6 @@ save_and_close (XedTab *tab,
save_tab (tab, window); save_tab (tab, window);
} }
static void
save_as_and_close (XedTab *tab,
XedWindow *window)
{
xed_debug (DEBUG_COMMANDS);
g_object_set_data (G_OBJECT (tab), XED_IS_CLOSING_TAB, NULL);
/* Trace tab state changes */
g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window);
xed_window_set_active_tab (window, tab);
save_as_tab (tab, window);
}
static void static void
save_and_close_all_documents (const GList *docs, save_and_close_all_documents (const GList *docs,
XedWindow *window) XedWindow *window)
@ -1266,9 +1420,9 @@ save_and_close_all_documents (const GList *docs,
GList *tabs; GList *tabs;
GList *l; GList *l;
GSList *sl; GSList *sl;
GSList *tabs_to_save_as; SaveAsData *data = NULL;
GSList *tabs_to_save_and_close; GSList *tabs_to_save_and_close = NULL;
GList *tabs_to_close; GList *tabs_to_close = NULL;
xed_debug (DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
@ -1276,19 +1430,13 @@ save_and_close_all_documents (const GList *docs,
tabs = gtk_container_get_children (GTK_CONTAINER (_xed_window_get_notebook (window))); tabs = gtk_container_get_children (GTK_CONTAINER (_xed_window_get_notebook (window)));
tabs_to_save_as = NULL;
tabs_to_save_and_close = NULL;
tabs_to_close = NULL;
l = tabs; l = tabs;
while (l != NULL) while (l != NULL)
{ {
XedTab *t; XedTab *t = XED_TAB (l->data);;
XedTabState state; XedTabState state;
XedDocument *doc; XedDocument *doc;
t = XED_TAB (l->data);
state = xed_tab_get_state (t); state = xed_tab_get_state (t);
doc = xed_tab_get_document (t); doc = xed_tab_get_document (t);
@ -1337,9 +1485,15 @@ save_and_close_all_documents (const GList *docs,
user is running xed - Paolo (Dec. 8, 2005) */ user is running xed - Paolo (Dec. 8, 2005) */
if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc)) if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
{ {
g_object_set_data (G_OBJECT (t), XED_IS_CLOSING_TAB, GBOOLEAN_TO_POINTER (TRUE)); if (data == NULL)
{
data = g_slice_new (SaveAsData);
data->window = g_object_ref (window);
data->tabs_to_save_as = NULL;
data->close_tabs = TRUE;
}
tabs_to_save_as = g_slist_prepend (tabs_to_save_as, t); data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
} }
else else
{ {
@ -1371,20 +1525,11 @@ save_and_close_all_documents (const GList *docs,
} }
g_slist_free (tabs_to_save_and_close); g_slist_free (tabs_to_save_and_close);
/* Save As and close all the files in tabs_to_save_as */ /* Save As and close all the files in data->tabs_to_save_as. */
if (tabs_to_save_as != NULL) if (data != NULL)
{ {
XedTab *tab; data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
save_as_documents_list (data);
tabs_to_save_as = g_slist_reverse (tabs_to_save_as );
g_return_if_fail (g_object_get_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS) == NULL);
g_object_set_data (G_OBJECT (window), XED_LIST_OF_TABS_TO_SAVE_AS, tabs_to_save_as);
tab = XED_TAB (tabs_to_save_as->data);
save_as_and_close (tab, window);
} }
} }

View File

@ -46,7 +46,7 @@
void _xed_cmd_help_contents (GtkAction *action, void _xed_cmd_help_contents (GtkAction *action,
XedWindow *window) XedWindow *window)
{ {
xed_debug(DEBUG_COMMANDS); xed_debug (DEBUG_COMMANDS);
xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (window), NULL, NULL); xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (window), NULL, NULL);
} }
@ -67,3 +67,33 @@ void _xed_cmd_help_about (GtkAction *action,
"website", "http://github.com/linuxmint/xed", "website", "http://github.com/linuxmint/xed",
NULL); NULL);
} }
void
_xed_cmd_help_keyboard_shortcuts (GtkAction *action,
XedWindow *window)
{
static GtkWidget *shortcuts_window;
xed_debug (DEBUG_COMMANDS);
if (shortcuts_window == NULL)
{
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/org/x/editor/ui/xed-shortcuts.ui");
shortcuts_window = GTK_WIDGET (gtk_builder_get_object (builder, "shortcuts-xed"));
g_signal_connect (shortcuts_window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &shortcuts_window);
g_object_unref (builder);
}
if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (shortcuts_window)))
{
gtk_window_set_transient_for (GTK_WINDOW (shortcuts_window), GTK_WINDOW (window));
}
gtk_widget_show_all (shortcuts_window);
gtk_window_present (GTK_WINDOW (shortcuts_window));
}

View File

@ -12,6 +12,8 @@ void xed_commands_load_location (XedWindow *window, GFile *location, const GtkSo
/* Ignore non-existing URIs */ /* Ignore non-existing URIs */
GSList *xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos); GSList *xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos);
void xed_commands_save_document (XedWindow *window, XedDocument *document); void xed_commands_save_document (XedWindow *window, XedDocument *document);
void xed_commands_save_document_async (XedDocument *document, XedWindow *window, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
gboolean xed_commands_save_document_finish (XedDocument *document, GAsyncResult *result);
void xed_commands_save_all_documents (XedWindow *window); void xed_commands_save_all_documents (XedWindow *window);
/* /*
@ -64,6 +66,7 @@ void _xed_cmd_documents_move_to_new_window (GtkAction *action, XedWindow *window
void _xed_cmd_help_contents (GtkAction *action, XedWindow *window); void _xed_cmd_help_contents (GtkAction *action, XedWindow *window);
void _xed_cmd_help_about (GtkAction *action, XedWindow *window); void _xed_cmd_help_about (GtkAction *action, XedWindow *window);
void _xed_cmd_help_keyboard_shortcuts (GtkAction *action, XedWindow *window);
void _xed_cmd_file_close_tab (XedTab *tab, XedWindow *window); void _xed_cmd_file_close_tab (XedTab *tab, XedWindow *window);

View File

@ -0,0 +1,21 @@
#ifndef __XED_DOCUMENT_PRIVATE_H__
#define __XED_DOCUMENT_PRIVATE_H__
#include "xed-document.h"
G_BEGIN_DECLS
glong _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc);
gboolean _xed_document_needs_saving (XedDocument *doc);
gboolean _xed_document_get_empty_search (XedDocument *doc);
void _xed_document_set_create (XedDocument *doc,
gboolean create);
gboolean _xed_document_get_create (XedDocument *doc);
G_END_DECLS
#endif /* __XED_DOCUMENT_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -37,29 +37,14 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define XED_TYPE_DOCUMENT (xed_document_get_type()) #define XED_TYPE_DOCUMENT (xed_document_get_type())
#define XED_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENT, XedDocument))
#define XED_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENT, XedDocumentClass)) G_DECLARE_DERIVABLE_TYPE (XedDocument, xed_document, XED, DOCUMENT, GtkSourceBuffer)
#define XED_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENT))
#define XED_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT))
#define XED_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENT, XedDocumentClass))
#define XED_METADATA_ATTRIBUTE_POSITION "metadata::xed-position" #define XED_METADATA_ATTRIBUTE_POSITION "metadata::xed-position"
#define XED_METADATA_ATTRIBUTE_ENCODING "metadata::xed-encoding" #define XED_METADATA_ATTRIBUTE_ENCODING "metadata::xed-encoding"
#define XED_METADATA_ATTRIBUTE_LANGUAGE "metadata::xed-language" #define XED_METADATA_ATTRIBUTE_LANGUAGE "metadata::xed-language"
typedef struct _XedDocument XedDocument;
typedef struct _XedDocumentPrivate XedDocumentPrivate;
typedef struct _XedDocumentClass XedDocumentClass;
struct _XedDocument
{
GtkSourceBuffer buffer;
/*< private > */
XedDocumentPrivate *priv;
};
struct _XedDocumentClass struct _XedDocumentClass
{ {
GtkSourceBufferClass parent_class; GtkSourceBufferClass parent_class;
@ -77,8 +62,6 @@ struct _XedDocumentClass
void (* saved) (XedDocument *document); void (* saved) (XedDocument *document);
}; };
GType xed_document_get_type (void) G_GNUC_CONST;
XedDocument *xed_document_new (void); XedDocument *xed_document_new (void);
GtkSourceFile *xed_document_get_file (XedDocument *doc); GtkSourceFile *xed_document_get_file (XedDocument *doc);
@ -138,24 +121,6 @@ void xed_document_set_search_context (XedDocument *doc,
GtkSourceSearchContext *xed_document_get_search_context (XedDocument *doc); GtkSourceSearchContext *xed_document_get_search_context (XedDocument *doc);
/* Non exported functions */
glong _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc);
void _xed_document_apply_error_style (XedDocument *doc,
GtkTextIter *start,
GtkTextIter *end);
/* Note: this is a sync stat: use only on local files */
gboolean _xed_document_check_externally_modified (XedDocument *doc);
gboolean _xed_document_needs_saving (XedDocument *doc);
void _xed_document_set_create (XedDocument *doc,
gboolean create);
gboolean _xed_document_get_create (XedDocument *doc);
G_END_DECLS G_END_DECLS
#endif /* __XED_DOCUMENT_H__ */ #endif /* __XED_DOCUMENT_H__ */

View File

@ -21,23 +21,15 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
/*
* Modified by the xed Team, 2003-2007. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#include <time.h>
#include <stdlib.h>
#include <libxml/xmlreader.h> #include <libxml/xmlreader.h>
#include "xed-metadata-manager.h" #include "xed-metadata-manager.h"
#include "xed-debug.h" #include "xed-debug.h"
/* /*
#define XED_METADATA_VERBOSE_DEBUG 1 #define XED_METADATA_VERBOSE_DEBUG 1
*/ */
#define MAX_ITEMS 50 #define MAX_ITEMS 50
typedef struct _XedMetadataManager XedMetadataManager; typedef struct _XedMetadataManager XedMetadataManager;
@ -45,21 +37,21 @@ typedef struct _Item Item;
struct _Item struct _Item
{ {
time_t atime; /* time of last access */ gint64 atime; /* time of last access in seconds since January 1, 1970 UTC */
GHashTable *values; GHashTable *values;
}; };
struct _XedMetadataManager struct _XedMetadataManager
{ {
gboolean values_loaded; /* It is true if the file gboolean values_loaded; /* It is true if the file
has been read */ has been read */
guint timeout_id; guint timeout_id;
GHashTable *items; GHashTable *items;
gchar *metadata_filename; gchar *metadata_filename;
}; };
static gboolean xed_metadata_manager_save (gpointer data); static gboolean xed_metadata_manager_save (gpointer data);
@ -70,34 +62,34 @@ static XedMetadataManager *xed_metadata_manager = NULL;
static void static void
item_free (gpointer data) item_free (gpointer data)
{ {
Item *item; Item *item;
g_return_if_fail (data != NULL); g_return_if_fail (data != NULL);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
item = (Item *)data; item = (Item *)data;
if (item->values != NULL) if (item->values != NULL)
g_hash_table_destroy (item->values); g_hash_table_destroy (item->values);
g_free (item); g_free (item);
} }
static void static void
xed_metadata_manager_arm_timeout (void) xed_metadata_manager_arm_timeout (void)
{ {
if (xed_metadata_manager->timeout_id == 0) if (xed_metadata_manager->timeout_id == 0)
{ {
xed_metadata_manager->timeout_id = xed_metadata_manager->timeout_id =
g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE, g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
2, 2,
(GSourceFunc)xed_metadata_manager_save, (GSourceFunc)xed_metadata_manager_save,
NULL, NULL,
NULL); NULL);
} }
} }
/** /**
@ -110,22 +102,22 @@ xed_metadata_manager_arm_timeout (void)
void void
xed_metadata_manager_init (const gchar *metadata_filename) xed_metadata_manager_init (const gchar *metadata_filename)
{ {
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
if (xed_metadata_manager != NULL) if (xed_metadata_manager != NULL)
return; return;
xed_metadata_manager = g_new0 (XedMetadataManager, 1); xed_metadata_manager = g_new0 (XedMetadataManager, 1);
xed_metadata_manager->values_loaded = FALSE; xed_metadata_manager->values_loaded = FALSE;
xed_metadata_manager->items = xed_metadata_manager->items =
g_hash_table_new_full (g_str_hash, g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
item_free); item_free);
xed_metadata_manager->metadata_filename = g_strdup (metadata_filename); xed_metadata_manager->metadata_filename = g_strdup (metadata_filename);
return; return;
} }
@ -139,154 +131,159 @@ xed_metadata_manager_init (const gchar *metadata_filename)
void void
xed_metadata_manager_shutdown (void) xed_metadata_manager_shutdown (void)
{ {
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
if (xed_metadata_manager == NULL) if (xed_metadata_manager == NULL)
return; return;
if (xed_metadata_manager->timeout_id) if (xed_metadata_manager->timeout_id)
{ {
g_source_remove (xed_metadata_manager->timeout_id); g_source_remove (xed_metadata_manager->timeout_id);
xed_metadata_manager->timeout_id = 0; xed_metadata_manager->timeout_id = 0;
xed_metadata_manager_save (NULL); xed_metadata_manager_save (NULL);
} }
if (xed_metadata_manager->items != NULL) if (xed_metadata_manager->items != NULL)
g_hash_table_destroy (xed_metadata_manager->items); g_hash_table_destroy (xed_metadata_manager->items);
g_free (gedit_metadata_manager->metadata_filename); g_free (xed_metadata_manager->metadata_filename);
g_free (xed_metadata_manager); g_free (xed_metadata_manager);
xed_metadata_manager = NULL; xed_metadata_manager = NULL;
} }
static void static void
parseItem (xmlDocPtr doc, xmlNodePtr cur) parseItem (xmlDocPtr doc, xmlNodePtr cur)
{ {
Item *item; Item *item;
xmlChar *uri; xmlChar *uri;
xmlChar *atime; xmlChar *atime;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0) if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
return; return;
uri = xmlGetProp (cur, (const xmlChar *)"uri"); uri = xmlGetProp (cur, (const xmlChar *)"uri");
if (uri == NULL) if (uri == NULL)
return; return;
atime = xmlGetProp (cur, (const xmlChar *)"atime"); atime = xmlGetProp (cur, (const xmlChar *)"atime");
if (atime == NULL) if (atime == NULL)
{ {
xmlFree (uri); xmlFree (uri);
return; return;
} }
item = g_new0 (Item, 1); item = g_new0 (Item, 1);
item->atime = g_ascii_strtoull ((char *)atime, NULL, 0); item->atime = g_ascii_strtoll ((char *)atime, NULL, 0);
item->values = g_hash_table_new_full (g_str_hash, item->values = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
g_free); g_free);
cur = cur->xmlChildrenNode; cur = cur->xmlChildrenNode;
while (cur != NULL) while (cur != NULL)
{ {
if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0) if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
{ {
xmlChar *key; xmlChar *key;
xmlChar *value; xmlChar *value;
key = xmlGetProp (cur, (const xmlChar *)"key"); key = xmlGetProp (cur, (const xmlChar *)"key");
value = xmlGetProp (cur, (const xmlChar *)"value"); value = xmlGetProp (cur, (const xmlChar *)"value");
if ((key != NULL) && (value != NULL)) if ((key != NULL) && (value != NULL))
g_hash_table_insert (item->values, g_hash_table_insert (item->values,
g_strdup ((gchar *)key), g_strdup ((gchar *)key),
g_strdup ((gchar *)value)); g_strdup ((gchar *)value));
if (key != NULL) if (key != NULL)
xmlFree (key); xmlFree (key);
if (value != NULL) if (value != NULL)
xmlFree (value); xmlFree (value);
} }
cur = cur->next; cur = cur->next;
} }
g_hash_table_insert (xed_metadata_manager->items, g_hash_table_insert (xed_metadata_manager->items,
g_strdup ((gchar *)uri), g_strdup ((gchar *)uri),
item); item);
xmlFree (uri); xmlFree (uri);
xmlFree (atime); xmlFree (atime);
} }
static gboolean static gboolean
load_values (void) load_values (void)
{ {
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr cur; xmlNodePtr cur;
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
g_return_val_if_fail (xed_metadata_manager != NULL, FALSE); g_return_val_if_fail (xed_metadata_manager != NULL, FALSE);
g_return_val_if_fail (xed_metadata_manager->values_loaded == FALSE, FALSE); g_return_val_if_fail (xed_metadata_manager->values_loaded == FALSE, FALSE);
xed_metadata_manager->values_loaded = TRUE; xed_metadata_manager->values_loaded = TRUE;
xmlKeepBlanksDefault (0); xmlKeepBlanksDefault (0);
/* FIXME: file locking - Paolo */ /* FIXME: file locking - Paolo */
if ((xed_metadata_manager->metadata_filename == NULL) || if (xed_metadata_manager->metadata_filename == NULL)
(!g_file_test (xed_metadata_manager->metadata_filename, G_FILE_TEST_EXISTS))) {
{ return FALSE;
return FALSE; }
}
doc = xmlParseFile (xed_metadata_manager->metadata_filename); /* TODO: avoid races */
if (!g_file_test (xed_metadata_manager->metadata_filename, G_FILE_TEST_EXISTS))
{
return TRUE;
}
if (doc == NULL) doc = xmlParseFile (xed_metadata_manager->metadata_filename);
{
return FALSE;
}
cur = xmlDocGetRootElement (doc); if (doc == NULL)
if (cur == NULL) {
{ return FALSE;
g_message ("The metadata file '%s' is empty", g_path_get_basename (xed_metadata_manager->metadata_filename)); }
xmlFreeDoc (doc);
return FALSE; cur = xmlDocGetRootElement (doc);
} if (cur == NULL)
{
g_message ("The metadata file '%s' is empty", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) return TRUE;
{ }
g_message ("File '%s' is of the wrong type", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
return FALSE; if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
} {
g_message ("File '%s' is of the wrong type", g_path_get_basename (xed_metadata_manager->metadata_filename));
xmlFreeDoc (doc);
cur = xmlDocGetRootElement (doc); return FALSE;
cur = cur->xmlChildrenNode; }
while (cur != NULL) cur = xmlDocGetRootElement (doc);
{ cur = cur->xmlChildrenNode;
parseItem (doc, cur);
cur = cur->next; while (cur != NULL)
} {
parseItem (doc, cur);
xmlFreeDoc (doc); cur = cur->next;
}
return TRUE; xmlFreeDoc (doc);
return TRUE;
} }
/** /**
@ -298,48 +295,51 @@ load_values (void)
*/ */
gchar * gchar *
xed_metadata_manager_get (GFile *location, xed_metadata_manager_get (GFile *location,
const gchar *key) const gchar *key)
{ {
Item *item; Item *item;
gchar *value; gchar *value;
gchar *uri; gchar *uri;
g_return_val_if_fail (G_IS_FILE (location), NULL); g_return_val_if_fail (G_IS_FILE (location), NULL);
g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (key != NULL, NULL);
uri = g_file_get_uri (location); uri = g_file_get_uri (location);
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key ); xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key );
if (!xed_metadata_manager->values_loaded) if (!xed_metadata_manager->values_loaded)
{ {
gboolean res; gboolean res;
res = load_values (); res = load_values ();
if (!res) if (!res)
return NULL; {
} g_free (uri);
return NULL;
}
}
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items, item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
uri); uri);
g_free (uri); g_free (uri);
if (item == NULL) if (item == NULL)
return NULL; return NULL;
item->atime = time (NULL); item->atime = g_get_real_time () / 1000;
if (item->values == NULL) if (item->values == NULL)
return NULL; return NULL;
value = g_hash_table_lookup (item->values, key); value = g_hash_table_lookup (item->values, key);
if (value == NULL) if (value == NULL)
return NULL; return NULL;
else else
return g_strdup (value); return g_strdup (value);
} }
/** /**
@ -352,219 +352,221 @@ xed_metadata_manager_get (GFile *location,
*/ */
void void
xed_metadata_manager_set (GFile *location, xed_metadata_manager_set (GFile *location,
const gchar *key, const gchar *key,
const gchar *value) const gchar *value)
{ {
Item *item; Item *item;
gchar *uri; gchar *uri;
g_return_if_fail (G_IS_FILE (location)); g_return_if_fail (G_IS_FILE (location));
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
uri = g_file_get_uri (location); uri = g_file_get_uri (location);
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value); xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value);
if (!xed_metadata_manager->values_loaded) if (!xed_metadata_manager->values_loaded)
{ {
gboolean res; gboolean ok;
res = load_values (); ok = load_values ();
if (!res) if (!ok)
return; {
} g_free (uri);
return;
}
}
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items, item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
uri); uri);
if (item == NULL) if (item == NULL)
{ {
item = g_new0 (Item, 1); item = g_new0 (Item, 1);
g_hash_table_insert (xed_metadata_manager->items, g_hash_table_insert (xed_metadata_manager->items,
g_strdup (uri), g_strdup (uri),
item); item);
} }
if (item->values == NULL) if (item->values == NULL)
item->values = g_hash_table_new_full (g_str_hash, item->values = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, g_free,
g_free); g_free);
if (value != NULL) if (value != NULL)
g_hash_table_insert (item->values, g_hash_table_insert (item->values,
g_strdup (key), g_strdup (key),
g_strdup (value)); g_strdup (value));
else else
g_hash_table_remove (item->values, g_hash_table_remove (item->values,
key); key);
item->atime = time (NULL); item->atime = g_get_real_time () / 1000;
g_free (uri); g_free (uri);
xed_metadata_manager_arm_timeout (); xed_metadata_manager_arm_timeout ();
} }
static void static void
save_values (const gchar *key, const gchar *value, xmlNodePtr parent) save_values (const gchar *key, const gchar *value, xmlNodePtr parent)
{ {
xmlNodePtr xml_node; xmlNodePtr xml_node;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
if (value == NULL) if (value == NULL)
return; return;
xml_node = xmlNewChild (parent, xml_node = xmlNewChild (parent,
NULL, NULL,
(const xmlChar *)"entry", (const xmlChar *)"entry",
NULL); NULL);
xmlSetProp (xml_node, xmlSetProp (xml_node,
(const xmlChar *)"key", (const xmlChar *)"key",
(const xmlChar *)key); (const xmlChar *)key);
xmlSetProp (xml_node, xmlSetProp (xml_node,
(const xmlChar *)"value", (const xmlChar *)"value",
(const xmlChar *)value); (const xmlChar *)value);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value); xed_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value);
#endif #endif
} }
static void static void
save_item (const gchar *key, const gpointer *data, xmlNodePtr parent) save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
{ {
xmlNodePtr xml_node; xmlNodePtr xml_node;
const Item *item = (const Item *)data; const Item *item = (const Item *)data;
gchar *atime; gchar *atime;
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
#endif #endif
g_return_if_fail (key != NULL); g_return_if_fail (key != NULL);
if (item == NULL) if (item == NULL)
return; return;
xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL); xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key); xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "uri: %s", key); xed_debug_message (DEBUG_METADATA, "uri: %s", key);
#endif #endif
atime = g_strdup_printf ("%ld", item->atime); atime = g_strdup_printf ("%" G_GINT64_FORMAT, item->atime);
xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime); xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
#ifdef XED_METADATA_VERBOSE_DEBUG #ifdef XED_METADATA_VERBOSE_DEBUG
xed_debug_message (DEBUG_METADATA, "atime: %s", atime); xed_debug_message (DEBUG_METADATA, "atime: %s", atime);
#endif #endif
g_free (atime); g_free (atime);
g_hash_table_foreach (item->values, g_hash_table_foreach (item->values,
(GHFunc)save_values, (GHFunc)save_values,
xml_node); xml_node);
} }
static void static void
get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove) get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
{ {
const Item *item = (const Item *)value; const Item *item = (const Item *)value;
if (*key_to_remove == NULL) if (*key_to_remove == NULL)
{ {
*key_to_remove = key; *key_to_remove = key;
} }
else else
{ {
const Item *item_to_remove = const Item *item_to_remove =
g_hash_table_lookup (xed_metadata_manager->items, g_hash_table_lookup (xed_metadata_manager->items,
*key_to_remove); *key_to_remove);
g_return_if_fail (item_to_remove != NULL); g_return_if_fail (item_to_remove != NULL);
if (item->atime < item_to_remove->atime) if (item->atime < item_to_remove->atime)
{ {
*key_to_remove = key; *key_to_remove = key;
} }
} }
} }
static void static void
resize_items (void) resize_items (void)
{ {
while (g_hash_table_size (xed_metadata_manager->items) > MAX_ITEMS) while (g_hash_table_size (xed_metadata_manager->items) > MAX_ITEMS)
{ {
gpointer key_to_remove = NULL; gpointer key_to_remove = NULL;
g_hash_table_foreach (xed_metadata_manager->items, g_hash_table_foreach (xed_metadata_manager->items,
(GHFunc)get_oldest, (GHFunc)get_oldest,
&key_to_remove); &key_to_remove);
g_return_if_fail (key_to_remove != NULL); g_return_if_fail (key_to_remove != NULL);
g_hash_table_remove (xed_metadata_manager->items, g_hash_table_remove (xed_metadata_manager->items,
key_to_remove); key_to_remove);
} }
} }
static gboolean static gboolean
xed_metadata_manager_save (gpointer data) xed_metadata_manager_save (gpointer data)
{ {
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr root; xmlNodePtr root;
xed_debug (DEBUG_METADATA); xed_debug (DEBUG_METADATA);
xed_metadata_manager->timeout_id = 0; xed_metadata_manager->timeout_id = 0;
resize_items (); resize_items ();
xmlIndentTreeOutput = TRUE; xmlIndentTreeOutput = TRUE;
doc = xmlNewDoc ((const xmlChar *)"1.0"); doc = xmlNewDoc ((const xmlChar *)"1.0");
if (doc == NULL) if (doc == NULL)
return TRUE; return TRUE;
/* Create metadata root */ /* Create metadata root */
root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL); root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
xmlDocSetRootElement (doc, root); xmlDocSetRootElement (doc, root);
g_hash_table_foreach (xed_metadata_manager->items, g_hash_table_foreach (xed_metadata_manager->items,
(GHFunc)save_item, (GHFunc)save_item,
root); root);
/* FIXME: lock file - Paolo */ /* FIXME: lock file - Paolo */
if (xed_metadata_manager->metadata_filename != NULL) if (xed_metadata_manager->metadata_filename != NULL)
{ {
gchar *cache_dir; gchar *cache_dir;
int res; int res;
/* make sure the cache dir exists */ /* make sure the cache dir exists */
cache_dir = g_path_get_dirname (xed_metadata_manager->metadata_filename); cache_dir = g_path_get_dirname (xed_metadata_manager->metadata_filename);
res = g_mkdir_with_parents (cache_dir, 0755); res = g_mkdir_with_parents (cache_dir, 0755);
if (res != -1) if (res != -1)
{ {
xmlSaveFormatFile (xed_metadata_manager->metadata_filename, doc, 1); xmlSaveFormatFile (xed_metadata_manager->metadata_filename, doc, 1);
} }
g_free (cache_dir); g_free (cache_dir);
} }
xmlFreeDoc (doc); xmlFreeDoc (doc);
xed_debug_message (DEBUG_METADATA, "DONE"); xed_debug_message (DEBUG_METADATA, "DONE");
return FALSE; return FALSE;
} }

View File

@ -30,7 +30,7 @@
#ifndef __XED_METADATA_MANAGER_H__ #ifndef __XED_METADATA_MANAGER_H__
#define __XED_METADATA_MANAGER_H__ #define __XED_METADATA_MANAGER_H__
#include <glib.h> #include <gio/gio.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@ -543,6 +543,8 @@ button_release_cb (XedNotebook *notebook,
GdkEventButton *event, GdkEventButton *event,
gpointer data) gpointer data)
{ {
gboolean ret_val = FALSE;
if (notebook->priv->drag_in_progress) if (notebook->priv->drag_in_progress)
{ {
gint cur_page_num; gint cur_page_num;
@ -566,11 +568,23 @@ button_release_cb (XedNotebook *notebook,
} }
gtk_grab_remove (GTK_WIDGET (notebook)); gtk_grab_remove (GTK_WIDGET (notebook));
} }
else if ((event->type == GDK_BUTTON_RELEASE) && (event->button == 8))
{
gtk_notebook_prev_page (GTK_NOTEBOOK (notebook));
ret_val = TRUE;
}
else if ((event->type == GDK_BUTTON_RELEASE) && (event->button == 9))
{
gtk_notebook_next_page (GTK_NOTEBOOK (notebook));
ret_val = TRUE;
}
/* This must be called even if a drag isn't happening */ /* This must be called even if a drag isn't happening */
drag_stop (notebook); drag_stop (notebook);
return FALSE; return ret_val;
} }
static gboolean static gboolean
@ -638,13 +652,13 @@ notebook_scroll_event_cb (XedNotebook *notebook,
switch (event->direction) switch (event->direction)
{ {
case GDK_SCROLL_DOWN: case GDK_SCROLL_DOWN:
case GDK_SCROLL_RIGHT:
gtk_notebook_next_page (GTK_NOTEBOOK (notebook));
break;
case GDK_SCROLL_UP:
case GDK_SCROLL_LEFT: case GDK_SCROLL_LEFT:
gtk_notebook_prev_page (GTK_NOTEBOOK (notebook)); gtk_notebook_prev_page (GTK_NOTEBOOK (notebook));
break; break;
case GDK_SCROLL_UP:
case GDK_SCROLL_RIGHT:
gtk_notebook_next_page (GTK_NOTEBOOK (notebook));
break;
default: default:
break; break;
} }
@ -714,11 +728,9 @@ xed_notebook_init (XedNotebook *notebook)
notebook->priv->tab_scrolling_enabled = g_settings_get_boolean (notebook->priv->ui_settings, "enable-tab-scrolling"); notebook->priv->tab_scrolling_enabled = g_settings_get_boolean (notebook->priv->ui_settings, "enable-tab-scrolling");
gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
#if GTK_CHECK_VERSION (3, 20, 0)
gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
#endif
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
gtk_container_set_border_width (GTK_CONTAINER (notebook), 0);
g_signal_connect (notebook, "button-press-event", g_signal_connect (notebook, "button-press-event",
(GCallback)button_press_cb, NULL); (GCallback)button_press_cb, NULL);

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
* xed-preferences-dialog.c * xed-preferences-dialog.c
* This file is part of xed * This file is part of xed
* *
* Copyright (C) 2001-2005 Paolo Maggi * Copyright (C) 2001-2005 Paolo Maggi
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,14 +17,14 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, * Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
/* /*
* Modified by the xed Team, 2003. See the AUTHORS file for a * Modified by the xed Team, 2003. See the AUTHORS file for a
* list of people on the xed Team. * list of people on the xed Team.
* See the ChangeLog files for a list of changes. * See the ChangeLog files for a list of changes.
* *
* $Id$ * $Id$
*/ */
@ -32,54 +32,13 @@
#ifndef __XED_PREFERENCES_DIALOG_H__ #ifndef __XED_PREFERENCES_DIALOG_H__
#define __XED_PREFERENCES_DIALOG_H__ #define __XED_PREFERENCES_DIALOG_H__
#include <libxapp/xapp-preferences-window.h>
#include "xed-window.h" #include "xed-window.h"
G_BEGIN_DECLS G_BEGIN_DECLS
/* void xed_show_preferences_dialog (XedWindow *parent);
* Type checking and casting macros
*/
#define XED_TYPE_PREFERENCES_DIALOG (xed_preferences_dialog_get_type())
#define XED_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialog))
#define XED_PREFERENCES_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialog const))
#define XED_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialogClass))
#define XED_IS_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PREFERENCES_DIALOG))
#define XED_IS_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PREFERENCES_DIALOG))
#define XED_PREFERENCES_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialogClass))
/* Private structure type */
typedef struct _XedPreferencesDialogPrivate XedPreferencesDialogPrivate;
/*
* Main object structure
*/
typedef struct _XedPreferencesDialog XedPreferencesDialog;
struct _XedPreferencesDialog
{
GtkDialog dialog;
/*< private > */
XedPreferencesDialogPrivate *priv;
};
/*
* Class definition
*/
typedef struct _XedPreferencesDialogClass XedPreferencesDialogClass;
struct _XedPreferencesDialogClass
{
GtkDialogClass parent_class;
};
/*
* Public methods
*/
GType xed_preferences_dialog_get_type (void) G_GNUC_CONST;
void xed_show_preferences_dialog (XedWindow *parent);
G_END_DECLS G_END_DECLS

View File

@ -659,11 +659,8 @@ xed_searchbar_init (XedSearchbar *searchbar)
{ {
GtkWidget *content; GtkWidget *content;
GtkSizeGroup *size_group; GtkSizeGroup *size_group;
GtkStyleContext *context;
GtkCssProvider *provider;
GtkBuilder *builder; GtkBuilder *builder;
gchar *root_objects[] = { "searchbar_content", NULL }; gchar *root_objects[] = { "searchbar_content", NULL };
const gchar *data = ".button {padding: 0;}";
searchbar->priv = XED_SEARCHBAR_GET_PRIVATE (searchbar); searchbar->priv = XED_SEARCHBAR_GET_PRIVATE (searchbar);
@ -709,10 +706,7 @@ xed_searchbar_init (XedSearchbar *searchbar)
gtk_label_set_mnemonic_widget (GTK_LABEL (searchbar->priv->search_label), searchbar->priv->search_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (searchbar->priv->search_label), searchbar->priv->search_entry);
gtk_label_set_mnemonic_widget (GTK_LABEL (searchbar->priv->replace_label), searchbar->priv->replace_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (searchbar->priv->replace_label), searchbar->priv->replace_entry);
provider = gtk_css_provider_new (); gtk_style_context_add_class (gtk_widget_get_style_context (searchbar->priv->close_button), "close-button");
context = gtk_widget_get_style_context (searchbar->priv->close_button);
gtk_css_provider_load_from_data (provider, data, -1, NULL);
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (size_group, GTK_WIDGET (searchbar->priv->find_button)); gtk_size_group_add_widget (size_group, GTK_WIDGET (searchbar->priv->find_button));

View File

@ -282,26 +282,6 @@ on_auto_save_interval_changed (GSettings *settings,
g_list_free (docs); g_list_free (docs);
} }
static void
on_wrap_mode_changed (GSettings *settings,
const gchar *key,
XedSettings *xs)
{
GtkWrapMode wrap_mode;
GList *views, *l;
wrap_mode = g_settings_get_enum (settings, key);
views = xed_app_get_views (XED_APP (g_application_get_default ()));
for (l = views; l != NULL; l = g_list_next (l))
{
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (l->data), wrap_mode);
}
g_list_free (views);
}
static void static void
on_syntax_highlighting_changed (GSettings *settings, on_syntax_highlighting_changed (GSettings *settings,
const gchar *key, const gchar *key,

View File

@ -141,18 +141,14 @@ xed_status_combo_box_changed (XedStatusComboBox *combo,
static void static void
xed_status_combo_box_class_init (XedStatusComboBoxClass *klass) xed_status_combo_box_class_init (XedStatusComboBoxClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
static const gchar style[] = static const gchar style[] =
"* {\n" "* {\n"
"-GtkButton-default-border : 0;\n"
"-GtkButton-default-outside-border : 0;\n"
"-GtkButton-inner-border: 0;\n"
"-GtkWidget-focus-line-width : 0;\n"
"-GtkWidget-focus-padding : 0;\n"
"padding: 2px;\n" "padding: 2px;\n"
"}"; "}";
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = xed_status_combo_box_finalize; object_class->finalize = xed_status_combo_box_finalize;
object_class->get_property = xed_status_combo_box_get_property; object_class->get_property = xed_status_combo_box_get_property;
object_class->set_property = xed_status_combo_box_set_property; object_class->set_property = xed_status_combo_box_set_property;

View File

@ -43,6 +43,8 @@
#include "xed-print-preview.h" #include "xed-print-preview.h"
#include "xed-progress-info-bar.h" #include "xed-progress-info-bar.h"
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-enum-types.h" #include "xed-enum-types.h"
#include "xed-settings.h" #include "xed-settings.h"
#include "xed-view-frame.h" #include "xed-view-frame.h"
@ -1112,39 +1114,39 @@ view_focused_in (GtkWidget *widget,
XedTab *tab) XedTab *tab)
{ {
XedDocument *doc; XedDocument *doc;
GtkSourceFile *file;
g_return_val_if_fail (XED_IS_TAB (tab), FALSE); g_return_val_if_fail (XED_IS_TAB (tab), FALSE);
/* we try to detect file changes only in the normal state */ /* we try to detect file changes only in the normal state */
if (tab->priv->state != XED_TAB_STATE_NORMAL) if (tab->priv->state != XED_TAB_STATE_NORMAL)
{ {
return FALSE; return GDK_EVENT_PROPAGATE;
} }
/* we already asked, don't bug the user again */ /* we already asked, don't bug the user again */
if (!tab->priv->ask_if_externally_modified) if (!tab->priv->ask_if_externally_modified)
{ {
return FALSE; return GDK_EVENT_PROPAGATE;
} }
doc = xed_tab_get_document (tab); doc = xed_tab_get_document (tab);
file = xed_document_get_file (doc);
/* If file was never saved or is remote we do not check */ /* If file was never saved or is remote we do not check */
if (!xed_document_is_local (doc)) if (gtk_source_file_is_local (file))
{ {
return FALSE; gtk_source_file_check_file_on_disk (file);
if (gtk_source_file_is_externally_modified (file))
{
xed_tab_set_state (tab, XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
display_externally_modified_notification (tab);
}
} }
if (_xed_document_check_externally_modified (doc)) return GDK_EVENT_PROPAGATE;
{
xed_tab_set_state (tab, XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
display_externally_modified_notification (tab);
return FALSE;
}
return FALSE;
} }
static void static void

View File

@ -67,6 +67,8 @@ static const GtkActionEntry xed_always_sensitive_menu_entries[] =
N_("Open the xed manual"), G_CALLBACK (_xed_cmd_help_contents) }, N_("Open the xed manual"), G_CALLBACK (_xed_cmd_help_contents) },
{ "HelpAbout", "help-about-symbolic", N_("_About"), NULL, { "HelpAbout", "help-about-symbolic", N_("_About"), NULL,
N_("About this application"), G_CALLBACK (_xed_cmd_help_about) }, N_("About this application"), G_CALLBACK (_xed_cmd_help_about) },
{ "HelpShortcuts", NULL, N_("_Keyboard Shortcuts"), NULL,
N_("Show the keyboard shortcuts dialog"), G_CALLBACK (_xed_cmd_help_keyboard_shortcuts) },
/* Fullscreen toolbar */ /* Fullscreen toolbar */
{ "LeaveFullscreen", "view-restore-symbolic", NULL, { "LeaveFullscreen", "view-restore-symbolic", NULL,

View File

@ -7,7 +7,6 @@ G_DEFINE_TYPE (XedViewGutterRenderer, xed_view_gutter_renderer, GTK_SOURCE_TYPE_
static void static void
xed_view_gutter_renderer_class_init (XedViewGutterRendererClass *klass) xed_view_gutter_renderer_class_init (XedViewGutterRendererClass *klass)
{ {
GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass);
} }
static void static void

View File

@ -607,8 +607,36 @@ xed_view_class_init (XedViewClass *klass)
binding_set = gtk_binding_set_by_class (klass); binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_d, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, gtk_binding_entry_add_signal (binding_set,
GTK_DELETE_PARAGRAPHS, G_TYPE_INT, 1); GDK_KEY_d,
GDK_CONTROL_MASK,
"delete_from_cursor", 2,
G_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
G_TYPE_INT, 1);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_u,
GDK_CONTROL_MASK,
"change_case", 1,
G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_UPPER);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_l,
GDK_CONTROL_MASK,
"change_case", 1,
G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_LOWER);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_asciitilde,
GDK_CONTROL_MASK,
"change_case", 1,
G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_TOGGLE);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_t,
GDK_CONTROL_MASK,
"change_case", 1,
G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_TITLE);
} }
/** /**

View File

@ -66,9 +66,9 @@ struct _XedWindowPrivate
/* Widgets for fullscreen mode */ /* Widgets for fullscreen mode */
GtkWidget *fullscreen_controls; GtkWidget *fullscreen_controls;
GtkWidget *fullscreen_controls_container; GtkWidget *fullscreen_overlay;
guint fullscreen_animation_timeout_id; GtkWidget *fullscreen_eventbox;
gboolean fullscreen_animation_enter; GtkWidget *fullscreen_revealer;
/* statusbar and context ids for statusbar messages */ /* statusbar and context ids for statusbar messages */
GtkWidget *statusbar; GtkWidget *statusbar;

View File

@ -20,6 +20,8 @@
#include "xed-utils.h" #include "xed-utils.h"
#include "xed-commands.h" #include "xed-commands.h"
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-document.h"
#include "xed-document-private.h"
#include "xed-panel.h" #include "xed-panel.h"
#include "xed-documents-panel.h" #include "xed-documents-panel.h"
#include "xed-plugins-engine.h" #include "xed-plugins-engine.h"
@ -33,8 +35,6 @@
#define TAB_WIDTH_DATA "XedWindowTabWidthData" #define TAB_WIDTH_DATA "XedWindowTabWidthData"
#define LANGUAGE_DATA "XedWindowLanguageData" #define LANGUAGE_DATA "XedWindowLanguageData"
#define FULLSCREEN_ANIMATION_SPEED 4
#define XED_WINDOW_DEFAULT_WIDTH 650 #define XED_WINDOW_DEFAULT_WIDTH 650
#define XED_WINDOW_DEFAULT_HEIGHT 500 #define XED_WINDOW_DEFAULT_HEIGHT 500
@ -205,18 +205,6 @@ xed_window_dispose (GObject *object)
window->priv->dispose_has_run = TRUE; window->priv->dispose_has_run = TRUE;
} }
if (window->priv->fullscreen_animation_timeout_id != 0)
{
g_source_remove (window->priv->fullscreen_animation_timeout_id);
window->priv->fullscreen_animation_timeout_id = 0;
}
if (window->priv->fullscreen_controls != NULL)
{
gtk_widget_destroy (window->priv->fullscreen_controls);
window->priv->fullscreen_controls = NULL;
}
if (window->priv->recents_handler_id != 0) if (window->priv->recents_handler_id != 0)
{ {
GtkRecentManager *recent_manager; GtkRecentManager *recent_manager;
@ -1209,7 +1197,6 @@ create_menu_bar_and_toolbar (XedWindow *window,
GtkUIManager *manager; GtkUIManager *manager;
GtkRecentManager *recent_manager; GtkRecentManager *recent_manager;
GError *error = NULL; GError *error = NULL;
gchar *ui_file;
GtkWidget *tool_item; GtkWidget *tool_item;
GtkWidget *tool_box; GtkWidget *tool_box;
GtkWidget *box; GtkWidget *box;
@ -2182,7 +2169,7 @@ show_overview_map_changed (GObject *object,
map_frame = GTK_FRAME (object); map_frame = GTK_FRAME (object);
action = gtk_action_group_get_action (window->priv->always_sensitive_action_group, "ViewOverviewMap"); action = gtk_action_group_get_action (window->priv->always_sensitive_action_group, "ViewOverviewMap");
if (gtk_widget_get_visible (map_frame)) if (gtk_widget_get_visible (GTK_WIDGET (map_frame)))
{ {
overveiw_map_visible = TRUE; overveiw_map_visible = TRUE;
} }
@ -2235,7 +2222,7 @@ notebook_switch_page (GtkNotebook *book,
if (window->priv->show_overview_map_id) if (window->priv->show_overview_map_id)
{ {
g_signal_handler_disconnect (xed_view_frame_get_map_frame (_xed_tab_get_view_frame (window->priv->active_tab)), window->priv->show_overview_map_id); g_signal_handler_disconnect (xed_view_frame_get_map_frame (XED_VIEW_FRAME (_xed_tab_get_view_frame (window->priv->active_tab))), window->priv->show_overview_map_id);
window->priv->show_overview_map_id = 0; window->priv->show_overview_map_id = 0;
} }
} }
@ -2265,7 +2252,7 @@ notebook_switch_page (GtkNotebook *book,
update_languages_menu (window); update_languages_menu (window);
view = xed_tab_get_view (tab); view = xed_tab_get_view (tab);
map_frame = xed_view_frame_get_map_frame (_xed_tab_get_view_frame (tab)); map_frame = xed_view_frame_get_map_frame (XED_VIEW_FRAME (_xed_tab_get_view_frame (tab)));
/* sync the statusbar */ /* sync the statusbar */
update_cursor_position_statusbar (GTK_TEXT_BUFFER (xed_tab_get_document (tab)), window); update_cursor_position_statusbar (GTK_TEXT_BUFFER (xed_tab_get_document (tab)), window);
@ -2372,15 +2359,6 @@ set_sensitivity_according_to_window_state (XedWindow *window)
} }
} }
static void
update_tab_autosave (GtkWidget *widget,
gpointer data)
{
XedTab *tab = XED_TAB(widget);
gboolean *enabled = (gboolean *) data;
xed_tab_set_auto_save_enabled (tab, *enabled);
}
static void static void
analyze_tab_state (XedTab *tab, analyze_tab_state (XedTab *tab,
XedWindow *window) XedWindow *window)
@ -2456,7 +2434,7 @@ update_can_close (XedWindow *window)
GList *l; GList *l;
gboolean can_close = TRUE; gboolean can_close = TRUE;
tabs = xed_notebook_get_all_tabs (priv->notebook); tabs = xed_notebook_get_all_tabs (XED_NOTEBOOK (priv->notebook));
for (l = tabs; l != NULL; l = g_list_next (l)) for (l = tabs; l != NULL; l = g_list_next (l))
{ {
@ -2634,143 +2612,22 @@ drop_uris_cb (GtkWidget *widget,
load_uris_from_drop (window, uri_list); load_uris_from_drop (window, uri_list);
} }
static void
fullscreen_controls_show (XedWindow *window)
{
GdkScreen *screen;
GdkRectangle fs_rect;
gint min_h, nat_h;
screen = gtk_window_get_screen (GTK_WINDOW (window));
gdk_screen_get_monitor_geometry (
screen, gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET(window))),
&fs_rect);
gtk_widget_get_preferred_height (window->priv->fullscreen_controls_container, &min_h, &nat_h);
gtk_window_resize (GTK_WINDOW (window->priv->fullscreen_controls), fs_rect.width, nat_h);
gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls), fs_rect.x, fs_rect.y - nat_h + 1);
gtk_widget_show_all (window->priv->fullscreen_controls);
}
static gboolean static gboolean
run_fullscreen_animation (gpointer data) on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
{
XedWindow *window = XED_WINDOW(data);
GdkScreen *screen;
GdkRectangle fs_rect;
gint x, y;
screen = gtk_window_get_screen (GTK_WINDOW(window));
gdk_screen_get_monitor_geometry (screen,
gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET(window))),
&fs_rect);
gtk_window_get_position (GTK_WINDOW(window->priv->fullscreen_controls), &x, &y);
if (window->priv->fullscreen_animation_enter)
{
if (y == fs_rect.y)
{
window->priv->fullscreen_animation_timeout_id = 0;
return FALSE;
}
else
{
gtk_window_move (GTK_WINDOW(window->priv->fullscreen_controls), x, y + 1);
return TRUE;
}
}
else
{
gint w, h;
gtk_window_get_size (GTK_WINDOW(window->priv->fullscreen_controls), &w, &h);
if (y == fs_rect.y - h + 1)
{
window->priv->fullscreen_animation_timeout_id = 0;
return FALSE;
}
else
{
gtk_window_move (GTK_WINDOW(window->priv->fullscreen_controls), x, y - 1);
return TRUE;
}
}
}
static void
show_hide_fullscreen_toolbar (XedWindow *window,
gboolean show,
gint height)
{
GtkSettings *settings;
gboolean enable_animations;
settings = gtk_widget_get_settings (GTK_WIDGET(window));
g_object_get (G_OBJECT(settings), "gtk-enable-animations", &enable_animations, NULL);
if (enable_animations)
{
window->priv->fullscreen_animation_enter = show;
if (window->priv->fullscreen_animation_timeout_id == 0)
{
window->priv->fullscreen_animation_timeout_id = g_timeout_add (FULLSCREEN_ANIMATION_SPEED,
(GSourceFunc) run_fullscreen_animation, window);
}
}
else
{
GdkRectangle fs_rect;
GdkScreen *screen;
screen = gtk_window_get_screen (GTK_WINDOW(window));
gdk_screen_get_monitor_geometry (screen,
gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET(window))),
&fs_rect);
if (show)
{
gtk_window_move (GTK_WINDOW(window->priv->fullscreen_controls), fs_rect.x, fs_rect.y);
}
else
{
gtk_window_move (GTK_WINDOW(window->priv->fullscreen_controls), fs_rect.x, fs_rect.y - height + 1);
}
}
}
static gboolean
on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event, GdkEventCrossing *event,
XedWindow *window) XedWindow *window)
{ {
show_hide_fullscreen_toolbar (window, TRUE, 0); gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls), TRUE);
return FALSE; return FALSE;
} }
static gboolean static gboolean
on_fullscreen_controls_leave_notify_event (GtkWidget *widget, on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event, GdkEventCrossing *event,
XedWindow *window) XedWindow *window)
{ {
GdkDisplay *display; gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls), FALSE);
GdkScreen *screen;
gint w, h;
gint x, y;
display = gdk_display_get_default ();
screen = gtk_window_get_screen (GTK_WINDOW(window));
gtk_window_get_size (GTK_WINDOW(window->priv->fullscreen_controls), &w, &h);
gdk_display_get_pointer (display, &screen, &x, &y, NULL);
/* gtk seems to emit leave notify when clicking on tool items,
* work around it by checking the coordinates
*/
if (y >= h)
{
show_hide_fullscreen_toolbar (window, FALSE, h);
}
return FALSE; return FALSE;
} }
@ -2781,6 +2638,9 @@ fullscreen_controls_build (XedWindow *window)
XedWindowPrivate *priv = window->priv; XedWindowPrivate *priv = window->priv;
GtkAction *action; GtkAction *action;
GtkWidget *box; GtkWidget *box;
GtkWidget *toolbar;
GtkWidget *toolitem;
GtkWidget *toolbox;
GtkWidget *fullscreen_btn; GtkWidget *fullscreen_btn;
GtkWidget *separator; GtkWidget *separator;
GtkWidget *button; GtkWidget *button;
@ -2790,17 +2650,23 @@ fullscreen_controls_build (XedWindow *window)
return; return;
} }
priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP); priv->fullscreen_controls = gtk_revealer_new ();
gtk_widget_set_valign (priv->fullscreen_controls, GTK_ALIGN_START);
gtk_container_add (GTK_CONTAINER (priv->fullscreen_eventbox), priv->fullscreen_controls);
gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls), GTK_WINDOW (&window->window)); toolbar = gtk_toolbar_new ();
toolitem = gtk_tool_item_new ();
gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (toolitem), 0);
window->priv->fullscreen_controls_container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); toolbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (window->priv->fullscreen_controls_container), 6); gtk_style_context_add_class (gtk_widget_get_style_context (toolbar), "primary-toolbar");
gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls), window->priv->fullscreen_controls_container); gtk_container_add (GTK_CONTAINER (toolitem), toolbox);
gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls), toolbar);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_vexpand (box, FALSE); gtk_widget_set_vexpand (box, FALSE);
gtk_box_pack_start (GTK_BOX (window->priv->fullscreen_controls_container), box, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (toolbox), box, FALSE, FALSE, 0);
action = gtk_action_group_get_action (window->priv->always_sensitive_action_group, "FileNew"); action = gtk_action_group_get_action (window->priv->always_sensitive_action_group, "FileNew");
button = create_toolbar_button (action); button = create_toolbar_button (action);
@ -2856,13 +2722,15 @@ fullscreen_controls_build (XedWindow *window)
fullscreen_btn = create_toolbar_button (action); fullscreen_btn = create_toolbar_button (action);
gtk_box_pack_end (GTK_BOX (box), fullscreen_btn, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (box), fullscreen_btn, FALSE, FALSE, 0);
gtk_widget_show_all (window->priv->fullscreen_controls_container); gtk_widget_show_all (toolbox);
g_signal_connect(priv->fullscreen_controls, "enter-notify-event", g_signal_connect (priv->fullscreen_eventbox, "enter-notify-event",
G_CALLBACK (on_fullscreen_controls_enter_notify_event), window); G_CALLBACK (on_fullscreen_controls_enter_notify_event), window);
g_signal_connect(priv->fullscreen_controls, "leave-notify-event", g_signal_connect (priv->fullscreen_eventbox, "leave-notify-event",
G_CALLBACK (on_fullscreen_controls_leave_notify_event), window); G_CALLBACK (on_fullscreen_controls_leave_notify_event), window);
gtk_widget_set_size_request (priv->fullscreen_eventbox, -1, 1);
} }
static void static void
@ -3069,7 +2937,7 @@ notebook_tab_removed (XedNotebook *notebook,
--window->priv->num_tabs; --window->priv->num_tabs;
view = xed_tab_get_view (tab); view = xed_tab_get_view (tab);
frame = _xed_tab_get_view_frame (tab); frame = XED_VIEW_FRAME (_xed_tab_get_view_frame (tab));
doc = xed_tab_get_document (tab); doc = xed_tab_get_document (tab);
g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (sync_name), window); g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (sync_name), window);
@ -3272,7 +3140,7 @@ side_panel_size_allocate (GtkWidget *widget,
GtkAllocation *allocation, GtkAllocation *allocation,
XedWindow *window) XedWindow *window)
{ {
if (!xed_paned_get_is_animating (window->priv->hpaned)) if (!xed_paned_get_is_animating (XED_PANED (window->priv->hpaned)))
{ {
window->priv->side_panel_size = allocation->width; window->priv->side_panel_size = allocation->width;
} }
@ -3283,7 +3151,7 @@ bottom_panel_size_allocate (GtkWidget *widget,
GtkAllocation *allocation, GtkAllocation *allocation,
XedWindow *window) XedWindow *window)
{ {
if (!xed_paned_get_is_animating (window->priv->vpaned)) if (!xed_paned_get_is_animating (XED_PANED (window->priv->vpaned)))
{ {
window->priv->bottom_panel_size = allocation->height; window->priv->bottom_panel_size = allocation->height;
} }
@ -3404,7 +3272,7 @@ bottom_panel_item_removed (XedPanel *panel,
{ {
GtkAction *action; GtkAction *action;
xed_paned_close (window->priv->vpaned, 2); xed_paned_close (XED_PANED (window->priv->vpaned), 2);
gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->bottom_pane_button_revealer), FALSE); gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->bottom_pane_button_revealer), FALSE);
action = gtk_action_group_get_action (window->priv->panes_action_group, "ViewBottomPane"); action = gtk_action_group_get_action (window->priv->panes_action_group, "ViewBottomPane");
gtk_action_set_sensitive (action, FALSE); gtk_action_set_sensitive (action, FALSE);
@ -3529,14 +3397,7 @@ check_window_is_active (XedWindow *window,
{ {
if (window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN) if (window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN)
{ {
if (gtk_window_is_active (GTK_WINDOW(window))) gtk_widget_set_visible (window->priv->fullscreen_eventbox, gtk_window_is_active (GTK_WINDOW (window)));
{
gtk_widget_show (window->priv->fullscreen_controls);
}
else
{
gtk_widget_hide (window->priv->fullscreen_controls);
}
} }
} }
@ -3604,7 +3465,6 @@ xed_window_init (XedWindow *window)
window->priv->inhibition_cookie = 0; window->priv->inhibition_cookie = 0;
window->priv->dispose_has_run = FALSE; window->priv->dispose_has_run = FALSE;
window->priv->fullscreen_controls = NULL; window->priv->fullscreen_controls = NULL;
window->priv->fullscreen_animation_timeout_id = 0;
window->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor"); window->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
window->priv->ui_settings = g_settings_new ("org.x.editor.preferences.ui"); window->priv->ui_settings = g_settings_new ("org.x.editor.preferences.ui");
@ -3621,9 +3481,16 @@ xed_window_init (XedWindow *window)
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "xed-window"); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "xed-window");
main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), main_box); window->priv->fullscreen_overlay = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (window->priv->fullscreen_overlay), main_box);
gtk_container_add (GTK_CONTAINER (window), window->priv->fullscreen_overlay);
gtk_widget_show (window->priv->fullscreen_overlay);
gtk_widget_show (main_box); gtk_widget_show (main_box);
window->priv->fullscreen_eventbox = gtk_event_box_new ();
gtk_widget_set_valign (window->priv->fullscreen_eventbox, GTK_ALIGN_START);
gtk_overlay_add_overlay (GTK_OVERLAY (window->priv->fullscreen_overlay), window->priv->fullscreen_eventbox);
/* Add menu bar and toolbar bar */ /* Add menu bar and toolbar bar */
create_menu_bar_and_toolbar (window, main_box); create_menu_bar_and_toolbar (window, main_box);
@ -4322,7 +4189,8 @@ _xed_window_fullscreen (XedWindow *window)
gtk_widget_hide (window->priv->statusbar); gtk_widget_hide (window->priv->statusbar);
fullscreen_controls_build (window); fullscreen_controls_build (window);
fullscreen_controls_show (window);
gtk_widget_show_all (window->priv->fullscreen_eventbox);
} }
void void
@ -4359,7 +4227,7 @@ _xed_window_unfullscreen (XedWindow *window)
} }
g_signal_handlers_unblock_by_func (window->priv->statusbar, statusbar_visibility_changed, window); g_signal_handlers_unblock_by_func (window->priv->statusbar, statusbar_visibility_changed, window);
gtk_widget_hide (window->priv->fullscreen_controls); gtk_widget_hide (window->priv->fullscreen_eventbox);
} }
gboolean gboolean