Merge remote-tracking branch 'origin/master' into sheet
authorJohn Darrington <john@darrington.wattle.id.au>
Thu, 3 Aug 2017 05:37:27 +0000 (07:37 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Thu, 3 Aug 2017 05:37:27 +0000 (07:37 +0200)
61 files changed:
INSTALL
NEWS
configure.ac
lib/automake.mk
lib/gtk-contrib/COPYING.LESSER [deleted file]
lib/gtk-contrib/README [deleted file]
lib/gtk-contrib/automake.mk [deleted file]
lib/gtk-contrib/gtkxpaned.c [deleted file]
lib/gtk-contrib/gtkxpaned.h [deleted file]
src/data/case.c
src/data/variable.c
src/ui/gui/automake.mk
src/ui/gui/find-dialog.c
src/ui/gui/goto-case-dialog.c
src/ui/gui/goto-case-dialog.h
src/ui/gui/marshaller-list
src/ui/gui/missing-val-dialog.c
src/ui/gui/missing-val-dialog.h
src/ui/gui/pspp-sheet-private.h [deleted file]
src/ui/gui/pspp-sheet-selection.c [deleted file]
src/ui/gui/pspp-sheet-selection.h [deleted file]
src/ui/gui/pspp-sheet-view-column.c [deleted file]
src/ui/gui/pspp-sheet-view-column.h [deleted file]
src/ui/gui/pspp-sheet-view.c [deleted file]
src/ui/gui/pspp-sheet-view.h [deleted file]
src/ui/gui/pspp-widget-facade.c [deleted file]
src/ui/gui/pspp-widget-facade.h [deleted file]
src/ui/gui/psppire-button-editable.c [deleted file]
src/ui/gui/psppire-button-editable.h [deleted file]
src/ui/gui/psppire-cell-renderer-button.c [deleted file]
src/ui/gui/psppire-cell-renderer-button.h [deleted file]
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-editor.h
src/ui/gui/psppire-data-sheet.c
src/ui/gui/psppire-data-sheet.h
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-store.h
src/ui/gui/psppire-data-window.c
src/ui/gui/psppire-delimited-text.c [new file with mode: 0644]
src/ui/gui/psppire-delimited-text.h [new file with mode: 0644]
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dict.h
src/ui/gui/psppire-empty-list-store.c [deleted file]
src/ui/gui/psppire-empty-list-store.h [deleted file]
src/ui/gui/psppire-import-assistant.c
src/ui/gui/psppire-import-assistant.h
src/ui/gui/psppire-text-file.c [new file with mode: 0644]
src/ui/gui/psppire-text-file.h [new file with mode: 0644]
src/ui/gui/psppire-var-sheet-header.c [new file with mode: 0644]
src/ui/gui/psppire-var-sheet-header.h [new file with mode: 0644]
src/ui/gui/psppire-var-sheet.c [deleted file]
src/ui/gui/psppire-var-sheet.h [deleted file]
src/ui/gui/psppire-variable-sheet.c [new file with mode: 0644]
src/ui/gui/psppire-variable-sheet.h [new file with mode: 0644]
src/ui/gui/psppire.gtkrc [deleted file]
src/ui/gui/text-data-import.ui
src/ui/gui/value-variant.c [new file with mode: 0644]
src/ui/gui/value-variant.h [new file with mode: 0644]
src/ui/gui/var-type-dialog.c
src/ui/gui/var-type-dialog.h
src/ui/gui/widgets.c

diff --git a/INSTALL b/INSTALL
index f2e381947fdc521f7af3a9c4fcbb4b758c904d53..835092ede10b29846541546b2682bcbe1b6593d3 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -92,6 +92,8 @@ use the GUI, you must run `configure' with --without-gui.
     * GtkSourceView (http://projects.gnome.org/gtksourceview/) 
       version 3.4.0 or later.
 
+    * GNU Spread Sheet Widget (http://www.gnu.org/software/ssw)
+
 The following packages are optional:
 
 Installing the following packages will allow your PSPP program to read
diff --git a/NEWS b/NEWS
index a7a54c4d43579f70dce91b47f56eaf7f6ee77a50..f253c7b279338489f8bc171ec8c3679de466be77 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,7 @@ See the end for copying conditions.
 
 Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
 
-Changes from 0.10.2 to 0.10.5-pre3:
+Changes from 0.10.2 to 0.10.4
 
  * The REGRESSION command now has a /ORIGIN subcommand to perform
    regression through the origin.
@@ -33,6 +33,9 @@ Changes from 0.10.2 to 0.10.5-pre3:
 
  * Graphical user interface changes:
 
+ ** The code implementing the sheet rendering has been removed.  Instead we
+    use a third party library: spread-sheet-widget.
+
  ** There is a new menu: Edit|Options
 
  ** The Non Parametric Statistics Menu has a new item: "K Independent Samples".
index fc8761ad9076c3e5b34c612d3e3fff6a30590615..6e7984bf988889a7ad6f495cc5009d37df95ec54 100644 (file)
@@ -18,7 +18,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 dnl Initialize.
 AC_PREREQ(2.63)
-AC_INIT([GNU PSPP], [0.10.5-pre3], [bug-gnu-pspp@gnu.org], [pspp])
+AC_INIT([GNU PSPP], [0.10.4], [bug-gnu-pspp@gnu.org], [pspp])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_TESTDIR([tests])
@@ -112,8 +112,11 @@ if test "$with_cairo" != no && test "$with_gui" != "no"; then
   PKG_CHECK_MODULES([GTKSOURCEVIEW], [gtksourceview-3.0 >= 3.4.2], [],
     [PSPP_REQUIRED_PREREQ([gtksourceview 3.0 version 3.4.2 or later (or use --without-gui)])])
 
-  PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.32], [],
-    [PSPP_REQUIRED_PREREQ([glib 2.0 version 2.32 or later (or use --without-gui)])])
+  PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.44], [],
+    [PSPP_REQUIRED_PREREQ([glib 2.0 version 2.44 or later (or use --without-gui)])])
+
+  PKG_CHECK_MODULES([SPREAD_SHEET_WIDGET], [spread-sheet-widget >= 0.0], [],
+    [PSPP_REQUIRED_PREREQ([spread-sheet-widget 0.0 (or use --without-gui)])])
 
   AC_ARG_VAR([GLIB_GENMARSHAL])
   AC_CHECK_PROGS([GLIB_GENMARSHAL], [glib-genmarshal])
index e2c98cc42f834cf407864b6df08ad91497b4621d..dbda6b48a8f9222187ac5e6c2a4050deeba3dbce 100644 (file)
@@ -18,7 +18,3 @@
 
 include $(top_srcdir)/lib/linreg/automake.mk
 include $(top_srcdir)/lib/tukey/automake.mk
-
-if HAVE_GUI
-include $(top_srcdir)/lib/gtk-contrib/automake.mk
-endif
diff --git a/lib/gtk-contrib/COPYING.LESSER b/lib/gtk-contrib/COPYING.LESSER
deleted file mode 100644 (file)
index 8add30a..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-                 GNU LESSER GENERAL PUBLIC LICENSE
-                      Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL.  It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it.  You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
-  When we speak of free software, we are referring to freedom of use,
-not price.  Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
-  To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights.  These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  To protect each distributor, we want to make it very clear that
-there is no warranty for the free library.  Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-\f
-  Finally, software patents pose a constant threat to the existence of
-any free program.  We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder.  Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
-  Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License.  This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License.  We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
-  When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library.  The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom.  The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
-  We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License.  It also provides other free software developers Less
-of an advantage over competing non-free programs.  These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries.  However, the Lesser license provides advantages in certain
-special circumstances.
-
-  For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard.  To achieve this, non-free programs must be
-allowed to use the library.  A more frequent case is that a free
-library does the same job as widely used non-free libraries.  In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
-  In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software.  For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
-  Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-\f
-                 GNU LESSER GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-  
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-\f
-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-\f
-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-\f
-  6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Use a suitable shared library mechanism for linking with the
-    Library.  A suitable mechanism is one that (1) uses at run time a
-    copy of the library already present on the user's computer system,
-    rather than copying library functions into the executable, and (2)
-    will operate properly with a modified version of the library, if
-    the user installs one, as long as the modified version is
-    interface-compatible with the version that the work was made with.
-
-    c) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    d) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    e) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-\f
-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-\f
-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-\f
-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-                           NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-\f
-           How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Lesser General Public
-    License as published by the Free Software Foundation; either
-    version 2.1 of the License, or (at your option) any later version.
-
-    This library 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
-    Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public
-    License along with this library; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/lib/gtk-contrib/README b/lib/gtk-contrib/README
deleted file mode 100644 (file)
index c3ffaf2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-This is not part of the GNU PSPP program, but is used with GNU PSPP.
-
-This directory contains a version of the GtkXPaned widget.  It includes
-minor modifications. GtkXPaned is licensed under the GNU Lesser
-General Public License.  See COPYING.LESSER. 
diff --git a/lib/gtk-contrib/automake.mk b/lib/gtk-contrib/automake.mk
deleted file mode 100644 (file)
index ff1519d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# PSPP - a program for statistical analysis.
-# Copyright (C) 2017 Free Software Foundation, Inc.
-# 
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
-# 
-## Process this file with automake to produce Makefile.in  -*- makefile -*-
-
-noinst_LIBRARIES += lib/gtk-contrib/libxpaned.a
-
-lib_gtk_contrib_libxpaned_a_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
-
-lib_gtk_contrib_libxpaned_a_SOURCES = \
-       lib/gtk-contrib/gtkxpaned.c \
-       lib/gtk-contrib/gtkxpaned.h
-
-EXTRA_DIST += \
-       lib/gtk-contrib/README \
-       lib/gtk-contrib/COPYING.LESSER
-
diff --git a/lib/gtk-contrib/gtkxpaned.c b/lib/gtk-contrib/gtkxpaned.c
deleted file mode 100644 (file)
index 4b98059..0000000
+++ /dev/null
@@ -1,3353 +0,0 @@
-/*******************************************************************************
- **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
- **      10        20        30        40        50        60        70        80
- **
- **  library for GtkXPaned-widget, a 2x2 grid-like variation of GtkPaned of gtk+
- **  Copyright (C) 2012, 2013 Free Software Foundation, Inc.
- **  Copyright (C) 2005-2006 Mirco "MacSlow" Müller <macslow@bangang.de>
- **
- **  This library is free software; you can redistribute it and/or
- **  modify it under the terms of the GNU Lesser General Public
- **  License as published by the Free Software Foundation; either
- **  version 2.1 of the License, or (at your option) any later version.
- **
- **  This library 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
- **  Lesser General Public License for more details.
- **
- **  You should have received a copy of the GNU Lesser General Public
- **  License along with this library; if not, write to the Free Software
- **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- **
- **  GtkXPaned is based on GtkPaned which was done by...
- **
- **  "Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald"
- **
- **  and later modified by...
- **
- **  "the GTK+ Team and others 1997-2000"
- **
- *******************************************************************************/
-
-#include <config.h>
-#include "gtkxpaned.h"
-
-#include <gtk/gtk.h>
-#include <ui/gui/psppire-marshal.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkkeysyms-compat.h>
-
-enum WidgetProperties
-  {
-    PROP_0,
-    PROP_X_POSITION,
-    PROP_Y_POSITION,
-    PROP_POSITION_SET,
-    PROP_MIN_X_POSITION,
-    PROP_MIN_Y_POSITION,
-    PROP_MAX_X_POSITION,
-    PROP_MAX_Y_POSITION
-  };
-
-enum ChildProperties
-  {
-    CHILD_PROP_0,
-    CHILD_PROP_RESIZE,
-    CHILD_PROP_SHRINK
-  };
-
-enum WidgetSignals
-  {
-    CYCLE_CHILD_FOCUS,
-    TOGGLE_HANDLE_FOCUS,
-    MOVE_HANDLE,
-    CYCLE_HANDLE_FOCUS,
-    ACCEPT_POSITION,
-    CANCEL_POSITION,
-    LAST_SIGNAL
-  };
-
-static void gtk_xpaned_class_init (GtkXPanedClass * klass);
-
-static void gtk_xpaned_init (GtkXPaned * xpaned);
-
-static void
-gtk_xpaned_get_preferred_width (GtkWidget *widget,
-                                gint      *minimal_width,
-                                gint      *natural_width)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-  gint tl[2], tr[2], bl[2], br[2];
-  gint overhead;
-  gint w[2];
-  int i;
-
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child))
-    gtk_widget_get_preferred_width (xpaned->top_left_child, &tl[0], &tl[1]);
-  else
-    tl[0] = tl[1] = 0;
-
-  if (xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child))
-    gtk_widget_get_preferred_width (xpaned->top_right_child, &tr[0], &tr[1]);
-  else
-    tr[0] = tr[1] = 0;
-
-  if (xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child))
-    gtk_widget_get_preferred_width (xpaned->bottom_left_child, &bl[0], &bl[1]);
-  else
-    bl[0] = bl[1] = 0;
-
-  if (xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    gtk_widget_get_preferred_width (xpaned->bottom_right_child,
-                                    &br[0], &br[1]);
-  else
-    br[0] = br[1] = 0;
-
-  /* add 2 times the set border-width to the GtkXPaneds requisition */
-  overhead = gtk_container_get_border_width (GTK_CONTAINER (xpaned)) * 2;
-
-  /* also add the handle "thickness" to GtkXPaned's width requisition */
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child)
-      && xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child)
-      && xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child)
-      && xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    {
-      gint handle_size;
-
-      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-      overhead += handle_size;
-    }
-
-  for (i = 0; i < 2; i++)
-    w[i] = (br[i] ? br[i] : MAX (tl[i] + tr[i], bl[i])) + overhead;
-
-  *minimal_width = w[0];
-  *natural_width = w[1];
-}
-
-static void
-gtk_xpaned_get_preferred_height (GtkWidget *widget,
-                                gint      *minimal_height,
-                                gint      *natural_height)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-  gint tl[2], tr[2], bl[2], br[2];
-  gint overhead;
-  gint h[2];
-  int i;
-
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child))
-    gtk_widget_get_preferred_height (xpaned->top_left_child, &tl[0], &tl[1]);
-  else
-    tl[0] = tl[1] = 0;
-
-  if (xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child))
-    gtk_widget_get_preferred_height (xpaned->top_right_child, &tr[0], &tr[1]);
-  else
-    tr[0] = tr[1] = 0;
-
-  if (xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child))
-    gtk_widget_get_preferred_height (xpaned->bottom_left_child,
-                                     &bl[0], &bl[1]);
-  else
-    bl[0] = bl[1] = 0;
-
-  if (xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    gtk_widget_get_preferred_height (xpaned->bottom_right_child,
-                                    &br[0], &br[1]);
-  else
-    br[0] = br[1] = 0;
-
-  /* add 2 times the set border-width to the GtkXPaneds requisition */
-  overhead = gtk_container_get_border_width (GTK_CONTAINER (xpaned)) * 2;
-
-  /* also add the handle "thickness" to GtkXPaned's height-requisition */
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child)
-      && xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child)
-      && xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child)
-      && xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    {
-      gint handle_size;
-
-      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-      overhead += handle_size;
-    }
-
-  for (i = 0; i < 2; i++)
-    h[i] = (br[i] ? br[i] : bl[i] + MAX (tl[i], tr[i])) + overhead;
-
-  *minimal_height = h[0];
-  *natural_height = h[1];
-}
-
-static void gtk_xpaned_size_allocate (GtkWidget * widget,
-                                      GtkAllocation * allocation);
-
-static void gtk_xpaned_set_property (GObject * object,
-                                     guint prop_id,
-                                     const GValue * value,
-                                     GParamSpec * pspec);
-
-static void gtk_xpaned_get_property (GObject * object,
-                                     guint prop_id,
-                                     GValue * value, GParamSpec * pspec);
-
-static void gtk_xpaned_set_child_property (GtkContainer * container,
-                                           GtkWidget * child,
-                                           guint property_id,
-                                           const GValue * value,
-                                           GParamSpec * pspec);
-
-static void gtk_xpaned_get_child_property (GtkContainer * container,
-                                           GtkWidget * child,
-                                           guint property_id,
-                                           GValue * value,
-                                           GParamSpec * pspec);
-
-static void gtk_xpaned_finalize (GObject * object);
-
-static void gtk_xpaned_realize (GtkWidget * widget);
-
-static void gtk_xpaned_unrealize (GtkWidget * widget);
-
-static void gtk_xpaned_map (GtkWidget * widget);
-
-static void gtk_xpaned_unmap (GtkWidget * widget);
-
-static gboolean gtk_xpaned_draw (GtkWidget * widget,
-                                   cairo_t *ct);
-
-static gboolean gtk_xpaned_enter (GtkWidget * widget,
-                                  GdkEventCrossing * event);
-
-static gboolean gtk_xpaned_leave (GtkWidget * widget,
-                                  GdkEventCrossing * event);
-
-static gboolean gtk_xpaned_button_press (GtkWidget * widget,
-                                         GdkEventButton * event);
-
-static gboolean gtk_xpaned_button_release (GtkWidget * widget,
-                                           GdkEventButton * event);
-
-static gboolean gtk_xpaned_motion (GtkWidget * widget,
-                                   GdkEventMotion * event);
-
-static gboolean gtk_xpaned_focus (GtkWidget * widget,
-                                  GtkDirectionType direction);
-
-static void gtk_xpaned_add (GtkContainer * container, GtkWidget * widget);
-
-static void gtk_xpaned_remove (GtkContainer * container, GtkWidget * widget);
-
-static void gtk_xpaned_forall (GtkContainer * container,
-                               gboolean include_internals,
-                               GtkCallback callback, gpointer callback_data);
-
-static void gtk_xpaned_set_focus_child (GtkContainer * container,
-                                        GtkWidget * child);
-
-static void gtk_xpaned_set_saved_focus (GtkXPaned * xpaned,
-                                        GtkWidget * widget);
-
-static void gtk_xpaned_set_first_xpaned (GtkXPaned * xpaned,
-                                         GtkXPaned * first_xpaned);
-
-static void gtk_xpaned_set_last_top_left_child_focus (GtkXPaned * xpaned,
-                                                      GtkWidget * widget);
-
-static void gtk_xpaned_set_last_top_right_child_focus (GtkXPaned * xpaned,
-                                                       GtkWidget * widget);
-
-static void gtk_xpaned_set_last_bottom_left_child_focus (GtkXPaned * xpaned,
-                                                         GtkWidget * widget);
-
-static void gtk_xpaned_set_last_bottom_right_child_focus (GtkXPaned * xpaned,
-                                                          GtkWidget * widget);
-
-static gboolean gtk_xpaned_cycle_child_focus (GtkXPaned * xpaned,
-                                              gboolean reverse);
-
-static gboolean gtk_xpaned_cycle_handle_focus (GtkXPaned * xpaned,
-                                               gboolean reverse);
-
-static gboolean gtk_xpaned_move_handle (GtkXPaned * xpaned,
-                                        GtkScrollType scroll);
-
-static gboolean gtk_xpaned_accept_position (GtkXPaned * xpaned);
-
-static gboolean gtk_xpaned_cancel_position (GtkXPaned * xpaned);
-
-static gboolean gtk_xpaned_toggle_handle_focus (GtkXPaned * xpaned);
-
-static GType gtk_xpaned_child_type (GtkContainer * container);
-
-static GtkContainerClass *parent_class = NULL;
-
-struct _GtkXPanedPrivate
-{
-  GtkWidget *saved_focus;
-  GtkXPaned *first_xpaned;
-};
-
-GType
-gtk_xpaned_get_type (void)
-{
-  static GType xpaned_type = 0;
-
-  if (!xpaned_type)
-    {
-      static const GTypeInfo xpaned_info = {
-        sizeof (GtkXPanedClass),
-        NULL,                   /* base_init */
-        NULL,                   /* base_finalize */
-        (GClassInitFunc) gtk_xpaned_class_init,
-        NULL,                   /* class_finalize */
-        NULL,                   /* class_data */
-        sizeof (GtkXPaned),
-        0,                      /* n_preallocs */
-        (GInstanceInitFunc) gtk_xpaned_init
-      };
-
-      xpaned_type = g_type_register_static (GTK_TYPE_CONTAINER,
-                                            "GtkXPaned", &xpaned_info, 0);
-    }
-
-  return xpaned_type;
-}
-
-GtkWidget *
-gtk_xpaned_new (void)
-{
-  GtkXPaned *xpaned;
-
-  xpaned = g_object_new (GTK_TYPE_XPANED, NULL);
-
-  return GTK_WIDGET (xpaned);
-}
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static void
-add_tab_bindings (GtkBindingSet * binding_set, GdkModifierType modifiers)
-{
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_Tab, modifiers, "toggle_handle_focus", 0);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_KP_Tab,
-                                modifiers, "toggle_handle_focus", 0);
-}
-
-static void
-add_move_binding (GtkBindingSet * binding_set,
-                  guint keyval, GdkModifierType mask, GtkScrollType scroll)
-{
-  gtk_binding_entry_add_signal (binding_set,
-                                keyval,
-                                mask,
-                                "move_handle",
-                                1, GTK_TYPE_SCROLL_TYPE, scroll);
-}
-
-static void
-gtk_xpaned_class_init (GtkXPanedClass * class)
-{
-  GObjectClass *object_class;
-  GtkWidgetClass *widget_class;
-  GtkContainerClass *container_class;
-  GtkXPanedClass *xpaned_class;
-  GtkBindingSet *binding_set;
-
-  object_class = (GObjectClass *) class;
-  widget_class = (GtkWidgetClass *) class;
-  container_class = (GtkContainerClass *) class;
-  xpaned_class = (GtkXPanedClass *) class;
-
-  parent_class = g_type_class_peek_parent (class);
-
-  object_class->set_property = gtk_xpaned_set_property;
-  object_class->get_property = gtk_xpaned_get_property;
-  object_class->finalize = gtk_xpaned_finalize;
-
-  widget_class->realize = gtk_xpaned_realize;
-  widget_class->unrealize = gtk_xpaned_unrealize;
-  widget_class->map = gtk_xpaned_map;
-  widget_class->unmap = gtk_xpaned_unmap;
-  widget_class->draw = gtk_xpaned_draw;
-  widget_class->focus = gtk_xpaned_focus;
-  widget_class->enter_notify_event = gtk_xpaned_enter;
-  widget_class->leave_notify_event = gtk_xpaned_leave;
-  widget_class->button_press_event = gtk_xpaned_button_press;
-  widget_class->button_release_event = gtk_xpaned_button_release;
-  widget_class->motion_notify_event = gtk_xpaned_motion;
-  widget_class->get_preferred_width  = gtk_xpaned_get_preferred_width;
-  widget_class->get_preferred_height = gtk_xpaned_get_preferred_height;
-
-  widget_class->size_allocate = gtk_xpaned_size_allocate;
-
-  container_class->add = gtk_xpaned_add;
-  container_class->remove = gtk_xpaned_remove;
-  container_class->forall = gtk_xpaned_forall;
-  container_class->child_type = gtk_xpaned_child_type;
-  container_class->set_focus_child = gtk_xpaned_set_focus_child;
-  container_class->set_child_property = gtk_xpaned_set_child_property;
-  container_class->get_child_property = gtk_xpaned_get_child_property;
-
-  xpaned_class->cycle_child_focus = gtk_xpaned_cycle_child_focus;
-  xpaned_class->toggle_handle_focus = gtk_xpaned_toggle_handle_focus;
-  xpaned_class->move_handle = gtk_xpaned_move_handle;
-  xpaned_class->cycle_handle_focus = gtk_xpaned_cycle_handle_focus;
-  xpaned_class->accept_position = gtk_xpaned_accept_position;
-  xpaned_class->cancel_position = gtk_xpaned_cancel_position;
-
-  g_object_class_install_property (object_class,
-                                   PROP_X_POSITION,
-                                   g_param_spec_int ("x-position",
-                                                     ("x-Position"),
-                                                     ("x-Position of paned separator in pixels (0 means all the way to the left)"),
-                                                     0,
-                                                     G_MAXINT,
-                                                     0,
-                                                     G_PARAM_READABLE |
-                                                     G_PARAM_WRITABLE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_Y_POSITION,
-                                   g_param_spec_int ("y-position",
-                                                     "y-Position",
-                                                     "y-Position of paned separator in pixels (0 means all the way to the top)",
-                                                     0,
-                                                     G_MAXINT,
-                                                     0,
-                                                     G_PARAM_READABLE |
-                                                     G_PARAM_WRITABLE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_POSITION_SET,
-                                   g_param_spec_boolean ("position-set",
-                                                         "Position Set",
-                                                         "TRUE if the Position property should be used",
-                                                         FALSE,
-                                                         G_PARAM_READABLE |
-                                                         G_PARAM_WRITABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                           g_param_spec_int ("handle-size",
-                                                             "Handle Size",
-                                                             "Width of handle",
-                                                             0,
-                                                             G_MAXINT,
-                                                             3,
-                                                             G_PARAM_READABLE));
-  /**
-   * GtkXPaned:min-x-position:
-   *
-   * The smallest possible value for the x-position property. This property is derived from the
-   * size and shrinkability of the widget's children.
-   *
-   * Since: 2.4
-   */
-  g_object_class_install_property (object_class,
-                                   PROP_MIN_X_POSITION,
-                                   g_param_spec_int ("min-x-position",
-                                                     "Minimal x-Position",
-                                                     "Smallest possible value for the \"x-position\" property",
-                                                     0,
-                                                     G_MAXINT,
-                                                     0, G_PARAM_READABLE));
-
-  /**
-   * GtkXPaned:min-y-position:
-   *
-   * The smallest possible value for the y-position property. This property is derived from the
-   * size and shrinkability of the widget's children.
-   *
-   * Since: 2.4
-   */
-  g_object_class_install_property (object_class,
-                                   PROP_MIN_Y_POSITION,
-                                   g_param_spec_int ("min-y-position",
-                                                     "Minimal y-Position",
-                                                     "Smallest possible value for the \"y-position\" property",
-                                                     0,
-                                                     G_MAXINT,
-                                                     0, G_PARAM_READABLE));
-
-  /**
-   * GtkPaned:max-x-position:
-   *
-   * The largest possible value for the x-position property. This property is derived from the
-   * size and shrinkability of the widget's children.
-   *
-   * Since: 2.4
-   */
-  g_object_class_install_property (object_class,
-                                   PROP_MAX_X_POSITION,
-                                   g_param_spec_int ("max-x-position",
-                                                     "Maximal x-Position",
-                                                     "Largest possible value for the \"x-position\" property",
-                                                     0,
-                                                     G_MAXINT,
-                                                     G_MAXINT,
-                                                     G_PARAM_READABLE));
-
-  /**
-   * GtkPaned:max-y-position:
-   *
-   * The largest possible value for the y-position property. This property is derived from the
-   * size and shrinkability of the widget's children.
-   *
-   * Since: 2.4
-   */
-  g_object_class_install_property (object_class,
-                                   PROP_MAX_Y_POSITION,
-                                   g_param_spec_int ("max-y-position",
-                                                     "Maximal y-Position",
-                                                     "Largest possible value for the \"y-position\" property",
-                                                     0,
-                                                     G_MAXINT,
-                                                     G_MAXINT,
-                                                     G_PARAM_READABLE));
-
-  /**
-   * GtkPaned:resize:
-   *
-   * The "resize" child property determines whether the child expands and
-   * shrinks along with the paned widget.
-   *
-   * Since: 2.4
-   */
-  gtk_container_class_install_child_property (container_class,
-                                              CHILD_PROP_RESIZE,
-                                              g_param_spec_boolean ("resize",
-                                                                    "Resize",
-                                                                    "If TRUE, the child expands and shrinks along with the paned widget",
-                                                                    TRUE,
-                                                                    G_PARAM_READWRITE));
-
-  /**
-   * GtkPaned:shrink:
-   *
-   * The "shrink" child property determines whether the child can be made
-   * smaller than its requisition.
-   *
-   * Since: 2.4
-   */
-  gtk_container_class_install_child_property (container_class,
-                                              CHILD_PROP_SHRINK,
-                                              g_param_spec_boolean ("shrink",
-                                                                    "Shrink",
-                                                                    "If TRUE, the child can be made smaller than its requisition",
-                                                                    TRUE,
-                                                                    G_PARAM_READWRITE));
-
-  signals[CYCLE_CHILD_FOCUS] = g_signal_new ("cycle-child-focus",
-                                             G_TYPE_FROM_CLASS (object_class),
-                                             G_SIGNAL_RUN_LAST |
-                                             G_SIGNAL_ACTION,
-                                             G_STRUCT_OFFSET (GtkXPanedClass,
-                                                              cycle_child_focus),
-                                             NULL, NULL,
-                                             psppire_marshal_BOOLEAN__BOOLEAN,
-                                             G_TYPE_BOOLEAN, 1,
-                                             G_TYPE_BOOLEAN);
-
-  signals[TOGGLE_HANDLE_FOCUS] = g_signal_new ("toggle-handle-focus",
-                                               G_TYPE_FROM_CLASS
-                                               (object_class),
-                                               G_SIGNAL_RUN_LAST |
-                                               G_SIGNAL_ACTION,
-                                               G_STRUCT_OFFSET
-                                               (GtkXPanedClass,
-                                                toggle_handle_focus), NULL,
-                                               NULL,
-                                               psppire_marshal_BOOLEAN__VOID,
-                                               G_TYPE_BOOLEAN, 0);
-
-  signals[MOVE_HANDLE] = g_signal_new ("move-handle",
-                                       G_TYPE_FROM_CLASS (object_class),
-                                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                                       G_STRUCT_OFFSET (GtkXPanedClass,
-                                                        move_handle), NULL,
-                                       NULL, psppire_marshal_BOOLEAN__ENUM,
-                                       G_TYPE_BOOLEAN, 1,
-                                       GTK_TYPE_SCROLL_TYPE);
-
-  signals[CYCLE_HANDLE_FOCUS] = g_signal_new ("cycle-handle-focus",
-                                              G_TYPE_FROM_CLASS
-                                              (object_class),
-                                              G_SIGNAL_RUN_LAST |
-                                              G_SIGNAL_ACTION,
-                                              G_STRUCT_OFFSET (GtkXPanedClass,
-                                                               cycle_handle_focus),
-                                              NULL, NULL,
-                                              psppire_marshal_BOOLEAN__BOOLEAN,
-                                              G_TYPE_BOOLEAN, 1,
-                                              G_TYPE_BOOLEAN);
-
-  signals[ACCEPT_POSITION] = g_signal_new ("accept-position",
-                                           G_TYPE_FROM_CLASS (object_class),
-                                           G_SIGNAL_RUN_LAST |
-                                           G_SIGNAL_ACTION,
-                                           G_STRUCT_OFFSET (GtkXPanedClass,
-                                                            accept_position),
-                                           NULL, NULL,
-                                           psppire_marshal_BOOLEAN__VOID,
-                                           G_TYPE_BOOLEAN, 0);
-
-  signals[CANCEL_POSITION] = g_signal_new ("cancel-position",
-                                           G_TYPE_FROM_CLASS (object_class),
-                                           G_SIGNAL_RUN_LAST |
-                                           G_SIGNAL_ACTION,
-                                           G_STRUCT_OFFSET (GtkXPanedClass,
-                                                            cancel_position),
-                                           NULL, NULL,
-                                           psppire_marshal_BOOLEAN__VOID,
-                                           G_TYPE_BOOLEAN, 0);
-
-  binding_set = gtk_binding_set_by_class (class);
-
-  /* F6 and friends */
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_F6, 0,
-                                "cycle-child-focus", 1,
-                                G_TYPE_BOOLEAN, FALSE);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_F6, GDK_SHIFT_MASK,
-                                "cycle-child-focus", 1, G_TYPE_BOOLEAN, TRUE);
-
-  /* F8 and friends */
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_F8, 0,
-                                "cycle-handle-focus", 1,
-                                G_TYPE_BOOLEAN, FALSE);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_F8, GDK_SHIFT_MASK,
-                                "cycle-handle-focus", 1,
-                                G_TYPE_BOOLEAN, TRUE);
-
-  add_tab_bindings (binding_set, 0);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK);
-  add_tab_bindings (binding_set, GDK_SHIFT_MASK);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
-
-  /* accept and cancel positions */
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_Escape, 0, "cancel-position", 0);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_Return, 0, "accept-position", 0);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_KP_Enter, 0, "accept-position", 0);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_space, 0, "accept-position", 0);
-
-  gtk_binding_entry_add_signal (binding_set,
-                                GDK_KP_Space, 0, "accept-position", 0);
-
-  /* move handle */
-  add_move_binding (binding_set, GDK_Left, 0, GTK_SCROLL_STEP_LEFT);
-  add_move_binding (binding_set, GDK_KP_Left, 0, GTK_SCROLL_STEP_LEFT);
-  add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_LEFT);
-  add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_LEFT);
-
-  add_move_binding (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_RIGHT);
-  add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_RIGHT);
-  add_move_binding (binding_set, GDK_KP_Right, 0, GTK_SCROLL_STEP_RIGHT);
-  add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_RIGHT);
-
-  add_move_binding (binding_set, GDK_Up, 0, GTK_SCROLL_STEP_UP);
-  add_move_binding (binding_set, GDK_Up, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_UP);
-  add_move_binding (binding_set, GDK_KP_Up, 0, GTK_SCROLL_STEP_UP);
-  add_move_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_UP);
-  add_move_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_UP);
-  add_move_binding (binding_set, GDK_KP_Page_Up, 0, GTK_SCROLL_PAGE_UP);
-
-  add_move_binding (binding_set, GDK_Down, 0, GTK_SCROLL_STEP_DOWN);
-  add_move_binding (binding_set, GDK_Down, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_DOWN);
-  add_move_binding (binding_set, GDK_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
-  add_move_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
-                    GTK_SCROLL_PAGE_DOWN);
-  add_move_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
-  add_move_binding (binding_set, GDK_KP_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
-
-  add_move_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START);
-  add_move_binding (binding_set, GDK_KP_Home, 0, GTK_SCROLL_START);
-  add_move_binding (binding_set, GDK_End, 0, GTK_SCROLL_END);
-  add_move_binding (binding_set, GDK_KP_End, 0, GTK_SCROLL_END);
-}
-
-static GType
-gtk_xpaned_child_type (GtkContainer * container)
-{
-  if (!GTK_XPANED (container)->top_left_child ||
-      !GTK_XPANED (container)->top_right_child ||
-      !GTK_XPANED (container)->bottom_left_child ||
-      !GTK_XPANED (container)->bottom_right_child)
-    return GTK_TYPE_WIDGET;
-  else
-    return G_TYPE_NONE;
-}
-
-static void
-gtk_xpaned_init (GtkXPaned * xpaned)
-{
-  gtk_widget_set_can_focus (GTK_WIDGET (xpaned), TRUE);
-  gtk_widget_set_has_window (GTK_WIDGET (xpaned), FALSE);
-
-  xpaned->top_left_child = NULL;
-  xpaned->top_right_child = NULL;
-  xpaned->bottom_left_child = NULL;
-  xpaned->bottom_right_child = NULL;
-  xpaned->handle_east = NULL;
-  xpaned->handle_west = NULL;
-  xpaned->handle_north = NULL;
-  xpaned->handle_south = NULL;
-  xpaned->handle_middle = NULL;
-  xpaned->cursor_type_east = GDK_SB_V_DOUBLE_ARROW;
-  xpaned->cursor_type_west = GDK_SB_V_DOUBLE_ARROW;
-  xpaned->cursor_type_north = GDK_SB_H_DOUBLE_ARROW;
-  xpaned->cursor_type_south = GDK_SB_H_DOUBLE_ARROW;
-  xpaned->cursor_type_middle = GDK_FLEUR;
-
-  xpaned->handle_pos_east.width = 5;
-  xpaned->handle_pos_east.height = 5;
-  xpaned->handle_pos_west.width = 5;
-  xpaned->handle_pos_west.height = 5;
-  xpaned->handle_pos_north.width = 5;
-  xpaned->handle_pos_north.height = 5;
-  xpaned->handle_pos_south.width = 5;
-  xpaned->handle_pos_south.height = 5;
-  xpaned->handle_pos_middle.width = 5;
-  xpaned->handle_pos_middle.height = 5;
-
-  xpaned->position_set = FALSE;
-  xpaned->last_allocation.width = -1;
-  xpaned->last_allocation.height = -1;
-  xpaned->in_drag_vert = FALSE;
-  xpaned->in_drag_horiz = FALSE;
-  xpaned->in_drag_vert_and_horiz = FALSE;
-
-  xpaned->maximized[GTK_XPANED_TOP_LEFT] = FALSE;
-  xpaned->maximized[GTK_XPANED_TOP_RIGHT] = FALSE;
-  xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = FALSE;
-  xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = FALSE;
-
-  xpaned->priv = g_new0 (GtkXPanedPrivate, 1);
-  xpaned->last_top_left_child_focus = NULL;
-  xpaned->last_top_right_child_focus = NULL;
-  xpaned->last_bottom_left_child_focus = NULL;
-  xpaned->last_bottom_right_child_focus = NULL;
-  xpaned->in_recursion = FALSE;
-  xpaned->handle_prelit = FALSE;
-  xpaned->original_position.x = -1;
-  xpaned->original_position.y = -1;
-  xpaned->unmaximized_position.x = -1;
-  xpaned->unmaximized_position.y = -1;
-
-  xpaned->handle_pos_east.x = -1;
-  xpaned->handle_pos_east.y = -1;
-  xpaned->handle_pos_west.x = -1;
-  xpaned->handle_pos_west.y = -1;
-  xpaned->handle_pos_north.x = -1;
-  xpaned->handle_pos_north.y = -1;
-  xpaned->handle_pos_south.x = -1;
-  xpaned->handle_pos_south.y = -1;
-  xpaned->handle_pos_middle.x = -1;
-  xpaned->handle_pos_middle.y = -1;
-
-  xpaned->drag_pos.x = -1;
-  xpaned->drag_pos.y = -1;
-}
-
-void
-gtk_xpaned_compute_position (GtkXPaned * xpaned,
-                             const GtkAllocation * allocation,
-                             GtkRequisition * top_left_child_req,
-                             GtkRequisition * top_right_child_req,
-                             GtkRequisition * bottom_left_child_req,
-                             GtkRequisition * bottom_right_child_req);
-
-
-static void
-gtk_xpaned_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-  gint border_width = gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-  GtkAllocation top_left_child_allocation;
-  GtkAllocation top_right_child_allocation;
-  GtkAllocation bottom_left_child_allocation;
-  GtkAllocation bottom_right_child_allocation;
-  GtkRequisition top_left_child_requisition;
-  GtkRequisition top_right_child_requisition;
-  GtkRequisition bottom_left_child_requisition;
-  GtkRequisition bottom_right_child_requisition;
-  gint handle_size;
-
-  /* determine size of handle(s) */
-  gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-
-  gtk_widget_set_allocation (widget, allocation);
-
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child)
-      && xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child)
-      && xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child)
-      && xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    {
-      /* what sizes do the children want to be at least at */
-      gtk_widget_get_preferred_size (xpaned->top_left_child,
-                                     &top_left_child_requisition, NULL);
-      gtk_widget_get_preferred_size (xpaned->top_right_child,
-                                     &top_right_child_requisition, NULL);
-      gtk_widget_get_preferred_size (xpaned->bottom_left_child,
-                                     &bottom_left_child_requisition, NULL);
-      gtk_widget_get_preferred_size (xpaned->bottom_right_child,
-                                     &bottom_right_child_requisition, NULL);
-
-      /* determine the total requisition-sum of all requisitions of borders,
-       * handles, children etc. */
-      gtk_xpaned_compute_position (xpaned,
-                                   allocation,
-                                   &top_left_child_requisition,
-                                   &top_right_child_requisition,
-                                   &bottom_left_child_requisition,
-                                   &bottom_right_child_requisition);
-
-      /* calculate the current positions and sizes of the handles */
-      xpaned->handle_pos_east.x =
-        allocation->x + border_width +
-        xpaned->top_left_child_size.width + handle_size;
-      xpaned->handle_pos_east.y =
-        allocation->y + border_width +
-        xpaned->top_left_child_size.height;
-      xpaned->handle_pos_east.width =
-        allocation->width - xpaned->top_left_child_size.width -
-        2 * border_width - handle_size;
-      xpaned->handle_pos_east.height = handle_size;
-
-      xpaned->handle_pos_west.x = allocation->x + border_width;
-      xpaned->handle_pos_west.y = xpaned->handle_pos_east.y;
-      xpaned->handle_pos_west.width =
-        allocation->width - xpaned->handle_pos_east.width -
-        2 * border_width - handle_size;
-      xpaned->handle_pos_west.height = handle_size;
-
-      xpaned->handle_pos_north.x = xpaned->handle_pos_east.x - handle_size;
-      xpaned->handle_pos_north.y = allocation->y + border_width;
-      xpaned->handle_pos_north.width = handle_size;
-      xpaned->handle_pos_north.height =
-        xpaned->handle_pos_east.y - allocation->y - border_width;
-
-      xpaned->handle_pos_south.x = xpaned->handle_pos_north.x;
-      xpaned->handle_pos_south.y = xpaned->handle_pos_east.y + handle_size;
-      xpaned->handle_pos_south.width = handle_size;
-      xpaned->handle_pos_south.height =
-        allocation->height - xpaned->handle_pos_north.height -
-        2 * border_width - handle_size;
-
-
-#define CENTRUM 20
-      xpaned->handle_pos_middle.x = xpaned->handle_pos_north.x;
-      xpaned->handle_pos_middle.y = xpaned->handle_pos_east.y;
-      xpaned->handle_pos_middle.width = handle_size + CENTRUM;
-      xpaned->handle_pos_middle.height = handle_size + CENTRUM;
-
-      /* set allocation for top-left child */
-      top_left_child_allocation.x = allocation->x + border_width;
-      top_left_child_allocation.y = allocation->y + border_width;
-      top_left_child_allocation.width = xpaned->handle_pos_west.width;
-      top_left_child_allocation.height = xpaned->handle_pos_north.height;
-
-      /* set allocation for top-right child */
-      top_right_child_allocation.x =
-        allocation->x + border_width + handle_size +
-        top_left_child_allocation.width;
-      top_right_child_allocation.y = allocation->y + border_width;
-      top_right_child_allocation.width = xpaned->handle_pos_east.width;
-      top_right_child_allocation.height = xpaned->handle_pos_north.height;
-
-      /* set allocation for bottom-left child */
-      bottom_left_child_allocation.x = xpaned->handle_pos_west.x;
-      bottom_left_child_allocation.y = xpaned->handle_pos_south.y;
-      bottom_left_child_allocation.width = xpaned->handle_pos_west.width;
-      bottom_left_child_allocation.height = xpaned->handle_pos_south.height;
-
-      /* set allocation for bottom-right child */
-      bottom_right_child_allocation.x = top_right_child_allocation.x;
-      bottom_right_child_allocation.y = bottom_left_child_allocation.y;
-      bottom_right_child_allocation.width = xpaned->handle_pos_east.width;
-      bottom_right_child_allocation.height = xpaned->handle_pos_south.height;
-
-      if (gtk_widget_get_realized (widget))
-        {
-          if (gtk_widget_get_mapped (widget))
-            {
-              gdk_window_show (xpaned->handle_east);
-              gdk_window_show (xpaned->handle_west);
-              gdk_window_show (xpaned->handle_north);
-              gdk_window_show (xpaned->handle_south);
-              gdk_window_show (xpaned->handle_middle);
-            }
-
-          gdk_window_move_resize (xpaned->handle_east,
-                                  xpaned->handle_pos_east.x,
-                                  xpaned->handle_pos_east.y,
-                                  xpaned->handle_pos_east.width,
-                                  xpaned->handle_pos_east.height);
-
-          gdk_window_move_resize (xpaned->handle_west,
-                                  xpaned->handle_pos_west.x,
-                                  xpaned->handle_pos_west.y,
-                                  xpaned->handle_pos_west.width,
-                                  xpaned->handle_pos_west.height);
-
-          gdk_window_move_resize (xpaned->handle_north,
-                                  xpaned->handle_pos_north.x,
-                                  xpaned->handle_pos_north.y,
-                                  xpaned->handle_pos_north.width,
-                                  xpaned->handle_pos_north.height);
-
-          gdk_window_move_resize (xpaned->handle_south,
-                                  xpaned->handle_pos_south.x,
-                                  xpaned->handle_pos_south.y,
-                                  xpaned->handle_pos_south.width,
-                                  xpaned->handle_pos_south.height);
-
-          gdk_window_move_resize (xpaned->handle_middle,
-                                  xpaned->handle_pos_middle.x,
-                                  xpaned->handle_pos_middle.y,
-                                  xpaned->handle_pos_middle.width,
-                                  xpaned->handle_pos_middle.height);
-        }
-
-      /* Now allocate the childen, making sure, when resizing not to
-       * overlap the windows
-       */
-      if (gtk_widget_get_mapped (widget))
-        {
-          gtk_widget_size_allocate (xpaned->top_right_child,
-                                    &top_right_child_allocation);
-          gtk_widget_size_allocate (xpaned->top_left_child,
-                                    &top_left_child_allocation);
-          gtk_widget_size_allocate (xpaned->bottom_left_child,
-                                    &bottom_left_child_allocation);
-          gtk_widget_size_allocate (xpaned->bottom_right_child,
-                                    &bottom_right_child_allocation);
-        }
-    }
-}
-
-static void
-gtk_xpaned_set_property (GObject * object,
-                         guint prop_id,
-                         const GValue * value, GParamSpec * pspec)
-{
-  GtkXPaned *xpaned = GTK_XPANED (object);
-
-  switch (prop_id)
-    {
-    case PROP_X_POSITION:
-      gtk_xpaned_set_position_x (xpaned, g_value_get_int (value));
-      break;
-
-    case PROP_Y_POSITION:
-      gtk_xpaned_set_position_y (xpaned, g_value_get_int (value));
-      break;
-
-    case PROP_POSITION_SET:
-      xpaned->position_set = g_value_get_boolean (value);
-      gtk_widget_queue_resize (GTK_WIDGET (xpaned));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_xpaned_get_property (GObject * object,
-                         guint prop_id, GValue * value, GParamSpec * pspec)
-{
-  GtkXPaned *xpaned = GTK_XPANED (object);
-
-  switch (prop_id)
-    {
-    case PROP_X_POSITION:
-      g_value_set_int (value, xpaned->top_left_child_size.width);
-      break;
-
-    case PROP_Y_POSITION:
-      g_value_set_int (value, xpaned->top_left_child_size.height);
-      break;
-
-    case PROP_POSITION_SET:
-      g_value_set_boolean (value, xpaned->position_set);
-      break;
-
-    case PROP_MIN_X_POSITION:
-      g_value_set_int (value, xpaned->min_position.x);
-      break;
-
-    case PROP_MIN_Y_POSITION:
-      g_value_set_int (value, xpaned->min_position.y);
-      break;
-
-    case PROP_MAX_X_POSITION:
-      g_value_set_int (value, xpaned->max_position.x);
-      break;
-
-    case PROP_MAX_Y_POSITION:
-      g_value_set_int (value, xpaned->max_position.y);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_xpaned_set_child_property (GtkContainer * container,
-                               GtkWidget * child,
-                               guint property_id,
-                               const GValue * value, GParamSpec * pspec)
-{
-  GtkXPaned *xpaned = GTK_XPANED (container);
-  gboolean old_value = FALSE;
-  gboolean new_value = FALSE;
-
-  g_assert (child == xpaned->top_left_child ||
-            child == xpaned->top_right_child ||
-            child == xpaned->bottom_left_child ||
-            child == xpaned->bottom_right_child);
-
-  new_value = g_value_get_boolean (value);
-
-  switch (property_id)
-    {
-    case CHILD_PROP_RESIZE:
-      if (child == xpaned->top_left_child)
-        {
-          old_value = xpaned->top_left_child_resize;
-          xpaned->top_left_child_resize = new_value;
-        }
-      else if (child == xpaned->top_right_child)
-        {
-          old_value = xpaned->top_right_child_resize;
-          xpaned->top_right_child_resize = new_value;
-        }
-      else if (child == xpaned->bottom_left_child)
-        {
-          old_value = xpaned->bottom_left_child_resize;
-          xpaned->bottom_left_child_resize = new_value;
-        }
-      else if (child == xpaned->bottom_right_child)
-        {
-          old_value = xpaned->bottom_right_child_resize;
-          xpaned->bottom_right_child_resize = new_value;
-        }
-      break;
-
-    case CHILD_PROP_SHRINK:
-      if (child == xpaned->top_left_child)
-        {
-          old_value = xpaned->top_left_child_shrink;
-          xpaned->top_left_child_shrink = new_value;
-        }
-      else if (child == xpaned->top_right_child)
-        {
-          old_value = xpaned->top_right_child_shrink;
-          xpaned->top_right_child_shrink = new_value;
-        }
-      else if (child == xpaned->bottom_left_child)
-        {
-          old_value = xpaned->bottom_left_child_shrink;
-          xpaned->bottom_left_child_shrink = new_value;
-        }
-      else if (child == xpaned->bottom_right_child)
-        {
-          old_value = xpaned->bottom_right_child_shrink;
-          xpaned->bottom_right_child_shrink = new_value;
-        }
-      break;
-
-    default:
-      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
-                                                    property_id, pspec);
-      old_value = -1;           /* quiet gcc */
-      break;
-    }
-
-  if (old_value != new_value)
-    gtk_widget_queue_resize (GTK_WIDGET (container));
-}
-
-static void
-gtk_xpaned_get_child_property (GtkContainer * container,
-                               GtkWidget * child,
-                               guint property_id,
-                               GValue * value, GParamSpec * pspec)
-{
-  GtkXPaned *xpaned = GTK_XPANED (container);
-
-  g_assert (child == xpaned->top_left_child ||
-            child == xpaned->top_right_child ||
-            child == xpaned->bottom_left_child ||
-            child == xpaned->bottom_right_child);
-
-  switch (property_id)
-    {
-    case CHILD_PROP_RESIZE:
-      if (child == xpaned->top_left_child)
-        g_value_set_boolean (value, xpaned->top_left_child_resize);
-      else if (child == xpaned->top_right_child)
-        g_value_set_boolean (value, xpaned->top_right_child_resize);
-      else if (child == xpaned->bottom_left_child)
-        g_value_set_boolean (value, xpaned->bottom_left_child_resize);
-      else if (child == xpaned->bottom_right_child)
-        g_value_set_boolean (value, xpaned->bottom_right_child_resize);
-      break;
-
-    case CHILD_PROP_SHRINK:
-      if (child == xpaned->top_left_child)
-        g_value_set_boolean (value, xpaned->top_left_child_shrink);
-      else if (child == xpaned->top_right_child)
-        g_value_set_boolean (value, xpaned->top_right_child_shrink);
-      else if (child == xpaned->bottom_left_child)
-        g_value_set_boolean (value, xpaned->bottom_left_child_shrink);
-      else if (child == xpaned->bottom_right_child)
-        g_value_set_boolean (value, xpaned->bottom_right_child_shrink);
-      break;
-
-    default:
-      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
-                                                    property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_xpaned_finalize (GObject * object)
-{
-  GtkXPaned *xpaned = GTK_XPANED (object);
-
-  gtk_xpaned_set_saved_focus (xpaned, NULL);
-  gtk_xpaned_set_first_xpaned (xpaned, NULL);
-
-  g_free (xpaned->priv);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gtk_xpaned_realize (GtkWidget * widget)
-{
-  GtkXPaned *xpaned;
-  GdkWindowAttr attributes_east;
-  GdkWindowAttr attributes_west;
-  GdkWindowAttr attributes_north;
-  GdkWindowAttr attributes_south;
-  GdkWindowAttr attributes_middle;
-  gint attributes_mask_east;
-  gint attributes_mask_west;
-  gint attributes_mask_north;
-  gint attributes_mask_south;
-  gint attributes_mask_middle;
-
-  gtk_widget_set_realized (widget, TRUE);
-  xpaned = GTK_XPANED (widget);
-
-  gtk_widget_set_window (widget, gtk_widget_get_parent_window (widget));
-  //  g_object_ref (widget->window);
-
-  attributes_east.window_type = GDK_WINDOW_CHILD;
-  attributes_west.window_type = GDK_WINDOW_CHILD;
-  attributes_north.window_type = GDK_WINDOW_CHILD;
-  attributes_south.window_type = GDK_WINDOW_CHILD;
-  attributes_middle.window_type = GDK_WINDOW_CHILD;
-
-  attributes_east.wclass = GDK_INPUT_ONLY;
-  attributes_west.wclass = GDK_INPUT_ONLY;
-  attributes_north.wclass = GDK_INPUT_ONLY;
-  attributes_south.wclass = GDK_INPUT_ONLY;
-  attributes_middle.wclass = GDK_INPUT_ONLY;
-
-  attributes_east.x = xpaned->handle_pos_east.x;
-  attributes_east.y = xpaned->handle_pos_east.y;
-  attributes_east.width = xpaned->handle_pos_east.width;
-  attributes_east.height = xpaned->handle_pos_east.height;
-
-  attributes_west.x = xpaned->handle_pos_west.x;
-  attributes_west.y = xpaned->handle_pos_west.y;
-  attributes_west.width = xpaned->handle_pos_west.width;
-  attributes_west.height = xpaned->handle_pos_west.height;
-
-  attributes_north.x = xpaned->handle_pos_north.x;
-  attributes_north.y = xpaned->handle_pos_north.y;
-  attributes_north.width = xpaned->handle_pos_north.width;
-  attributes_north.height = xpaned->handle_pos_north.height;
-
-  attributes_south.x = xpaned->handle_pos_south.x;
-  attributes_south.y = xpaned->handle_pos_south.y;
-  attributes_south.width = xpaned->handle_pos_south.width;
-  attributes_south.height = xpaned->handle_pos_south.height;
-
-  attributes_middle.x = xpaned->handle_pos_middle.x;
-  attributes_middle.y = xpaned->handle_pos_middle.y;
-  attributes_middle.width = xpaned->handle_pos_middle.width;
-  attributes_middle.height = xpaned->handle_pos_middle.height;
-
-  attributes_east.cursor =
-    gdk_cursor_new_for_display (gtk_widget_get_display (widget),
-                                xpaned->cursor_type_east);
-  attributes_west.cursor =
-    gdk_cursor_new_for_display (gtk_widget_get_display (widget),
-                                xpaned->cursor_type_west);
-  attributes_north.cursor =
-    gdk_cursor_new_for_display (gtk_widget_get_display (widget),
-                                xpaned->cursor_type_north);
-  attributes_south.cursor =
-    gdk_cursor_new_for_display (gtk_widget_get_display (widget),
-                                xpaned->cursor_type_south);
-  attributes_middle.cursor =
-    gdk_cursor_new_for_display (gtk_widget_get_display (widget),
-                                xpaned->cursor_type_middle);
-
-  attributes_east.event_mask = gtk_widget_get_events (widget);
-  attributes_west.event_mask = gtk_widget_get_events (widget);
-  attributes_north.event_mask = gtk_widget_get_events (widget);
-  attributes_south.event_mask = gtk_widget_get_events (widget);
-  attributes_middle.event_mask = gtk_widget_get_events (widget);
-
-  attributes_east.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                                 GDK_BUTTON_RELEASE_MASK |
-                                 GDK_ENTER_NOTIFY_MASK |
-                                 GDK_LEAVE_NOTIFY_MASK |
-                                 GDK_POINTER_MOTION_MASK |
-                                 GDK_POINTER_MOTION_HINT_MASK);
-  attributes_west.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                                 GDK_BUTTON_RELEASE_MASK |
-                                 GDK_ENTER_NOTIFY_MASK |
-                                 GDK_LEAVE_NOTIFY_MASK |
-                                 GDK_POINTER_MOTION_MASK |
-                                 GDK_POINTER_MOTION_HINT_MASK);
-  attributes_north.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                                  GDK_BUTTON_RELEASE_MASK |
-                                  GDK_ENTER_NOTIFY_MASK |
-                                  GDK_LEAVE_NOTIFY_MASK |
-                                  GDK_POINTER_MOTION_MASK |
-                                  GDK_POINTER_MOTION_HINT_MASK);
-  attributes_south.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                                  GDK_BUTTON_RELEASE_MASK |
-                                  GDK_ENTER_NOTIFY_MASK |
-                                  GDK_LEAVE_NOTIFY_MASK |
-                                  GDK_POINTER_MOTION_MASK |
-                                  GDK_POINTER_MOTION_HINT_MASK);
-  attributes_middle.event_mask |= (GDK_BUTTON_PRESS_MASK |
-                                   GDK_BUTTON_RELEASE_MASK |
-                                   GDK_ENTER_NOTIFY_MASK |
-                                   GDK_LEAVE_NOTIFY_MASK |
-                                   GDK_POINTER_MOTION_MASK |
-                                   GDK_POINTER_MOTION_HINT_MASK);
-
-  attributes_mask_east = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
-  attributes_mask_west = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
-  attributes_mask_north = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
-  attributes_mask_south = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
-  attributes_mask_middle = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
-
-  xpaned->handle_east = gdk_window_new (gtk_widget_get_window (widget),
-                                        &attributes_east,
-                                        attributes_mask_east);
-  xpaned->handle_west = gdk_window_new (gtk_widget_get_window (widget),
-                                        &attributes_west,
-                                        attributes_mask_west);
-  xpaned->handle_north = gdk_window_new (gtk_widget_get_window (widget),
-                                         &attributes_north,
-                                         attributes_mask_north);
-  xpaned->handle_south = gdk_window_new (gtk_widget_get_window (widget),
-                                         &attributes_south,
-                                         attributes_mask_south);
-  xpaned->handle_middle = gdk_window_new (gtk_widget_get_window (widget),
-                                          &attributes_middle,
-                                          attributes_mask_middle);
-
-  gdk_window_set_user_data (xpaned->handle_east, xpaned);
-  gdk_window_set_user_data (xpaned->handle_west, xpaned);
-  gdk_window_set_user_data (xpaned->handle_north, xpaned);
-  gdk_window_set_user_data (xpaned->handle_south, xpaned);
-  gdk_window_set_user_data (xpaned->handle_middle, xpaned);
-
-  g_object_unref (attributes_east.cursor);
-  g_object_unref (attributes_west.cursor);
-  g_object_unref (attributes_north.cursor);
-  g_object_unref (attributes_south.cursor);
-  g_object_unref (attributes_middle.cursor);
-
-  if (xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child)
-      && xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child)
-      && xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child)
-      && xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    {
-      gdk_window_show (xpaned->handle_east);
-      gdk_window_show (xpaned->handle_west);
-      gdk_window_show (xpaned->handle_north);
-      gdk_window_show (xpaned->handle_south);
-      gdk_window_show (xpaned->handle_middle);
-    }
-}
-
-static void
-gtk_xpaned_unrealize (GtkWidget * widget)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  if (xpaned->handle_east)
-    {
-      gdk_window_set_user_data (xpaned->handle_east, NULL);
-      gdk_window_destroy (xpaned->handle_east);
-      xpaned->handle_east = NULL;
-    }
-
-  if (xpaned->handle_west)
-    {
-      gdk_window_set_user_data (xpaned->handle_west, NULL);
-      gdk_window_destroy (xpaned->handle_west);
-      xpaned->handle_west = NULL;
-    }
-
-  if (xpaned->handle_north)
-    {
-      gdk_window_set_user_data (xpaned->handle_north, NULL);
-      gdk_window_destroy (xpaned->handle_north);
-      xpaned->handle_north = NULL;
-    }
-
-  if (xpaned->handle_south)
-    {
-      gdk_window_set_user_data (xpaned->handle_south, NULL);
-      gdk_window_destroy (xpaned->handle_south);
-      xpaned->handle_south = NULL;
-    }
-
-  if (xpaned->handle_middle)
-    {
-      gdk_window_set_user_data (xpaned->handle_middle, NULL);
-      gdk_window_destroy (xpaned->handle_middle);
-      xpaned->handle_middle = NULL;
-    }
-
-  gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
-  gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
-  gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
-  gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
-  gtk_xpaned_set_saved_focus (xpaned, NULL);
-  gtk_xpaned_set_first_xpaned (xpaned, NULL);
-
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
-static void
-gtk_xpaned_map (GtkWidget * widget)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  gdk_window_show (xpaned->handle_east);
-  gdk_window_show (xpaned->handle_west);
-  gdk_window_show (xpaned->handle_north);
-  gdk_window_show (xpaned->handle_south);
-  gdk_window_show (xpaned->handle_middle);
-
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
-}
-
-static void
-gtk_xpaned_unmap (GtkWidget * widget)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  gdk_window_hide (xpaned->handle_east);
-  gdk_window_hide (xpaned->handle_west);
-  gdk_window_hide (xpaned->handle_north);
-  gdk_window_hide (xpaned->handle_south);
-  gdk_window_hide (xpaned->handle_middle);
-
-  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
-}
-
-static gboolean
-gtk_xpaned_draw (GtkWidget * widget, cairo_t *cr)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-  gint handle_size;
-
-  /* determine size of handle(s) */
-  gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-
-  /* I want the handle-"thickness" to be at least 3 */
-  g_assert (handle_size >= 3);
-
-  if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
-      xpaned->top_left_child
-      && gtk_widget_get_visible (xpaned->top_left_child)
-      && xpaned->top_right_child
-      && gtk_widget_get_visible (xpaned->top_right_child)
-      && xpaned->bottom_left_child
-      && gtk_widget_get_visible (xpaned->bottom_left_child)
-      && xpaned->bottom_right_child
-      && gtk_widget_get_visible (xpaned->bottom_right_child))
-    {
-      GtkStyleContext *context;
-
-      context = gtk_widget_get_style_context (widget);
-      gtk_render_handle (context, cr,
-                         xpaned->handle_pos_east.x - handle_size - 256 / 2,
-                         xpaned->handle_pos_west.y + 1,
-                         256 + handle_size, handle_size - 2);
-
-      gtk_render_handle (context, cr,
-                         xpaned->handle_pos_north.x + 1,
-                         xpaned->handle_pos_south.y - handle_size - 256 / 2,
-                         handle_size - 2, 256 + handle_size);
-    }
-
-  /* Chain up to draw children */
-  GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
-
-  return FALSE;
-}
-
-static gboolean
-is_rtl (GtkXPaned * xpaned)
-{
-  if (gtk_widget_get_direction (GTK_WIDGET (xpaned)) == GTK_TEXT_DIR_RTL)
-    return TRUE;
-
-  return FALSE;
-}
-
-static void
-update_drag (GtkXPaned * xpaned)
-{
-  GdkPoint pos;
-  GtkWidget *widget = GTK_WIDGET (xpaned);
-  gint handle_size;
-  GtkRequisition size;
-  GtkAllocation allocation;
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  gdk_window_get_device_position (gtk_widget_get_window (widget),
-                                  gdk_device_manager_get_client_pointer (
-                                    gdk_display_get_device_manager (
-                                      gtk_widget_get_display (widget))),
-                                  &pos.x, &pos.y, NULL);
-  if (!gtk_widget_get_has_window (widget))
-    {
-      pos.x -= allocation.x;
-      pos.y -= allocation.y;
-    }
-
-  if (xpaned->in_drag_vert)
-    {
-      pos.y -= xpaned->drag_pos.y;
-
-      if (is_rtl (xpaned))
-        {
-          gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-
-          size.height = allocation.height - pos.y - handle_size;
-        }
-      else
-        {
-          size.height = pos.y;
-        }
-
-      size.height -= gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-
-      size.height =
-        CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
-
-      if (size.height != xpaned->top_left_child_size.height)
-        gtk_xpaned_set_position_y (xpaned, size.height);
-    }
-
-  if (xpaned->in_drag_horiz)
-    {
-      pos.x -= xpaned->drag_pos.x;
-
-      if (is_rtl (xpaned))
-        {
-          gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-
-          size.width = allocation.width - pos.x - handle_size;
-        }
-      else
-        {
-          size.width = pos.x;
-        }
-
-      size.width -= gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-
-      size.width =
-        CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
-
-      if (size.width != xpaned->top_left_child_size.width)
-        gtk_xpaned_set_position_x (xpaned, size.width);
-    }
-
-  if (xpaned->in_drag_vert_and_horiz)
-    {
-      pos.x -= xpaned->drag_pos.x;
-      pos.y -= xpaned->drag_pos.y;
-
-      if (is_rtl (xpaned))
-        {
-          gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
-
-          size.width = allocation.width - pos.x - handle_size;
-          size.height = allocation.height - pos.y - handle_size;
-        }
-      else
-        {
-          size.width = pos.x;
-          size.height = pos.y;
-        }
-
-      size.width -= gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-      size.height -= gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-
-      size.width =
-        CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
-      size.height =
-        CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
-
-      if (size.width != xpaned->top_left_child_size.width)
-        gtk_xpaned_set_position_x (xpaned, size.width);
-
-      if (size.height != xpaned->top_left_child_size.height)
-        gtk_xpaned_set_position_y (xpaned, size.height);
-    }
-}
-
-static gboolean
-gtk_xpaned_enter (GtkWidget * widget, GdkEventCrossing * event)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  if (xpaned->in_drag_vert ||
-      xpaned->in_drag_horiz || xpaned->in_drag_vert_and_horiz)
-    update_drag (xpaned);
-  else
-    {
-      xpaned->handle_prelit = TRUE;
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_east.x,
-                                  xpaned->handle_pos_east.y,
-                                  xpaned->handle_pos_east.width,
-                                  xpaned->handle_pos_east.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_west.x,
-                                  xpaned->handle_pos_west.y,
-                                  xpaned->handle_pos_west.width,
-                                  xpaned->handle_pos_west.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_north.x,
-                                  xpaned->handle_pos_north.y,
-                                  xpaned->handle_pos_north.width,
-                                  xpaned->handle_pos_north.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_south.x,
-                                  xpaned->handle_pos_south.y,
-                                  xpaned->handle_pos_south.width,
-                                  xpaned->handle_pos_south.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_middle.x,
-                                  xpaned->handle_pos_middle.y,
-                                  xpaned->handle_pos_middle.width,
-                                  xpaned->handle_pos_middle.height);
-    }
-
-  return TRUE;
-}
-
-static gboolean
-gtk_xpaned_leave (GtkWidget * widget, GdkEventCrossing * event)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  if (xpaned->in_drag_vert ||
-      xpaned->in_drag_horiz || xpaned->in_drag_vert_and_horiz)
-    update_drag (xpaned);
-  else
-    {
-      xpaned->handle_prelit = FALSE;
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_east.x,
-                                  xpaned->handle_pos_east.y,
-                                  xpaned->handle_pos_east.width,
-                                  xpaned->handle_pos_east.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_west.x,
-                                  xpaned->handle_pos_west.y,
-                                  xpaned->handle_pos_west.width,
-                                  xpaned->handle_pos_west.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_north.x,
-                                  xpaned->handle_pos_north.y,
-                                  xpaned->handle_pos_north.width,
-                                  xpaned->handle_pos_north.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_south.x,
-                                  xpaned->handle_pos_south.y,
-                                  xpaned->handle_pos_south.width,
-                                  xpaned->handle_pos_south.height);
-
-      gtk_widget_queue_draw_area (widget,
-                                  xpaned->handle_pos_middle.x,
-                                  xpaned->handle_pos_middle.y,
-                                  xpaned->handle_pos_middle.width,
-                                  xpaned->handle_pos_middle.height);
-    }
-
-  return TRUE;
-}
-
-static gboolean
-gtk_xpaned_focus (GtkWidget * widget, GtkDirectionType direction)
-{
-  gboolean retval;
-
-  /* This is a hack, but how can this be done without
-   * excessive cut-and-paste from gtkcontainer.c?
-   */
-
-  gtk_widget_set_can_focus (GTK_WIDGET (widget), FALSE);
-  retval = (*GTK_WIDGET_CLASS (parent_class)->focus) (widget, direction);
-  gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE);
-
-  return retval;
-}
-
-static void
-gtk_xpaned_button_press_grab (GdkWindow *handle, GdkEventButton *event)
-{
-  /* We need a server grab here, not gtk_grab_add(), since
-   * we don't want to pass events on to the widget's children */
-  gdk_device_grab (event->device, handle,
-                   GDK_OWNERSHIP_NONE,
-                   FALSE,
-                   (GDK_POINTER_MOTION_HINT_MASK
-                    | GDK_BUTTON1_MOTION_MASK
-                    | GDK_BUTTON_RELEASE_MASK
-                    | GDK_ENTER_NOTIFY_MASK
-                    | GDK_LEAVE_NOTIFY_MASK),
-                   NULL, event->time);
-}
-
-static gboolean
-gtk_xpaned_button_press (GtkWidget * widget, GdkEventButton * event)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  /* if any child is currently maximized, jump right back */
-  if (xpaned->maximized[GTK_XPANED_TOP_LEFT] ||
-      xpaned->maximized[GTK_XPANED_TOP_RIGHT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-    return FALSE;
-
-  /* if user is dragging the handles around */
-  if (!xpaned->in_drag_vert_and_horiz &&
-      event->window != xpaned->handle_east &&
-      event->window != xpaned->handle_west &&
-      event->window != xpaned->handle_north &&
-      event->window != xpaned->handle_south &&
-      event->window == xpaned->handle_middle && event->button == 1)
-    {
-      xpaned->in_drag_vert_and_horiz = TRUE;
-      gtk_xpaned_button_press_grab (xpaned->handle_middle, event);
-      xpaned->drag_pos.x = event->x;
-      xpaned->drag_pos.y = event->y;
-
-      return TRUE;
-    }
-  else if (!xpaned->in_drag_vert &&
-           event->window == xpaned->handle_east &&
-           event->window != xpaned->handle_west &&
-           event->window != xpaned->handle_north &&
-           event->window != xpaned->handle_south &&
-           event->window != xpaned->handle_middle && event->button == 1)
-    {
-      xpaned->in_drag_vert = TRUE;
-      gtk_xpaned_button_press_grab (xpaned->handle_east, event);
-      xpaned->drag_pos.y = event->y;
-
-      return TRUE;
-    }
-  else if (!xpaned->in_drag_vert &&
-           event->window != xpaned->handle_east &&
-           event->window == xpaned->handle_west &&
-           event->window != xpaned->handle_north &&
-           event->window != xpaned->handle_south &&
-           event->window != xpaned->handle_middle && event->button == 1)
-    {
-      xpaned->in_drag_vert = TRUE;
-      gtk_xpaned_button_press_grab (xpaned->handle_west, event);
-      xpaned->drag_pos.y = event->y;
-
-      return TRUE;
-    }
-  else if (!xpaned->in_drag_horiz &&
-           event->window != xpaned->handle_east &&
-           event->window != xpaned->handle_west &&
-           event->window == xpaned->handle_north &&
-           event->window != xpaned->handle_south &&
-           event->window != xpaned->handle_middle && event->button == 1)
-    {
-      xpaned->in_drag_horiz = TRUE;
-      gtk_xpaned_button_press_grab (xpaned->handle_north, event);
-      xpaned->drag_pos.x = event->x;
-
-      return TRUE;
-    }
-  else if (!xpaned->in_drag_horiz &&
-           event->window != xpaned->handle_east &&
-           event->window != xpaned->handle_west &&
-           event->window != xpaned->handle_north &&
-           event->window == xpaned->handle_south &&
-           event->window != xpaned->handle_middle && event->button == 1)
-    {
-      xpaned->in_drag_horiz = TRUE;
-      gtk_xpaned_button_press_grab (xpaned->handle_south, event);
-      xpaned->drag_pos.x = event->x;
-
-      return TRUE;
-    }
-  return FALSE;
-}
-
-static gboolean
-gtk_xpaned_button_release (GtkWidget * widget, GdkEventButton * event)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  if (xpaned->in_drag_vert && (event->button == 1))
-    {
-      xpaned->in_drag_vert = FALSE;
-      xpaned->drag_pos.y = -1;
-      xpaned->position_set = TRUE;
-      gdk_device_ungrab (event->device, event->time);
-      return TRUE;
-    }
-  else if (xpaned->in_drag_horiz && (event->button == 1))
-    {
-      xpaned->in_drag_horiz = FALSE;
-      xpaned->drag_pos.x = -1;
-      xpaned->position_set = TRUE;
-      gdk_device_ungrab (event->device, event->time);
-      return TRUE;
-    }
-  else if (xpaned->in_drag_vert_and_horiz && (event->button == 1))
-    {
-      xpaned->in_drag_vert_and_horiz = FALSE;
-      xpaned->drag_pos.x = -1;
-      xpaned->drag_pos.y = -1;
-      xpaned->position_set = TRUE;
-      gdk_device_ungrab (event->device, event->time);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_xpaned_motion (GtkWidget * widget, GdkEventMotion * event)
-{
-  GtkXPaned *xpaned = GTK_XPANED (widget);
-
-  if (xpaned->in_drag_vert ||
-      xpaned->in_drag_horiz || xpaned->in_drag_vert_and_horiz)
-
-    {
-      update_drag (xpaned);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-void
-gtk_xpaned_add_top_left (GtkXPaned * xpaned, GtkWidget * widget)
-{
-  gtk_xpaned_pack_top_left (xpaned, widget, FALSE, TRUE);
-}
-
-void
-gtk_xpaned_add_top_right (GtkXPaned * xpaned, GtkWidget * widget)
-{
-  gtk_xpaned_pack_top_right (xpaned, widget, FALSE, TRUE);
-}
-
-void
-gtk_xpaned_add_bottom_left (GtkXPaned * xpaned, GtkWidget * widget)
-{
-  gtk_xpaned_pack_bottom_left (xpaned, widget, FALSE, TRUE);
-}
-
-void
-gtk_xpaned_add_bottom_right (GtkXPaned * xpaned, GtkWidget * widget)
-{
-  gtk_xpaned_pack_bottom_right (xpaned, widget, FALSE, TRUE);
-}
-
-void
-gtk_xpaned_pack_top_left (GtkXPaned * xpaned,
-                          GtkWidget * child, gboolean resize, gboolean shrink)
-{
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  if (!xpaned->top_left_child)
-    {
-      xpaned->top_left_child = child;
-      xpaned->top_left_child_resize = resize;
-      xpaned->top_left_child_shrink = shrink;
-
-      gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
-    }
-}
-
-void
-gtk_xpaned_pack_top_right (GtkXPaned * xpaned,
-                           GtkWidget * child,
-                           gboolean resize, gboolean shrink)
-{
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  if (!xpaned->top_right_child)
-    {
-      xpaned->top_right_child = child;
-      xpaned->top_right_child_resize = resize;
-      xpaned->top_right_child_shrink = shrink;
-
-      gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
-    }
-}
-
-void
-gtk_xpaned_pack_bottom_left (GtkXPaned * xpaned,
-                             GtkWidget * child,
-                             gboolean resize, gboolean shrink)
-{
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  if (!xpaned->bottom_left_child)
-    {
-      xpaned->bottom_left_child = child;
-      xpaned->bottom_left_child_resize = resize;
-      xpaned->bottom_left_child_shrink = shrink;
-
-      gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
-    }
-}
-
-void
-gtk_xpaned_pack_bottom_right (GtkXPaned * xpaned,
-                              GtkWidget * child,
-                              gboolean resize, gboolean shrink)
-{
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  if (!xpaned->bottom_right_child)
-    {
-      xpaned->bottom_right_child = child;
-      xpaned->bottom_right_child_resize = resize;
-      xpaned->bottom_right_child_shrink = shrink;
-
-      gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
-    }
-}
-
-static void
-gtk_xpaned_add (GtkContainer * container, GtkWidget * widget)
-{
-  GtkXPaned *xpaned;
-
-  g_return_if_fail (GTK_IS_XPANED (container));
-
-  xpaned = GTK_XPANED (container);
-
-  if (!xpaned->top_left_child)
-    gtk_xpaned_add_top_left (xpaned, widget);
-  else if (!xpaned->top_right_child)
-    gtk_xpaned_add_top_right (xpaned, widget);
-  else if (!xpaned->bottom_left_child)
-    gtk_xpaned_add_bottom_left (xpaned, widget);
-  else if (!xpaned->bottom_right_child)
-    gtk_xpaned_add_bottom_right (xpaned, widget);
-  else
-    g_warning ("GtkXPaned cannot have more than 4 children\n");
-}
-
-static void
-gtk_xpaned_remove (GtkContainer * container, GtkWidget * widget)
-{
-  GtkXPaned *xpaned;
-  gboolean was_visible;
-
-  xpaned = GTK_XPANED (container);
-  was_visible = gtk_widget_get_visible (widget);
-
-  if (xpaned->top_left_child == widget)
-    {
-      gtk_widget_unparent (widget);
-
-      xpaned->top_left_child = NULL;
-
-      if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
-        gtk_widget_queue_resize (GTK_WIDGET (container));
-    }
-  else if (xpaned->top_right_child == widget)
-    {
-      gtk_widget_unparent (widget);
-
-      xpaned->top_right_child = NULL;
-
-      if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
-        gtk_widget_queue_resize (GTK_WIDGET (container));
-    }
-  else if (xpaned->bottom_left_child == widget)
-    {
-      gtk_widget_unparent (widget);
-
-      xpaned->bottom_left_child = NULL;
-
-      if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
-        gtk_widget_queue_resize (GTK_WIDGET (container));
-    }
-  else if (xpaned->bottom_right_child == widget)
-    {
-      gtk_widget_unparent (widget);
-
-      xpaned->bottom_right_child = NULL;
-
-      if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
-        gtk_widget_queue_resize (GTK_WIDGET (container));
-    }
-  else
-    g_warning ("GtkXPaned has no more children attached\n");
-
-}
-
-static void
-gtk_xpaned_forall (GtkContainer * container,
-                   gboolean include_internals,
-                   GtkCallback callback, gpointer callback_data)
-{
-  GtkXPaned *xpaned;
-
-  g_return_if_fail (callback != NULL);
-
-  xpaned = GTK_XPANED (container);
-
-  if (xpaned->top_left_child)
-    (*callback) (xpaned->top_left_child, callback_data);
-  if (xpaned->top_right_child)
-    (*callback) (xpaned->top_right_child, callback_data);
-  if (xpaned->bottom_left_child)
-    (*callback) (xpaned->bottom_left_child, callback_data);
-  if (xpaned->bottom_right_child)
-    (*callback) (xpaned->bottom_right_child, callback_data);
-}
-
-/**
- * gtk_xpaned_get_position_x:
- * @paned: a #GtkXPaned widget
- *
- * Obtains the x-position of the divider.
- *
- * Return value: x-position of the divider
- **/
-gint
-gtk_xpaned_get_position_x (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
-
-  return xpaned->top_left_child_size.width;
-}
-
-/**
- * gtk_xpaned_get_position_y:
- * @paned: a #GtkXPaned widget
- *
- * Obtains the y-position of the divider.
- *
- * Return value: y-position of the divider
- **/
-gint
-gtk_xpaned_get_position_y (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
-
-  return xpaned->top_left_child_size.height;
-}
-
-/**
- * gtk_xpaned_set_position_x:
- * @paned: a #GtkXPaned widget
- * @xposition: pixel x-position of divider, a negative values
- *                        of a component mean that the position is unset.
- *
- * Sets the x-position of the divider between the four panes.
- **/
-void
-gtk_xpaned_set_position_x (GtkXPaned * xpaned, gint xposition)
-{
-  GObject *object;
-
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-
-  /* if any child is currently maximized, jump right back */
-  if (xpaned->maximized[GTK_XPANED_TOP_LEFT] ||
-      xpaned->maximized[GTK_XPANED_TOP_RIGHT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-    return;
-
-  object = G_OBJECT (xpaned);
-
-  if (xposition >= 0)
-    {
-      /* We don't clamp here - the assumption is that
-       * if the total allocation changes at the same time
-       * as the position, the position set is with reference
-       * to the new total size. If only the position changes,
-       * then clamping will occur in gtk_paned_compute_position()
-       */
-
-      xpaned->top_left_child_size.width = xposition;
-      xpaned->position_set = TRUE;
-    }
-  else
-    {
-      xpaned->position_set = FALSE;
-    }
-
-  g_object_freeze_notify (object);
-  g_object_notify (object, "x-position");
-  g_object_notify (object, "position-set");
-  g_object_thaw_notify (object);
-
-  gtk_widget_queue_resize (GTK_WIDGET (xpaned));
-}
-
-/**
- * gtk_xpaned_set_position_y:
- * @paned: a #GtkXPaned widget
- * @yposition: pixel y-position of divider, a negative values
- *                        of a component mean that the position is unset.
- *
- * Sets the y-position of the divider between the four panes.
- **/
-void
-gtk_xpaned_set_position_y (GtkXPaned * xpaned, gint yposition)
-{
-  GObject *object;
-
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-
-  /* if any child is currently maximized, jump right back */
-  if (xpaned->maximized[GTK_XPANED_TOP_LEFT] ||
-      xpaned->maximized[GTK_XPANED_TOP_RIGHT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
-      xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-    return;
-
-  object = G_OBJECT (xpaned);
-
-  if (yposition >= 0)
-    {
-      /* We don't clamp here - the assumption is that
-       * if the total allocation changes at the same time
-       * as the position, the position set is with reference
-       * to the new total size. If only the position changes,
-       * then clamping will occur in gtk_paned_compute_position()
-       */
-
-      xpaned->top_left_child_size.height = yposition;
-      xpaned->position_set = TRUE;
-    }
-  else
-    {
-      xpaned->position_set = FALSE;
-    }
-
-  g_object_freeze_notify (object);
-  g_object_notify (object, "y-position");
-  g_object_notify (object, "position-set");
-  g_object_thaw_notify (object);
-
-  gtk_widget_queue_resize (GTK_WIDGET (xpaned));
-}
-
-/* this call is private and only intended for internal use! */
-void
-gtk_xpaned_save_unmaximized_x (GtkXPaned * xpaned)
-{
-  xpaned->unmaximized_position.x = gtk_xpaned_get_position_x (xpaned);
-}
-
-/* this call is private and only intended for internal use! */
-void
-gtk_xpaned_save_unmaximized_y (GtkXPaned * xpaned)
-{
-  xpaned->unmaximized_position.y = gtk_xpaned_get_position_y (xpaned);
-}
-
-/* this call is private and only intended for internal use! */
-gint
-gtk_xpaned_fetch_unmaximized_x (GtkXPaned * xpaned)
-{
-  return xpaned->unmaximized_position.x;
-}
-
-/* this call is private and only intended for internal use! */
-gint
-gtk_xpaned_fetch_unmaximized_y (GtkXPaned * xpaned)
-{
-  return xpaned->unmaximized_position.y;
-}
-
-/**
- * gtk_xpaned_get_top_left_child:
- * @xpaned: a #GtkXPaned widget
- *
- * Obtains the top-left child of the xpaned widget.
- *
- * Return value: top-left child, or %NULL if it is not set.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_xpaned_get_top_left_child (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
-
-  return xpaned->top_left_child;
-}
-
-/**
- * gtk_xpaned_get_top_right_child:
- * @xpaned: a #GtkXPaned widget
- *
- * Obtains the top-right child of the xpaned widget.
- *
- * Return value: top-right child, or %NULL if it is not set.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_xpaned_get_top_right_child (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
-
-  return xpaned->top_right_child;
-}
-
-/**
- * gtk_xpaned_get_bottom_left_child:
- * @xpaned: a #GtkXPaned widget
- *
- * Obtains the bottom-left child of the xpaned widget.
- *
- * Return value: bottom-left child, or %NULL if it is not set.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_xpaned_get_bottom_left_child (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
-
-  return xpaned->bottom_left_child;
-}
-
-/**
- * gtk_xpaned_get_bottom_right_child:
- * @xpaned: a #GtkXPaned widget
- *
- * Obtains the bottom-right child of the xpaned widget.
- *
- * Return value: bottom-right child, or %NULL if it is not set.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_xpaned_get_bottom_right_child (GtkXPaned * xpaned)
-{
-  g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
-
-  return xpaned->bottom_right_child;
-}
-
-gboolean
-gtk_xpaned_maximize_top_left (GtkXPaned * xpaned, gboolean maximize)
-{
-  if (maximize)
-    {
-      /* see if any child is already maximized */
-      if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-        {
-          /* save current position */
-          gtk_xpaned_save_unmaximized_x (xpaned);
-          gtk_xpaned_save_unmaximized_y (xpaned);
-
-          /* set new maximized position */
-          gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
-          gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
-
-          /* mark maximized flag for top-left child */
-          xpaned->maximized[GTK_XPANED_TOP_LEFT] = TRUE;
-
-          return TRUE;
-        }
-      /* already one child maximized, report error */
-      else
-        return FALSE;
-    }
-  else
-    {
-      /* verify that top-left child is really currently maximized */
-      if (xpaned->maximized[GTK_XPANED_TOP_LEFT])
-        {
-          /* clear maximized flat for top-left child */
-          xpaned->maximized[GTK_XPANED_TOP_LEFT] = FALSE;
-
-          /* restore unmaximized position */
-          gtk_xpaned_set_position_x (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_x (xpaned));
-          gtk_xpaned_set_position_y (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_y (xpaned));
-
-          return TRUE;
-        }
-      /* top-left child is currently not maximized, report error */
-      else
-        return FALSE;
-    }
-}
-
-gboolean
-gtk_xpaned_maximize_top_right (GtkXPaned * xpaned, gboolean maximize)
-{
-  if (maximize)
-    {
-      /* see if any child is already maximized */
-      if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-        {
-          /* save current position */
-          gtk_xpaned_save_unmaximized_x (xpaned);
-          gtk_xpaned_save_unmaximized_y (xpaned);
-
-          /* set new maximized position */
-          gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
-          gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
-
-          /* mark maximized flag for top-right child */
-          xpaned->maximized[GTK_XPANED_TOP_RIGHT] = TRUE;
-
-          return TRUE;
-        }
-      /* already one child maximized, report error */
-      else
-        return FALSE;
-    }
-  else
-    {
-      /* verify that top-right child is really currently maximized */
-      if (xpaned->maximized[GTK_XPANED_TOP_RIGHT])
-        {
-          /* clear maximized flat for top-right child */
-          xpaned->maximized[GTK_XPANED_TOP_RIGHT] = FALSE;
-
-          /* restore unmaximized position */
-          gtk_xpaned_set_position_x (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_x (xpaned));
-          gtk_xpaned_set_position_y (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_y (xpaned));
-
-          return TRUE;
-        }
-      /* top-right child is currently not maximized, report error */
-      else
-        return FALSE;
-    }
-}
-
-gboolean
-gtk_xpaned_maximize_bottom_left (GtkXPaned * xpaned, gboolean maximize)
-{
-  if (maximize)
-    {
-      /* see if any child is already maximized */
-      if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-        {
-          /* save current position */
-          gtk_xpaned_save_unmaximized_x (xpaned);
-          gtk_xpaned_save_unmaximized_y (xpaned);
-
-          /* set new maximized position */
-          gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
-          gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
-
-          /* mark maximized flag for bottom-left child */
-          xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = TRUE;
-
-          return TRUE;
-        }
-      /* already one child maximized, report error */
-      else
-        return FALSE;
-    }
-  else
-    {
-      /* verify that bottom-left child is really currently maximized */
-      if (xpaned->maximized[GTK_XPANED_BOTTOM_LEFT])
-        {
-          /* clear maximized flat for bottom-left child */
-          xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = FALSE;
-
-          /* restore unmaximized position */
-          gtk_xpaned_set_position_x (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_x (xpaned));
-          gtk_xpaned_set_position_y (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_y (xpaned));
-
-          return TRUE;
-        }
-      /* bottom-left child is currently not maximized, report error */
-      else
-        return FALSE;
-    }
-}
-
-gboolean
-gtk_xpaned_maximize_bottom_right (GtkXPaned * xpaned, gboolean maximize)
-{
-  if (maximize)
-    {
-      /* see if any child is already maximized */
-      if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
-          !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-        {
-          /* save current position */
-          gtk_xpaned_save_unmaximized_x (xpaned);
-          gtk_xpaned_save_unmaximized_y (xpaned);
-
-          /* set new maximized position */
-          gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
-          gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
-
-          /* mark maximized flag for bottom-right child */
-          xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = TRUE;
-
-          return TRUE;
-        }
-      /* already one child maximized, report error */
-      else
-        return FALSE;
-    }
-  else
-    {
-      /* verify that bottom-right child is really currently maximized */
-      if (xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
-        {
-          /* clear maximized flat for bottom-right child */
-          xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = FALSE;
-
-          /* restore unmaximized position */
-          gtk_xpaned_set_position_x (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_x (xpaned));
-          gtk_xpaned_set_position_y (xpaned,
-                                     gtk_xpaned_fetch_unmaximized_y (xpaned));
-
-          return TRUE;
-        }
-      /* bottom-right child is currently not maximized, report error */
-      else
-        return FALSE;
-    }
-}
-
-void
-gtk_xpaned_compute_position (GtkXPaned * xpaned,
-                             const GtkAllocation * allocation,
-                             GtkRequisition * top_left_child_req,
-                             GtkRequisition * top_right_child_req,
-                             GtkRequisition * bottom_left_child_req,
-                             GtkRequisition * bottom_right_child_req)
-{
-  GdkPoint old_position;
-  GdkPoint old_min_position;
-  GdkPoint old_max_position;
-  gint handle_size;
-  gint border_width = gtk_container_get_border_width (GTK_CONTAINER (xpaned));
-
-  g_return_if_fail (GTK_IS_XPANED (xpaned));
-
-  old_position.x = xpaned->top_left_child_size.width;
-  old_position.y = xpaned->top_left_child_size.height;
-  old_min_position.x = xpaned->min_position.x;
-  old_min_position.y = xpaned->min_position.y;
-  old_max_position.x = xpaned->max_position.x;
-  old_max_position.y = xpaned->max_position.y;
-
-  xpaned->min_position.x =
-    xpaned->top_left_child_shrink ? 0 : top_left_child_req->width;
-  xpaned->min_position.y =
-    xpaned->top_left_child_shrink ? 0 : top_left_child_req->height;
-
-  gtk_widget_style_get (GTK_WIDGET (xpaned), "handle-size", &handle_size,
-                        NULL);
-
-  xpaned->max_position.x = allocation->width - 2 * border_width - handle_size;
-  xpaned->max_position.y =
-    allocation->height - 2 * border_width - handle_size;
-  if (!xpaned->top_left_child_shrink)
-    xpaned->max_position.x =
-      MAX (1, xpaned->max_position.x - top_left_child_req->width);
-  xpaned->max_position.x =
-    MAX (xpaned->min_position.x, xpaned->max_position.x);
-
-  if (!xpaned->position_set)
-    {
-      if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
-        {
-          xpaned->top_left_child_size.width =
-            MAX (0, allocation->width - top_right_child_req->width);
-          xpaned->top_left_child_size.height =
-            MAX (0, allocation->height - top_right_child_req->height);
-        }
-      else if (!xpaned->top_left_child_resize
-               && xpaned->top_right_child_resize)
-        {
-          xpaned->top_left_child_size.width = top_left_child_req->width;
-          xpaned->top_left_child_size.height = top_left_child_req->height;
-        }
-      else
-        {
-          xpaned->top_left_child_size.width = allocation->width * 0.5 + 0.5;
-          xpaned->top_left_child_size.height = allocation->height * 0.5 + 0.5;
-        }
-    }
-  else
-    {
-      /* If the position was set before the initial allocation.
-      ** (paned->last_allocation <= 0) just clamp it and leave it. */
-      if (xpaned->last_allocation.width > 0)
-        {
-          if (xpaned->top_left_child_resize
-              && !xpaned->top_right_child_resize)
-            {
-              xpaned->top_left_child_size.width += allocation->width
-                - xpaned->last_allocation.width;
-
-              xpaned->top_left_child_size.height += allocation->height
-                - xpaned->last_allocation.height;
-            }
-          else
-            if (!
-                (!xpaned->top_left_child_resize
-                 && xpaned->top_right_child_resize))
-              {
-                xpaned->top_left_child_size.width = allocation->width
-                  * ((gdouble) xpaned->top_left_child_size.width /
-                     (xpaned->last_allocation.width)) + 0.5;
-
-                xpaned->top_left_child_size.height = allocation->height
-                  * ((gdouble) xpaned->top_left_child_size.height /
-                     (xpaned->last_allocation.height)) + 0.5;
-              }
-        }
-      if (xpaned->last_allocation.height > 0)
-        {
-          if (xpaned->top_left_child_resize
-              && !xpaned->top_right_child_resize)
-            {
-              xpaned->top_left_child_size.width +=
-                allocation->width - xpaned->last_allocation.width;
-              xpaned->top_left_child_size.height +=
-                allocation->height - xpaned->last_allocation.height;
-            }
-          else
-            if (!
-                (!xpaned->top_left_child_resize
-                 && xpaned->top_right_child_resize))
-              {
-                xpaned->top_left_child_size.width =
-                  allocation->width *
-                  ((gdouble) xpaned->top_left_child_size.width /
-                   (xpaned->last_allocation.width)) + 0.5;
-                xpaned->top_left_child_size.height =
-                  allocation->height *
-                  ((gdouble) xpaned->top_left_child_size.height /
-                   (xpaned->last_allocation.height)) + 0.5;
-              }
-        }
-
-    }
-
-  xpaned->top_left_child_size.width =
-    CLAMP (xpaned->top_left_child_size.width, xpaned->min_position.x,
-           xpaned->max_position.x);
-  xpaned->top_left_child_size.height =
-    CLAMP (xpaned->top_left_child_size.height, xpaned->min_position.y,
-           xpaned->max_position.y);
-
-  xpaned->top_right_child_size.width =
-    CLAMP (xpaned->top_right_child_size.width, xpaned->min_position.x,
-           xpaned->max_position.x);
-  xpaned->top_right_child_size.height =
-    CLAMP (xpaned->top_right_child_size.height, xpaned->min_position.y,
-           xpaned->max_position.y);
-
-  xpaned->bottom_left_child_size.width =
-    CLAMP (xpaned->bottom_left_child_size.width, xpaned->min_position.x,
-           xpaned->max_position.x);
-  xpaned->bottom_left_child_size.height =
-    CLAMP (xpaned->bottom_left_child_size.height, xpaned->min_position.y,
-           xpaned->max_position.y);
-
-  xpaned->bottom_right_child_size.width =
-    CLAMP (xpaned->bottom_right_child_size.width, xpaned->min_position.x,
-           xpaned->max_position.x);
-  xpaned->bottom_right_child_size.height =
-    CLAMP (xpaned->bottom_right_child_size.height, xpaned->min_position.y,
-           xpaned->max_position.y);
-
-  gtk_widget_set_child_visible (xpaned->top_left_child, TRUE);
-  gtk_widget_set_child_visible (xpaned->top_right_child, TRUE);
-  gtk_widget_set_child_visible (xpaned->bottom_left_child, TRUE);
-  gtk_widget_set_child_visible (xpaned->bottom_right_child, TRUE);
-
-  g_object_freeze_notify (G_OBJECT (xpaned));
-
-  if (xpaned->top_left_child_size.width != old_position.x)
-    g_object_notify (G_OBJECT (xpaned), "x-position");
-  if (xpaned->top_left_child_size.height != old_position.y)
-    g_object_notify (G_OBJECT (xpaned), "y-position");
-
-  if (xpaned->top_right_child_size.width != old_position.x)
-    g_object_notify (G_OBJECT (xpaned), "x-position");
-  if (xpaned->top_right_child_size.height != old_position.y)
-    g_object_notify (G_OBJECT (xpaned), "y-position");
-
-  if (xpaned->bottom_left_child_size.width != old_position.x)
-    g_object_notify (G_OBJECT (xpaned), "x-position");
-  if (xpaned->bottom_left_child_size.height != old_position.y)
-    g_object_notify (G_OBJECT (xpaned), "y-position");
-
-  if (xpaned->bottom_right_child_size.width != old_position.x)
-    g_object_notify (G_OBJECT (xpaned), "x-position");
-  if (xpaned->bottom_right_child_size.height != old_position.y)
-    g_object_notify (G_OBJECT (xpaned), "y-position");
-
-  if (xpaned->min_position.x != old_min_position.x)
-    g_object_notify (G_OBJECT (xpaned), "min-x-position");
-  if (xpaned->min_position.y != old_min_position.y)
-    g_object_notify (G_OBJECT (xpaned), "min-y-position");
-
-  if (xpaned->max_position.x != old_max_position.x)
-    g_object_notify (G_OBJECT (xpaned), "max-y-position");
-  if (xpaned->max_position.y != old_max_position.y)
-    g_object_notify (G_OBJECT (xpaned), "max-y-position");
-
-  g_object_thaw_notify (G_OBJECT (xpaned));
-
-  xpaned->last_allocation.width = allocation->width;
-  xpaned->last_allocation.height = allocation->height;
-}
-
-static void
-gtk_xpaned_set_saved_focus (GtkXPaned * xpaned, GtkWidget * widget)
-{
-  if (xpaned->priv->saved_focus)
-    g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
-                                  (gpointer *) & (xpaned->priv->saved_focus));
-
-  xpaned->priv->saved_focus = widget;
-
-  if (xpaned->priv->saved_focus)
-    g_object_add_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
-                               (gpointer *) & (xpaned->priv->saved_focus));
-}
-
-static void
-gtk_xpaned_set_first_xpaned (GtkXPaned * xpaned, GtkXPaned * first_xpaned)
-{
-  if (xpaned->priv->first_xpaned)
-    g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
-                                  (gpointer *) & (xpaned->priv->
-                                                  first_xpaned));
-
-  xpaned->priv->first_xpaned = first_xpaned;
-
-  if (xpaned->priv->first_xpaned)
-    g_object_add_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
-                               (gpointer *) & (xpaned->priv->first_xpaned));
-}
-
-static void
-gtk_xpaned_set_last_top_left_child_focus (GtkXPaned * xpaned,
-                                          GtkWidget * widget)
-{
-  if (xpaned->last_top_left_child_focus)
-    g_object_remove_weak_pointer (G_OBJECT
-                                  (xpaned->last_top_left_child_focus),
-                                  (gpointer *) & (xpaned->
-                                                  last_top_left_child_focus));
-
-  xpaned->last_top_left_child_focus = widget;
-
-  if (xpaned->last_top_left_child_focus)
-    g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_left_child_focus),
-                               (gpointer *) & (xpaned->
-                                               last_top_left_child_focus));
-}
-
-static void
-gtk_xpaned_set_last_top_right_child_focus (GtkXPaned * xpaned,
-                                           GtkWidget * widget)
-{
-  if (xpaned->last_top_right_child_focus)
-    g_object_remove_weak_pointer (G_OBJECT
-                                  (xpaned->last_top_right_child_focus),
-                                  (gpointer *) & (xpaned->
-                                                  last_top_right_child_focus));
-
-  xpaned->last_top_right_child_focus = widget;
-
-  if (xpaned->last_top_right_child_focus)
-    g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_right_child_focus),
-                               (gpointer *) & (xpaned->
-                                               last_top_right_child_focus));
-}
-
-static void
-gtk_xpaned_set_last_bottom_left_child_focus (GtkXPaned * xpaned,
-                                             GtkWidget * widget)
-{
-  if (xpaned->last_bottom_left_child_focus)
-    g_object_remove_weak_pointer (G_OBJECT
-                                  (xpaned->last_bottom_left_child_focus),
-                                  (gpointer *) & (xpaned->
-                                                  last_bottom_left_child_focus));
-
-  xpaned->last_bottom_left_child_focus = widget;
-
-  if (xpaned->last_bottom_left_child_focus)
-    g_object_add_weak_pointer (G_OBJECT
-                               (xpaned->last_bottom_left_child_focus),
-                               (gpointer *) & (xpaned->
-                                               last_bottom_left_child_focus));
-}
-
-static void
-gtk_xpaned_set_last_bottom_right_child_focus (GtkXPaned * xpaned,
-                                              GtkWidget * widget)
-{
-  if (xpaned->last_bottom_right_child_focus)
-    g_object_remove_weak_pointer (G_OBJECT
-                                  (xpaned->last_bottom_right_child_focus),
-                                  (gpointer *) & (xpaned->
-                                                  last_bottom_right_child_focus));
-
-  xpaned->last_bottom_right_child_focus = widget;
-
-  if (xpaned->last_bottom_right_child_focus)
-    g_object_add_weak_pointer (G_OBJECT
-                               (xpaned->last_bottom_right_child_focus),
-                               (gpointer *) & (xpaned->
-                                               last_bottom_right_child_focus));
-}
-
-static GtkWidget *
-xpaned_get_focus_widget (GtkXPaned * xpaned)
-{
-  GtkWidget *toplevel;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
-  if (gtk_widget_is_toplevel (toplevel))
-    return gtk_window_get_focus (GTK_WINDOW (toplevel));
-
-  return NULL;
-}
-
-static void
-gtk_xpaned_set_focus_child (GtkContainer * container, GtkWidget * focus_child)
-{
-  GtkXPaned *xpaned;
-
-  g_return_if_fail (GTK_IS_XPANED (container));
-
-  xpaned = GTK_XPANED (container);
-
-  if (focus_child == NULL)
-    {
-      GtkWidget *last_focus;
-      GtkWidget *w;
-
-      last_focus = xpaned_get_focus_widget (xpaned);
-
-      if (last_focus)
-        {
-          /* If there is one or more paned widgets between us and the
-           * focus widget, we want the topmost of those as last_focus
-           */
-          for (w = last_focus; w != GTK_WIDGET (xpaned); w = gtk_widget_get_parent (w))
-            if (GTK_IS_XPANED (w))
-              last_focus = w;
-
-          if (gtk_container_get_focus_child (container) == xpaned->top_left_child)
-            gtk_xpaned_set_last_top_left_child_focus (xpaned, last_focus);
-          else if (gtk_container_get_focus_child (container) == xpaned->top_right_child)
-            gtk_xpaned_set_last_top_right_child_focus (xpaned, last_focus);
-          else if (gtk_container_get_focus_child (container) == xpaned->bottom_left_child)
-            gtk_xpaned_set_last_bottom_left_child_focus (xpaned, last_focus);
-          else if (gtk_container_get_focus_child (container) == xpaned->bottom_right_child)
-            gtk_xpaned_set_last_bottom_right_child_focus (xpaned, last_focus);
-        }
-    }
-
-  if (parent_class->set_focus_child)
-    (*parent_class->set_focus_child) (container, focus_child);
-}
-
-static void
-gtk_xpaned_get_cycle_chain (GtkXPaned * xpaned,
-                            GtkDirectionType direction, GList ** widgets)
-{
-  GtkContainer *container = GTK_CONTAINER (xpaned);
-  GtkWidget *ancestor = NULL;
-  GList *temp_list = NULL;
-  GList *list;
-
-  if (xpaned->in_recursion)
-    return;
-
-  g_assert (widgets != NULL);
-
-  if (xpaned->last_top_left_child_focus &&
-      !gtk_widget_is_ancestor (xpaned->last_top_left_child_focus,
-                               GTK_WIDGET (xpaned)))
-    {
-      gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
-    }
-
-  if (xpaned->last_top_right_child_focus &&
-      !gtk_widget_is_ancestor (xpaned->last_top_right_child_focus,
-                               GTK_WIDGET (xpaned)))
-    {
-      gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
-    }
-
-  if (xpaned->last_bottom_left_child_focus &&
-      !gtk_widget_is_ancestor (xpaned->last_bottom_left_child_focus,
-                               GTK_WIDGET (xpaned)))
-    {
-      gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
-    }
-
-  if (xpaned->last_bottom_right_child_focus &&
-      !gtk_widget_is_ancestor (xpaned->last_bottom_right_child_focus,
-                               GTK_WIDGET (xpaned)))
-    {
-      gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
-    }
-
-  if (gtk_widget_get_parent (GTK_WIDGET (xpaned)))
-    ancestor = gtk_widget_get_ancestor (gtk_widget_get_parent (GTK_WIDGET (xpaned)),
-                                        GTK_TYPE_XPANED);
-
-  /* The idea here is that temp_list is a list of widgets we want to cycle
-   * to. The list is prioritized so that the first element is our first
-   * choice, the next our second, and so on.
-   *
-   * We can't just use g_list_reverse(), because we want to try
-   * paned->last_child?_focus before paned->child?, both when we
-   * are going forward and backward.
-   */
-  if (direction == GTK_DIR_TAB_FORWARD)
-    {
-      if (gtk_container_get_focus_child (container) == xpaned->top_left_child)
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_right_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->top_right_child)
-        {
-          temp_list = g_list_append (temp_list, ancestor);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->bottom_left_child)
-        {
-          temp_list = g_list_append (temp_list, ancestor);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->bottom_right_child)
-        {
-          temp_list = g_list_append (temp_list, ancestor);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_left_child);
-        }
-      else
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_left_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_right_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-    }
-  else
-    {
-      if (gtk_container_get_focus_child (container) == xpaned->top_left_child)
-        {
-          temp_list = g_list_append (temp_list, ancestor);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_right_child);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->top_right_child)
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->bottom_right_child)
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->top_right_child)
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-      else
-        {
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_right_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_right_child);
-          temp_list =
-            g_list_append (temp_list, xpaned->last_top_left_child_focus);
-          temp_list = g_list_append (temp_list, xpaned->top_left_child);
-          temp_list = g_list_append (temp_list, ancestor);
-        }
-    }
-
-  /* Walk the list and expand all the paned widgets. */
-  for (list = temp_list; list != NULL; list = list->next)
-    {
-      GtkWidget *widget = list->data;
-
-      if (widget)
-        {
-          if (GTK_IS_XPANED (widget))
-            {
-              xpaned->in_recursion = TRUE;
-              gtk_xpaned_get_cycle_chain (GTK_XPANED (widget),
-                                          direction, widgets);
-              xpaned->in_recursion = FALSE;
-            }
-          else
-            {
-              *widgets = g_list_append (*widgets, widget);
-            }
-        }
-    }
-
-  g_list_free (temp_list);
-}
-
-static gboolean
-gtk_xpaned_cycle_child_focus (GtkXPaned * xpaned, gboolean reversed)
-{
-  GList *cycle_chain = NULL;
-  GList *list;
-
-  GtkDirectionType direction =
-    reversed ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
-
-  /* ignore f6 if the handle is focused */
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    return TRUE;
-
-  /* we can't just let the event propagate up the hierarchy,
-   * because the paned will want to cycle focus _unless_ an
-   * ancestor paned handles the event
-   */
-  gtk_xpaned_get_cycle_chain (xpaned, direction, &cycle_chain);
-
-  for (list = cycle_chain; list != NULL; list = list->next)
-    if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
-      break;
-
-  g_list_free (cycle_chain);
-
-  return TRUE;
-}
-
-static void
-get_child_xpanes (GtkWidget * widget, GList ** xpanes)
-{
-  if (GTK_IS_XPANED (widget))
-    {
-      GtkXPaned *xpaned = GTK_XPANED (widget);
-
-      get_child_xpanes (xpaned->top_left_child, xpanes);
-      *xpanes = g_list_prepend (*xpanes, widget);
-      get_child_xpanes (xpaned->top_right_child, xpanes);
-      *xpanes = g_list_prepend (*xpanes, widget);
-      get_child_xpanes (xpaned->bottom_left_child, xpanes);
-      *xpanes = g_list_prepend (*xpanes, widget);
-      get_child_xpanes (xpaned->bottom_right_child, xpanes);
-    }
-  else if (GTK_IS_CONTAINER (widget))
-    {
-      gtk_container_foreach (GTK_CONTAINER (widget),
-                             (GtkCallback) get_child_xpanes, xpanes);
-    }
-}
-
-static GList *
-get_all_xpanes (GtkXPaned * xpaned)
-{
-  GtkXPaned *topmost = NULL;
-  GList *result = NULL;
-  GtkWidget *w;
-
-  for (w = GTK_WIDGET (xpaned); w != NULL; w = gtk_widget_get_parent (w))
-    {
-      if (GTK_IS_XPANED (w))
-        topmost = GTK_XPANED (w);
-    }
-
-  g_assert (topmost);
-
-  get_child_xpanes (GTK_WIDGET (topmost), &result);
-
-  return g_list_reverse (result);
-}
-
-static void
-gtk_xpaned_find_neighbours (GtkXPaned * xpaned,
-                            GtkXPaned ** next, GtkXPaned ** prev)
-{
-  GList *all_xpanes;
-  GList *this_link;
-
-  all_xpanes = get_all_xpanes (xpaned);
-  g_assert (all_xpanes);
-
-  this_link = g_list_find (all_xpanes, xpaned);
-
-  g_assert (this_link);
-
-  if (this_link->next)
-    *next = this_link->next->data;
-  else
-    *next = all_xpanes->data;
-
-  if (this_link->prev)
-    *prev = this_link->prev->data;
-  else
-    *prev = g_list_last (all_xpanes)->data;
-
-  g_list_free (all_xpanes);
-}
-
-static gboolean
-gtk_xpaned_move_handle (GtkXPaned * xpaned, GtkScrollType scroll)
-{
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    {
-      GdkPoint old_position;
-      GdkPoint new_position;
-      gint increment;
-
-      enum
-      {
-        SINGLE_STEP_SIZE = 1,
-        PAGE_STEP_SIZE = 75
-      };
-
-      new_position.x = old_position.x = gtk_xpaned_get_position_x (xpaned);
-      new_position.y = old_position.y = gtk_xpaned_get_position_y (xpaned);
-      increment = 0;
-
-      switch (scroll)
-        {
-        case GTK_SCROLL_STEP_LEFT:
-        case GTK_SCROLL_STEP_UP:
-        case GTK_SCROLL_STEP_BACKWARD:
-          increment = -SINGLE_STEP_SIZE;
-          break;
-
-        case GTK_SCROLL_STEP_RIGHT:
-        case GTK_SCROLL_STEP_DOWN:
-        case GTK_SCROLL_STEP_FORWARD:
-          increment = SINGLE_STEP_SIZE;
-          break;
-
-        case GTK_SCROLL_PAGE_LEFT:
-        case GTK_SCROLL_PAGE_UP:
-        case GTK_SCROLL_PAGE_BACKWARD:
-          increment = -PAGE_STEP_SIZE;
-          break;
-
-        case GTK_SCROLL_PAGE_RIGHT:
-        case GTK_SCROLL_PAGE_DOWN:
-        case GTK_SCROLL_PAGE_FORWARD:
-          increment = PAGE_STEP_SIZE;
-          break;
-
-        case GTK_SCROLL_START:
-          new_position.x = xpaned->min_position.x;
-          new_position.y = xpaned->min_position.y;
-          break;
-
-        case GTK_SCROLL_END:
-          new_position.x = xpaned->max_position.x;
-          new_position.y = xpaned->max_position.y;
-          break;
-
-        default:
-          break;
-        }
-
-      if (increment)
-        {
-          if (is_rtl (xpaned))
-            increment = -increment;
-
-          new_position.x = old_position.x + increment;
-          new_position.y = old_position.y + increment;
-        }
-
-      new_position.x = CLAMP (new_position.x,
-                              xpaned->min_position.x, xpaned->max_position.x);
-
-      new_position.y = CLAMP (new_position.y,
-                              xpaned->min_position.y, xpaned->max_position.y);
-
-      if (old_position.x != new_position.x)
-        gtk_xpaned_set_position_x (xpaned, new_position.x);
-
-      if (old_position.y != new_position.y)
-        gtk_xpaned_set_position_y (xpaned, new_position.y);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-gtk_xpaned_restore_focus (GtkXPaned * xpaned)
-{
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    {
-      if (xpaned->priv->saved_focus &&
-          gtk_widget_get_sensitive (xpaned->priv->saved_focus))
-        {
-          gtk_widget_grab_focus (xpaned->priv->saved_focus);
-        }
-      else
-        {
-          /* the saved focus is somehow not available for focusing,
-           * try
-           *   1) tabbing into the paned widget
-           * if that didn't work,
-           *   2) unset focus for the window if there is one
-           */
-
-          if (!gtk_widget_child_focus
-              (GTK_WIDGET (xpaned), GTK_DIR_TAB_FORWARD))
-            {
-              GtkWidget *toplevel =
-                gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
-
-              if (GTK_IS_WINDOW (toplevel))
-                gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
-            }
-        }
-
-      gtk_xpaned_set_saved_focus (xpaned, NULL);
-      gtk_xpaned_set_first_xpaned (xpaned, NULL);
-    }
-}
-
-static gboolean
-gtk_xpaned_accept_position (GtkXPaned * xpaned)
-{
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    {
-      xpaned->original_position.x = -1;
-      xpaned->original_position.y = -1;
-      gtk_xpaned_restore_focus (xpaned);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_xpaned_cancel_position (GtkXPaned * xpaned)
-{
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    {
-      if (xpaned->original_position.x != -1)
-        {
-          gtk_xpaned_set_position_x (xpaned, xpaned->original_position.x);
-          xpaned->original_position.x = -1;
-        }
-
-      if (xpaned->original_position.y != -1)
-        {
-          gtk_xpaned_set_position_y (xpaned, xpaned->original_position.y);
-          xpaned->original_position.y = -1;
-        }
-
-      gtk_xpaned_restore_focus (xpaned);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_xpaned_cycle_handle_focus (GtkXPaned * xpaned, gboolean reversed)
-{
-  GtkXPaned *next;
-  GtkXPaned *prev;
-
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    {
-      GtkXPaned *focus = NULL;
-
-      if (!xpaned->priv->first_xpaned)
-        {
-          /* The first_pane has disappeared. As an ad-hoc solution,
-           * we make the currently focused paned the first_paned. To the
-           * user this will seem like the paned cycling has been reset.
-           */
-          gtk_xpaned_set_first_xpaned (xpaned, xpaned);
-        }
-
-      gtk_xpaned_find_neighbours (xpaned, &next, &prev);
-
-      if (reversed && prev &&
-          prev != xpaned && xpaned != xpaned->priv->first_xpaned)
-        {
-          focus = prev;
-        }
-      else if (!reversed &&
-               next && next != xpaned && next != xpaned->priv->first_xpaned)
-        {
-          focus = next;
-        }
-      else
-        {
-          gtk_xpaned_accept_position (xpaned);
-          return TRUE;
-        }
-
-      g_assert (focus);
-
-      gtk_xpaned_set_saved_focus (focus, xpaned->priv->saved_focus);
-      gtk_xpaned_set_first_xpaned (focus, xpaned->priv->first_xpaned);
-
-      gtk_xpaned_set_saved_focus (xpaned, NULL);
-      gtk_xpaned_set_first_xpaned (xpaned, NULL);
-
-      gtk_widget_grab_focus (GTK_WIDGET (focus));
-
-      if (!gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-        {
-          xpaned->original_position.x = -1;
-          xpaned->original_position.y = -1;
-          focus->original_position.x = gtk_xpaned_get_position_x (focus);
-          focus->original_position.y = gtk_xpaned_get_position_y (focus);
-        }
-    }
-  else
-    {
-      GtkContainer *container = GTK_CONTAINER (xpaned);
-      GtkXPaned *focus;
-      GtkXPaned *first;
-      GtkXPaned *prev;
-      GtkXPaned *next;
-      GtkWidget *toplevel;
-
-      gtk_xpaned_find_neighbours (xpaned, &next, &prev);
-
-      if (gtk_container_get_focus_child (container) == xpaned->top_left_child)
-        {
-          if (reversed)
-            {
-              focus = prev;
-              first = xpaned;
-            }
-          else
-            {
-              focus = xpaned;
-              first = xpaned;
-            }
-        }
-      else if (gtk_container_get_focus_child (container) == xpaned->top_right_child)
-        {
-          if (reversed)
-            {
-              focus = xpaned;
-              first = next;
-            }
-          else
-            {
-              focus = next;
-              first = next;
-            }
-        }
-      else
-        {
-          /* Focus is not inside this xpaned, and we don't have focus.
-           * Presumably this happened because the application wants us
-           * to start keyboard navigating.
-           */
-          focus = xpaned;
-
-          if (reversed)
-            first = xpaned;
-          else
-            first = next;
-        }
-
-      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
-
-      if (GTK_IS_WINDOW (toplevel))
-        gtk_xpaned_set_saved_focus (focus,
-                                    gtk_window_get_focus (GTK_WINDOW (toplevel)));
-      gtk_xpaned_set_first_xpaned (focus, first);
-      focus->original_position.x = gtk_xpaned_get_position_x (focus);
-      focus->original_position.y = gtk_xpaned_get_position_y (focus);
-
-      gtk_widget_grab_focus (GTK_WIDGET (focus));
-    }
-
-  return TRUE;
-}
-
-static gboolean
-gtk_xpaned_toggle_handle_focus (GtkXPaned * xpaned)
-{
-  /* This function/signal has the wrong name. It is called when you
-   * press Tab or Shift-Tab and what we do is act as if
-   * the user pressed Return and then Tab or Shift-Tab
-   */
-  if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
-    gtk_xpaned_accept_position (xpaned);
-
-  return FALSE;
-}
-
-/*#define __GTK_XPANED_C__*/
-/*#include "gtkaliasdef.c"*/
diff --git a/lib/gtk-contrib/gtkxpaned.h b/lib/gtk-contrib/gtkxpaned.h
deleted file mode 100644 (file)
index bb6b196..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*******************************************************************************
-**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
-**      10        20        30        40        50        60        70        80
-**
-**  library for GtkXPaned-widget, a 2x2 grid-like variation of GtkPaned of gtk+
-**  Copyright (C) 2005-2006 Mirco "MacSlow" Müller <macslow@bangang.de>
-**
-**  This library is free software; you can redistribute it and/or
-**  modify it under the terms of the GNU Lesser General Public
-**  License as published by the Free Software Foundation; either
-**  version 2.1 of the License, or (at your option) any later version.
-**
-**  This library 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
-**  Lesser General Public License for more details.
-**
-**  You should have received a copy of the GNU Lesser General Public
-**  License along with this library; if not, write to the Free Software
-**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-**
-**  GtkXPaned is based on GtkPaned which was done by...
-**
-**  "Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald"
-**
-**  and later modified by...
-**
-**  "the GTK+ Team and others 1997-2000"
-**
-*******************************************************************************/
-
-#ifndef GTK_XPANED_H
-#define GTK_XPANED_H
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-#define GTK_TYPE_XPANED                  (gtk_xpaned_get_type ())
-#define GTK_XPANED(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_XPANED, GtkXPaned))
-#define GTK_XPANED_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_XPANED, GtkXPanedClass))
-#define GTK_IS_XPANED(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_XPANED))
-#define GTK_IS_XPANED_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XPANED))
-#define GTK_XPANED_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_XPANED, GtkXPanedClass))
-typedef struct _GtkXPaned GtkXPaned;
-typedef struct _GtkXPanedClass GtkXPanedClass;
-typedef struct _GtkXPanedPrivate GtkXPanedPrivate;
-
-typedef enum _GtkXPanedChild
-{
-  GTK_XPANED_TOP_LEFT = 0,
-  GTK_XPANED_TOP_RIGHT,
-  GTK_XPANED_BOTTOM_LEFT,
-  GTK_XPANED_BOTTOM_RIGHT
-} GtkXPanedChild;
-
-struct _GtkXPaned
-{
-  GtkContainer container;
-
-  GtkWidget *top_left_child;
-  GtkWidget *top_right_child;
-  GtkWidget *bottom_left_child;
-  GtkWidget *bottom_right_child;
-
-  GdkWindow *handle_east;
-  GdkWindow *handle_west;
-  GdkWindow *handle_north;
-  GdkWindow *handle_south;
-  GdkWindow *handle_middle;
-
-  GdkCursorType cursor_type_east;
-  GdkCursorType cursor_type_west;
-  GdkCursorType cursor_type_north;
-  GdkCursorType cursor_type_south;
-  GdkCursorType cursor_type_middle;
-
-  /*< private > */
-  GdkRectangle handle_pos_east;
-  GdkRectangle handle_pos_west;
-  GdkRectangle handle_pos_north;
-  GdkRectangle handle_pos_south;
-  GdkRectangle handle_pos_middle;
-  GtkRequisition top_left_child_size;
-  GtkRequisition top_right_child_size;
-  GtkRequisition bottom_left_child_size;
-  GtkRequisition bottom_right_child_size;
-
-  GtkRequisition last_allocation;
-  GdkPoint min_position;
-  GdkPoint max_position;
-  gboolean maximized[4];
-
-  guint position_set:1;
-  guint in_drag_vert:1;
-  guint in_drag_horiz:1;
-  guint in_drag_vert_and_horiz:1;
-  guint top_left_child_shrink:1;
-  guint top_left_child_resize:1;
-  guint top_right_child_shrink:1;
-  guint top_right_child_resize:1;
-  guint bottom_left_child_shrink:1;
-  guint bottom_left_child_resize:1;
-  guint bottom_right_child_shrink:1;
-  guint bottom_right_child_resize:1;
-  guint in_recursion:1;
-  guint handle_prelit:1;
-
-  GtkWidget *last_top_left_child_focus;
-  GtkWidget *last_top_right_child_focus;
-  GtkWidget *last_bottom_left_child_focus;
-  GtkWidget *last_bottom_right_child_focus;
-  GtkXPanedPrivate *priv;
-
-  GdkPoint drag_pos;
-  GdkPoint original_position;
-  GdkPoint unmaximized_position;
-};
-
-struct _GtkXPanedClass
-{
-  GtkContainerClass parent_class;
-    gboolean (*cycle_child_focus) (GtkXPaned * xpaned, gboolean reverse);
-    gboolean (*toggle_handle_focus) (GtkXPaned * xpaned);
-    gboolean (*move_handle) (GtkXPaned * xpaned, GtkScrollType scroll);
-    gboolean (*cycle_handle_focus) (GtkXPaned * xpaned, gboolean reverse);
-    gboolean (*accept_position) (GtkXPaned * xpaned);
-    gboolean (*cancel_position) (GtkXPaned * xpaned);
-};
-
-GType
-gtk_xpaned_get_type (void)
-  G_GNUC_CONST;
-     GtkWidget *gtk_xpaned_new (void);
-     void gtk_xpaned_add_top_left (GtkXPaned * xpaned, GtkWidget * child);
-     void gtk_xpaned_add_top_right (GtkXPaned * xpaned, GtkWidget * child);
-     void gtk_xpaned_add_bottom_left (GtkXPaned * xpaned, GtkWidget * child);
-     void gtk_xpaned_add_bottom_right (GtkXPaned * xpaned, GtkWidget * child);
-     void gtk_xpaned_pack_top_left (GtkXPaned * xpaned, GtkWidget * child,
-                                    gboolean resize, gboolean shrink);
-     void gtk_xpaned_pack_top_right (GtkXPaned * xpaned, GtkWidget * child,
-                                     gboolean resize, gboolean shrink);
-     void gtk_xpaned_pack_bottom_left (GtkXPaned * xpaned, GtkWidget * child,
-                                       gboolean resize, gboolean shrink);
-     void gtk_xpaned_pack_bottom_right (GtkXPaned * xpaned, GtkWidget * child,
-                                        gboolean resize, gboolean shrink);
-     gint gtk_xpaned_get_position_x (GtkXPaned * xpaned);
-     gint gtk_xpaned_get_position_y (GtkXPaned * xpaned);
-     void gtk_xpaned_set_position_x (GtkXPaned * xpaned, gint xposition);
-     void gtk_xpaned_set_position_y (GtkXPaned * xpaned, gint yposition);
-     void gtk_xpaned_save_unmaximized_x (GtkXPaned * xpaned);
-     void gtk_xpaned_save_unmaximized_y (GtkXPaned * xpaned);
-     gint gtk_xpaned_fetch_unmaximized_x (GtkXPaned * xpaned);
-     gint gtk_xpaned_fetch_unmaximized_y (GtkXPaned * xpaned);
-     GtkWidget *gtk_xpaned_get_top_left_child (GtkXPaned * xpaned);
-     GtkWidget *gtk_xpaned_get_top_right_child (GtkXPaned * xpaned);
-     GtkWidget *gtk_xpaned_get_bottom_right_child (GtkXPaned * xpaned);
-     GtkWidget *gtk_xpaned_get_bottom_left_child (GtkXPaned * xpaned);
-     gboolean gtk_xpaned_maximize_top_left (GtkXPaned * xpaned,
-                                            gboolean maximize);
-     gboolean gtk_xpaned_maximize_top_right (GtkXPaned * xpaned,
-                                             gboolean maximize);
-     gboolean gtk_xpaned_maximize_bottom_left (GtkXPaned * xpaned,
-                                               gboolean maximize);
-     gboolean gtk_xpaned_maximize_bottom_right (GtkXPaned * xpaned,
-                                                gboolean maximize);
-
-/* Internal function */
-#if !defined (GTK_DISABLE_DEPRECATED) || defined (GTK_COMPILATION)
-     void gtk_xpaned_compute_position (GtkXPaned * xpaned,
-                                       const GtkAllocation * allocation,
-                                       GtkRequisition * top_left_child_req,
-                                       GtkRequisition * top_right_child_req,
-                                       GtkRequisition * bottom_left_child_req,
-                                       GtkRequisition *
-                                       bottom_right_child_req);
-#endif /* !GTK_DISABLE_DEPRECATED || GTK_COMPILATION */
-#ifndef GTK_DISABLE_DEPRECATED
-#define        gtk_xpaned_gutter_size(p,s) (void) 0
-#define        gtk_xpaned_set_gutter_size(p,s) (void) 0
-#endif /* GTK_DISABLE_DEPRECATED */
-
-G_END_DECLS
-#endif /* GTK_XPANED_H */
index fe569de200e671721ef510a2ab78797386c27b03..76769223980e0f820081c2aa6cb1df676bf9937e 100644 (file)
@@ -39,7 +39,7 @@
 #endif
 
 static size_t case_size (const struct caseproto *);
-static bool variable_matches_case (const struct ccase *,
+static void assert_variable_matches_case (const struct ccase *,
                                    const struct variable *);
 static void copy_forward (struct ccase *dst, size_t dst_idx,
                           const struct ccase *src, size_t src_idx,
@@ -264,7 +264,7 @@ case_copy_in (struct ccase *c,
 const union value *
 case_data (const struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   return &c->values[var_get_case_index (v)];
 }
 
@@ -286,7 +286,7 @@ case_data_idx (const struct ccase *c, size_t idx)
 union value *
 case_data_rw (struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   assert (!case_is_shared (c));
   return &c->values[var_get_case_index (v)];
 }
@@ -310,7 +310,7 @@ case_data_rw_idx (struct ccase *c, size_t idx)
 double
 case_num (const struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   return c->values[var_get_case_index (v)].f;
 }
 
@@ -332,8 +332,8 @@ case_num_idx (const struct ccase *c, size_t idx)
 const uint8_t *
 case_str (const struct ccase *c, const struct variable *v)
 {
+  assert_variable_matches_case (c, v);
   size_t idx = var_get_case_index (v);
-  assert (variable_matches_case (c, v));
   return value_str (&c->values[idx], caseproto_get_width (c->proto, idx));
 }
 
@@ -360,8 +360,8 @@ case_str_idx (const struct ccase *c, size_t idx)
 uint8_t *
 case_str_rw (struct ccase *c, const struct variable *v)
 {
+  assert_variable_matches_case (c, v);
   size_t idx = var_get_case_index (v);
-  assert (variable_matches_case (c, v));
   assert (!case_is_shared (c));
   return value_str_rw (&c->values[idx], caseproto_get_width (c->proto, idx));
 }
@@ -468,12 +468,12 @@ case_size (const struct caseproto *proto)
    or write data in C.
 
    Useful in assertions. */
-static bool UNUSED
-variable_matches_case (const struct ccase *c, const struct variable *v)
+static void
+assert_variable_matches_case (const struct ccase *c, const struct variable *v)
 {
   size_t case_idx = var_get_case_index (v);
-  return (case_idx < caseproto_get_n_widths (c->proto)
-          && caseproto_get_width (c->proto, case_idx) == var_get_width (v));
+  assert (case_idx < caseproto_get_n_widths (c->proto));
+  assert (caseproto_get_width (c->proto, case_idx) == var_get_width (v));
 }
 
 /* Internal helper function for case_copy(). */
index 3e3c72a6bb7299eb7fb434f4feaed620ad0230f2..656a06204f1dc077b73987c4f2e18395209edfbe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Free Software Foundation, Inc.
 
    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
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
+
+/* This should follow the definition in Gtk */
+typedef struct
+{
+  int value;
+  const char *name;
+  const char *label;
+} GEnumValue;
+
+const GEnumValue align[] =
+  {
+    {ALIGN_LEFT,   "left", N_("Left")},
+    {ALIGN_RIGHT,  "right", N_("Right")},
+    {ALIGN_CENTRE, "center", N_("Center")},
+    {0,0,0}
+  };
+
+const GEnumValue measure[] =
+  {
+    {MEASURE_NOMINAL, "nominal", N_("Nominal")},
+    {MEASURE_ORDINAL, "ordinal", N_("Ordinal")},
+    {MEASURE_SCALE,   "scale", N_("Scale")},
+    {0,0,0}
+  };
+
+const GEnumValue role[] =
+  {
+    {ROLE_INPUT,  "input",    N_("Input")},
+    {ROLE_TARGET, "output",   N_("Output")},
+    {ROLE_BOTH,   "both",     N_("Both")},
+    {ROLE_NONE,   "none",     N_("None")},
+    {ROLE_PARTITION, "partition", N_("Partition")},
+    {ROLE_SPLIT,  "split",    N_("Split")},
+    {0,0,0}
+  };
 
 /* A variable. */
 struct variable
@@ -771,20 +807,8 @@ measure_is_valid (enum measure m)
 const char *
 measure_to_string (enum measure m)
 {
-  switch (m)
-    {
-    case MEASURE_NOMINAL:
-      return _("Nominal");
-
-    case MEASURE_ORDINAL:
-      return _("Ordinal");
-
-    case MEASURE_SCALE:
-      return _("Scale");
-
-    default:
-      return "Invalid";
-    }
+  assert (m == measure[m].value);
+  return gettext (measure[m].label);
 }
 
 /* Returns a string version of measurement level M, for use in PSPP command
@@ -866,31 +890,10 @@ var_role_is_valid (enum var_role role)
 
 /* Returns a string version of ROLE, for display to a user. */
 const char *
-var_role_to_string (enum var_role role)
+var_role_to_string (enum var_role r)
 {
-  switch (role)
-    {
-    case ROLE_INPUT:
-      return _("Input");
-
-    case ROLE_TARGET:
-      return _("Output");
-
-    case ROLE_BOTH:
-      return _("Both");
-
-    case ROLE_NONE:
-      return _("None");
-
-    case ROLE_PARTITION:
-      return _("Partition");
-
-    case ROLE_SPLIT:
-      return _("Split");
-
-    default:
-      return "Invalid";
-    }
+  assert (r == role[r].value);
+  return gettext (role[r].label);
 }
 
 /* Returns a string version of ROLE, for use in PSPP comamnd syntax. */
@@ -996,20 +999,8 @@ alignment_is_valid (enum alignment a)
 const char *
 alignment_to_string (enum alignment a)
 {
-  switch (a)
-    {
-    case ALIGN_LEFT:
-      return _("Left");
-
-    case ALIGN_RIGHT:
-      return _("Right");
-
-    case ALIGN_CENTRE:
-      return _("Center");
-
-    default:
-      return "Invalid";
-    }
+  assert (a == align[a].value);
+  return gettext (align[a].label);
 }
 
 /* Returns a string version of alignment A, for use in PSPP command syntax. */
index 3d10ed022910f4e438ef181cbded1e74c1d9d82f..1877263b73eac257ef0354d5f8bdfba91c752b40 100644 (file)
@@ -85,13 +85,14 @@ EXTRA_DIST += \
        src/ui/gui/marshaller-list \
        src/ui/gui/pspplogo.svg
 
+src_ui_gui_psppire_CPPFLAGS=
 
 if HAVE_GUI
-bin_PROGRAMS += src/ui/gui/psppire 
-noinst_PROGRAMS += src/ui/gui/spreadsheet-test 
+bin_PROGRAMS += src/ui/gui/psppire
+noinst_PROGRAMS += src/ui/gui/spreadsheet-test
 
-src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) $(GTKSOURCEVIEW_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1 
-src_ui_gui_spreadsheet_test_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1 
+src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) $(GTKSOURCEVIEW_CFLAGS) $(SPREAD_SHEET_WIDGET_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
+src_ui_gui_spreadsheet_test_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
 
 
 src_ui_gui_psppire_LDFLAGS = \
@@ -107,13 +108,13 @@ endif
 
 
 src_ui_gui_psppire_LDADD = \
-       lib/gtk-contrib/libxpaned.a \
        src/ui/libuicommon.la \
        src/libpspp.la \
        src/libpspp-core.la \
        $(GTK_LIBS) \
        $(GTHREAD_LIBS) \
        $(GTKSOURCEVIEW_LIBS) \
+       $(SPREAD_SHEET_WIDGET_LIBS) \
        $(CAIRO_LIBS) \
        $(LIBINTL) \
        $(GSL_LIBS)
@@ -137,23 +138,9 @@ INSTALL_DATA_HOOKS += install-lang
 
 dist_src_ui_gui_psppire_DATA = \
        $(UI_FILES) \
-       $(top_srcdir)/src/ui/gui/pspp.lang \
-       $(top_srcdir)/src/ui/gui/psppire.gtkrc
+       $(top_srcdir)/src/ui/gui/pspp.lang
 
 src_ui_gui_psppire_SOURCES = \
-       src/ui/gui/pspp-sheet-private.h \
-       src/ui/gui/pspp-sheet-selection.c \
-       src/ui/gui/pspp-sheet-selection.h \
-       src/ui/gui/pspp-sheet-view-column.c \
-       src/ui/gui/pspp-sheet-view-column.h \
-       src/ui/gui/pspp-sheet-view.c \
-       src/ui/gui/pspp-sheet-view.h \
-       src/ui/gui/pspp-widget-facade.c \
-       src/ui/gui/pspp-widget-facade.h \
-       src/ui/gui/psppire-button-editable.c \
-       src/ui/gui/psppire-button-editable.h \
-       src/ui/gui/psppire-cell-renderer-button.c \
-       src/ui/gui/psppire-cell-renderer-button.h \
        src/ui/gui/psppire-dialog.c \
        src/ui/gui/psppire-keypad.c \
        src/ui/gui/psppire-selector.c \
@@ -196,8 +183,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-conf.h \
        src/ui/gui/psppire-data-editor.c \
        src/ui/gui/psppire-data-editor.h \
-       src/ui/gui/psppire-data-sheet.c \
-       src/ui/gui/psppire-data-sheet.h \
        src/ui/gui/psppire-data-store.c \
        src/ui/gui/psppire-data-store.h \
        src/ui/gui/psppire-data-window.c \
@@ -293,8 +278,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dict.h \
        src/ui/gui/psppire-dictview.c \
        src/ui/gui/psppire-dictview.h \
-       src/ui/gui/psppire-empty-list-store.c \
-       src/ui/gui/psppire-empty-list-store.h \
        src/ui/gui/psppire-encoding-selector.c \
        src/ui/gui/psppire-encoding-selector.h \
        src/ui/gui/psppire-format.c \
@@ -317,14 +300,22 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-select-dest.h \
        src/ui/gui/psppire-syntax-window.c \
        src/ui/gui/psppire-syntax-window.h \
+       src/ui/gui/psppire-delimited-text.c \
+       src/ui/gui/psppire-delimited-text.h \
+       src/ui/gui/psppire-text-file.c \
+       src/ui/gui/psppire-text-file.h \
        src/ui/gui/psppire-val-chooser.c \
        src/ui/gui/psppire-val-chooser.h \
        src/ui/gui/psppire-value-entry.c \
        src/ui/gui/psppire-value-entry.h \
        src/ui/gui/psppire-var-ptr.c \
        src/ui/gui/psppire-var-ptr.h \
-       src/ui/gui/psppire-var-sheet.c \
-       src/ui/gui/psppire-var-sheet.h \
+       src/ui/gui/psppire-data-sheet.c \
+       src/ui/gui/psppire-data-sheet.h \
+       src/ui/gui/psppire-variable-sheet.c \
+       src/ui/gui/psppire-variable-sheet.h \
+       src/ui/gui/psppire-var-sheet-header.h \
+       src/ui/gui/psppire-var-sheet-header.c \
        src/ui/gui/psppire-window.c \
        src/ui/gui/psppire-window.h \
        src/ui/gui/psppire-window-base.c \
@@ -339,6 +330,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/var-display.h \
        src/ui/gui/var-type-dialog.c \
        src/ui/gui/var-type-dialog.h \
+       src/ui/gui/value-variant.c \
+       src/ui/gui/value-variant.h \
        src/ui/gui/widget-io.c \
        src/ui/gui/widget-io.h \
        src/ui/gui/widgets.c \
@@ -412,6 +405,7 @@ BUILT_SOURCES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h src/u
 
 CLEANFILES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h \
        src/ui/gui/resources.c $(nodist_src_ui_gui_psppire_DATA)
+
 endif HAVE_GUI
 
 #ensure the installcheck passes even if there is no X server available
@@ -419,7 +413,7 @@ installcheck-local:
        DISPLAY=/invalid/port $(MAKE) $(AM_MAKEFLAGS) installcheck-binPROGRAMS
 
 # <gtk/gtk.h> wrapper
-src_ui_gui_psppire_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/ui/gui/include
+src_ui_gui_psppire_CPPFLAGS += $(AM_CPPFLAGS) -Isrc/ui/gui/include
 BUILT_SOURCES += src/ui/gui/include/gtk/gtk.h
 src/ui/gui/include/gtk/gtk.h: src/ui/gui/include/gtk/gtk.in.h
        @$(MKDIR_P) src/ui/gui/include/gtk
index fddbe8c49bb74759f4e18a33747dd5c3e9f9ad1e..123f7cf69b3148e4a846fc42a6646c4205a05f53 100644 (file)
@@ -36,7 +36,6 @@ which match particular strings */
 #include "ui/gui/dict-display.h"
 #include "ui/gui/find-dialog.h"
 #include "ui/gui/helper.h"
-#include "ui/gui/psppire-data-sheet.h"
 #include "ui/gui/psppire-data-store.h"
 #include "ui/gui/psppire-data-window.h"
 #include "ui/gui/psppire-dialog.h"
@@ -100,13 +99,12 @@ refresh (GObject *obj, const struct find_dialog *fd)
 static void
 do_find (GObject *obj, const struct find_dialog *fd)
 {
-  PsppireDataSheet *data_sheet;
   casenumber x = -1;
   gint column = -1;
   glong row;
 
-  data_sheet = psppire_data_editor_get_active_data_sheet (fd->de->data_editor);
-  row = psppire_data_sheet_get_selected_case (data_sheet);
+
+  row = 10;
 
   find_value (fd, row, &x, &column);
 
@@ -115,8 +113,6 @@ do_find (GObject *obj, const struct find_dialog *fd)
       gtk_notebook_set_current_page (GTK_NOTEBOOK (fd->de->data_editor),
                                     PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
-      psppire_data_sheet_goto_case (data_sheet, x);
-      psppire_data_sheet_goto_variable (data_sheet, column);
     }
 }
 
index 282f41636883c21315d1f21d6ed08cfa1903a922..1b5e39a45dfd204628a0f676df5baf1fd950254c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2011, 2012  Free Software Foundation
+   Copyright (C) 2007, 2011, 2012, 2016  Free Software Foundation
 
    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
 #include "psppire-dialog.h"
 #include "psppire-data-window.h"
 #include "psppire-data-store.h"
+#include "psppire-data-sheet.h"
 
 
 static void
 refresh (PsppireDataSheet *ds, GtkBuilder *xml)
 {
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
-  casenumber case_count ;
+  PsppireDataStore *store = NULL;
+  g_object_get (ds, "data-model", &store, NULL);
 
   GtkWidget *case_num_entry = get_widget_assert (xml, "goto-case-case-num-entry");
-
-  case_count =  psppire_data_store_get_case_count (data_store);
+  casenumber case_count =  gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
 
   gtk_spin_button_set_range (GTK_SPIN_BUTTON (case_num_entry), 1, case_count);
 }
@@ -51,18 +51,23 @@ goto_case_dialog (PsppireDataSheet *ds)
 
   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
 
-  if ( response == PSPPIRE_RESPONSE_GOTO )
+  if (response == PSPPIRE_RESPONSE_GOTO)
     {
-      PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
-      glong case_num;
-      GtkWidget *case_num_entry =
-       get_widget_assert (xml, "goto-case-case-num-entry");
+      PsppireDataStore *store = NULL;
+      g_object_get (ds, "data-model", &store, NULL);
 
-      case_num = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (case_num_entry))
-       - FIRST_CASE_NUMBER ;
-
-      if (case_num >= 0
-          && case_num < psppire_data_store_get_case_count (data_store))
-        psppire_data_sheet_goto_case (ds, case_num);
+      GtkWidget *case_num_entry =
+       get_widget_assert (xml, "goto-case-case-num-entry");
+
+      glong case_num =
+       gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (case_num_entry))
+       - FIRST_CASE_NUMBER ;
+
+      if (case_num >= 0 &&
+         case_num < gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ds), NULL))
+      {
+       ssw_sheet_scroll_to (ds, -1, case_num);
+       ssw_sheet_set_active_cell (ds, -1, case_num, 0);
+      }
     }
 }
index e7c70eee258fec818241c6c6ea232d72b4f24f70..422cdff37a17947b0a9c22d23117b46f78a65bef 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "psppire-data-sheet.h"
 
+
 void goto_case_dialog (PsppireDataSheet *ds);
 
 #endif
index 0f38e6fc2ea18c1ca6ccfb3c812faf8da4d0a204..5b6c0e5b586f1eb12a07b63946fa86023bc915d9 100644 (file)
@@ -12,3 +12,4 @@ VOID:INT,INT
 VOID:OBJECT,OBJECT
 VOID:POINTER,INT,INT
 VOID:INT,UINT,POINTER
+VOID:UINT,UINT,UINT
index 45916dd9325a3431d31f230b6f8f9dac1ff36c3e..83ec504edde789941812d75c392df4ec445c8f9e 100644 (file)
@@ -151,7 +151,7 @@ psppire_missing_val_dialog_new (const struct variable *var)
                   NULL));
 }
 
-void
+gint
 psppire_missing_val_dialog_run (GtkWindow *parent_window,
                                 const struct variable *var,
                                 struct missing_values *mv)
@@ -163,12 +163,14 @@ psppire_missing_val_dialog_run (GtkWindow *parent_window,
   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
   gtk_widget_show (GTK_WIDGET (dialog));
 
-  if (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK)
+  gint result = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
+  if (result == GTK_RESPONSE_OK)
     mv_copy (mv, psppire_missing_val_dialog_get_missing_values (dialog));
   else
     mv_copy (mv, var_get_missing_values (var));
 
   gtk_widget_destroy (GTK_WIDGET (dialog));
+  return result;
 }
 
 
index 12bf110129d043bc369c5027ee481416bb5b34b8..6d04d55bd5cd942cc68bad7b97b53d71c5bc0746 100644 (file)
@@ -71,7 +71,7 @@ void psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *,
 const struct missing_values *psppire_missing_val_dialog_get_missing_values (
   const PsppireMissingValDialog *);
 
-void psppire_missing_val_dialog_run (GtkWindow *parent_window,
+gint psppire_missing_val_dialog_run (GtkWindow *parent_window,
                                      const struct variable *,
                                      struct missing_values *);
 
diff --git a/src/ui/gui/pspp-sheet-private.h b/src/ui/gui/pspp-sheet-private.h
deleted file mode 100644 (file)
index e01fd47..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
- /* PSPPIRE - a graphical user interface for PSPP.
-    Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeprivate.h
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GTK_TREE_PRIVATE_H__
-#define __GTK_TREE_PRIVATE_H__
-
-
-#include <gtk/gtk.h>
-#include "libpspp/range-tower.h"
-#include "ui/gui/pspp-sheet-view.h"
-#include "ui/gui/pspp-sheet-view-column.h"
-
-#define TREE_VIEW_DRAG_WIDTH 6
-
-typedef enum
-{
-  PSPP_SHEET_VIEW_IN_COLUMN_RESIZE = 1 << 2,
-  PSPP_SHEET_VIEW_HEADERS_VISIBLE = 1 << 4,
-  PSPP_SHEET_VIEW_DRAW_KEYFOCUS = 1 << 5,
-  PSPP_SHEET_VIEW_MODEL_SETUP = 1 << 6,
-  PSPP_SHEET_VIEW_IN_COLUMN_DRAG = 1 << 7
-} PsppSheetViewFlags;
-
-enum
-{
-  DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
-  DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
-  DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
-  DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
-  DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
-};
-
-enum
-{
-  RUBBER_BAND_OFF = 0,
-  RUBBER_BAND_MAYBE_START = 1,
-  RUBBER_BAND_ACTIVE = 2
-};
-
-#define PSPP_SHEET_VIEW_SET_FLAG(tree_view, flag)   G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END
-#define PSPP_SHEET_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END
-#define PSPP_SHEET_VIEW_FLAG_SET(tree_view, flag)   ((tree_view->priv->flags&flag)==flag)
-#define TREE_VIEW_HEADER_HEIGHT(tree_view)        (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE)?tree_view->priv->header_height:0)
-#define TREE_VIEW_COLUMN_REQUESTED_WIDTH(column)  (CLAMP (column->requested_width, (column->min_width!=-1)?column->min_width:column->requested_width, (column->max_width!=-1)?column->max_width:column->requested_width))
-
- /* This lovely little value is used to determine how far away from the title bar
-  * you can move the mouse and still have a column drag work.
-  */
-#define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*TREE_VIEW_HEADER_HEIGHT(tree_view))
-
-typedef struct _PsppSheetViewColumnReorder PsppSheetViewColumnReorder;
-struct _PsppSheetViewColumnReorder
-{
-  gint left_align;
-  gint right_align;
-  PsppSheetViewColumn *left_column;
-  PsppSheetViewColumn *right_column;
-};
-
-struct _PsppSheetViewPrivate
-{
-  GtkTreeModel *model;
-
-  guint flags;
-  /* tree information */
-  gint row_count;
-  struct range_tower *selected;
-
-  /* Container info */
-  GList *children;
-  gint width;
-  gint height;
-
-  /* Adjustments */
-  GtkAdjustment *hadjustment;
-  GtkAdjustment *vadjustment;
-
-  /* Sub windows */
-  GdkWindow *bin_window;
-  GdkWindow *header_window;
-
-  /* Scroll position state keeping */
-  GtkTreeRowReference *top_row;
-  gint top_row_dy;
-  /* dy == y pos of top_row + top_row_dy */
-  /* we cache it for simplicity of the code */
-  gint dy;
-
-  guint presize_handler_timer;
-  guint validate_rows_timer;
-  guint scroll_sync_timer;
-
-  /* Indentation and expander layout */
-  gint expander_size;
-
-  /* Key navigation (focus), selection */
-  gint cursor_offset;
-
-  GtkTreeRowReference *anchor;
-  GtkTreeRowReference *cursor;
-
-  PsppSheetViewColumn *focus_column;
-
-  /* Current pressed node, previously pressed, prelight */
-  gint pressed_button;
-  gint press_start_x;
-  gint press_start_y;
-  gint press_start_node;
-
-  gint event_last_x;
-  gint event_last_y;
-
-  guint last_button_time;
-  gint last_button_x;
-  gint last_button_y;
-
-  int prelight_node;
-
-  /* Cell Editing */
-  PsppSheetViewColumn *edited_column;
-  gint edited_row;
-
-  /* Selection information */
-  PsppSheetSelection *selection;
-
-  /* Header information */
-  gint n_columns;
-  GList *columns;
-  gint header_height;
-  gint n_selected_columns;
-
-  PsppSheetViewColumnDropFunc column_drop_func;
-  gpointer column_drop_func_data;
-  GDestroyNotify column_drop_func_data_destroy;
-  GList *column_drag_info;
-  PsppSheetViewColumnReorder *cur_reorder;
-
-  /* Interactive Header reordering */
-  GdkWindow *drag_window;
-  GdkWindow *drag_highlight_window;
-  PsppSheetViewColumn *drag_column;
-  gint drag_column_x;
-
-  /* Interactive Header Resizing */
-  gint drag_pos;
-  gint x_drag;
-
-  /* Non-interactive Header Resizing, expand flag support */
-  gint prev_width;
-
-  /* ATK Hack */
-  PsppSheetDestroyCountFunc destroy_count_func;
-  gpointer destroy_count_data;
-  GDestroyNotify destroy_count_destroy;
-
-  /* Scroll timeout (e.g. during dnd, rubber banding) */
-  guint scroll_timeout;
-
-  /* Row drag-and-drop */
-  GtkTreeRowReference *drag_dest_row;
-  PsppSheetViewDropPosition drag_dest_pos;
-  guint open_dest_timeout;
-
-  /* Rubber banding */
-  gint rubber_band_status;
-  gint rubber_band_x;
-  gint rubber_band_y;
-  gint rubber_band_shift;
-  gint rubber_band_ctrl;
-
-  int rubber_band_start_node;
-
-  int rubber_band_end_node;
-
-  /* Rectangular selection. */
-  PsppSheetViewColumn *anchor_column; /* XXX needs to be a weak pointer? */
-
-  /* fixed height */
-  gint fixed_height;
-  gboolean fixed_height_set;
-
-  /* Scroll-to functionality when unrealized */
-  GtkTreeRowReference *scroll_to_path;
-  PsppSheetViewColumn *scroll_to_column;
-  gfloat scroll_to_row_align;
-  gfloat scroll_to_col_align;
-
-  /* Interactive search */
-  gint selected_iter;
-  gint search_column;
-  PsppSheetViewSearchPositionFunc search_position_func;
-  PsppSheetViewSearchEqualFunc search_equal_func;
-  gpointer search_user_data;
-  GDestroyNotify search_destroy;
-  gpointer search_position_user_data;
-  GDestroyNotify search_position_destroy;
-  GtkWidget *search_window;
-  GtkWidget *search_entry;
-  guint search_entry_changed_id;
-  guint typeselect_flush_timeout;
-
-  /* Grid and tree lines */
-  PsppSheetViewGridLines grid_lines;
-
-  /* Special cells. */
-  PsppSheetViewSpecialCells special_cells;
-
-  /* Tooltip support */
-  gint tooltip_column;
-
-  /* Cached style for button facades in columns. */
-  GtkStyle *button_style;
-
-  /* Here comes the bitfield */
-  guint scroll_to_use_align : 1;
-
-  guint reorderable : 1;
-  guint header_has_focus : 1;
-  guint drag_column_window_state : 3;
-  /* hint to display rows in alternating colors */
-  guint has_rules : 1;
-
-  /* for DnD */
-  guint empty_view_drop : 1;
-
-  guint init_hadjust_value : 1;
-
-  guint in_top_row_to_dy : 1;
-
-  /* interactive search */
-  guint enable_search : 1;
-  guint disable_popdown : 1;
-  guint search_custom_entry_set : 1;
-
-  guint hover_selection : 1;
-  guint imcontext_changed : 1;
-
-  guint rubber_banding_enable : 1;
-
-  guint in_grab : 1;
-
-  guint post_validation_flag : 1;
-
-  /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
-
-  guint search_entry_avoid_unhandled_binding : 1;
-  /* GtkScrollablePolicy needs to be checked when
-   * driving the scrollable adjustment values */
-  guint hscroll_policy : 1;
-  guint vscroll_policy : 1;
-
-  /* For optimisation of size allocate requests */
-  guint resized : 1;
- };
-
-#ifdef __GNUC__
-
-#define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "%s (%s): assertion `%s' failed.\n"                     \
-               "There is a disparity between the internal view of the PsppSheetView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                G_STRLOC,                                               \
-                G_STRFUNC,                                              \
-                #expr);                                                 \
-         return ret;                                                    \
-       };                               }G_STMT_END
-
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "%s (%s): assertion `%s' failed.\n"                     \
-               "There is a disparity between the internal view of the PsppSheetView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                G_STRLOC,                                               \
-                G_STRFUNC,                                              \
-                #expr);                                                 \
-         return;                                                        \
-       };                               }G_STMT_END
-
-#else
-
-#define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "file %s: line %d: assertion `%s' failed.\n"       \
-               "There is a disparity between the internal view of the PsppSheetView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                __FILE__,                                               \
-                __LINE__,                                               \
-                #expr);                                                 \
-         return ret;                                                    \
-       };                               }G_STMT_END
-
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
-     if (!(expr))                                                       \
-       {                                                                \
-         g_log (G_LOG_DOMAIN,                                           \
-                G_LOG_LEVEL_CRITICAL,                                   \
-               "file %s: line %d: assertion '%s' failed.\n"            \
-               "There is a disparity between the internal view of the PsppSheetView,\n"    \
-               "and the GtkTreeModel.  This generally means that the model has changed\n"\
-               "without letting the view know.  Any display from now on is likely to\n"  \
-               "be incorrect.\n",                                                        \
-                __FILE__,                                               \
-                __LINE__,                                               \
-                #expr);                                                 \
-         return;                                                        \
-       };                               }G_STMT_END
-#endif
-
-
-/* functions that shouldn't be exported */
-void         _pspp_sheet_selection_internal_select_node (PsppSheetSelection  *selection,
-                                                      int                node,
-                                                      GtkTreePath       *path,
-                                                       PsppSheetSelectMode  mode,
-                                                      gboolean           override_browse_mode);
-void         _pspp_sheet_selection_emit_changed         (PsppSheetSelection  *selection);
-void         _pspp_sheet_view_find_node                 (PsppSheetView       *tree_view,
-                                                      GtkTreePath       *path,
-                                                      int              *node);
-GtkTreePath *_pspp_sheet_view_find_path                 (PsppSheetView       *tree_view,
-                                                      int                    node);
-void         _pspp_sheet_view_child_move_resize         (PsppSheetView       *tree_view,
-                                                      GtkWidget         *widget,
-                                                      gint               x,
-                                                      gint               y,
-                                                      gint               width,
-                                                      gint               height);
-void         _pspp_sheet_view_queue_draw_node           (PsppSheetView       *tree_view,
-                                                      int                    node,
-                                                      const GdkRectangle *clip_rect);
-
-void _pspp_sheet_view_column_realize_button   (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_set_tree_view    (PsppSheetViewColumn *column,
-                                            PsppSheetView       *tree_view);
-void _pspp_sheet_view_column_unset_model      (PsppSheetViewColumn *column,
-                                            GtkTreeModel      *old_model);
-void _pspp_sheet_view_column_unset_tree_view  (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_set_width        (PsppSheetViewColumn *column,
-                                            gint               width);
-void _pspp_sheet_view_column_start_drag       (PsppSheetView       *tree_view,
-                                            PsppSheetViewColumn *column);
-gboolean _pspp_sheet_view_column_cell_event   (PsppSheetViewColumn  *tree_column,
-                                            GtkCellEditable   **editable_widget,
-                                            GdkEvent           *event,
-                                            gchar              *path_string,
-                                            const GdkRectangle *background_area,
-                                            const GdkRectangle *cell_area,
-                                            guint               flags);
-void _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
-                                         GtkCellEditable   *editable_widget);
-void _pspp_sheet_view_column_stop_editing  (PsppSheetViewColumn *tree_column);
-void _pspp_sheet_view_install_mark_rows_col_dirty (PsppSheetView *tree_view);
-void             _pspp_sheet_view_column_autosize          (PsppSheetView       *tree_view,
-                                                         PsppSheetViewColumn *column);
-
-gboolean         _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column);
-GtkCellRenderer *_pspp_sheet_view_column_get_edited_cell   (PsppSheetViewColumn *column);
-gint             _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column);
-GtkCellRenderer *_pspp_sheet_view_column_get_cell_at_pos   (PsppSheetViewColumn *column,
-                                                         gint               x);
-
-PsppSheetSelection* _pspp_sheet_selection_new                (void);
-PsppSheetSelection* _pspp_sheet_selection_new_with_tree_view (PsppSheetView      *tree_view);
-void              _pspp_sheet_selection_set_tree_view      (PsppSheetSelection *selection,
-                                                          PsppSheetView      *tree_view);
-
-void             _pspp_sheet_view_column_cell_render      (PsppSheetViewColumn  *tree_column,
-                                                           cairo_t *cr,
-                                                         const GdkRectangle *background_area,
-                                                         const GdkRectangle *cell_area,
-                                                         guint               flags);
-void             _pspp_sheet_view_column_get_focus_area   (PsppSheetViewColumn  *tree_column,
-                                                         const GdkRectangle *background_area,
-                                                         const GdkRectangle *cell_area,
-                                                         GdkRectangle       *focus_area);
-gboolean         _pspp_sheet_view_column_cell_focus       (PsppSheetViewColumn  *tree_column,
-                                                         gint                direction,
-                                                         gboolean            left,
-                                                         gboolean            right);
-void             _pspp_sheet_view_column_cell_draw_focus  (PsppSheetViewColumn  *tree_column,
-                                                           cairo_t *cr,
-                                                         const GdkRectangle *background_area,
-                                                         const GdkRectangle *cell_area,
-                                                         guint               flags);
-void             _pspp_sheet_view_column_cell_set_dirty         (PsppSheetViewColumn  *tree_column);
-void              _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
-                                                           GtkCellRenderer   *cell,
-                                                           gint              *left,
-                                                           gint              *right);
-
-gboolean pspp_sheet_view_node_is_selected (PsppSheetView *tree_view,
-                                           int node);
-void pspp_sheet_view_node_select (PsppSheetView *tree_view,
-                                  int node);
-void pspp_sheet_view_node_unselect (PsppSheetView *tree_view,
-                                    int node);
-
-gint
-pspp_sheet_view_node_next (PsppSheetView *tree_view,
-                           gint node);
-gint
-pspp_sheet_view_node_prev (PsppSheetView *tree_view,
-                           gint node);
-
-#endif /* __GTK_TREE_PRIVATE_H__ */
-
diff --git a/src/ui/gui/pspp-sheet-selection.c b/src/ui/gui/pspp-sheet-selection.c
deleted file mode 100644 (file)
index 9808914..0000000
+++ /dev/null
@@ -1,1303 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeselection.h
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "ui/gui/pspp-sheet-private.h"
-
-#include <gtk/gtk.h>
-#include <string.h>
-
-#include "ui/gui/pspp-sheet-selection.h"
-
-#include "libpspp/range-set.h"
-
-static void pspp_sheet_selection_finalize          (GObject               *object);
-static gint pspp_sheet_selection_real_select_all   (PsppSheetSelection      *selection);
-static gint pspp_sheet_selection_real_unselect_all (PsppSheetSelection      *selection);
-static gint pspp_sheet_selection_real_select_node  (PsppSheetSelection      *selection,
-                                                 int node,
-                                                 gboolean               select);
-
-enum
-{
-  CHANGED,
-  LAST_SIGNAL
-};
-
-static guint tree_selection_signals [LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (PsppSheetSelection, pspp_sheet_selection, G_TYPE_OBJECT)
-
-static void
-pspp_sheet_selection_class_init (PsppSheetSelectionClass *class)
-{
-  GObjectClass *object_class;
-
-  object_class = (GObjectClass*) class;
-
-  object_class->finalize = pspp_sheet_selection_finalize;
-  class->changed = NULL;
-
-  tree_selection_signals[CHANGED] =
-    g_signal_new ("changed",
-                 G_OBJECT_CLASS_TYPE (object_class),
-                 G_SIGNAL_RUN_FIRST,
-                 G_STRUCT_OFFSET (PsppSheetSelectionClass, changed),
-                 NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-}
-
-static void
-pspp_sheet_selection_init (PsppSheetSelection *selection)
-{
-  selection->type = PSPP_SHEET_SELECTION_SINGLE;
-}
-
-static void
-pspp_sheet_selection_finalize (GObject *object)
-{
-  G_OBJECT_CLASS (pspp_sheet_selection_parent_class)->finalize (object);
-}
-
-/**
- * _pspp_sheet_selection_new:
- *
- * Creates a new #PsppSheetSelection object.  This function should not be invoked,
- * as each #PsppSheetView will create its own #PsppSheetSelection.
- *
- * Return value: A newly created #PsppSheetSelection object.
- **/
-PsppSheetSelection*
-_pspp_sheet_selection_new (void)
-{
-  PsppSheetSelection *selection;
-
-  selection = g_object_new (PSPP_TYPE_SHEET_SELECTION, NULL);
-
-  return selection;
-}
-
-/**
- * _pspp_sheet_selection_new_with_tree_view:
- * @tree_view: The #PsppSheetView.
- *
- * Creates a new #PsppSheetSelection object.  This function should not be invoked,
- * as each #PsppSheetView will create its own #PsppSheetSelection.
- *
- * Return value: A newly created #PsppSheetSelection object.
- **/
-PsppSheetSelection*
-_pspp_sheet_selection_new_with_tree_view (PsppSheetView *tree_view)
-{
-  PsppSheetSelection *selection;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  selection = _pspp_sheet_selection_new ();
-  _pspp_sheet_selection_set_tree_view (selection, tree_view);
-
-  return selection;
-}
-
-/**
- * _pspp_sheet_selection_set_tree_view:
- * @selection: A #PsppSheetSelection.
- * @tree_view: The #PsppSheetView.
- *
- * Sets the #PsppSheetView of @selection.  This function should not be invoked, as
- * it is used internally by #PsppSheetView.
- **/
-void
-_pspp_sheet_selection_set_tree_view (PsppSheetSelection *selection,
-                                   PsppSheetView      *tree_view)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  if (tree_view != NULL)
-    g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  selection->tree_view = tree_view;
-}
-
-/**
- * pspp_sheet_selection_set_mode:
- * @selection: A #PsppSheetSelection.
- * @type: The selection mode
- *
- * Sets the selection mode of the @selection.  If the previous type was
- * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, then the
- * anchor is kept selected, if it was previously selected.
- **/
-void
-pspp_sheet_selection_set_mode (PsppSheetSelection *selection,
-                            PsppSheetSelectionMode  type)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-
-  if (selection->type == type)
-    return;
-
-  if (type == PSPP_SHEET_SELECTION_NONE)
-    {
-      pspp_sheet_selection_unselect_all (selection);
-
-      gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-      selection->tree_view->priv->anchor = NULL;
-    }
-  else if (type == PSPP_SHEET_SELECTION_SINGLE ||
-          type == PSPP_SHEET_SELECTION_BROWSE)
-    {
-      int node = -1;
-      gint selected = FALSE;
-      GtkTreePath *anchor_path = NULL;
-
-      if (selection->tree_view->priv->anchor)
-       {
-          anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
-          if (anchor_path)
-            {
-              _pspp_sheet_view_find_node (selection->tree_view,
-                                        anchor_path,
-                                        &node);
-
-              if (node >= 0 && pspp_sheet_view_node_is_selected (selection->tree_view, node))
-                selected = TRUE;
-            }
-       }
-
-      /* We do this so that we unconditionally unset all rows
-       */
-      pspp_sheet_selection_unselect_all (selection);
-
-      if (node >= 0 && selected)
-       _pspp_sheet_selection_internal_select_node (selection,
-                                                 node,
-                                                 anchor_path,
-                                                  0,
-                                                 FALSE);
-      if (anchor_path)
-       gtk_tree_path_free (anchor_path);
-    }
-
-  /* XXX unselect all columns when switching to/from rectangular selection? */
-
-  selection->type = type;
-}
-
-/**
- * pspp_sheet_selection_get_mode:
- * @selection: a #PsppSheetSelection
- *
- * Gets the selection mode for @selection. See
- * pspp_sheet_selection_set_mode().
- *
- * Return value: the current selection mode
- **/
-PsppSheetSelectionMode
-pspp_sheet_selection_get_mode (PsppSheetSelection *selection)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), PSPP_SHEET_SELECTION_SINGLE);
-
-  return selection->type;
-}
-
-/**
- * pspp_sheet_selection_get_tree_view:
- * @selection: A #PsppSheetSelection
- *
- * Returns the tree view associated with @selection.
- *
- * Return value: A #PsppSheetView
- **/
-PsppSheetView *
-pspp_sheet_selection_get_tree_view (PsppSheetSelection *selection)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
-
-  return selection->tree_view;
-}
-
-/**
- * pspp_sheet_selection_get_selected:
- * @selection: A #PsppSheetSelection.
- * @model: (out) (allow-none): A pointer to set to the #GtkTreeModel, or NULL.
- * @iter: (allow-none): The #GtkTreeIter, or NULL.
- *
- * Sets @iter to the currently selected node if @selection is set to
- * #PSPP_SHEET_SELECTION_SINGLE or #PSPP_SHEET_SELECTION_BROWSE.  @iter may be
- * NULL if you just want to test if @selection has any selected nodes.  @model
- * is filled with the current model as a convenience.  This function will not
- * work if @selection's mode is #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE.
- *
- * Return value: TRUE, if there is a selected node.
- **/
-gboolean
-pspp_sheet_selection_get_selected (PsppSheetSelection  *selection,
-                                GtkTreeModel     **model,
-                                GtkTreeIter       *iter)
-{
-  int node;
-  GtkTreePath *anchor_path;
-  gboolean retval;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
-  g_return_val_if_fail (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
-                        selection->type != PSPP_SHEET_SELECTION_RECTANGLE,
-                        FALSE);
-  g_return_val_if_fail (selection->tree_view != NULL, FALSE);
-
-  /* Clear the iter */
-  if (iter)
-    memset (iter, 0, sizeof (GtkTreeIter));
-
-  if (model)
-    *model = selection->tree_view->priv->model;
-
-  if (selection->tree_view->priv->anchor == NULL)
-    return FALSE;
-
-  anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
-  if (anchor_path == NULL)
-    return FALSE;
-
-  retval = FALSE;
-
-  _pspp_sheet_view_find_node (selection->tree_view,
-                              anchor_path,
-                              &node);
-
-  if (pspp_sheet_view_node_is_selected (selection->tree_view, node))
-    {
-      /* we only want to return the anchor if it exists in the rbtree and
-       * is selected.
-       */
-      if (iter == NULL)
-       retval = TRUE;
-      else
-        retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
-                                          iter,
-                                          anchor_path);
-    }
-  else
-    {
-      /* We don't want to return the anchor if it isn't actually selected.
-       */
-      retval = FALSE;
-    }
-
-  gtk_tree_path_free (anchor_path);
-
-  return retval;
-}
-
-/**
- * pspp_sheet_selection_get_selected_rows:
- * @selection: A #PsppSheetSelection.
- * @model: (allow-none): A pointer to set to the #GtkTreeModel, or NULL.
- *
- * Creates a list of path of all selected rows. Additionally, if you are
- * planning on modifying the model after calling this function, you may
- * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
- * To do this, you can use gtk_tree_row_reference_new().
- *
- * To free the return value, use:
- * |[
- * g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
- * g_list_free (list);
- * ]|
- *
- * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
- *
- * Since: 2.2
- **/
-GList *
-pspp_sheet_selection_get_selected_rows (PsppSheetSelection   *selection,
-                                      GtkTreeModel      **model)
-{
-  const struct range_tower_node *node;
-  unsigned long int start;
-  GList *list = NULL;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
-  g_return_val_if_fail (selection->tree_view != NULL, NULL);
-
-  if (model)
-    *model = selection->tree_view->priv->model;
-
-  if (selection->tree_view->priv->row_count == 0)
-    return NULL;
-
-  if (selection->type == PSPP_SHEET_SELECTION_NONE)
-    return NULL;
-  else if (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
-           selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      GtkTreeIter iter;
-
-      if (pspp_sheet_selection_get_selected (selection, NULL, &iter))
-        {
-         GtkTreePath *path;
-
-         path = gtk_tree_model_get_path (selection->tree_view->priv->model, &iter);
-         list = g_list_append (list, path);
-
-         return list;
-       }
-
-      return NULL;
-    }
-
-  RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
-    {
-      unsigned long int width = range_tower_node_get_width (node);
-      unsigned long int index;
-
-      for (index = start; index < start + width; index++)
-        list = g_list_prepend (list, gtk_tree_path_new_from_indices (index, -1));
-    }
-
-  return g_list_reverse (list);
-}
-
-/**
- * pspp_sheet_selection_count_selected_rows:
- * @selection: A #PsppSheetSelection.
- *
- * Returns the number of rows that have been selected in @tree.
- *
- * Return value: The number of rows selected.
- *
- * Since: 2.2
- **/
-gint
-pspp_sheet_selection_count_selected_rows (PsppSheetSelection *selection)
-{
-  const struct range_tower_node *node;
-  unsigned long int start;
-  gint count = 0;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), 0);
-  g_return_val_if_fail (selection->tree_view != NULL, 0);
-
-  if (selection->tree_view->priv->row_count == 0)
-    return 0;
-
-  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
-      selection->type == PSPP_SHEET_SELECTION_BROWSE)
-    {
-      if (pspp_sheet_selection_get_selected (selection, NULL, NULL))
-       return 1;
-      else
-       return 0;
-    }
-
-  count = 0;
-  RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
-    count += range_tower_node_get_width (node);
-
-  return count;
-}
-
-/* pspp_sheet_selection_selected_foreach helper */
-static void
-model_changed (gpointer data)
-{
-  gboolean *stop = (gboolean *)data;
-
-  *stop = TRUE;
-}
-
-/**
- * pspp_sheet_selection_selected_foreach:
- * @selection: A #PsppSheetSelection.
- * @func: The function to call for each selected node.
- * @data: user data to pass to the function.
- *
- * Calls a function for each selected node. Note that you cannot modify
- * the tree or selection from within this function. As a result,
- * pspp_sheet_selection_get_selected_rows() might be more useful.
- **/
-void
-pspp_sheet_selection_selected_foreach (PsppSheetSelection            *selection,
-                                    PsppSheetSelectionForeachFunc  func,
-                                    gpointer                     data)
-{
-  const struct range_tower_node *node;
-  unsigned long int start;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-
-  gulong inserted_id, deleted_id, reordered_id, changed_id;
-  gboolean stop = FALSE;
-
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-
-  if (func == NULL ||
-      selection->tree_view->priv->row_count == 0)
-    return;
-
-  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
-      selection->type == PSPP_SHEET_SELECTION_BROWSE)
-    {
-      if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
-       {
-         path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-         gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
-         (* func) (selection->tree_view->priv->model, path, &iter, data);
-         gtk_tree_path_free (path);
-       }
-      return;
-    }
-
-  model = selection->tree_view->priv->model;
-  g_object_ref (model);
-
-  /* connect to signals to monitor changes in treemodel */
-  inserted_id = g_signal_connect_swapped (model, "row-inserted",
-                                         G_CALLBACK (model_changed),
-                                         &stop);
-  deleted_id = g_signal_connect_swapped (model, "row-deleted",
-                                        G_CALLBACK (model_changed),
-                                        &stop);
-  reordered_id = g_signal_connect_swapped (model, "rows-reordered",
-                                          G_CALLBACK (model_changed),
-                                          &stop);
-  changed_id = g_signal_connect_swapped (selection->tree_view, "notify::model",
-                                        G_CALLBACK (model_changed),
-                                        &stop);
-
-  RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
-    {
-      unsigned long int width = range_tower_node_get_width (node);
-      unsigned long int index;
-
-      for (index = start; index < start + width; index++)
-        {
-          GtkTreePath *path;
-          GtkTreeIter iter;
-
-          path = gtk_tree_path_new_from_indices (index, -1);
-          gtk_tree_model_get_iter (model, &iter, path);
-         (* func) (model, path, &iter, data);
-          gtk_tree_path_free (path);
-        }
-    }
-
-  g_signal_handler_disconnect (model, inserted_id);
-  g_signal_handler_disconnect (model, deleted_id);
-  g_signal_handler_disconnect (model, reordered_id);
-  g_signal_handler_disconnect (selection->tree_view, changed_id);
-  g_object_unref (model);
-
-  /* check if we have to spew a scary message */
-  if (stop)
-    g_warning ("The model has been modified from within pspp_sheet_selection_selected_foreach.\n"
-              "This function is for observing the selections of the tree only.  If\n"
-              "you are trying to get all selected items from the tree, try using\n"
-              "pspp_sheet_selection_get_selected_rows instead.\n");
-}
-
-/**
- * pspp_sheet_selection_select_path:
- * @selection: A #PsppSheetSelection.
- * @path: The #GtkTreePath to be selected.
- *
- * Select the row at @path.
- **/
-void
-pspp_sheet_selection_select_path (PsppSheetSelection *selection,
-                               GtkTreePath      *path)
-{
-  int node;
-  PsppSheetSelectMode mode = 0;
-
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (path != NULL);
-
-   _pspp_sheet_view_find_node (selection->tree_view,
-                               path,
-                               &node);
-
-  if (node < 0 || pspp_sheet_view_node_is_selected (selection->tree_view, node))
-    return;
-
-  if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-      selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-    mode = PSPP_SHEET_SELECT_MODE_TOGGLE;
-
-  _pspp_sheet_selection_internal_select_node (selection,
-                                           node,
-                                           path,
-                                            mode,
-                                           FALSE);
-}
-
-/**
- * pspp_sheet_selection_unselect_path:
- * @selection: A #PsppSheetSelection.
- * @path: The #GtkTreePath to be unselected.
- *
- * Unselects the row at @path.
- **/
-void
-pspp_sheet_selection_unselect_path (PsppSheetSelection *selection,
-                                 GtkTreePath      *path)
-{
-  int node;
-
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (path != NULL);
-
-  _pspp_sheet_view_find_node (selection->tree_view,
-                              path,
-                              &node);
-
-  if (node < 0 || !pspp_sheet_view_node_is_selected (selection->tree_view, node))
-    return;
-
-  _pspp_sheet_selection_internal_select_node (selection,
-                                           node,
-                                           path,
-                                            PSPP_SHEET_SELECT_MODE_TOGGLE,
-                                           TRUE);
-}
-
-/**
- * pspp_sheet_selection_select_iter:
- * @selection: A #PsppSheetSelection.
- * @iter: The #GtkTreeIter to be selected.
- *
- * Selects the specified iterator.
- **/
-void
-pspp_sheet_selection_select_iter (PsppSheetSelection *selection,
-                               GtkTreeIter      *iter)
-{
-  GtkTreePath *path;
-
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (selection->tree_view->priv->model != NULL);
-  g_return_if_fail (iter != NULL);
-
-  path = gtk_tree_model_get_path (selection->tree_view->priv->model,
-                                 iter);
-
-  if (path == NULL)
-    return;
-
-  pspp_sheet_selection_select_path (selection, path);
-  gtk_tree_path_free (path);
-}
-
-
-/**
- * pspp_sheet_selection_unselect_iter:
- * @selection: A #PsppSheetSelection.
- * @iter: The #GtkTreeIter to be unselected.
- *
- * Unselects the specified iterator.
- **/
-void
-pspp_sheet_selection_unselect_iter (PsppSheetSelection *selection,
-                                 GtkTreeIter      *iter)
-{
-  GtkTreePath *path;
-
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (selection->tree_view->priv->model != NULL);
-  g_return_if_fail (iter != NULL);
-
-  path = gtk_tree_model_get_path (selection->tree_view->priv->model,
-                                 iter);
-
-  if (path == NULL)
-    return;
-
-  pspp_sheet_selection_unselect_path (selection, path);
-  gtk_tree_path_free (path);
-}
-
-/**
- * pspp_sheet_selection_path_is_selected:
- * @selection: A #PsppSheetSelection.
- * @path: A #GtkTreePath to check selection on.
- *
- * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
- * does not point to a valid location, %FALSE is returned
- *
- * Return value: %TRUE if @path is selected.
- **/
-gboolean
-pspp_sheet_selection_path_is_selected (PsppSheetSelection *selection,
-                                    GtkTreePath      *path)
-{
-  int node;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
-  g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (selection->tree_view != NULL, FALSE);
-
-  if (selection->tree_view->priv->model == NULL)
-    return FALSE;
-
-  _pspp_sheet_view_find_node (selection->tree_view,
-                                 path,
-                                 &node);
-
-  if (node < 0 || !pspp_sheet_view_node_is_selected (selection->tree_view, node))
-    return FALSE;
-
-  return TRUE;
-}
-
-/**
- * pspp_sheet_selection_iter_is_selected:
- * @selection: A #PsppSheetSelection
- * @iter: A valid #GtkTreeIter
- *
- * Returns %TRUE if the row at @iter is currently selected.
- *
- * Return value: %TRUE, if @iter is selected
- **/
-gboolean
-pspp_sheet_selection_iter_is_selected (PsppSheetSelection *selection,
-                                    GtkTreeIter      *iter)
-{
-  GtkTreePath *path;
-  gboolean retval;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
-  g_return_val_if_fail (iter != NULL, FALSE);
-  g_return_val_if_fail (selection->tree_view != NULL, FALSE);
-  g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
-
-  path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
-  if (path == NULL)
-    return FALSE;
-
-  retval = pspp_sheet_selection_path_is_selected (selection, path);
-  gtk_tree_path_free (path);
-
-  return retval;
-}
-
-
-/* We have a real_{un,}select_all function that doesn't emit the signal, so we
- * can use it in other places without fear of the signal being emitted.
- */
-static gint
-pspp_sheet_selection_real_select_all (PsppSheetSelection *selection)
-{
-  const struct range_tower_node *node;
-  int row_count = selection->tree_view->priv->row_count;
-
-  if (row_count == 0)
-    return FALSE;
-
-  node = range_tower_first (selection->tree_view->priv->selected);
-  if (node
-      && range_tower_node_get_start (node) == 0
-      && range_tower_node_get_width (node) >= row_count)
-    return FALSE;
-
-  range_tower_set1 (selection->tree_view->priv->selected, 0, row_count);
-  pspp_sheet_selection_select_all_columns (selection);
-
-  /* XXX we could invalidate individual visible rows instead */
-  gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, NULL, TRUE);
-
-  return TRUE;
-}
-
-/**
- * pspp_sheet_selection_select_all:
- * @selection: A #PsppSheetSelection.
- *
- * Selects all the nodes and column. @selection must be set to
- * #PSPP_SHEET_SELECTION_MULTIPLE or  #PSPP_SHEET_SELECTION_RECTANGLE mode.
- **/
-void
-pspp_sheet_selection_select_all (PsppSheetSelection *selection)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-
-  if (selection->tree_view->priv->row_count == 0 || selection->tree_view->priv->model == NULL)
-    return;
-
-  g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-                    selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
-
-  if (pspp_sheet_selection_real_select_all (selection))
-    g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-static gint
-pspp_sheet_selection_real_unselect_all (PsppSheetSelection *selection)
-{
-  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
-      selection->type == PSPP_SHEET_SELECTION_BROWSE)
-    {
-      int node = -1;
-      GtkTreePath *anchor_path;
-
-      if (selection->tree_view->priv->anchor == NULL)
-       return FALSE;
-
-      anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
-      if (anchor_path == NULL)
-        return FALSE;
-
-      _pspp_sheet_view_find_node (selection->tree_view,
-                                anchor_path,
-                               &node);
-
-      gtk_tree_path_free (anchor_path);
-
-      if (node < 0)
-        return FALSE;
-
-      if (pspp_sheet_view_node_is_selected (selection->tree_view, node))
-       {
-         if (pspp_sheet_selection_real_select_node (selection, node, FALSE))
-           {
-             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-             selection->tree_view->priv->anchor = NULL;
-             return TRUE;
-           }
-       }
-      return FALSE;
-    }
-  else if (range_tower_is_empty (selection->tree_view->priv->selected))
-    return FALSE;
-  else
-    {
-      range_tower_set0 (selection->tree_view->priv->selected, 0, ULONG_MAX);
-      pspp_sheet_selection_unselect_all_columns (selection);
-
-      /* XXX we could invalidate individual visible rows instead */
-      gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, NULL, TRUE);
-
-      return TRUE;
-    }
-}
-
-/**
- * pspp_sheet_selection_unselect_all:
- * @selection: A #PsppSheetSelection.
- *
- * Unselects all the nodes and columns.
- **/
-void
-pspp_sheet_selection_unselect_all (PsppSheetSelection *selection)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-
-  if (selection->tree_view->priv->row_count == 0 || selection->tree_view->priv->model == NULL)
-    return;
-
-  if (pspp_sheet_selection_real_unselect_all (selection))
-    g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-enum
-{
-  RANGE_SELECT,
-  RANGE_UNSELECT
-};
-
-static gint
-pspp_sheet_selection_real_modify_range (PsppSheetSelection *selection,
-                                      gint              mode,
-                                     GtkTreePath      *start_path,
-                                     GtkTreePath      *end_path)
-{
-  int start_node, end_node;
-  GtkTreePath *anchor_path = NULL;
-  gboolean dirty = FALSE;
-
-  switch (gtk_tree_path_compare (start_path, end_path))
-    {
-    case 1:
-      _pspp_sheet_view_find_node (selection->tree_view,
-                               end_path,
-                               &start_node);
-      _pspp_sheet_view_find_node (selection->tree_view,
-                               start_path,
-                               &end_node);
-      anchor_path = start_path;
-      break;
-    case 0:
-      _pspp_sheet_view_find_node (selection->tree_view,
-                               start_path,
-                               &start_node);
-      end_node = start_node;
-      anchor_path = start_path;
-      break;
-    case -1:
-      _pspp_sheet_view_find_node (selection->tree_view,
-                               start_path,
-                               &start_node);
-      _pspp_sheet_view_find_node (selection->tree_view,
-                               end_path,
-                               &end_node);
-      anchor_path = start_path;
-      break;
-    }
-
-  g_return_val_if_fail (start_node >= 0, FALSE);
-  g_return_val_if_fail (end_node >= 0, FALSE);
-
-  if (anchor_path)
-    {
-      if (selection->tree_view->priv->anchor)
-       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
-      selection->tree_view->priv->anchor =
-       gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view),
-                                         selection->tree_view->priv->model,
-                                         anchor_path);
-    }
-
-  do
-    {
-      dirty |= pspp_sheet_selection_real_select_node (selection, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
-
-      if (start_node == end_node)
-       break;
-
-      start_node = pspp_sheet_view_node_next (selection->tree_view, start_node);
-      if (start_node < 0)
-        {
-          /* we just ran out of tree.  That means someone passed in bogus values.
-           */
-          return dirty;
-        }
-    }
-  while (TRUE);
-
-  return dirty;
-}
-
-/**
- * pspp_sheet_selection_select_range:
- * @selection: A #PsppSheetSelection.
- * @start_path: The initial node of the range.
- * @end_path: The final node of the range.
- *
- * Selects a range of nodes, determined by @start_path and @end_path inclusive.
- * @selection must be set to #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE mode.
- **/
-void
-pspp_sheet_selection_select_range (PsppSheetSelection *selection,
-                                GtkTreePath      *start_path,
-                                GtkTreePath      *end_path)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-                    selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
-  g_return_if_fail (selection->tree_view->priv->model != NULL);
-
-  if (pspp_sheet_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
-    g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-/**
- * pspp_sheet_selection_unselect_range:
- * @selection: A #PsppSheetSelection.
- * @start_path: The initial node of the range.
- * @end_path: The initial node of the range.
- *
- * Unselects a range of nodes, determined by @start_path and @end_path
- * inclusive.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_selection_unselect_range (PsppSheetSelection *selection,
-                                   GtkTreePath      *start_path,
-                                  GtkTreePath      *end_path)
-{
-  g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-  g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (selection->tree_view->priv->model != NULL);
-
-  if (pspp_sheet_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
-    g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-struct range_set *
-pspp_sheet_selection_get_range_set (PsppSheetSelection *selection)
-{
-  const struct range_tower_node *node;
-  unsigned long int start;
-  struct range_set *set;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection),
-                        range_set_create ());
-  g_return_val_if_fail (selection->tree_view != NULL, range_set_create ());
-
-  set = range_set_create ();
-  RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
-    range_set_set1 (set, start, range_tower_node_get_width (node));
-  return set;
-}
-
-/* Called internally by gtktreeview.c It handles actually selecting the tree.
- */
-
-/*
- * docs about the 'override_browse_mode', we set this flag when we want to
- * unset select the node and override the select browse mode behaviour (that is
- * 'one node should *always* be selected').
- */
-void
-_pspp_sheet_selection_internal_select_node (PsppSheetSelection *selection,
-                                         int               node,
-                                         GtkTreePath      *path,
-                                          PsppSheetSelectMode mode,
-                                         gboolean          override_browse_mode)
-{
-  gint dirty = FALSE;
-  GtkTreePath *anchor_path = NULL;
-
-  if (selection->type == PSPP_SHEET_SELECTION_NONE)
-    return;
-
-  if (selection->tree_view->priv->anchor)
-    anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
-  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
-      selection->type == PSPP_SHEET_SELECTION_BROWSE)
-    {
-      /* just unselect */
-      if (selection->type == PSPP_SHEET_SELECTION_BROWSE && override_browse_mode)
-        {
-         dirty = pspp_sheet_selection_real_unselect_all (selection);
-       }
-      /* Did we try to select the same node again? */
-      else if (selection->type == PSPP_SHEET_SELECTION_SINGLE &&
-              anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
-       {
-         if ((mode & PSPP_SHEET_SELECT_MODE_TOGGLE) == PSPP_SHEET_SELECT_MODE_TOGGLE)
-           {
-             dirty = pspp_sheet_selection_real_unselect_all (selection);
-           }
-       }
-      else
-       {
-         if (anchor_path)
-           {
-              dirty = pspp_sheet_selection_real_unselect_all (selection);
-
-             /* if dirty is TRUE at this point, we successfully unselected the
-              * old one, and can then select the new one */
-             if (dirty)
-               {
-                 if (selection->tree_view->priv->anchor)
-                    {
-                      gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-                      selection->tree_view->priv->anchor = NULL;
-                    }
-
-                 if (pspp_sheet_selection_real_select_node (selection, node, TRUE))
-                   {
-                     selection->tree_view->priv->anchor =
-                       gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-                   }
-               }
-           }
-         else
-           {
-             if (pspp_sheet_selection_real_select_node (selection, node, TRUE))
-               {
-                 dirty = TRUE;
-                 if (selection->tree_view->priv->anchor)
-                   gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
-                 selection->tree_view->priv->anchor =
-                   gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-               }
-           }
-       }
-    }
-  else if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-           selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      if ((mode & PSPP_SHEET_SELECT_MODE_EXTEND) == PSPP_SHEET_SELECT_MODE_EXTEND
-          && (anchor_path == NULL))
-       {
-         if (selection->tree_view->priv->anchor)
-           gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
-         selection->tree_view->priv->anchor =
-           gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-         dirty = pspp_sheet_selection_real_select_node (selection, node, TRUE);
-       }
-      else if ((mode & (PSPP_SHEET_SELECT_MODE_EXTEND | PSPP_SHEET_SELECT_MODE_TOGGLE)) == (PSPP_SHEET_SELECT_MODE_EXTEND | PSPP_SHEET_SELECT_MODE_TOGGLE))
-       {
-         pspp_sheet_selection_select_range (selection,
-                                          anchor_path,
-                                          path);
-       }
-      else if ((mode & PSPP_SHEET_SELECT_MODE_TOGGLE) == PSPP_SHEET_SELECT_MODE_TOGGLE)
-       {
-          bool selected = pspp_sheet_view_node_is_selected (selection->tree_view, node);
-         if (selection->tree_view->priv->anchor)
-           gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
-         selection->tree_view->priv->anchor =
-           gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-
-         if (selected)
-           dirty |= pspp_sheet_selection_real_select_node (selection, node, FALSE);
-         else
-           dirty |= pspp_sheet_selection_real_select_node (selection, node, TRUE);
-       }
-      else if ((mode & PSPP_SHEET_SELECT_MODE_EXTEND) == PSPP_SHEET_SELECT_MODE_EXTEND)
-       {
-         dirty = pspp_sheet_selection_real_unselect_all (selection);
-         dirty |= pspp_sheet_selection_real_modify_range (selection,
-                                                         RANGE_SELECT,
-                                                        anchor_path,
-                                                        path);
-       }
-      else
-       {
-         dirty = pspp_sheet_selection_real_unselect_all (selection);
-
-         if (selection->tree_view->priv->anchor)
-           gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
-         selection->tree_view->priv->anchor =
-           gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-
-         dirty |= pspp_sheet_selection_real_select_node (selection, node, TRUE);
-       }
-    }
-
-  if (anchor_path)
-    gtk_tree_path_free (anchor_path);
-
-  if (dirty)
-    g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-
-void
-_pspp_sheet_selection_emit_changed (PsppSheetSelection *selection)
-{
-  g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-/* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
- */
-
-static gint
-pspp_sheet_selection_real_select_node (PsppSheetSelection *selection,
-                                    int               node,
-                                    gboolean          select)
-{
-  select = !! select;
-  if (pspp_sheet_view_node_is_selected (selection->tree_view, node) != select)
-    {
-      if (select)
-        pspp_sheet_view_node_select (selection->tree_view, node);
-      else
-        pspp_sheet_view_node_unselect (selection->tree_view, node);
-
-      _pspp_sheet_view_queue_draw_node (selection->tree_view, node, NULL);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-void
-pspp_sheet_selection_unselect_all_columns (PsppSheetSelection *selection)
-{
-  PsppSheetView *sheet_view = selection->tree_view;
-  gboolean changed;
-  GList *list;
-
-  changed = FALSE;
-  for (list = sheet_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column = list->data;
-      if (column->selected)
-        {
-          column->selected = FALSE;
-          changed = TRUE;
-        }
-    }
-  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
-      _pspp_sheet_selection_emit_changed (selection);
-    }
-}
-
-GList *
-pspp_sheet_selection_get_selected_columns (PsppSheetSelection *selection)
-{
-  PsppSheetView *sheet_view = selection->tree_view;
-  GList *selected_columns = NULL;
-  GList *iter;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
-  g_return_val_if_fail (selection->tree_view != NULL, NULL);
-
-  if (selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
-    return NULL;
-
-  for (iter = sheet_view->priv->columns; iter; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      if (column->selected)
-        selected_columns = g_list_prepend (selected_columns, column);
-    }
-  return g_list_reverse (selected_columns);
-}
-
-gint
-pspp_sheet_selection_count_selected_columns (PsppSheetSelection *selection)
-{
-  PsppSheetView *sheet_view = selection->tree_view;
-  GList *list;
-  gint n;
-
-  n = 0;
-  for (list = sheet_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column = list->data;
-      if (column->selected)
-        n++;
-    }
-  return n;
-}
-
-void
-pspp_sheet_selection_select_all_columns (PsppSheetSelection *selection)
-{
-  PsppSheetView *sheet_view = selection->tree_view;
-  gboolean changed;
-  GList *list;
-
-  changed = FALSE;
-  for (list = sheet_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column = list->data;
-      if (!column->selected && column->selectable)
-        {
-          /* XXX should use pspp_sheet_view_column_set_selected() here (and
-             elsewhere) but we want to call
-             _pspp_sheet_selection_emit_changed() only once for all the
-             columns. */
-          column->selected = TRUE;
-          changed = TRUE;
-        }
-    }
-  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      _pspp_sheet_selection_emit_changed (selection);
-      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
-    }
-}
-
-void
-pspp_sheet_selection_select_column (PsppSheetSelection        *selection,
-                                    PsppSheetViewColumn       *column)
-{
-  if (!column->selected && column->selectable)
-    {
-      column->selected = TRUE;
-      if (selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-        {
-          _pspp_sheet_selection_emit_changed (selection);
-          gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
-        }
-    }
-}
-
-void
-pspp_sheet_selection_select_column_range  (PsppSheetSelection        *selection,
-                                           PsppSheetViewColumn       *first,
-                                           PsppSheetViewColumn       *last)
-{
-  PsppSheetView *sheet_view = selection->tree_view;
-  gboolean in_range;
-  gboolean changed;
-  GList *list;
-
-  in_range = FALSE;
-  changed = FALSE;
-  for (list = sheet_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column = list->data;
-      gboolean c0 = column == first;
-      gboolean c1 = column == last;
-
-      if (in_range || c0 || c1)
-        {
-          if (!column->selected && column->selectable)
-            {
-              column->selected = TRUE;
-              changed = TRUE;
-            }
-        }
-
-      in_range = in_range ^ c0 ^ c1;
-    }
-  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      _pspp_sheet_selection_emit_changed (selection);
-      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
-    }
-}
diff --git a/src/ui/gui/pspp-sheet-selection.h b/src/ui/gui/pspp-sheet-selection.h
deleted file mode 100644 (file)
index ded218c..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeselection.h
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __PSPP_SHEET_SELECTION_H__
-#define __PSPP_SHEET_SELECTION_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-
-#define PSPP_TYPE_SHEET_SELECTION                      (pspp_sheet_selection_get_type ())
-#define PSPP_SHEET_SELECTION(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelection))
-#define PSPP_SHEET_SELECTION_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelectionClass))
-#define PSPP_IS_SHEET_SELECTION(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_SELECTION))
-#define PSPP_IS_SHEET_SELECTION_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_SELECTION))
-#define PSPP_SHEET_SELECTION_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelectionClass))
-
-typedef enum
-  {
-    /* Same as GtkSelectionMode. */
-    PSPP_SHEET_SELECTION_NONE = GTK_SELECTION_NONE,
-    PSPP_SHEET_SELECTION_SINGLE = GTK_SELECTION_SINGLE,
-    PSPP_SHEET_SELECTION_BROWSE = GTK_SELECTION_BROWSE,
-    PSPP_SHEET_SELECTION_MULTIPLE = GTK_SELECTION_MULTIPLE,
-
-    /* PsppSheetView extension. */
-    PSPP_SHEET_SELECTION_RECTANGLE = 10
-  }
-PsppSheetSelectionMode;
-
-typedef gboolean (* PsppSheetSelectionFunc)    (PsppSheetSelection  *selection,
-                                             GtkTreeModel      *model,
-                                             GtkTreePath       *path,
-                                              gboolean           path_currently_selected,
-                                             gpointer           data);
-typedef void (* PsppSheetSelectionForeachFunc) (GtkTreeModel      *model,
-                                             GtkTreePath       *path,
-                                             GtkTreeIter       *iter,
-                                             gpointer           data);
-
-struct _PsppSheetSelection
-{
-  GObject parent;
-
-  /*< private >*/
-
-  PsppSheetView *PSEAL (tree_view);
-  PsppSheetSelectionMode PSEAL (type);
-};
-
-struct _PsppSheetSelectionClass
-{
-  GObjectClass parent_class;
-
-  void (* changed) (PsppSheetSelection *selection);
-
-  /* Padding for future expansion */
-  void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
-};
-
-
-GType            pspp_sheet_selection_get_type            (void) G_GNUC_CONST;
-
-void             pspp_sheet_selection_set_mode            (PsppSheetSelection            *selection,
-                                                        PsppSheetSelectionMode             type);
-PsppSheetSelectionMode pspp_sheet_selection_get_mode        (PsppSheetSelection            *selection);
-void             pspp_sheet_selection_set_select_function (PsppSheetSelection            *selection,
-                                                        PsppSheetSelectionFunc         func,
-                                                        gpointer                     data,
-                                                        GDestroyNotify               destroy);
-gpointer         pspp_sheet_selection_get_user_data       (PsppSheetSelection            *selection);
-PsppSheetView*     pspp_sheet_selection_get_tree_view       (PsppSheetSelection            *selection);
-
-PsppSheetSelectionFunc pspp_sheet_selection_get_select_function (PsppSheetSelection        *selection);
-
-/* Only meaningful if PSPP_SHEET_SELECTION_SINGLE or PSPP_SHEET_SELECTION_BROWSE is set */
-/* Use selected_foreach or get_selected_rows for
-   PSPP_SHEET_SELECTION_MULTIPLE */
-gboolean         pspp_sheet_selection_get_selected        (PsppSheetSelection            *selection,
-                                                        GtkTreeModel               **model,
-                                                        GtkTreeIter                 *iter);
-GList *          pspp_sheet_selection_get_selected_rows   (PsppSheetSelection            *selection,
-                                                         GtkTreeModel               **model);
-gint             pspp_sheet_selection_count_selected_rows (PsppSheetSelection            *selection);
-void             pspp_sheet_selection_selected_foreach    (PsppSheetSelection            *selection,
-                                                        PsppSheetSelectionForeachFunc  func,
-                                                        gpointer                     data);
-void             pspp_sheet_selection_select_path         (PsppSheetSelection            *selection,
-                                                        GtkTreePath                 *path);
-void             pspp_sheet_selection_unselect_path       (PsppSheetSelection            *selection,
-                                                        GtkTreePath                 *path);
-void             pspp_sheet_selection_select_iter         (PsppSheetSelection            *selection,
-                                                        GtkTreeIter                 *iter);
-void             pspp_sheet_selection_unselect_iter       (PsppSheetSelection            *selection,
-                                                        GtkTreeIter                 *iter);
-gboolean         pspp_sheet_selection_path_is_selected    (PsppSheetSelection            *selection,
-                                                        GtkTreePath                 *path);
-gboolean         pspp_sheet_selection_iter_is_selected    (PsppSheetSelection            *selection,
-                                                        GtkTreeIter                 *iter);
-void             pspp_sheet_selection_select_all          (PsppSheetSelection            *selection);
-void             pspp_sheet_selection_unselect_all        (PsppSheetSelection            *selection);
-void             pspp_sheet_selection_select_range        (PsppSheetSelection            *selection,
-                                                        GtkTreePath                 *start_path,
-                                                        GtkTreePath                 *end_path);
-void             pspp_sheet_selection_unselect_range      (PsppSheetSelection            *selection,
-                                                         GtkTreePath                 *start_path,
-                                                        GtkTreePath                 *end_path);
-struct range_set *pspp_sheet_selection_get_range_set (PsppSheetSelection *selection);
-
-
-GList *          pspp_sheet_selection_get_selected_columns (PsppSheetSelection            *selection);
-gint             pspp_sheet_selection_count_selected_columns (PsppSheetSelection            *selection);
-void             pspp_sheet_selection_select_all_columns (PsppSheetSelection        *selection);
-void             pspp_sheet_selection_unselect_all_columns (PsppSheetSelection        *selection);
-void             pspp_sheet_selection_select_column        (PsppSheetSelection        *selection,
-                                                            PsppSheetViewColumn       *column);
-void             pspp_sheet_selection_select_column_range  (PsppSheetSelection        *selection,
-                                                            PsppSheetViewColumn       *first,
-                                                            PsppSheetViewColumn       *last);
-
-G_END_DECLS
-
-#endif /* __PSPP_SHEET_SELECTION_H__ */
diff --git a/src/ui/gui/pspp-sheet-view-column.c b/src/ui/gui/pspp-sheet-view-column.c
deleted file mode 100644 (file)
index cd3fae3..0000000
+++ /dev/null
@@ -1,4345 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2015 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeviewcolumn.c
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "ui/gui/pspp-sheet-private.h"
-
-#include <errno.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/pspp-widget-facade.h"
-
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-
-#define P_(STRING) STRING
-#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-
-enum
-{
-  PROP_0,
-  PROP_VISIBLE,
-  PROP_RESIZABLE,
-  PROP_WIDTH,
-  PROP_SPACING,
-  PROP_FIXED_WIDTH,
-  PROP_MIN_WIDTH,
-  PROP_MAX_WIDTH,
-  PROP_TITLE,
-  PROP_EXPAND,
-  PROP_CLICKABLE,
-  PROP_WIDGET,
-  PROP_ALIGNMENT,
-  PROP_REORDERABLE,
-  PROP_SORT_INDICATOR,
-  PROP_SORT_ORDER,
-  PROP_SORT_COLUMN_ID,
-  PROP_QUICK_EDIT,
-  PROP_SELECTED,
-  PROP_SELECTABLE,
-  PROP_ROW_HEAD,
-  PROP_TABBABLE
-};
-
-enum
-{
-  CLICKED,
-  QUERY_TOOLTIP,
-  POPUP_MENU,
-  BUTTON_PRESS_EVENT,
-  LAST_SIGNAL
-};
-
-typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
-struct _PsppSheetViewColumnCellInfo
-{
-  GtkCellRenderer *cell;
-  GSList *attributes;
-  PsppSheetCellDataFunc func;
-  gpointer func_data;
-  GDestroyNotify destroy;
-  gint requested_width;
-  gint real_width;
-  guint expand : 1;
-  guint pack : 1;
-  guint has_focus : 1;
-  guint in_editing_mode : 1;
-};
-
-/* Type methods */
-static void pspp_sheet_view_column_cell_layout_init              (GtkCellLayoutIface      *iface);
-
-/* GObject methods */
-static void pspp_sheet_view_column_set_property                  (GObject                 *object,
-                                                               guint                    prop_id,
-                                                               const GValue            *value,
-                                                               GParamSpec              *pspec);
-static void pspp_sheet_view_column_get_property                  (GObject                 *object,
-                                                               guint                    prop_id,
-                                                               GValue                  *value,
-                                                               GParamSpec              *pspec);
-static void pspp_sheet_view_column_finalize                      (GObject                 *object);
-
-/* GtkCellLayout implementation */
-static void pspp_sheet_view_column_cell_layout_pack_start         (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell,
-                                                                 gboolean               expand);
-static void pspp_sheet_view_column_cell_layout_pack_end           (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell,
-                                                                 gboolean               expand);
-static void pspp_sheet_view_column_cell_layout_clear              (GtkCellLayout         *cell_layout);
-static void pspp_sheet_view_column_cell_layout_add_attribute      (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell,
-                                                                 const gchar           *attribute,
-                                                                 gint                   column);
-static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell,
-                                                                 GtkCellLayoutDataFunc  func,
-                                                                 gpointer               func_data,
-                                                                 GDestroyNotify         destroy);
-static void pspp_sheet_view_column_cell_layout_clear_attributes   (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell);
-static void pspp_sheet_view_column_cell_layout_reorder            (GtkCellLayout         *cell_layout,
-                                                                 GtkCellRenderer       *cell,
-                                                                 gint                   position);
-static GList *pspp_sheet_view_column_cell_layout_get_cells        (GtkCellLayout         *cell_layout);
-
-/* Button handling code */
-static void pspp_sheet_view_column_create_button                 (PsppSheetViewColumn       *tree_column);
-void pspp_sheet_view_column_update_button                 (PsppSheetViewColumn       *tree_column);
-
-/* Button signal handlers */
-static gint pspp_sheet_view_column_button_event                  (GtkWidget               *widget,
-                                                               GdkEventButton             *event,
-                                                               gpointer                 data);
-static void pspp_sheet_view_column_button_clicked                (GtkWidget               *widget,
-                                                               gpointer                 data);
-static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
-                                                      gpointer data);
-static gboolean pspp_sheet_view_column_mnemonic_activate         (GtkWidget *widget,
-                                                               gboolean   group_cycling,
-                                                               gpointer   data);
-static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
-static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
-                                                              GdkEventButton *);
-
-/* Property handlers */
-static void pspp_sheet_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
-                                                               PsppSheetViewColumn       *tree_column);
-
-/* Internal functions */
-static void pspp_sheet_view_column_sort                          (PsppSheetViewColumn       *tree_column,
-                                                               gpointer                 data);
-static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn       *tree_column);
-static void pspp_sheet_view_column_set_attributesv               (PsppSheetViewColumn       *tree_column,
-                                                               GtkCellRenderer         *cell_renderer,
-                                                               va_list                  args);
-static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
-                                                                     GtkCellRenderer   *cell_renderer);
-
-/* cell list manipulation */
-static GList *pspp_sheet_view_column_cell_first                  (PsppSheetViewColumn      *tree_column);
-static GList *pspp_sheet_view_column_cell_last                   (PsppSheetViewColumn      *tree_column);
-static GList *pspp_sheet_view_column_cell_next                   (PsppSheetViewColumn      *tree_column,
-                                                               GList                  *current);
-static GList *pspp_sheet_view_column_cell_prev                   (PsppSheetViewColumn      *tree_column,
-                                                               GList                  *current);
-static void pspp_sheet_view_column_clear_attributes_by_info      (PsppSheetViewColumn      *tree_column,
-                                                               PsppSheetViewColumnCellInfo *info);
-/* GtkBuildable implementation */
-static void pspp_sheet_view_column_buildable_init                 (GtkBuildableIface     *iface);
-
-static guint tree_column_signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, G_TYPE_OBJECT,
-                        G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
-                                               pspp_sheet_view_column_cell_layout_init)
-                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
-                                               pspp_sheet_view_column_buildable_init))
-
-
-static void
-pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
-{
-  GObjectClass *object_class;
-
-  object_class = (GObjectClass*) class;
-
-  class->clicked = on_pspp_sheet_view_column_button_clicked;
-  class->button_press_event = on_pspp_sheet_view_column_button_press_event;
-
-  object_class->finalize = pspp_sheet_view_column_finalize;
-  object_class->set_property = pspp_sheet_view_column_set_property;
-  object_class->get_property = pspp_sheet_view_column_get_property;
-
-  tree_column_signals[CLICKED] =
-    g_signal_new ("clicked",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
-                  g_signal_accumulator_true_handled, NULL,
-                  psppire_marshal_BOOLEAN__VOID,
-                  G_TYPE_BOOLEAN, 0);
-
-  tree_column_signals[POPUP_MENU] =
-    g_signal_new ("popup-menu",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-
-  tree_column_signals[QUERY_TOOLTIP] =
-    g_signal_new ("query-tooltip",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  g_signal_accumulator_true_handled, NULL,
-                  psppire_marshal_BOOLEAN__OBJECT,
-                  G_TYPE_BOOLEAN, 1,
-                  GTK_TYPE_TOOLTIP);
-
-  tree_column_signals[BUTTON_PRESS_EVENT] =
-    g_signal_new ("button-press-event",
-                  G_OBJECT_CLASS_TYPE (object_class),
-                  G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
-                  g_signal_accumulator_true_handled, NULL,
-                  psppire_marshal_BOOLEAN__BOXED,
-                  G_TYPE_BOOLEAN, 1,
-                  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_VISIBLE,
-                                   g_param_spec_boolean ("visible",
-                                                        P_("Visible"),
-                                                        P_("Whether to display the column"),
-                                                         TRUE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_RESIZABLE,
-                                   g_param_spec_boolean ("resizable",
-                                                        P_("Resizable"),
-                                                        P_("Column is user-resizable"),
-                                                         FALSE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_WIDTH,
-                                   g_param_spec_int ("width",
-                                                    P_("Width"),
-                                                    P_("Current width of the column"),
-                                                    0,
-                                                    G_MAXINT,
-                                                    0,
-                                                    GTK_PARAM_READABLE));
-  g_object_class_install_property (object_class,
-                                   PROP_SPACING,
-                                   g_param_spec_int ("spacing",
-                                                    P_("Spacing"),
-                                                    P_("Space which is inserted between cells"),
-                                                    0,
-                                                    G_MAXINT,
-                                                    0,
-                                                    GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_FIXED_WIDTH,
-                                   g_param_spec_int ("fixed-width",
-                                                     P_("Fixed Width"),
-                                                     P_("Current fixed width of the column"),
-                                                     1,
-                                                     G_MAXINT,
-                                                     100,
-                                                     GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_MIN_WIDTH,
-                                   g_param_spec_int ("min-width",
-                                                     P_("Minimum Width"),
-                                                     P_("Minimum allowed width of the column"),
-                                                     -1,
-                                                     G_MAXINT,
-                                                     -1,
-                                                     GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_MAX_WIDTH,
-                                   g_param_spec_int ("max-width",
-                                                     P_("Maximum Width"),
-                                                     P_("Maximum allowed width of the column"),
-                                                     -1,
-                                                     G_MAXINT,
-                                                     -1,
-                                                     GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_TITLE,
-                                   g_param_spec_string ("title",
-                                                        P_("Title"),
-                                                        P_("Title to appear in column header"),
-                                                        "",
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_EXPAND,
-                                   g_param_spec_boolean ("expand",
-                                                        P_("Expand"),
-                                                        P_("Column gets share of extra width allocated to the widget"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_CLICKABLE,
-                                   g_param_spec_boolean ("clickable",
-                                                        P_("Clickable"),
-                                                        P_("Whether the header can be clicked"),
-                                                         FALSE,
-                                                         GTK_PARAM_READWRITE));
-
-
-  g_object_class_install_property (object_class,
-                                   PROP_WIDGET,
-                                   g_param_spec_object ("widget",
-                                                        P_("Widget"),
-                                                        P_("Widget to put in column header button instead of column title"),
-                                                        GTK_TYPE_WIDGET,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_ALIGNMENT,
-                                   g_param_spec_float ("alignment",
-                                                       P_("Alignment"),
-                                                       P_("X Alignment of the column header text or widget"),
-                                                       0.0,
-                                                       1.0,
-                                                       0.0,
-                                                       GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_REORDERABLE,
-                                   g_param_spec_boolean ("reorderable",
-                                                        P_("Reorderable"),
-                                                        P_("Whether the column can be reordered around the headers"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_SORT_INDICATOR,
-                                   g_param_spec_boolean ("sort-indicator",
-                                                        P_("Sort indicator"),
-                                                        P_("Whether to show a sort indicator"),
-                                                         FALSE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_SORT_ORDER,
-                                   g_param_spec_enum ("sort-order",
-                                                      P_("Sort order"),
-                                                      P_("Sort direction the sort indicator should indicate"),
-                                                      GTK_TYPE_SORT_TYPE,
-                                                      GTK_SORT_ASCENDING,
-                                                      GTK_PARAM_READWRITE));
-
-  /**
-   * PsppSheetViewColumn:sort-column-id:
-   *
-   * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
-   * clickable. Set to %-1 to make the column unsortable.
-   *
-   * Since: 2.18
-   **/
-  g_object_class_install_property (object_class,
-                                   PROP_SORT_COLUMN_ID,
-                                   g_param_spec_int ("sort-column-id",
-                                                     P_("Sort column ID"),
-                                                     P_("Logical sort column ID this column sorts on when selected for sorting"),
-                                                     -1,
-                                                     G_MAXINT,
-                                                     -1,
-                                                     GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_QUICK_EDIT,
-                                   g_param_spec_boolean ("quick-edit",
-                                                         P_("Quick edit"),
-                                                         P_("If true, editing starts upon the first click in the column.  If false, the first click selects the column and a second click is needed to begin editing.  This has no effect on cells that are not editable."),
-                                                         TRUE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_SELECTED,
-                                   g_param_spec_boolean ("selected",
-                                                         P_("Selected"),
-                                                         P_("If true, this column is selected as part of a rectangular selection."),
-                                                         FALSE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_SELECTABLE,
-                                   g_param_spec_boolean ("selectable",
-                                                         P_("Selectable"),
-                                                         P_("If true, this column may be selected as part of a rectangular selection."),
-                                                         TRUE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_ROW_HEAD,
-                                   g_param_spec_boolean ("row-head",
-                                                         P_("Row head"),
-                                                         P_("If true, this column is a \"row head\", equivalent to a column head.  If rectangular selection is enabled, then shift+click and control+click in the column select row ranges and toggle row selection, respectively.  The column should ordinarily include a button cell; clicking on the button will select the row (and deselect all other rows)."),
-                                                         FALSE,
-                                                         GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_TABBABLE,
-                                   g_param_spec_boolean ("tabbable",
-                                                         P_("Tabbable"),
-                                                         P_("If true, Tab and Shift+Tab visit this column.  If false, Tab and Shift+Tab skip this column."),
-                                                         TRUE,
-                                                         GTK_PARAM_READWRITE));
-}
-
-
-static void _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
-                                                  GtkBuilder   *builder,
-                                                  GObject      *child,
-                                                  const gchar  *tagname,
-                                                  gpointer     *data);
-
-
-static void _cell_layout_buildable_add_child (GtkBuildable      *buildable,
-                                                 GtkBuilder        *builder,
-                                                 GObject           *child,
-                                                 const gchar       *type);
-
-
-static gboolean _cell_layout_buildable_custom_tag_start (GtkBuildable  *buildable,
-                                             GtkBuilder    *builder,
-                                             GObject       *child,
-                                             const gchar   *tagname,
-                                             GMarkupParser *parser,
-                                        gpointer      *data);
-
-
-static void
-pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
-{
-  iface->add_child = _cell_layout_buildable_add_child;
-  iface->custom_tag_start = _cell_layout_buildable_custom_tag_start;
-  iface->custom_tag_end = _cell_layout_buildable_custom_tag_end;
-}
-
-static void
-pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
-{
-  iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
-  iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
-  iface->clear = pspp_sheet_view_column_cell_layout_clear;
-  iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
-  iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
-  iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
-  iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
-  iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
-}
-
-static void
-pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
-{
-  tree_column->button = NULL;
-  tree_column->halign = GTK_ALIGN_START;
-  tree_column->width = 0;
-  tree_column->spacing = 0;
-  tree_column->requested_width = -1;
-  tree_column->min_width = -1;
-  tree_column->max_width = -1;
-  tree_column->resized_width = 0;
-  tree_column->visible = TRUE;
-  tree_column->resizable = FALSE;
-  tree_column->expand = FALSE;
-  tree_column->clickable = FALSE;
-  tree_column->dirty = TRUE;
-  tree_column->selected = FALSE;
-  tree_column->selectable = TRUE;
-  tree_column->row_head = FALSE;
-  tree_column->tabbable = TRUE;
-  tree_column->sort_order = GTK_SORT_ASCENDING;
-  tree_column->show_sort_indicator = FALSE;
-  tree_column->property_changed_signal = 0;
-  tree_column->sort_clicked_signal = 0;
-  tree_column->sort_column_changed_signal = 0;
-  tree_column->sort_column_id = -1;
-  tree_column->reorderable = FALSE;
-  tree_column->maybe_reordered = FALSE;
-  tree_column->fixed_width = 1;
-  tree_column->use_resized_width = FALSE;
-  tree_column->title = g_strdup ("");
-  tree_column->quick_edit = TRUE;
-}
-
-static void
-pspp_sheet_view_column_finalize (GObject *object)
-{
-  PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
-  GList *list;
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
-      if (info->destroy)
-       {
-         GDestroyNotify d = info->destroy;
-
-         info->destroy = NULL;
-         d (info->func_data);
-       }
-      pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
-      g_object_unref (info->cell);
-      g_free (info);
-    }
-
-  g_free (tree_column->title);
-  g_list_free (tree_column->cell_list);
-
-  if (tree_column->child)
-    g_object_unref (tree_column->child);
-
-  G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
-}
-
-static void
-pspp_sheet_view_column_set_property (GObject         *object,
-                                   guint            prop_id,
-                                   const GValue    *value,
-                                   GParamSpec      *pspec)
-{
-  PsppSheetViewColumn *tree_column;
-
-  tree_column = PSPP_SHEET_VIEW_COLUMN (object);
-
-  switch (prop_id)
-    {
-    case PROP_VISIBLE:
-      pspp_sheet_view_column_set_visible (tree_column,
-                                        g_value_get_boolean (value));
-      break;
-
-    case PROP_RESIZABLE:
-      pspp_sheet_view_column_set_resizable (tree_column,
-                                         g_value_get_boolean (value));
-      break;
-
-    case PROP_FIXED_WIDTH:
-      pspp_sheet_view_column_set_fixed_width (tree_column,
-                                           g_value_get_int (value));
-      break;
-
-    case PROP_MIN_WIDTH:
-      pspp_sheet_view_column_set_min_width (tree_column,
-                                          g_value_get_int (value));
-      break;
-
-    case PROP_MAX_WIDTH:
-      pspp_sheet_view_column_set_max_width (tree_column,
-                                          g_value_get_int (value));
-      break;
-
-    case PROP_SPACING:
-      pspp_sheet_view_column_set_spacing (tree_column,
-                                       g_value_get_int (value));
-      break;
-
-    case PROP_TITLE:
-      pspp_sheet_view_column_set_title (tree_column,
-                                      g_value_get_string (value));
-      break;
-
-    case PROP_EXPAND:
-      pspp_sheet_view_column_set_expand (tree_column,
-                                      g_value_get_boolean (value));
-      break;
-
-    case PROP_CLICKABLE:
-      pspp_sheet_view_column_set_clickable (tree_column,
-                                          g_value_get_boolean (value));
-      break;
-
-    case PROP_WIDGET:
-      pspp_sheet_view_column_set_widget (tree_column,
-                                       (GtkWidget*) g_value_get_object (value));
-      break;
-
-    case PROP_ALIGNMENT:
-      pspp_sheet_view_column_set_alignment (tree_column,
-                                          g_value_get_float (value));
-      break;
-
-    case PROP_REORDERABLE:
-      pspp_sheet_view_column_set_reorderable (tree_column,
-                                           g_value_get_boolean (value));
-      break;
-
-    case PROP_SORT_INDICATOR:
-      pspp_sheet_view_column_set_sort_indicator (tree_column,
-                                               g_value_get_boolean (value));
-      break;
-
-    case PROP_SORT_ORDER:
-      pspp_sheet_view_column_set_sort_order (tree_column,
-                                           g_value_get_enum (value));
-      break;
-
-    case PROP_SORT_COLUMN_ID:
-      pspp_sheet_view_column_set_sort_column_id (tree_column,
-                                               g_value_get_int (value));
-      break;
-
-    case PROP_QUICK_EDIT:
-      pspp_sheet_view_column_set_quick_edit (tree_column,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_SELECTED:
-      pspp_sheet_view_column_set_selected (tree_column,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_SELECTABLE:
-      pspp_sheet_view_column_set_selectable (tree_column,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_ROW_HEAD:
-      pspp_sheet_view_column_set_row_head (tree_column,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_TABBABLE:
-      pspp_sheet_view_column_set_tabbable (tree_column,
-                                           g_value_get_boolean (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-pspp_sheet_view_column_get_property (GObject         *object,
-                                   guint            prop_id,
-                                   GValue          *value,
-                                   GParamSpec      *pspec)
-{
-  PsppSheetViewColumn *tree_column;
-
-  tree_column = PSPP_SHEET_VIEW_COLUMN (object);
-
-  switch (prop_id)
-    {
-    case PROP_VISIBLE:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_visible (tree_column));
-      break;
-
-    case PROP_RESIZABLE:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_resizable (tree_column));
-      break;
-
-    case PROP_WIDTH:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_width (tree_column));
-      break;
-
-    case PROP_SPACING:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_spacing (tree_column));
-      break;
-
-    case PROP_FIXED_WIDTH:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_fixed_width (tree_column));
-      break;
-
-    case PROP_MIN_WIDTH:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_min_width (tree_column));
-      break;
-
-    case PROP_MAX_WIDTH:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_max_width (tree_column));
-      break;
-
-    case PROP_TITLE:
-      g_value_set_string (value,
-                          pspp_sheet_view_column_get_title (tree_column));
-      break;
-
-    case PROP_EXPAND:
-      g_value_set_boolean (value,
-                          pspp_sheet_view_column_get_expand (tree_column));
-      break;
-
-    case PROP_CLICKABLE:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_clickable (tree_column));
-      break;
-
-    case PROP_WIDGET:
-      g_value_set_object (value,
-                          (GObject*) pspp_sheet_view_column_get_widget (tree_column));
-      break;
-
-    case PROP_ALIGNMENT:
-      g_value_set_float (value,
-                         pspp_sheet_view_column_get_alignment (tree_column));
-      break;
-
-    case PROP_REORDERABLE:
-      g_value_set_boolean (value,
-                          pspp_sheet_view_column_get_reorderable (tree_column));
-      break;
-
-    case PROP_SORT_INDICATOR:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_sort_indicator (tree_column));
-      break;
-
-    case PROP_SORT_ORDER:
-      g_value_set_enum (value,
-                        pspp_sheet_view_column_get_sort_order (tree_column));
-      break;
-
-    case PROP_SORT_COLUMN_ID:
-      g_value_set_int (value,
-                       pspp_sheet_view_column_get_sort_column_id (tree_column));
-      break;
-
-    case PROP_QUICK_EDIT:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_quick_edit (tree_column));
-      break;
-
-    case PROP_SELECTED:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_selected (tree_column));
-      break;
-
-    case PROP_SELECTABLE:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_selectable (tree_column));
-      break;
-
-    case PROP_ROW_HEAD:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_row_head (tree_column));
-      break;
-
-    case PROP_TABBABLE:
-      g_value_set_boolean (value,
-                           pspp_sheet_view_column_get_tabbable (tree_column));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-/* Implementation of GtkCellLayout interface
- */
-
-static void
-pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout   *cell_layout,
-                                             GtkCellRenderer *cell,
-                                             gboolean         expand)
-{
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumnCellInfo *cell_info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-  g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
-
-  g_object_ref_sink (cell);
-
-  cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
-  cell_info->cell = cell;
-  cell_info->expand = expand ? TRUE : FALSE;
-  cell_info->pack = GTK_PACK_START;
-  cell_info->has_focus = 0;
-  cell_info->attributes = NULL;
-
-  column->cell_list = g_list_append (column->cell_list, cell_info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout   *cell_layout,
-                                           GtkCellRenderer *cell,
-                                           gboolean         expand)
-{
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumnCellInfo *cell_info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-  g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
-
-  g_object_ref_sink (cell);
-
-  cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
-  cell_info->cell = cell;
-  cell_info->expand = expand ? TRUE : FALSE;
-  cell_info->pack = GTK_PACK_END;
-  cell_info->has_focus = 0;
-  cell_info->attributes = NULL;
-
-  column->cell_list = g_list_append (column->cell_list, cell_info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
-{
-  PsppSheetViewColumn *column;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
-  while (column->cell_list)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
-
-      pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
-      g_object_unref (info->cell);
-      g_free (info);
-      column->cell_list = g_list_delete_link (column->cell_list,
-                                             column->cell_list);
-    }
-}
-
-static void
-pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout   *cell_layout,
-                                                GtkCellRenderer *cell,
-                                                const gchar     *attribute,
-                                                gint             column)
-{
-  PsppSheetViewColumn *tree_column;
-  PsppSheetViewColumnCellInfo *info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
-  info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
-  g_return_if_fail (info != NULL);
-
-  info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
-  info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
-
-  if (tree_column->tree_view)
-    _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
-                                                     GtkCellRenderer       *cell,
-                                                     GtkCellLayoutDataFunc  func,
-                                                     gpointer               func_data,
-                                                     GDestroyNotify         destroy)
-{
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumnCellInfo *info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
-  info = pspp_sheet_view_column_get_cell_info (column, cell);
-  g_return_if_fail (info != NULL);
-
-  if (info->destroy)
-    {
-      GDestroyNotify d = info->destroy;
-
-      info->destroy = NULL;
-      d (info->func_data);
-    }
-
-  info->func = (PsppSheetCellDataFunc)func;
-  info->func_data = func_data;
-  info->destroy = destroy;
-
-  if (column->tree_view)
-    _pspp_sheet_view_column_cell_set_dirty (column);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout    *cell_layout,
-                                                   GtkCellRenderer  *cell_renderer)
-{
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumnCellInfo *info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
-  info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
-  if (info)
-    pspp_sheet_view_column_clear_attributes_by_info (column, info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout   *cell_layout,
-                                          GtkCellRenderer *cell,
-                                          gint             position)
-{
-  GList *link;
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumnCellInfo *info;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
-  column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
-  info = pspp_sheet_view_column_get_cell_info (column, cell);
-
-  g_return_if_fail (info != NULL);
-  g_return_if_fail (position >= 0);
-
-  link = g_list_find (column->cell_list, info);
-
-  g_return_if_fail (link != NULL);
-
-  column->cell_list = g_list_delete_link (column->cell_list, link);
-  column->cell_list = g_list_insert (column->cell_list, info, position);
-
-  if (column->tree_view)
-    gtk_widget_queue_draw (column->tree_view);
-}
-
-static void
-pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
-                                              PsppSheetViewColumnCellInfo *info)
-{
-  GSList *list;
-
-  list = info->attributes;
-
-  while (list && list->next)
-    {
-      g_free (list->data);
-      list = list->next->next;
-    }
-  g_slist_free (info->attributes);
-  info->attributes = NULL;
-
-  if (tree_column->tree_view)
-    _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-static gboolean
-on_query_tooltip (GtkWidget  *widget,
-                  gint        x,
-                  gint        y,
-                  gboolean    keyboard_mode,
-                  GtkTooltip *tooltip,
-                  gpointer    user_data)
-{
-  PsppSheetViewColumn *tree_column = user_data;
-  gboolean handled;
-
-  g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
-                 tooltip, &handled);
-  return handled;
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
-                   gpointer user_data)
-{
-  PsppSheetViewColumn *tree_column = user_data;
-  gboolean handled;
-
-  /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
-  g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
-                 0, event, &handled);
-  return handled;
-}
-
-/* Helper functions
- */
-
-/* Button handling code
- */
-static void
-pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
-{
-  PsppSheetView *tree_view;
-  GtkWidget *child;
-  GtkWidget *hbox;
-
-  tree_view = (PsppSheetView *) tree_column->tree_view;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (tree_column->button == NULL);
-
-  tree_column->button = gtk_button_new ();
-  gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
-
-  /* make sure we own a reference to it as well. */
-  if (tree_view->priv->header_window)
-    gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
-  gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
-
-  g_signal_connect (tree_column->button, "event",
-                   G_CALLBACK (pspp_sheet_view_column_button_event),
-                   tree_column);
-  g_signal_connect (tree_column->button, "clicked",
-                   G_CALLBACK (pspp_sheet_view_column_button_clicked),
-                   tree_column);
-  g_signal_connect (tree_column->button, "popup-menu",
-                   G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
-                   tree_column);
-  g_signal_connect (tree_column->button, "button-press-event",
-                    G_CALLBACK (on_button_pressed), tree_column);
-
-  g_signal_connect (tree_column->button, "query-tooltip",
-                    G_CALLBACK (on_query_tooltip), tree_column);
-  g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
-
-  tree_column->bin = gtk_event_box_new ();
-  g_object_set (tree_column->bin, "halign", GTK_ALIGN_CENTER, NULL);
-
-  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
-
-  if (tree_column->child)
-    child = tree_column->child;
-  else
-    {
-      child = gtk_label_new (tree_column->title);
-      gtk_widget_show (child);
-    }
-
-  g_signal_connect (child, "mnemonic-activate",
-                   G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
-                   tree_column);
-
-
-  gtk_box_pack_start (GTK_BOX (hbox), tree_column->bin, TRUE, TRUE, 0);
-
-  gtk_container_add (GTK_CONTAINER (tree_column->bin), child);
-  gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
-
-  gtk_widget_show (hbox);
-  gtk_widget_show (tree_column->bin);
-  pspp_sheet_view_column_update_button (tree_column);
-}
-
-void
-pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
-{
-  gint sort_column_id = -1;
-  GtkWidget *alignment;
-  GtkWidget *current_child;
-  GtkTreeModel *model;
-  gboolean can_focus;
-
-  if (tree_column->tree_view)
-    model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
-  else
-    model = NULL;
-
-  /* Create a button if necessary */
-  if (tree_column->visible &&
-      tree_column->button == NULL &&
-      tree_column->tree_view &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    pspp_sheet_view_column_create_button (tree_column);
-
-  if (! tree_column->button)
-    return;
-
-  alignment = tree_column->bin;
-  current_child = gtk_bin_get_child (GTK_BIN (alignment));
-
-  /* Set up the actual button */
-  g_object_set (alignment,
-               "halign", tree_column->halign,
-               "valign", GTK_ALIGN_CENTER, NULL);
-
-  if (tree_column->child)
-    {
-      if (current_child != tree_column->child)
-       {
-         gtk_container_remove (GTK_CONTAINER (alignment),
-                               current_child);
-         gtk_container_add (GTK_CONTAINER (alignment),
-                            tree_column->child);
-       }
-    }
-  else
-    {
-      if (current_child == NULL)
-       {
-         current_child = gtk_label_new (NULL);
-         gtk_widget_show (current_child);
-         gtk_container_add (GTK_CONTAINER (alignment),
-                            current_child);
-       }
-
-      g_return_if_fail (GTK_IS_LABEL (current_child));
-
-      if (tree_column->title)
-       gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
-                                         tree_column->title);
-      else
-       gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
-                                         "");
-    }
-
-  if (GTK_IS_TREE_SORTABLE (model))
-    gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
-                                         &sort_column_id,
-                                         NULL);
-
-
-  /* It's always safe to hide the button.  It isn't always safe to show it, as
-   * if you show it before it's realized, it'll get the wrong window. */
-  if (tree_column->button &&
-      tree_column->tree_view != NULL &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      if (tree_column->visible)
-       {
-         gtk_widget_show (tree_column->button);
-         if (tree_column->window)
-           {
-             if (tree_column->resizable)
-               {
-                 gdk_window_show (tree_column->window);
-                 gdk_window_raise (tree_column->window);
-               }
-             else
-               {
-                 gdk_window_hide (tree_column->window);
-               }
-           }
-       }
-      else
-       {
-         gtk_widget_hide (tree_column->button);
-         if (tree_column->window)
-           gdk_window_hide (tree_column->window);
-       }
-    }
-
-  can_focus = pspp_sheet_view_column_can_focus (tree_column);
-  gtk_widget_set_can_focus (tree_column->button, can_focus);
-  if (!can_focus && gtk_widget_has_focus (tree_column->button))
-    {
-      GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
-      if (gtk_widget_is_toplevel (toplevel))
-        {
-          gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
-        }
-    }
-
-  /* Queue a resize on the assumption that we always want to catch all changes
-   * and columns don't change all that often.
-   */
-  if (gtk_widget_get_realized (tree_column->tree_view))
-     gtk_widget_queue_resize (tree_column->tree_view);
-
-}
-
-/* Button signal handlers
- */
-
-static gint
-pspp_sheet_view_column_button_event (GtkWidget *widget,
-                                  GdkEventButton  *event,
-                                  gpointer   data)
-{
-  PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
-
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  if (event->type == GDK_BUTTON_PRESS &&
-      column->reorderable &&
-      ((GdkEventButton *)event)->button == 1)
-    {
-      column->maybe_reordered = TRUE;
-      gdk_window_get_device_position (gtk_button_get_event_window (GTK_BUTTON (widget)),
-                                     event->device,
-                             &column->drag_x,
-                             &column->drag_y,
-                             NULL);
-      gtk_widget_grab_focus (widget);
-    }
-
-  if (event->type == GDK_BUTTON_RELEASE ||
-      event->type == GDK_LEAVE_NOTIFY)
-    column->maybe_reordered = FALSE;
-
-  if (event->type == GDK_MOTION_NOTIFY &&
-      column->maybe_reordered &&
-      (gtk_drag_check_threshold (widget,
-                                column->drag_x,
-                                column->drag_y,
-                                (gint) ((GdkEventMotion *)event)->x,
-                                (gint) ((GdkEventMotion *)event)->y)))
-    {
-      column->maybe_reordered = FALSE;
-      _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
-      return TRUE;
-    }
-  if (column->clickable == FALSE)
-    {
-      switch (event->type)
-       {
-       case GDK_MOTION_NOTIFY:
-       case GDK_BUTTON_RELEASE:
-       case GDK_ENTER_NOTIFY:
-       case GDK_LEAVE_NOTIFY:
-         return TRUE;
-       default:
-         return FALSE;
-       }
-    }
-  return FALSE;
-}
-
-static gboolean
-all_rows_selected (PsppSheetView *sheet_view)
-{
-  PsppSheetSelection *selection = sheet_view->priv->selection;
-  gint n_rows, n_selected_rows;
-
-  n_rows = sheet_view->priv->row_count;
-  n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
-
-  return n_rows > 0 && n_selected_rows >= n_rows;
-}
-
-static gboolean
-on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
-                                              GdkEventButton *event)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
-  PsppSheetSelection *selection;
-  GSignalInvocationHint *hint;
-  guint modifiers;
-
-  /* We only want to run first, not last, but combining that with return type
-     `gboolean' makes GObject warn, so just ignore the run_last call. */
-  hint = g_signal_get_invocation_hint (column);
-  g_return_val_if_fail (hint != NULL, FALSE);
-  if (hint->run_type != G_SIGNAL_RUN_FIRST)
-    return FALSE;
-
-  g_return_val_if_fail (sheet_view != NULL, FALSE);
-
-  selection = sheet_view->priv->selection;
-  g_return_val_if_fail (selection != NULL, FALSE);
-
-  if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
-    return FALSE;
-
-  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
-  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
-    {
-      if (pspp_sheet_selection_count_selected_columns (selection) <= 1
-          || !all_rows_selected (sheet_view))
-        {
-          pspp_sheet_selection_select_all (selection);
-          pspp_sheet_selection_unselect_all_columns (selection);
-          pspp_sheet_selection_select_column (selection, column);
-          sheet_view->priv->anchor_column = column;
-        }
-      return FALSE;
-    }
-  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
-           && modifiers == GDK_CONTROL_MASK)
-    {
-      gboolean is_selected;
-
-      if (!all_rows_selected (sheet_view))
-        {
-          pspp_sheet_selection_select_all (selection);
-          pspp_sheet_selection_unselect_all_columns (selection);
-        }
-      sheet_view->priv->anchor_column = column;
-
-      is_selected = pspp_sheet_view_column_get_selected (column);
-      pspp_sheet_view_column_set_selected (column, !is_selected);
-
-      return TRUE;
-    }
-  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
-           && modifiers == GDK_SHIFT_MASK)
-    {
-      if (!all_rows_selected (sheet_view))
-        {
-          pspp_sheet_selection_select_all (selection);
-          pspp_sheet_selection_unselect_all_columns (selection);
-          sheet_view->priv->anchor_column = column;
-        }
-      else if (sheet_view->priv->anchor_column == NULL)
-        sheet_view->priv->anchor_column = column;
-
-      pspp_sheet_selection_unselect_all_columns (selection);
-      pspp_sheet_selection_select_column_range (selection,
-                                                sheet_view->priv->anchor_column,
-                                                column);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
-{
-  PsppSheetSelection *selection;
-  PsppSheetView *sheet_view;
-
-  sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
-    {
-      pspp_sheet_selection_select_all (selection);
-      if (pspp_sheet_view_column_get_row_head (column))
-        pspp_sheet_selection_select_all_columns (selection);
-      else
-        {
-          pspp_sheet_selection_unselect_all_columns (selection);
-          pspp_sheet_selection_select_column (selection, column);
-        }
-      sheet_view->priv->anchor_column = column;
-      return TRUE;
-    }
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
-{
-  PsppSheetViewColumn *column = data;
-  gboolean handled;
-
-  g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
-}
-
-static void
-pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
-{
-  g_signal_emit_by_name (data, "popup-menu");
-}
-
-static gboolean
-pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
-                                       gboolean   group_cycling,
-                                       gpointer   data)
-{
-  PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
-
-  PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
-  if (column->clickable)
-    gtk_button_clicked (GTK_BUTTON (column->button));
-  else if (gtk_widget_get_can_focus (column->button))
-    gtk_widget_grab_focus (column->button);
-  else
-    gtk_widget_grab_focus (column->tree_view);
-
-  return TRUE;
-}
-
-static void
-pspp_sheet_view_model_sort_column_changed (GtkTreeSortable   *sortable,
-                                        PsppSheetViewColumn *column)
-{
-  gint sort_column_id;
-  GtkSortType order;
-
-  if (gtk_tree_sortable_get_sort_column_id (sortable,
-                                           &sort_column_id,
-                                           &order))
-    {
-      if (sort_column_id == column->sort_column_id)
-       {
-         pspp_sheet_view_column_set_sort_indicator (column, TRUE);
-         pspp_sheet_view_column_set_sort_order (column, order);
-       }
-      else
-       {
-         pspp_sheet_view_column_set_sort_indicator (column, FALSE);
-       }
-    }
-  else
-    {
-      pspp_sheet_view_column_set_sort_indicator (column, FALSE);
-    }
-}
-
-static void
-pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
-                          gpointer           data)
-{
-  gint sort_column_id;
-  GtkSortType order;
-  gboolean has_sort_column;
-  gboolean has_default_sort_func;
-
-  g_return_if_fail (tree_column->tree_view != NULL);
-
-  has_sort_column =
-    gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
-                                         &sort_column_id,
-                                         &order);
-  has_default_sort_func =
-    gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
-
-  if (has_sort_column &&
-      sort_column_id == tree_column->sort_column_id)
-    {
-      if (order == GTK_SORT_ASCENDING)
-       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
-                                             tree_column->sort_column_id,
-                                             GTK_SORT_DESCENDING);
-      else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
-       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
-                                             GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
-                                             GTK_SORT_ASCENDING);
-      else
-       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
-                                             tree_column->sort_column_id,
-                                             GTK_SORT_ASCENDING);
-    }
-  else
-    {
-      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
-                                           tree_column->sort_column_id,
-                                           GTK_SORT_ASCENDING);
-    }
-}
-
-
-static void
-pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
-{
-  GtkTreeModel *model;
-
-  if (tree_column->tree_view == NULL)
-    return;
-
-  model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
-
-  if (model == NULL)
-    return;
-
-  if (GTK_IS_TREE_SORTABLE (model) &&
-      tree_column->sort_column_id != -1)
-    {
-      gint real_sort_column_id;
-      GtkSortType real_order;
-
-      if (tree_column->sort_column_changed_signal == 0)
-        tree_column->sort_column_changed_signal =
-         g_signal_connect (model, "sort-column-changed",
-                           G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
-                           tree_column);
-
-      if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
-                                               &real_sort_column_id,
-                                               &real_order) &&
-         (real_sort_column_id == tree_column->sort_column_id))
-       {
-         pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
-         pspp_sheet_view_column_set_sort_order (tree_column, real_order);
-       }
-      else
-       {
-         pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
-       }
-   }
-}
-
-
-/* Exported Private Functions.
- * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
- */
-
-void
-_pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
-{
-  GtkAllocation allocation;
-  PsppSheetView *tree_view;
-  GdkWindowAttr attr;
-  guint attributes_mask;
-  gboolean rtl;
-
-  tree_view = (PsppSheetView *)column->tree_view;
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
-  g_return_if_fail (tree_view->priv->header_window != NULL);
-  if (!column->button)
-    return;
-
-  g_return_if_fail (column->button != NULL);
-
-  gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
-
-  if (column->visible)
-    gtk_widget_show (column->button);
-
-  attr.window_type = GDK_WINDOW_CHILD;
-  attr.wclass = GDK_INPUT_ONLY;
-  attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
-  attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
-                    (GDK_BUTTON_PRESS_MASK |
-                    GDK_BUTTON_RELEASE_MASK |
-                    GDK_POINTER_MOTION_MASK |
-                    GDK_POINTER_MOTION_HINT_MASK |
-                    GDK_KEY_PRESS_MASK);
-  attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
-  attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
-                                           GDK_SB_H_DOUBLE_ARROW);
-  attr.y = 0;
-  attr.width = TREE_VIEW_DRAG_WIDTH;
-  attr.height = tree_view->priv->header_height;
-  gtk_widget_get_allocation (column->button, &allocation);
-  attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
-  column->window = gdk_window_new (tree_view->priv->header_window,
-                                  &attr, attributes_mask);
-  gdk_window_set_user_data (column->window, tree_view);
-
-  pspp_sheet_view_column_update_button (column);
-
-  g_object_unref (attr.cursor);
-}
-
-void
-_pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
-{
-  g_return_if_fail (column != NULL);
-  if (column->window != NULL)
-    {
-      gdk_window_set_user_data (column->window, NULL);
-      gdk_window_destroy (column->window);
-      column->window = NULL;
-    }
-}
-
-void
-_pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
-                                  GtkTreeModel      *old_model)
-{
-  if (column->sort_column_changed_signal)
-    {
-      g_signal_handler_disconnect (old_model,
-                                  column->sort_column_changed_signal);
-      column->sort_column_changed_signal = 0;
-    }
-  pspp_sheet_view_column_set_sort_indicator (column, FALSE);
-}
-
-void
-_pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
-                                    PsppSheetView       *tree_view)
-{
-  g_assert (column->tree_view == NULL);
-
-  column->tree_view = GTK_WIDGET (tree_view);
-  pspp_sheet_view_column_create_button (column);
-
-  column->property_changed_signal =
-         g_signal_connect_swapped (tree_view,
-                                   "notify::model",
-                                   G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
-                                   column);
-
-  pspp_sheet_view_column_setup_sort_column_id_callback (column);
-}
-
-void
-_pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
-{
-  if (column->tree_view && column->button)
-    {
-      gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
-    }
-  if (column->property_changed_signal)
-    {
-      g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
-      column->property_changed_signal = 0;
-    }
-
-  if (column->sort_column_changed_signal)
-    {
-      g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
-                                  column->sort_column_changed_signal);
-      column->sort_column_changed_signal = 0;
-    }
-
-  column->tree_view = NULL;
-  column->button = NULL;
-}
-
-gboolean
-_pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
-{
-  GList *list;
-
-  for (list = column->cell_list; list; list = list->next)
-    {
-      GtkCellRendererMode mode;
-      g_object_get (((PsppSheetViewColumnCellInfo *)list->data)->cell, "mode", &mode, NULL);
-      if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
-       return TRUE;
-    }
-
-  return FALSE;
-}
-
-/* gets cell being edited */
-GtkCellRenderer *
-_pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
-{
-  GList *list;
-
-  for (list = column->cell_list; list; list = list->next)
-    if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
-      return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
-
-  return NULL;
-}
-
-gint
-_pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
-{
-  gint i = 0;
-  GList *list;
-
-  for (list = column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *cellinfo = list->data;
-
-      GtkCellRendererMode mode;
-      g_object_get (cellinfo->cell, "mode", &mode, NULL);
-
-      if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
-         mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
-         gtk_cell_renderer_get_visible (cellinfo->cell))
-       i++;
-    }
-
-  return i;
-}
-
-GtkCellRenderer *
-_pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
-                                      gint               x)
-{
-  GList *list;
-  gint current_x = 0;
-
-  list = pspp_sheet_view_column_cell_first (column);
-  for (; list; list = pspp_sheet_view_column_cell_next (column, list))
-   {
-     PsppSheetViewColumnCellInfo *cellinfo = list->data;
-     if (current_x <= x && x <= current_x + cellinfo->real_width)
-       return cellinfo->cell;
-     current_x += cellinfo->real_width;
-   }
-
-  return NULL;
-}
-
-/* Public Functions */
-
-
-/**
- * pspp_sheet_view_column_new:
- *
- * Creates a new #PsppSheetViewColumn.
- *
- * Return value: A newly created #PsppSheetViewColumn.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_column_new (void)
-{
-  PsppSheetViewColumn *tree_column;
-
-  tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
-
-  return tree_column;
-}
-
-/**
- * pspp_sheet_view_column_new_with_attributes:
- * @title: The title to set the header to.
- * @cell: The #GtkCellRenderer.
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Creates a new #PsppSheetViewColumn with a number of default values.  This is
- * equivalent to calling pspp_sheet_view_column_set_title(),
- * pspp_sheet_view_column_pack_start(), and
- * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
- *
- * Here's a simple example:
- * |[
- *  enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
- *  ...
- *  {
- *    PsppSheetViewColumn *column;
- *    GtkCellRenderer   *renderer = gtk_cell_renderer_text_new ();
- *
- *    column = pspp_sheet_view_column_new_with_attributes ("Title",
- *                                                       renderer,
- *                                                       "text", TEXT_COLUMN,
- *                                                       "foreground", COLOR_COLUMN,
- *                                                       NULL);
- *  }
- * ]|
- *
- * Return value: A newly created #PsppSheetViewColumn.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_column_new_with_attributes (const gchar     *title,
-                                         GtkCellRenderer *cell,
-                                         ...)
-{
-  PsppSheetViewColumn *retval;
-  va_list args;
-
-  retval = pspp_sheet_view_column_new ();
-
-  pspp_sheet_view_column_set_title (retval, title);
-  pspp_sheet_view_column_pack_start (retval, cell, TRUE);
-
-  va_start (args, cell);
-  pspp_sheet_view_column_set_attributesv (retval, cell, args);
-  va_end (args);
-
-  return retval;
-}
-
-static PsppSheetViewColumnCellInfo *
-pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
-                                   GtkCellRenderer   *cell_renderer)
-{
-  GList *list;
-  for (list = tree_column->cell_list; list; list = list->next)
-    if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
-      return (PsppSheetViewColumnCellInfo *) list->data;
-  return NULL;
-}
-
-
-/**
- * pspp_sheet_view_column_pack_start:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell: The #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
- *
- * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
- * the @cell is allocated no more space than it needs. Any unused space is divided
- * evenly between cells for which @expand is %TRUE.
- **/
-void
-pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
-                                GtkCellRenderer   *cell,
-                                gboolean           expand)
-{
-  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
-}
-
-/**
- * pspp_sheet_view_column_pack_end:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell: The #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
- *
- * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
- * is allocated no more space than it needs. Any unused space is divided
- * evenly between cells for which @expand is %TRUE.
- **/
-void
-pspp_sheet_view_column_pack_end (PsppSheetViewColumn  *tree_column,
-                              GtkCellRenderer    *cell,
-                              gboolean            expand)
-{
-  gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
-}
-
-/**
- * pspp_sheet_view_column_clear:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Unsets all the mappings on all renderers on the @tree_column.
- **/
-void
-pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
-{
-  gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
-}
-
-static GList *
-pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
-{
-  PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
-  GList *retval = NULL, *list;
-
-  g_return_val_if_fail (tree_column != NULL, NULL);
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
-
-      retval = g_list_append (retval, info->cell);
-    }
-
-  return retval;
-}
-
-/**
- * pspp_sheet_view_column_get_cell_renderers:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns a newly-allocated #GList of all the cell renderers in the column,
- * in no particular order.  The list must be freed with g_list_free().
- *
- * Return value: A list of #GtkCellRenderers
- *
- * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
- **/
-GList *
-pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
-{
-  return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_add_attribute:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_renderer: the #GtkCellRenderer to set attributes on
- * @attribute: An attribute on the renderer
- * @column: The column position on the model to get the attribute from.
- *
- * Adds an attribute mapping to the list in @tree_column.  The @column is the
- * column of the model to get a value from, and the @attribute is the
- * parameter on @cell_renderer to be set from the value. So for example
- * if column 2 of the model contains strings, you could have the
- * "text" attribute of a #GtkCellRendererText get its values from
- * column 2.
- **/
-void
-pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
-                                   GtkCellRenderer   *cell_renderer,
-                                   const gchar       *attribute,
-                                   gint               column)
-{
-  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
-                                 cell_renderer, attribute, column);
-}
-
-static void
-pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
-                                     GtkCellRenderer   *cell_renderer,
-                                     va_list            args)
-{
-  gchar *attribute;
-  gint column;
-
-  attribute = va_arg (args, gchar *);
-
-  pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
-
-  while (attribute != NULL)
-    {
-      column = va_arg (args, gint);
-      pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
-      attribute = va_arg (args, gchar *);
-    }
-}
-
-/**
- * pspp_sheet_view_column_set_attributes:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Sets the attributes in the list as the attributes of @tree_column.
- * The attributes should be in attribute/column order, as in
- * pspp_sheet_view_column_add_attribute(). All existing attributes
- * are removed, and replaced with the new attributes.
- **/
-void
-pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
-                                    GtkCellRenderer   *cell_renderer,
-                                    ...)
-{
-  va_list args;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
-  g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
-
-  va_start (args, cell_renderer);
-  pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
-  va_end (args);
-}
-
-
-/**
- * pspp_sheet_view_column_set_cell_data_func:
- * @tree_column: A #PsppSheetViewColumn
- * @cell_renderer: A #GtkCellRenderer
- * @func: The #PsppSheetViewColumnFunc to use.
- * @func_data: The user data for @func.
- * @destroy: The destroy notification for @func_data
- *
- * Sets the #PsppSheetViewColumnFunc to use for the column.  This
- * function is used instead of the standard attributes mapping for
- * setting the column value, and should set the value of @tree_column's
- * cell renderer as appropriate.  @func may be %NULL to remove an
- * older one.
- **/
-void
-pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn   *tree_column,
-                                        GtkCellRenderer     *cell_renderer,
-                                        PsppSheetCellDataFunc  func,
-                                        gpointer             func_data,
-                                        GDestroyNotify       destroy)
-{
-  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
-                                      cell_renderer,
-                                      (GtkCellLayoutDataFunc)func,
-                                      func_data, destroy);
-}
-
-
-/**
- * pspp_sheet_view_column_clear_attributes:
- * @tree_column: a #PsppSheetViewColumn
- * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
- *
- * Clears all existing attributes previously set with
- * pspp_sheet_view_column_set_attributes().
- **/
-void
-pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
-                                      GtkCellRenderer   *cell_renderer)
-{
-  gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
-                                    cell_renderer);
-}
-
-/**
- * pspp_sheet_view_column_set_spacing:
- * @tree_column: A #PsppSheetViewColumn.
- * @spacing: distance between cell renderers in pixels.
- *
- * Sets the spacing field of @tree_column, which is the number of pixels to
- * place between cell renderers packed into it.
- **/
-void
-pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
-                                 gint               spacing)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (spacing >= 0);
-
-  if (tree_column->spacing == spacing)
-    return;
-
-  tree_column->spacing = spacing;
-  if (tree_column->tree_view)
-    _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-/**
- * pspp_sheet_view_column_get_spacing:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the spacing of @tree_column.
- *
- * Return value: the spacing of @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
-  return tree_column->spacing;
-}
-
-/* Options for manipulating the columns */
-
-/**
- * pspp_sheet_view_column_set_visible:
- * @tree_column: A #PsppSheetViewColumn.
- * @visible: %TRUE if the @tree_column is visible.
- *
- * Sets the visibility of @tree_column.
- **/
-void
-pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
-                                 gboolean           visible)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  visible = !! visible;
-
-  if (tree_column->visible == visible)
-    return;
-
-  tree_column->visible = visible;
-
-  if (tree_column->visible)
-    _pspp_sheet_view_column_cell_set_dirty (tree_column);
-
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "visible");
-}
-
-/**
- * pspp_sheet_view_column_get_visible:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns %TRUE if @tree_column is visible.
- *
- * Return value: whether the column is visible or not.  If it is visible, then
- * the tree will show the column.
- **/
-gboolean
-pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->visible;
-}
-
-/**
- * pspp_sheet_view_column_set_resizable:
- * @tree_column: A #PsppSheetViewColumn
- * @resizable: %TRUE, if the column can be resized
- *
- * If @resizable is %TRUE, then the user can explicitly resize the column by
- * grabbing the outer edge of the column button.
- **/
-void
-pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
-                                   gboolean           resizable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  resizable = !! resizable;
-
-  if (tree_column->resizable == resizable)
-    return;
-
-  tree_column->resizable = resizable;
-
-  pspp_sheet_view_column_update_button (tree_column);
-
-  g_object_notify (G_OBJECT (tree_column), "resizable");
-}
-
-/**
- * pspp_sheet_view_column_get_resizable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the @tree_column can be resized by the end user.
- *
- * Return value: %TRUE, if the @tree_column can be resized.
- **/
-gboolean
-pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->resizable;
-}
-
-
-/**
- * pspp_sheet_view_column_get_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the current size of @tree_column in pixels.
- *
- * Return value: The current width of @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
-  return tree_column->width;
-}
-
-/**
- * pspp_sheet_view_column_set_fixed_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @fixed_width: The size to set @tree_column to. Must be greater than 0.
- *
- * Sets the size of the column in pixels.  The size of the column is clamped to
- * the min/max width for the column.  Please note that the min/max width of the
- * column doesn't actually affect the "fixed_width" property of the widget, just
- * the actual size when displayed.
- **/
-void
-pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
-                                     gint               fixed_width)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (fixed_width > 0);
-
-  tree_column->fixed_width = fixed_width;
-  tree_column->use_resized_width = FALSE;
-
-  if (tree_column->tree_view &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      gtk_widget_queue_resize (tree_column->tree_view);
-    }
-
-  g_object_notify (G_OBJECT (tree_column), "fixed-width");
-}
-
-/**
- * pspp_sheet_view_column_get_fixed_width:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the fixed width of the column.  This value is only meaning may not be
- * the actual width of the column on the screen, just what is requested.
- *
- * Return value: the fixed width of the column
- **/
-gint
-pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
-  return tree_column->fixed_width;
-}
-
-/**
- * pspp_sheet_view_column_set_min_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @min_width: The minimum width of the column in pixels, or -1.
- *
- * Sets the minimum width of the @tree_column.  If @min_width is -1, then the
- * minimum width is unset.
- **/
-void
-pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
-                                   gint               min_width)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (min_width >= -1);
-
-  if (min_width == tree_column->min_width)
-    return;
-
-  if (tree_column->visible &&
-      tree_column->tree_view != NULL &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      if (min_width > tree_column->width)
-       gtk_widget_queue_resize (tree_column->tree_view);
-    }
-
-  tree_column->min_width = min_width;
-  g_object_freeze_notify (G_OBJECT (tree_column));
-  if (tree_column->max_width != -1 && tree_column->max_width < min_width)
-    {
-      tree_column->max_width = min_width;
-      g_object_notify (G_OBJECT (tree_column), "max-width");
-    }
-  g_object_notify (G_OBJECT (tree_column), "min-width");
-  g_object_thaw_notify (G_OBJECT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_get_min_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
- * width is set.
- *
- * Return value: The minimum width of the @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
-
-  return tree_column->min_width;
-}
-
-/**
- * pspp_sheet_view_column_set_max_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @max_width: The maximum width of the column in pixels, or -1.
- *
- * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
- * maximum width is unset.  Note, the column can actually be wider than max
- * width if it's the last column in a view.  In this case, the column expands to
- * fill any extra space.
- **/
-void
-pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
-                                   gint               max_width)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (max_width >= -1);
-
-  if (max_width == tree_column->max_width)
-    return;
-
-  if (tree_column->visible &&
-      tree_column->tree_view != NULL &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      if (max_width != -1 && max_width < tree_column->width)
-       gtk_widget_queue_resize (tree_column->tree_view);
-    }
-
-  tree_column->max_width = max_width;
-  g_object_freeze_notify (G_OBJECT (tree_column));
-  if (max_width != -1 && max_width < tree_column->min_width)
-    {
-      tree_column->min_width = max_width;
-      g_object_notify (G_OBJECT (tree_column), "min-width");
-    }
-  g_object_notify (G_OBJECT (tree_column), "max-width");
-  g_object_thaw_notify (G_OBJECT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_get_max_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
- * width is set.
- *
- * Return value: The maximum width of the @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
-
-  return tree_column->max_width;
-}
-
-/**
- * pspp_sheet_view_column_clicked:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Emits the "clicked" signal on the column.  This function will only work if
- * @tree_column is clickable.
- **/
-void
-pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  if (tree_column->visible &&
-      tree_column->button &&
-      tree_column->clickable)
-    gtk_button_clicked (GTK_BUTTON (tree_column->button));
-}
-
-/**
- * pspp_sheet_view_column_set_title:
- * @tree_column: A #PsppSheetViewColumn.
- * @title: The title of the @tree_column.
- *
- * Sets the title of the @tree_column.  If a custom widget has been set, then
- * this value is ignored.
- **/
-void
-pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
-                               const gchar       *title)
-{
-  gchar *new_title;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  new_title = g_strdup (title);
-  g_free (tree_column->title);
-  tree_column->title = new_title;
-
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "title");
-}
-
-/**
- * pspp_sheet_view_column_get_title:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the title of the widget.
- *
- * Return value: the title of the column. This string should not be
- * modified or freed.
- **/
-const gchar *
-pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
-  return tree_column->title;
-}
-
-/**
- * pspp_sheet_view_column_set_expand:
- * @tree_column: A #PsppSheetViewColumn
- * @expand: %TRUE if the column should take available extra space, %FALSE if not
- *
- * Sets the column to take available extra space.  This space is shared equally
- * amongst all columns that have the expand set to %TRUE.  If no column has this
- * option set, then the last column gets all extra space.  By default, every
- * column is created with this %FALSE.
- *
- * Since: 2.4
- **/
-void
-pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
-                                gboolean           expand)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  expand = !!expand;
-  if (tree_column->expand == expand)
-    return;
-  tree_column->expand = expand;
-
-  if (tree_column->visible &&
-      tree_column->tree_view != NULL &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      /* We want to continue using the original width of the
-       * column that includes additional space added by the user
-       * resizing the columns and possibly extra (expanded) space, which
-       * are not included in the resized width.
-       */
-      tree_column->use_resized_width = FALSE;
-
-      gtk_widget_queue_resize (tree_column->tree_view);
-    }
-
-  g_object_notify (G_OBJECT (tree_column), "expand");
-}
-
-/**
- * pspp_sheet_view_column_get_expand:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Return %TRUE if the column expands to take any available space.
- *
- * Return value: %TRUE, if the column expands
- *
- * Since: 2.4
- **/
-gboolean
-pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->expand;
-}
-
-/**
- * pspp_sheet_view_column_set_clickable:
- * @tree_column: A #PsppSheetViewColumn.
- * @clickable: %TRUE if the header is active.
- *
- * Sets the header to be active if @active is %TRUE.  When the header is active,
- * then it can take keyboard focus, and can be clicked.
- **/
-void
-pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
-                                    gboolean           clickable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  clickable = !! clickable;
-  if (tree_column->clickable == clickable)
-    return;
-
-  tree_column->clickable = clickable;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "clickable");
-}
-
-/**
- * pspp_sheet_view_column_get_clickable:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Returns %TRUE if the user can click on the header for the column.
- *
- * Return value: %TRUE if user can click the column header.
- **/
-gboolean
-pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->clickable;
-}
-
-/**
- * pspp_sheet_view_column_set_widget:
- * @tree_column: A #PsppSheetViewColumn.
- * @widget: (allow-none): A child #GtkWidget, or %NULL.
- *
- * Sets the widget in the header to be @widget.  If widget is %NULL, then the
- * header button is set with a #GtkLabel set to the title of @tree_column.
- **/
-void
-pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
-                                GtkWidget         *widget)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
-
-  if (widget)
-    g_object_ref_sink (widget);
-
-  if (tree_column->child)
-    g_object_unref (tree_column->child);
-
-  tree_column->child = widget;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "widget");
-}
-
-/**
- * pspp_sheet_view_column_get_widget:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the #GtkWidget in the button on the column header.  If a custom
- * widget has not been set then %NULL is returned.
- *
- * Return value: The #GtkWidget in the column header, or %NULL
- **/
-GtkWidget *
-pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
-  return tree_column->child;
-}
-
-/**
- * pspp_sheet_view_column_set_alignment:
- * @tree_column: A #PsppSheetViewColumn.
- * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
- *
- * Sets the alignment of the title or custom widget inside the column header.
- * The alignment determines its location inside the button.
- **/
-void
-pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
-                                    GtkAlign  xalign)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-
-  if (tree_column->halign == xalign)
-    return;
-
-  tree_column->halign = xalign;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "alignment");
-}
-
-/**
- * pspp_sheet_view_column_get_alignment:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the current x alignment of @tree_column.
- *
- * Return value: The current alignent of @tree_column.
- **/
-GtkAlign
-pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), GTK_ALIGN_CENTER);
-
-  return tree_column->halign;
-}
-
-
-/**
- * pspp_sheet_view_column_set_reorderable:
- * @tree_column: A #PsppSheetViewColumn
- * @reorderable: %TRUE, if the column can be reordered.
- *
- * If @reorderable is %TRUE, then the column can be reordered by the end user
- * dragging the header.
- **/
-void
-pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
-                                     gboolean           reorderable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  /*  if (reorderable)
-      pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
-
-  reorderable = !!reorderable;
-  if (tree_column->reorderable == reorderable)
-    return;
-
-  tree_column->reorderable = reorderable;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "reorderable");
-}
-
-/**
- * pspp_sheet_view_column_get_reorderable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the @tree_column can be reordered by the user.
- *
- * Return value: %TRUE if the @tree_column can be reordered by the user.
- **/
-gboolean
-pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->reorderable;
-}
-
-/**
- * pspp_sheet_view_column_set_quick_edit:
- * @tree_column: A #PsppSheetViewColumn
- * @quick_edit: If true, editing starts upon the first click in the column.  If
- * false, the first click selects the column and a second click is needed to
- * begin editing.  This has no effect on cells that are not editable.
- **/
-void
-pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
-                                     gboolean           quick_edit)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  quick_edit = !!quick_edit;
-  if (tree_column->quick_edit != quick_edit)
-    {
-      tree_column->quick_edit = quick_edit;
-      g_object_notify (G_OBJECT (tree_column), "quick-edit");
-    }
-}
-
-/**
- * pspp_sheet_view_column_get_quick_edit:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if editing starts upon the first click in the column.  Returns
- * %FALSE, the first click selects the column and a second click is needed to
- * begin editing.  This is not meaningful for cells that are not editable.
- *
- * Return value: %TRUE if editing starts upon the first click.
- **/
-gboolean
-pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->quick_edit;
-}
-
-
-/**
- * pspp_sheet_view_column_set_selected:
- * @tree_column: A #PsppSheetViewColumn
- * @selected: If true, the column is selected as part of a rectangular
- * selection.
- **/
-void
-pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
-                                     gboolean           selected)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  selected = !!selected;
-  if (tree_column->selected != selected)
-    {
-      PsppSheetSelection *selection;
-      PsppSheetView *sheet_view;
-
-      if (tree_column->tree_view != NULL)
-        gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
-      tree_column->selected = selected;
-      g_object_notify (G_OBJECT (tree_column), "selected");
-
-      sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
-                                      tree_column));
-      selection = pspp_sheet_view_get_selection (sheet_view);
-      _pspp_sheet_selection_emit_changed (selection);
-    }
-}
-
-/**
- * pspp_sheet_view_column_get_selected:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is selected as part of a rectangular
- * selection.
- *
- * Return value: %TRUE if the column is selected as part of a rectangular
- * selection.
- **/
-gboolean
-pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->selected;
-}
-
-/**
- * pspp_sheet_view_column_set_selectable:
- * @tree_column: A #PsppSheetViewColumn
- * @selectable: If true, the column may be selected as part of a rectangular
- * selection.
- **/
-void
-pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
-                                     gboolean           selectable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  selectable = !!selectable;
-  if (tree_column->selectable != selectable)
-    {
-      if (tree_column->tree_view != NULL)
-        gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
-      tree_column->selectable = selectable;
-      g_object_notify (G_OBJECT (tree_column), "selectable");
-    }
-}
-
-/**
- * pspp_sheet_view_column_get_selectable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column may be selected as part of a rectangular
- * selection.
- *
- * Return value: %TRUE if the column may be selected as part of a rectangular
- * selection.
- **/
-gboolean
-pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->selectable;
-}
-
-
-/**
- * pspp_sheet_view_column_set_row_head:
- * @tree_column: A #PsppSheetViewColumn
- * @row_head: If true, the column is a "row head", analogous to a column head.
- * See the description of the row-head property for more information.
- **/
-void
-pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
-                                     gboolean           row_head)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  row_head = !!row_head;
-  if (tree_column->row_head != row_head)
-    {
-      tree_column->row_head = row_head;
-      g_object_notify (G_OBJECT (tree_column), "row_head");
-    }
-}
-
-/**
- * pspp_sheet_view_column_get_row_head:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is a row head.
- *
- * Return value: %TRUE if the column is a row head.
- **/
-gboolean
-pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->row_head;
-}
-
-
-/**
- * pspp_sheet_view_column_set_tabbable:
- * @tree_column: A #PsppSheetViewColumn
- * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
- * in the sheet visit this column.  If false, Tab and Shift+Tab skip this
- * column.
- **/
-void
-pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
-                                     gboolean           tabbable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  tabbable = !!tabbable;
-  if (tree_column->tabbable != tabbable)
-    {
-      tree_column->tabbable = tabbable;
-      g_object_notify (G_OBJECT (tree_column), "tabbable");
-    }
-}
-
-/**
- * pspp_sheet_view_column_get_tabbable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is tabbable.
- *
- * Return value: %TRUE if the column is tabbable.
- **/
-gboolean
-pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->tabbable;
-}
-
-
-/**
- * pspp_sheet_view_column_set_sort_column_id:
- * @tree_column: a #PsppSheetViewColumn
- * @sort_column_id: The @sort_column_id of the model to sort on.
- *
- * Sets the logical @sort_column_id that this column sorts on when this column
- * is selected for sorting.  Doing so makes the column header clickable.
- **/
-void
-pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
-                                        gint               sort_column_id)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (sort_column_id >= -1);
-
-  if (tree_column->sort_column_id == sort_column_id)
-    return;
-
-  tree_column->sort_column_id = sort_column_id;
-
-  /* Handle unsetting the id */
-  if (sort_column_id == -1)
-    {
-      GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
-
-      if (tree_column->sort_clicked_signal)
-       {
-         g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
-         tree_column->sort_clicked_signal = 0;
-       }
-
-      if (tree_column->sort_column_changed_signal)
-       {
-         g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
-         tree_column->sort_column_changed_signal = 0;
-       }
-
-      pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
-      pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
-      pspp_sheet_view_column_set_clickable (tree_column, FALSE);
-      g_object_notify (G_OBJECT (tree_column), "sort-column-id");
-      return;
-    }
-
-  pspp_sheet_view_column_set_clickable (tree_column, TRUE);
-
-  if (! tree_column->sort_clicked_signal)
-    tree_column->sort_clicked_signal = g_signal_connect (tree_column,
-                                                         "clicked",
-                                                         G_CALLBACK (pspp_sheet_view_column_sort),
-                                                         NULL);
-
-  pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "sort-column-id");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_column_id:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the logical @sort_column_id that the model sorts on when this
- * column is selected for sorting.
- * See pspp_sheet_view_column_set_sort_column_id().
- *
- * Return value: the current @sort_column_id for this column, or -1 if
- *               this column can't be used for sorting.
- **/
-gint
-pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
-  return tree_column->sort_column_id;
-}
-
-/**
- * pspp_sheet_view_column_set_sort_indicator:
- * @tree_column: a #PsppSheetViewColumn
- * @setting: %TRUE to display an indicator that the column is sorted
- *
- * Call this function with a @setting of %TRUE to display an arrow in
- * the header button indicating the column is sorted. Call
- * pspp_sheet_view_column_set_sort_order() to change the direction of
- * the arrow.
- *
- **/
-void
-pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn     *tree_column,
-                                         gboolean               setting)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  setting = setting != FALSE;
-
-  if (setting == tree_column->show_sort_indicator)
-    return;
-
-  tree_column->show_sort_indicator = setting;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "sort-indicator");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_indicator:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
- *
- * Return value: whether the sort indicator arrow is displayed
- **/
-gboolean
-pspp_sheet_view_column_get_sort_indicator  (PsppSheetViewColumn     *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return tree_column->show_sort_indicator;
-}
-
-/**
- * pspp_sheet_view_column_set_sort_order:
- * @tree_column: a #PsppSheetViewColumn
- * @order: sort order that the sort indicator should indicate
- *
- * Changes the appearance of the sort indicator.
- *
- * This <emphasis>does not</emphasis> actually sort the model.  Use
- * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
- * support.  This function is primarily for custom sorting behavior, and should
- * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
- * that. For custom models, the mechanism will vary.
- *
- * The sort indicator changes direction to indicate normal sort or reverse sort.
- * Note that you must have the sort indicator enabled to see anything when
- * calling this function; see pspp_sheet_view_column_set_sort_indicator().
- **/
-void
-pspp_sheet_view_column_set_sort_order      (PsppSheetViewColumn     *tree_column,
-                                          GtkSortType            order)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  if (order == tree_column->sort_order)
-    return;
-
-  tree_column->sort_order = order;
-  pspp_sheet_view_column_update_button (tree_column);
-  g_object_notify (G_OBJECT (tree_column), "sort-order");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_order:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the value set by pspp_sheet_view_column_set_sort_order().
- *
- * Return value: the sort order the sort indicator is indicating
- **/
-GtkSortType
-pspp_sheet_view_column_get_sort_order      (PsppSheetViewColumn     *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
-  return tree_column->sort_order;
-}
-
-/**
- * pspp_sheet_view_column_cell_set_cell_data:
- * @tree_column: A #PsppSheetViewColumn.
- * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
- * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
- *
- * Sets the cell renderer based on the @tree_model and @iter.  That is, for
- * every attribute mapping in @tree_column, it will get a value from the set
- * column on the @iter, and use that value to set the attribute on the cell
- * renderer.  This is used primarily by the #PsppSheetView.
- **/
-void
-pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
-                                        GtkTreeModel      *tree_model,
-                                        GtkTreeIter       *iter)
-{
-  GSList *list;
-  GValue value = { 0, };
-  GList *cell_list;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  if (tree_model == NULL)
-    return;
-
-  for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
-      GObject *cell = (GObject *) info->cell;
-
-      list = info->attributes;
-
-      g_object_freeze_notify (cell);
-
-      while (list && list->next)
-       {
-         gtk_tree_model_get_value (tree_model, iter,
-                                   GPOINTER_TO_INT (list->next->data),
-                                   &value);
-         g_object_set_property (cell, (gchar *) list->data, &value);
-         g_value_unset (&value);
-         list = list->next->next;
-       }
-
-      if (info->func)
-       (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
-      g_object_thaw_notify (G_OBJECT (info->cell));
-    }
-
-}
-
-/**
- * pspp_sheet_view_column_cell_get_size:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
- * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
- * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
- * @width: (allow-none): location to return width needed to render a cell, or %NULL
- * @height: (allow-none): location to return height needed to render a cell, or %NULL
- *
- * Obtains the width and height needed to render the column.  This is used
- * primarily by the #PsppSheetView.
- **/
-void
-pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn  *tree_column,
-                                   const GdkRectangle *cell_area,
-                                   gint               *x_offset,
-                                   gint               *y_offset,
-                                   gint               *width,
-                                   gint               *height)
-{
-  GList *list;
-  gboolean first_cell = TRUE;
-  gint focus_line_width;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  if (height)
-    * height = 0;
-  if (width)
-    * width = 0;
-
-  gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-      gboolean visible;
-      gint new_height = 0;
-      gint new_width = 0;
-      g_object_get (info->cell, "visible", &visible, NULL);
-
-      if (visible == FALSE)
-       continue;
-
-      if (first_cell == FALSE && width)
-       *width += tree_column->spacing;
-
-      gtk_cell_renderer_get_padding (info->cell, x_offset, y_offset);
-      gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
-                                            NULL, &new_width);
-
-      gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
-                                             NULL, &new_height);
-
-
-      if (height)
-       * height = MAX (*height, new_height + focus_line_width * 2);
-      info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
-      if (width)
-       * width += info->requested_width;
-      first_cell = FALSE;
-    }
-}
-
-/* rendering, event handling and rendering focus are somewhat complicated, and
- * quite a bit of code.  Rather than duplicate them, we put them together to
- * keep the code in one place.
- *
- * To better understand what's going on, check out
- * docs/tree-column-sizing.png
- */
-enum {
-  CELL_ACTION_RENDER,
-  CELL_ACTION_FOCUS,
-  CELL_ACTION_EVENT
-};
-
-static gboolean
-pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn  *tree_column,
-                                           cairo_t *cr,
-                                         const GdkRectangle *background_area,
-                                         const GdkRectangle *cell_area,
-                                         guint               flags,
-                                         gint                action,
-                                         GdkRectangle       *focus_rectangle, /* FOCUS  */
-                                         GtkCellEditable   **editable_widget, /* EVENT  */
-                                         GdkEvent           *event,           /* EVENT  */
-                                         gchar              *path_string)     /* EVENT  */
-{
-  GList *list;
-  GdkRectangle real_cell_area;
-  GdkRectangle real_background_area;
-  gint depth = 0;
-  gint expand_cell_count = 0;
-  gint full_requested_width = 0;
-  gint extra_space;
-  gint min_x, min_y, max_x, max_y;
-  gint focus_line_width;
-  gint special_cells;
-  gint horizontal_separator;
-  gboolean cursor_row = FALSE;
-  gboolean first_cell = TRUE;
-  gboolean rtl;
-  /* If we have rtl text, we need to transform our areas */
-  GdkRectangle rtl_cell_area;
-  GdkRectangle rtl_background_area;
-
-  min_x = G_MAXINT;
-  min_y = G_MAXINT;
-  max_x = 0;
-  max_y = 0;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
-  special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
-
-  if (special_cells > 1 && action == CELL_ACTION_FOCUS)
-    {
-      PsppSheetViewColumnCellInfo *info = NULL;
-      gboolean found_has_focus = FALSE;
-
-      /* one should have focus */
-      for (list = tree_column->cell_list; list; list = list->next)
-        {
-         info = list->data;
-         if (info && info->has_focus)
-           {
-             found_has_focus = TRUE;
-             break;
-           }
-       }
-
-      if (!found_has_focus)
-        {
-         /* give the first one focus */
-         info = pspp_sheet_view_column_cell_first (tree_column)->data;
-         info->has_focus = TRUE;
-       }
-    }
-
-  cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
-                       "focus-line-width", &focus_line_width,
-                       "horizontal-separator", &horizontal_separator,
-                       NULL);
-
-  real_cell_area = *cell_area;
-  real_background_area = *background_area;
-
-
-  real_cell_area.x += focus_line_width;
-  real_cell_area.y += focus_line_width;
-  real_cell_area.height -= 2 * focus_line_width;
-
-  if (rtl)
-    depth = real_background_area.width - real_cell_area.width;
-  else
-    depth = real_cell_area.x - real_background_area.x;
-
-  /* Find out how much extra space we have to allocate */
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
-
-      if (! gtk_cell_renderer_get_visible (info->cell))
-       continue;
-
-      if (info->expand == TRUE)
-       expand_cell_count ++;
-      full_requested_width += info->requested_width;
-
-      if (!first_cell)
-       full_requested_width += tree_column->spacing;
-
-      first_cell = FALSE;
-    }
-
-  extra_space = cell_area->width - full_requested_width;
-  if (extra_space < 0)
-    extra_space = 0;
-  else if (extra_space > 0 && expand_cell_count > 0)
-    extra_space /= expand_cell_count;
-
-  /* iterate list for GTK_PACK_START cells */
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
-      if (info->pack == GTK_PACK_END)
-       continue;
-
-      if (! gtk_cell_renderer_get_visible (info->cell))
-       continue;
-
-      if ((info->has_focus || special_cells == 1) && cursor_row)
-       flags |= GTK_CELL_RENDERER_FOCUSED;
-      else
-        flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-      info->real_width = info->requested_width + (info->expand?extra_space:0);
-
-      /* We constrain ourselves to only the width available */
-      if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
-       {
-         info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
-       }
-
-      if (real_cell_area.x > cell_area->x + cell_area->width)
-       break;
-
-      real_cell_area.width = info->real_width;
-      real_cell_area.width -= 2 * focus_line_width;
-
-      if (list->next)
-       {
-         real_background_area.width = info->real_width + depth;
-       }
-      else
-       {
-          /* fill the rest of background for the last cell */
-         real_background_area.width = background_area->x + background_area->width - real_background_area.x;
-       }
-
-      rtl_cell_area = real_cell_area;
-      rtl_background_area = real_background_area;
-
-      if (rtl)
-       {
-         rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
-         rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
-       }
-
-      /* RENDER */
-      if (action == CELL_ACTION_RENDER)
-       {
-         gtk_cell_renderer_render (info->cell,
-                                   cr,
-                                   tree_column->tree_view,
-                                   &rtl_background_area,
-                                   &rtl_cell_area,
-                                   flags);
-       }
-      /* FOCUS */
-      else if (action == CELL_ACTION_FOCUS)
-       {
-         gint x_offset, y_offset, width, height;
-
-         gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
-                                                 NULL, &height);
-
-         gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
-                                                 NULL, &width);
-
-
-         gtk_cell_renderer_get_padding (info->cell,
-                                        &x_offset, &y_offset);
-
-         if (special_cells > 1)
-           {
-             if (info->has_focus)
-               {
-                 min_x = rtl_cell_area.x + x_offset;
-                 max_x = min_x + width;
-                 min_y = rtl_cell_area.y + y_offset;
-                 max_y = min_y + height;
-               }
-           }
-         else
-           {
-             if (min_x > (rtl_cell_area.x + x_offset))
-               min_x = rtl_cell_area.x + x_offset;
-             if (max_x < rtl_cell_area.x + x_offset + width)
-               max_x = rtl_cell_area.x + x_offset + width;
-             if (min_y > (rtl_cell_area.y + y_offset))
-               min_y = rtl_cell_area.y + y_offset;
-             if (max_y < rtl_cell_area.y + y_offset + height)
-               max_y = rtl_cell_area.y + y_offset + height;
-           }
-       }
-      /* EVENT */
-      else if (action == CELL_ACTION_EVENT)
-       {
-         gboolean try_event = FALSE;
-
-         if (event)
-           {
-             if (special_cells == 1)
-               {
-                 /* only 1 activatable cell -> whole column can activate */
-                 if (cell_area->x <= ((GdkEventButton *)event)->x &&
-                     cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
-                   try_event = TRUE;
-               }
-             else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
-                 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
-                 /* only activate cell if the user clicked on an individual
-                  * cell
-                  */
-               try_event = TRUE;
-           }
-         else if (special_cells > 1 && info->has_focus)
-           try_event = TRUE;
-         else if (special_cells == 1)
-           try_event = TRUE;
-
-         if (try_event)
-           {
-             gboolean visible, mode;
-
-             g_object_get (info->cell,
-                           "visible", &visible,
-                           "mode", &mode,
-                           NULL);
-             if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
-               {
-                 if (gtk_cell_renderer_activate (info->cell,
-                                                 event,
-                                                 tree_column->tree_view,
-                                                 path_string,
-                                                 &rtl_background_area,
-                                                 &rtl_cell_area,
-                                                 flags))
-                   {
-                      flags &= ~GTK_CELL_RENDERER_FOCUSED;
-                     return TRUE;
-                   }
-               }
-             else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
-               {
-                 *editable_widget =
-                   gtk_cell_renderer_start_editing (info->cell,
-                                                    event,
-                                                    tree_column->tree_view,
-                                                    path_string,
-                                                    &rtl_background_area,
-                                                    &rtl_cell_area,
-                                                    flags);
-
-                 if (*editable_widget != NULL)
-                   {
-                     g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
-                     info->in_editing_mode = TRUE;
-                     pspp_sheet_view_column_focus_cell (tree_column, info->cell);
-
-                      flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-                     return TRUE;
-                   }
-               }
-           }
-       }
-
-      flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-      real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
-      real_background_area.x += real_background_area.width + tree_column->spacing;
-
-      /* Only needed for first cell */
-      depth = 0;
-    }
-
-  /* iterate list for PACK_END cells */
-  for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
-      if (info->pack == GTK_PACK_START)
-       continue;
-
-      if (! gtk_cell_renderer_get_visible (info->cell))
-       continue;
-
-      if ((info->has_focus || special_cells == 1) && cursor_row)
-       flags |= GTK_CELL_RENDERER_FOCUSED;
-      else
-        flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-      info->real_width = info->requested_width + (info->expand?extra_space:0);
-
-      /* We constrain ourselves to only the width available */
-      if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
-       {
-         info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
-       }
-
-      if (real_cell_area.x > cell_area->x + cell_area->width)
-       break;
-
-      real_cell_area.width = info->real_width;
-      real_cell_area.width -= 2 * focus_line_width;
-      real_background_area.width = info->real_width + depth;
-
-      rtl_cell_area = real_cell_area;
-      rtl_background_area = real_background_area;
-      if (rtl)
-       {
-         rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
-         rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
-       }
-
-      /* RENDER */
-      if (action == CELL_ACTION_RENDER)
-       {
-         gtk_cell_renderer_render (info->cell,
-                                   cr,
-                                   tree_column->tree_view,
-                                   &rtl_background_area,
-                                   &rtl_cell_area,
-                                   flags);
-       }
-      /* FOCUS */
-      else if (action == CELL_ACTION_FOCUS)
-       {
-         gint x_offset, y_offset, width, height;
-
-         gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
-                                                 NULL, &height);
-
-         gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
-                                                 NULL, &width);
-
-
-         gtk_cell_renderer_get_padding (info->cell,
-                                        &x_offset, &y_offset);
-
-         if (special_cells > 1)
-           {
-             if (info->has_focus)
-               {
-                 min_x = rtl_cell_area.x + x_offset;
-                 max_x = min_x + width;
-                 min_y = rtl_cell_area.y + y_offset;
-                 max_y = min_y + height;
-               }
-           }
-         else
-           {
-             if (min_x > (rtl_cell_area.x + x_offset))
-               min_x = rtl_cell_area.x + x_offset;
-             if (max_x < rtl_cell_area.x + x_offset + width)
-               max_x = rtl_cell_area.x + x_offset + width;
-             if (min_y > (rtl_cell_area.y + y_offset))
-               min_y = rtl_cell_area.y + y_offset;
-             if (max_y < rtl_cell_area.y + y_offset + height)
-               max_y = rtl_cell_area.y + y_offset + height;
-           }
-       }
-      /* EVENT */
-      else if (action == CELL_ACTION_EVENT)
-        {
-         gboolean try_event = FALSE;
-
-         if (event)
-           {
-             if (special_cells == 1)
-               {
-                 /* only 1 activatable cell -> whole column can activate */
-                 if (cell_area->x <= ((GdkEventButton *)event)->x &&
-                     cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
-                   try_event = TRUE;
-               }
-             else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
-                 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
-               /* only activate cell if the user clicked on an individual
-                * cell
-                */
-               try_event = TRUE;
-           }
-         else if (special_cells > 1 && info->has_focus)
-           try_event = TRUE;
-         else if (special_cells == 1)
-           try_event = TRUE;
-
-         if (try_event)
-           {
-             gboolean visible, mode;
-
-             g_object_get (info->cell,
-                           "visible", &visible,
-                           "mode", &mode,
-                           NULL);
-             if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
-               {
-                 if (gtk_cell_renderer_activate (info->cell,
-                                                 event,
-                                                 tree_column->tree_view,
-                                                 path_string,
-                                                 &rtl_background_area,
-                                                 &rtl_cell_area,
-                                                 flags))
-                   {
-                     flags &= ~GTK_CELL_RENDERER_FOCUSED;
-                     return TRUE;
-                   }
-               }
-             else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
-               {
-                 *editable_widget =
-                   gtk_cell_renderer_start_editing (info->cell,
-                                                    event,
-                                                    tree_column->tree_view,
-                                                    path_string,
-                                                    &rtl_background_area,
-                                                    &rtl_cell_area,
-                                                    flags);
-
-                 if (*editable_widget != NULL)
-                   {
-                     g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
-                     info->in_editing_mode = TRUE;
-                     pspp_sheet_view_column_focus_cell (tree_column, info->cell);
-
-                     flags &= ~GTK_CELL_RENDERER_FOCUSED;
-                     return TRUE;
-                   }
-               }
-           }
-       }
-
-      flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-      real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
-      real_background_area.x += (real_background_area.width + tree_column->spacing);
-
-      /* Only needed for first cell */
-      depth = 0;
-    }
-
-  /* fill focus_rectangle when required */
-  if (action == CELL_ACTION_FOCUS)
-    {
-      if (min_x >= max_x || min_y >= max_y)
-       {
-         *focus_rectangle = *cell_area;
-         /* don't change the focus_rectangle, just draw it nicely inside
-          * the cell area */
-       }
-      else
-       {
-         focus_rectangle->x = min_x - focus_line_width;
-         focus_rectangle->y = min_y - focus_line_width;
-         focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
-         focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
-       }
-    }
-
-  return FALSE;
-}
-
-/**
- * pspp_sheet_view_column_cell_render:
- * @tree_column: A #PsppSheetViewColumn.
- * @window: a #GdkDrawable to draw to
- * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
- * @cell_area: area normally rendered by a cell renderer
- * @flags: flags that affect rendering
- *
- * Renders the cell contained by #tree_column. This is used primarily by the
- * #PsppSheetView.
- **/
-void
-_pspp_sheet_view_column_cell_render (PsppSheetViewColumn  *tree_column,
-                                    cairo_t *cr,
-                                  const GdkRectangle *background_area,
-                                  const GdkRectangle *cell_area,
-                                  guint               flags)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (background_area != NULL);
-  g_return_if_fail (cell_area != NULL);
-
-  pspp_sheet_view_column_cell_process_action (tree_column,
-                                             cr,
-                                           background_area,
-                                           cell_area,
-                                           flags,
-                                           CELL_ACTION_RENDER,
-                                           NULL, NULL, NULL, NULL);
-}
-
-gboolean
-_pspp_sheet_view_column_cell_event (PsppSheetViewColumn  *tree_column,
-                                 GtkCellEditable   **editable_widget,
-                                 GdkEvent           *event,
-                                 gchar              *path_string,
-                                 const GdkRectangle *background_area,
-                                 const GdkRectangle *cell_area,
-                                 guint               flags)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  return pspp_sheet_view_column_cell_process_action (tree_column,
-                                                  NULL,
-                                                  background_area,
-                                                  cell_area,
-                                                  flags,
-                                                  CELL_ACTION_EVENT,
-                                                  NULL,
-                                                  editable_widget,
-                                                  event,
-                                                  path_string);
-}
-
-void
-_pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn  *tree_column,
-                                     const GdkRectangle *background_area,
-                                     const GdkRectangle *cell_area,
-                                     GdkRectangle       *focus_area)
-{
-  pspp_sheet_view_column_cell_process_action (tree_column,
-                                           NULL,
-                                           background_area,
-                                           cell_area,
-                                           0,
-                                           CELL_ACTION_FOCUS,
-                                           focus_area,
-                                           NULL, NULL, NULL);
-}
-
-
-/* cell list manipulation */
-static GList *
-pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
-{
-  GList *list = tree_column->cell_list;
-
-  /* first GTK_PACK_START cell we find */
-  for ( ; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = list->data;
-      if (info->pack == GTK_PACK_START)
-       return list;
-    }
-
-  /* hmm, else the *last* GTK_PACK_END cell */
-  list = g_list_last (tree_column->cell_list);
-
-  for ( ; list; list = list->prev)
-    {
-      PsppSheetViewColumnCellInfo *info = list->data;
-      if (info->pack == GTK_PACK_END)
-       return list;
-    }
-
-  return NULL;
-}
-
-static GList *
-pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
-{
-  GList *list = tree_column->cell_list;
-
-  /* *first* GTK_PACK_END cell we find */
-  for ( ; list ; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = list->data;
-      if (info->pack == GTK_PACK_END)
-       return list;
-    }
-
-  /* hmm, else the last GTK_PACK_START cell */
-  list = g_list_last (tree_column->cell_list);
-
-  for ( ; list; list = list->prev)
-    {
-      PsppSheetViewColumnCellInfo *info = list->data;
-      if (info->pack == GTK_PACK_START)
-       return list;
-    }
-
-  return NULL;
-}
-
-
-static GList *
-pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
-                               GList             *current)
-{
-  GList *list;
-  PsppSheetViewColumnCellInfo *info = current->data;
-
-  if (info->pack == GTK_PACK_START)
-    {
-      for (list = current->next; list; list = list->next)
-        {
-         PsppSheetViewColumnCellInfo *inf = list->data;
-         if (inf->pack == GTK_PACK_START)
-           return list;
-       }
-
-      /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
-      list = g_list_last (tree_column->cell_list);
-      for (; list; list = list->prev)
-        {
-         PsppSheetViewColumnCellInfo *inf = list->data;
-         if (inf->pack == GTK_PACK_END)
-           return list;
-       }
-    }
-
-  for (list = current->prev; list; list = list->prev)
-    {
-      PsppSheetViewColumnCellInfo *inf = list->data;
-      if (inf->pack == GTK_PACK_END)
-       return list;
-    }
-
-  return NULL;
-}
-
-static GList *
-pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
-                               GList             *current)
-{
-  GList *list;
-  PsppSheetViewColumnCellInfo *info = current->data;
-
-  if (info->pack == GTK_PACK_END)
-    {
-      for (list = current->next; list; list = list->next)
-        {
-         PsppSheetViewColumnCellInfo *inf = list->data;
-         if (inf->pack == GTK_PACK_END)
-           return list;
-       }
-
-      /* out of GTK_PACK_END, get last GTK_PACK_START one */
-      list = g_list_last (tree_column->cell_list);
-      for ( ; list; list = list->prev)
-        {
-         PsppSheetViewColumnCellInfo *inf = list->data;
-         if (inf->pack == GTK_PACK_START)
-           return list;
-       }
-    }
-
-  for (list = current->prev; list; list = list->prev)
-    {
-      PsppSheetViewColumnCellInfo *inf = list->data;
-      if (inf->pack == GTK_PACK_START)
-       return list;
-    }
-
-  return NULL;
-}
-
-gboolean
-_pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
-                                 gint               direction,
-                                 gboolean           left,
-                                 gboolean           right)
-{
-  gint count;
-  gboolean rtl;
-
-  count = _pspp_sheet_view_column_count_special_cells (tree_column);
-  rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
-
-  /* if we are the current focus column and have multiple editable cells,
-   * try to select the next one, else move the focus to the next column
-   */
-  if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
-    {
-      if (count > 1)
-        {
-          GList *next, *prev;
-         GList *list = tree_column->cell_list;
-         PsppSheetViewColumnCellInfo *info = NULL;
-
-         /* find current focussed cell */
-         for ( ; list; list = list->next)
-           {
-             info = list->data;
-             if (info->has_focus)
-               break;
-           }
-
-         /* not a focussed cell in the focus column? */
-         if (!list || !info || !info->has_focus)
-           return FALSE;
-
-         if (rtl)
-           {
-             prev = pspp_sheet_view_column_cell_next (tree_column, list);
-             next = pspp_sheet_view_column_cell_prev (tree_column, list);
-           }
-         else
-           {
-             next = pspp_sheet_view_column_cell_next (tree_column, list);
-             prev = pspp_sheet_view_column_cell_prev (tree_column, list);
-           }
-
-         info->has_focus = FALSE;
-         if (direction > 0 && next)
-           {
-             info = next->data;
-             info->has_focus = TRUE;
-             return TRUE;
-           }
-         else if (direction > 0 && !next && !right)
-           {
-             /* keep focus on last cell */
-             if (rtl)
-               info = pspp_sheet_view_column_cell_first (tree_column)->data;
-             else
-               info = pspp_sheet_view_column_cell_last (tree_column)->data;
-
-             info->has_focus = TRUE;
-             return TRUE;
-           }
-         else if (direction < 0 && prev)
-           {
-             info = prev->data;
-             info->has_focus = TRUE;
-             return TRUE;
-           }
-         else if (direction < 0 && !prev && !left)
-           {
-             /* keep focus on first cell */
-             if (rtl)
-               info = pspp_sheet_view_column_cell_last (tree_column)->data;
-             else
-               info = pspp_sheet_view_column_cell_first (tree_column)->data;
-
-             info->has_focus = TRUE;
-             return TRUE;
-           }
-       }
-      return FALSE;
-    }
-
-  /* we get focus, if we have multiple editable cells, give the correct one
-   * focus
-   */
-  if (count > 1)
-    {
-      GList *list = tree_column->cell_list;
-
-      /* clear focus first */
-      for ( ; list ; list = list->next)
-        {
-         PsppSheetViewColumnCellInfo *info = list->data;
-         if (info->has_focus)
-           info->has_focus = FALSE;
-       }
-
-      list = NULL;
-      if (rtl)
-        {
-         if (direction > 0)
-           list = pspp_sheet_view_column_cell_last (tree_column);
-         else if (direction < 0)
-           list = pspp_sheet_view_column_cell_first (tree_column);
-       }
-      else
-        {
-         if (direction > 0)
-           list = pspp_sheet_view_column_cell_first (tree_column);
-         else if (direction < 0)
-           list = pspp_sheet_view_column_cell_last (tree_column);
-       }
-
-      if (list)
-       ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
-    }
-
-  return TRUE;
-}
-
-void
-_pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn  *tree_column,
-                                        cairo_t *cr,
-                                      const GdkRectangle *background_area,
-                                      const GdkRectangle *cell_area,
-                                      guint               flags)
-{
-  gint focus_line_width;
-  GtkStateType cell_state;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
-                       "focus-line-width", &focus_line_width, NULL);
-  if (tree_column->editable_widget)
-    {
-      /* This function is only called on the editable row when editing.
-       */
-#if 0
-      gtk_paint_focus (tree_column->tree_view->style,
-                      window,
-                      gtk_widget_get_state (tree_column->tree_view),
-                      NULL,
-                      tree_column->tree_view,
-                      "treeview",
-                      cell_area->x - focus_line_width,
-                      cell_area->y - focus_line_width,
-                      cell_area->width + 2 * focus_line_width,
-                      cell_area->height + 2 * focus_line_width);
-#endif
-    }
-  else
-    {
-      GdkRectangle focus_rectangle;
-      pspp_sheet_view_column_cell_process_action (tree_column,
-                                                 cr,
-                                               background_area,
-                                               cell_area,
-                                               flags,
-                                               CELL_ACTION_FOCUS,
-                                               &focus_rectangle,
-                                               NULL, NULL, NULL);
-
-      cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
-             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
-             (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
-
-      gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
-                      cr,
-                      cell_state,
-                      tree_column->tree_view,
-                      "treeview",
-                      focus_rectangle.x,
-                      focus_rectangle.y,
-                      focus_rectangle.width,
-                      focus_rectangle.height);
-    }
-}
-
-/**
- * pspp_sheet_view_column_cell_is_visible:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if any of the cells packed into the @tree_column are visible.
- * For this to be meaningful, you must first initialize the cells with
- * pspp_sheet_view_column_cell_set_cell_data()
- *
- * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
- **/
-gboolean
-pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
-{
-  GList *list;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
-      if (gtk_cell_renderer_get_visible (info->cell))
-       return TRUE;
-    }
-
-  return FALSE;
-}
-
-/**
- * pspp_sheet_view_column_focus_cell:
- * @tree_column: A #PsppSheetViewColumn
- * @cell: A #GtkCellRenderer
- *
- * Sets the current keyboard focus to be at @cell, if the column contains
- * 2 or more editable and activatable cells.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
-                                GtkCellRenderer   *cell)
-{
-  GList *list;
-  gboolean found_cell = FALSE;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
-    return;
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = list->data;
-
-      if (info->cell == cell)
-        {
-         info->has_focus = TRUE;
-         found_cell = TRUE;
-         break;
-       }
-    }
-
-  if (found_cell)
-    {
-      for (list = tree_column->cell_list; list; list = list->next)
-        {
-         PsppSheetViewColumnCellInfo *info = list->data;
-
-         if (info->cell != cell)
-           info->has_focus = FALSE;
-        }
-
-      /* FIXME: redraw? */
-    }
-}
-
-void
-_pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
-{
-  GList *list;
-
-  for (list = tree_column->cell_list; list; list = list->next)
-    {
-      PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
-      info->requested_width = 0;
-    }
-  tree_column->dirty = TRUE;
-  tree_column->requested_width = -1;
-  tree_column->width = 0;
-
-  if (tree_column->tree_view &&
-      PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized &&
-      gtk_widget_get_realized (tree_column->tree_view))
-    {
-      PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized = FALSE;
-      _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
-      gtk_widget_queue_resize (tree_column->tree_view);
-    }
-}
-
-void
-_pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
-                                    GtkCellEditable   *cell_editable)
-{
-  g_return_if_fail (tree_column->editable_widget == NULL);
-
-  tree_column->editable_widget = cell_editable;
-}
-
-void
-_pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
-{
-  GList *list;
-
-  g_return_if_fail (tree_column->editable_widget != NULL);
-
-  tree_column->editable_widget = NULL;
-  for (list = tree_column->cell_list; list; list = list->next)
-    ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
-}
-
-void
-_pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
-                                         GtkCellRenderer   *cell,
-                                         gint              *left,
-                                         gint              *right)
-{
-  GList *list;
-  PsppSheetViewColumnCellInfo *info;
-  gint l, r;
-  gboolean rtl;
-
-  l = r = 0;
-
-  list = pspp_sheet_view_column_cell_first (column);
-
-  while (list)
-    {
-      info = (PsppSheetViewColumnCellInfo *)list->data;
-
-      list = pspp_sheet_view_column_cell_next (column, list);
-
-      if (info->cell == cell)
-       break;
-
-      if (gtk_cell_renderer_get_visible (info->cell))
-       l += info->real_width + column->spacing;
-    }
-
-  while (list)
-    {
-      info = (PsppSheetViewColumnCellInfo *)list->data;
-
-      list = pspp_sheet_view_column_cell_next (column, list);
-
-      if (gtk_cell_renderer_get_visible (info->cell))
-       r += info->real_width + column->spacing;
-    }
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
-  if (left)
-    *left = rtl ? r : l;
-
-  if (right)
-    *right = rtl ? l : r;
-}
-
-/**
- * pspp_sheet_view_column_cell_get_position:
- * @tree_column: a #PsppSheetViewColumn
- * @cell_renderer: a #GtkCellRenderer
- * @start_pos: return location for the horizontal position of @cell within
- *            @tree_column, may be %NULL
- * @width: return location for the width of @cell, may be %NULL
- *
- * Obtains the horizontal position and size of a cell in a column. If the
- * cell is not found in the column, @start_pos and @width are not changed and
- * %FALSE is returned.
- *
- * Return value: %TRUE if @cell belongs to @tree_column.
- */
-gboolean
-pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
-                                       GtkCellRenderer   *cell_renderer,
-                                       gint              *start_pos,
-                                       gint              *width)
-{
-  GList *list;
-  gint current_x = 0;
-  gboolean found_cell = FALSE;
-  PsppSheetViewColumnCellInfo *cellinfo = NULL;
-
-  list = pspp_sheet_view_column_cell_first (tree_column);
-  for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
-    {
-      cellinfo = list->data;
-      if (cellinfo->cell == cell_renderer)
-        {
-          found_cell = TRUE;
-          break;
-        }
-
-      if (gtk_cell_renderer_get_visible (cellinfo->cell))
-        current_x += cellinfo->real_width;
-    }
-
-  if (found_cell)
-    {
-      if (start_pos)
-        *start_pos = current_x;
-      if (width)
-        *width = cellinfo->real_width;
-    }
-
-  return found_cell;
-}
-
-/**
- * pspp_sheet_view_column_queue_resize:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Flags the column, and the cell renderers added to this column, to have
- * their sizes renegotiated.
- *
- * Since: 2.8
- **/
-void
-pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-  if (tree_column->tree_view)
-    _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-/**
- * pspp_sheet_view_column_get_tree_view:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns the #PsppSheetView wherein @tree_column has been inserted.  If
- * @column is currently not inserted in any tree view, %NULL is
- * returned.
- *
- * Return value: The tree view wherein @column has been inserted if any,
- *               %NULL otherwise.
- *
- * Since: 2.12
- */
-GtkWidget *
-pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
-  return tree_column->tree_view;
-}
-
-typedef struct {
-  GtkCellLayout   *cell_layout;
-  GtkCellRenderer *renderer;
-  gchar           *attr_name;
-} AttributesSubParserData;
-
-static void
-attributes_start_element (GMarkupParseContext *context,
-                          const gchar         *element_name,
-                          const gchar        **names,
-                          const gchar        **values,
-                          gpointer             user_data,
-                          GError             **error)
-{
-  AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
-  guint i;
-
-  if (strcmp (element_name, "attribute") == 0)
-    {
-      for (i = 0; names[i]; i++)
-        if (strcmp (names[i], "name") == 0)
-          parser_data->attr_name = g_strdup (values[i]);
-    }
-  else if (strcmp (element_name, "attributes") == 0)
-    return;
-  else
-    g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
-}
-
-static void
-attributes_text_element (GMarkupParseContext *context,
-                         const gchar         *text,
-                         gsize                text_len,
-                         gpointer             user_data,
-                         GError             **error)
-{
-  AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
-  glong l;
-  gchar *endptr;
-  gchar *string;
-
-  if (!parser_data->attr_name)
-    return;
-
-  errno = 0;
-  string = g_strndup (text, text_len);
-  l = strtol (string, &endptr, 0);
-  if (errno || endptr == string)
-    {
-      g_set_error (error,
-                   GTK_BUILDER_ERROR,
-                   GTK_BUILDER_ERROR_INVALID_VALUE,
-                   "Could not parse integer `%s'",
-                   string);
-      g_free (string);
-      return;
-    }
-  g_free (string);
-
-  gtk_cell_layout_add_attribute (parser_data->cell_layout,
-                                 parser_data->renderer,
-                                 parser_data->attr_name, l);
-  g_free (parser_data->attr_name);
-  parser_data->attr_name = NULL;
-}
-
-static const GMarkupParser attributes_parser =
-  {
-    attributes_start_element,
-    NULL,
-    attributes_text_element,
-  };
-
-static gboolean
-_cell_layout_buildable_custom_tag_start (GtkBuildable  *buildable,
-                                             GtkBuilder    *builder,
-                                             GObject       *child,
-                                             const gchar   *tagname,
-                                             GMarkupParser *parser,
-                                             gpointer      *data)
-{
-  AttributesSubParserData *parser_data;
-
-  if (!child)
-    return FALSE;
-
-  if (strcmp (tagname, "attributes") == 0)
-    {
-      parser_data = g_slice_new0 (AttributesSubParserData);
-      parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
-      parser_data->renderer = GTK_CELL_RENDERER (child);
-      parser_data->attr_name = NULL;
-
-      *parser = attributes_parser;
-      *data = parser_data;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
-                                           GtkBuilder   *builder,
-                                           GObject      *child,
-                                           const gchar  *tagname,
-                                           gpointer     *data)
-{
-  AttributesSubParserData *parser_data;
-
-  parser_data = (AttributesSubParserData*)data;
-  g_assert (!parser_data->attr_name);
-  g_slice_free (AttributesSubParserData, parser_data);
-}
-
-static void
-_cell_layout_buildable_add_child (GtkBuildable      *buildable,
-                                      GtkBuilder        *builder,
-                                      GObject           *child,
-                                      const gchar       *type)
-{
-  GtkCellLayoutIface *iface;
-
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (child));
-
-  iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
-  g_return_if_fail (iface->pack_start != NULL);
-  iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
-}
-
-void
-pspp_sheet_view_column_size_request (PsppSheetViewColumn       *tree_column,
-                                     GtkRequisition            *request)
-{
-  GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
-  GtkRequisition label_req;
-  GtkRequisition align_req;
-  GtkRequisition arrow_req;
-  GtkRequisition hbox_req;
-  GtkStyle **button_style;
-
-  if (tree_column->button)
-    {
-      gtk_widget_get_preferred_size (tree_column->button, NULL, request);
-      return;
-    }
-
-  facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
-  facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
-  facade_arrow_get_size_request (0, 0, &arrow_req);
-
-  facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
-  facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
-  facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
-
-  button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
-  if (*button_style == NULL)
-    {
-      *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
-      g_object_ref (*button_style);
-    }
-  facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
-}
-
-void
-pspp_sheet_view_column_size_allocate (PsppSheetViewColumn       *tree_column,
-                                      GtkAllocation             *allocation)
-{
-  tree_column->allocation = *allocation;
-  if (tree_column->button)
-    gtk_widget_size_allocate (tree_column->button, allocation);
-}
-
-gboolean
-pspp_sheet_view_column_can_focus (PsppSheetViewColumn       *tree_column)
-{
-  return tree_column->reorderable || tree_column->clickable;
-}
diff --git a/src/ui/gui/pspp-sheet-view-column.h b/src/ui/gui/pspp-sheet-view-column.h
deleted file mode 100644 (file)
index 65eede2..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeviewcolumn.h
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __PSPP_SHEET_VIEW_COLUMN_H__
-#define __PSPP_SHEET_VIEW_COLUMN_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPP_TYPE_SHEET_VIEW_COLUMN         (pspp_sheet_view_column_get_type ())
-#define PSPP_SHEET_VIEW_COLUMN(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumn))
-#define PSPP_SHEET_VIEW_COLUMN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumnClass))
-#define PSPP_IS_SHEET_VIEW_COLUMN(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN))
-#define PSPP_IS_SHEET_VIEW_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_VIEW_COLUMN))
-#define PSPP_SHEET_VIEW_COLUMN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumnClass))
-
-typedef struct _PsppSheetViewColumn      PsppSheetViewColumn;
-typedef struct _PsppSheetViewColumnClass PsppSheetViewColumnClass;
-
-typedef void (* PsppSheetCellDataFunc) (PsppSheetViewColumn *tree_column,
-                                        GtkCellRenderer   *cell,
-                                        GtkTreeModel      *tree_model,
-                                        GtkTreeIter       *iter,
-                                        gpointer           data);
-
-
-struct _PsppSheetViewColumn
-{
-  GObject parent;
-
-  GtkWidget *PSEAL (tree_view);
-  GtkWidget *PSEAL (button);
-  GtkWidget *PSEAL (child);
-  GtkWidget *PSEAL (bin);
-  GdkWindow *PSEAL (window);
-  GtkCellEditable *PSEAL (editable_widget);
-  GtkAlign PSEAL (halign);
-  guint PSEAL (property_changed_signal);
-  gint PSEAL (spacing);
-  GtkAllocation PSEAL (allocation);
-
-  /* Sizing fields */
-  /* see gtk+/doc/tree-column-sizing.txt for more information on them */
-  gint PSEAL (requested_width);
-  gint PSEAL (button_request);
-  gint PSEAL (resized_width);
-  gint PSEAL (width);
-  gint PSEAL (fixed_width);
-  gint PSEAL (min_width);
-  gint PSEAL (max_width);
-
-  /* dragging columns */
-  gint PSEAL (drag_x);
-  gint PSEAL (drag_y);
-
-  gchar *PSEAL (title);
-  GList *PSEAL (cell_list);
-
-  /* Sorting */
-  guint PSEAL (sort_clicked_signal);
-  guint PSEAL (sort_column_changed_signal);
-  gint PSEAL (sort_column_id);
-  GtkSortType PSEAL (sort_order);
-
-  /* Flags */
-  guint PSEAL (visible)             : 1;
-  guint PSEAL (resizable)           : 1;
-  guint PSEAL (clickable)           : 1;
-  guint PSEAL (dirty)               : 1;
-  guint PSEAL (show_sort_indicator) : 1;
-  guint PSEAL (maybe_reordered)     : 1;
-  guint PSEAL (reorderable)         : 1;
-  guint PSEAL (use_resized_width)   : 1;
-  guint PSEAL (expand)              : 1;
-  guint PSEAL (quick_edit)          : 1;
-  guint PSEAL (selected)            : 1;
-  guint PSEAL (selectable)          : 1;
-  guint PSEAL (row_head)            : 1;
-  guint PSEAL (tabbable)            : 1;
-};
-
-struct _PsppSheetViewColumnClass
-{
-  GObjectClass parent_class;
-
-  gboolean (*clicked) (PsppSheetViewColumn *tree_column);
-  gboolean (*button_press_event) (PsppSheetViewColumn *,
-                                  GdkEventButton *);
-
-  /* Padding for future expansion */
-  void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
-};
-
-GType                   pspp_sheet_view_column_get_type            (void) G_GNUC_CONST;
-PsppSheetViewColumn      *pspp_sheet_view_column_new                 (void);
-PsppSheetViewColumn      *pspp_sheet_view_column_new_with_attributes (const gchar             *title,
-                                                                 GtkCellRenderer         *cell,
-                                                                 ...) G_GNUC_NULL_TERMINATED;
-void                    pspp_sheet_view_column_pack_start          (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell,
-                                                                 gboolean                 expand);
-void                    pspp_sheet_view_column_pack_end            (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell,
-                                                                 gboolean                 expand);
-void                    pspp_sheet_view_column_clear               (PsppSheetViewColumn       *tree_column);
-
-GList                  *pspp_sheet_view_column_get_cell_renderers  (PsppSheetViewColumn       *tree_column);
-
-void                    pspp_sheet_view_column_add_attribute       (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell_renderer,
-                                                                 const gchar             *attribute,
-                                                                 gint                     column);
-void                    pspp_sheet_view_column_set_attributes      (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell_renderer,
-                                                                 ...) G_GNUC_NULL_TERMINATED;
-void                    pspp_sheet_view_column_set_cell_data_func  (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell_renderer,
-                                                                 PsppSheetCellDataFunc      func,
-                                                                 gpointer                 func_data,
-                                                                 GDestroyNotify           destroy);
-void                    pspp_sheet_view_column_clear_attributes    (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell_renderer);
-void                    pspp_sheet_view_column_set_spacing         (PsppSheetViewColumn       *tree_column,
-                                                                 gint                     spacing);
-gint                    pspp_sheet_view_column_get_spacing         (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_visible         (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 visible);
-gboolean                pspp_sheet_view_column_get_visible         (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_resizable       (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 resizable);
-gboolean                pspp_sheet_view_column_get_resizable       (PsppSheetViewColumn       *tree_column);
-gint                    pspp_sheet_view_column_get_width           (PsppSheetViewColumn       *tree_column);
-gint                    pspp_sheet_view_column_get_fixed_width     (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_fixed_width     (PsppSheetViewColumn       *tree_column,
-                                                                 gint                     fixed_width);
-void                    pspp_sheet_view_column_set_min_width       (PsppSheetViewColumn       *tree_column,
-                                                                 gint                     min_width);
-gint                    pspp_sheet_view_column_get_min_width       (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_max_width       (PsppSheetViewColumn       *tree_column,
-                                                                 gint                     max_width);
-gint                    pspp_sheet_view_column_get_max_width       (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_clicked             (PsppSheetViewColumn       *tree_column);
-
-
-
-/* Options for manipulating the column headers
- */
-void                    pspp_sheet_view_column_set_title           (PsppSheetViewColumn       *tree_column,
-                                                                 const gchar             *title);
-const gchar   *         pspp_sheet_view_column_get_title           (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_expand          (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 expand);
-gboolean                pspp_sheet_view_column_get_expand          (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_clickable       (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 clickable);
-gboolean                pspp_sheet_view_column_get_clickable       (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_widget          (PsppSheetViewColumn       *tree_column,
-                                                                 GtkWidget               *widget);
-GtkWidget              *pspp_sheet_view_column_get_widget          (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_alignment       (PsppSheetViewColumn       *tree_columna,
-                                                                 GtkAlign                   xalign);
-GtkAlign                  pspp_sheet_view_column_get_alignment       (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_reorderable     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 reorderable);
-gboolean                pspp_sheet_view_column_get_reorderable     (PsppSheetViewColumn       *tree_column);
-
-void                    pspp_sheet_view_column_set_quick_edit     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 quick_edit);
-gboolean                pspp_sheet_view_column_get_quick_edit     (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_selected     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 selected);
-gboolean                pspp_sheet_view_column_get_selected     (PsppSheetViewColumn       *tree_column);
-
-void                    pspp_sheet_view_column_set_selectable     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 selectable);
-gboolean                pspp_sheet_view_column_get_selectable     (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_row_head     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 row_head);
-gboolean                pspp_sheet_view_column_get_row_head     (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_tabbable     (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 tabbable);
-gboolean                pspp_sheet_view_column_get_tabbable     (PsppSheetViewColumn       *tree_column);
-
-
-
-/* You probably only want to use pspp_sheet_view_column_set_sort_column_id.  The
- * other sorting functions exist primarily to let others do their own custom sorting.
- */
-void                    pspp_sheet_view_column_set_sort_column_id  (PsppSheetViewColumn       *tree_column,
-                                                                 gint                     sort_column_id);
-gint                    pspp_sheet_view_column_get_sort_column_id  (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_sort_indicator  (PsppSheetViewColumn       *tree_column,
-                                                                 gboolean                 setting);
-gboolean                pspp_sheet_view_column_get_sort_indicator  (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_set_sort_order      (PsppSheetViewColumn       *tree_column,
-                                                                 GtkSortType              order);
-GtkSortType             pspp_sheet_view_column_get_sort_order      (PsppSheetViewColumn       *tree_column);
-
-
-/* These functions are meant primarily for interaction between the PsppSheetView and the column.
- */
-void                    pspp_sheet_view_column_cell_set_cell_data  (PsppSheetViewColumn       *tree_column,
-                                                                 GtkTreeModel            *tree_model,
-                                                                 GtkTreeIter             *iter);
-void                    pspp_sheet_view_column_cell_get_size       (PsppSheetViewColumn       *tree_column,
-                                                                 const GdkRectangle      *cell_area,
-                                                                 gint                    *x_offset,
-                                                                 gint                    *y_offset,
-                                                                 gint                    *width,
-                                                                 gint                    *height);
-gboolean                pspp_sheet_view_column_cell_is_visible     (PsppSheetViewColumn       *tree_column);
-void                    pspp_sheet_view_column_focus_cell          (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell);
-gboolean                pspp_sheet_view_column_cell_get_position   (PsppSheetViewColumn       *tree_column,
-                                                                 GtkCellRenderer         *cell_renderer,
-                                                                 gint                    *start_pos,
-                                                                 gint                    *width);
-void                    pspp_sheet_view_column_queue_resize        (PsppSheetViewColumn       *tree_column);
-GtkWidget              *pspp_sheet_view_column_get_tree_view       (PsppSheetViewColumn       *tree_column);
-
-void                    pspp_sheet_view_column_size_request       (PsppSheetViewColumn       *tree_column,
-                                                                    GtkRequisition             *requisition);
-
-void                    pspp_sheet_view_column_size_allocate       (PsppSheetViewColumn       *tree_column,
-                                                                    GtkAllocation             *allocation);
-gboolean                pspp_sheet_view_column_can_focus           (PsppSheetViewColumn       *tree_column);
-
-G_END_DECLS
-
-
-#endif /* __PSPP_SHEET_VIEW_COLUMN_H__ */
diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c
deleted file mode 100644 (file)
index e06ed49..0000000
+++ /dev/null
@@ -1,12532 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2013, 2015 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeview.c
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "ui/gui/pspp-sheet-private.h"
-
-#include <gtk/gtk.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkkeysyms-compat.h>
-#include <string.h>
-
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/pspp-sheet-selection.h"
-
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-
-#define P_(STRING) STRING
-#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-
-/* Many keyboard shortcuts for Mac are the same as for X
- * except they use Command key instead of Control (e.g. Cut,
- * Copy, Paste). This symbol is for those simple cases. */
-#ifndef GDK_WINDOWING_QUARTZ
-#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_CONTROL_MASK
-#else
-#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_META_MASK
-#endif
-
-#define PSPP_SHEET_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
-#define PSPP_SHEET_VIEW_PRIORITY_SCROLL_SYNC (PSPP_SHEET_VIEW_PRIORITY_VALIDATE + 2)
-#define PSPP_SHEET_VIEW_TIME_MS_PER_IDLE 30
-#define SCROLL_EDGE_SIZE 15
-#define EXPANDER_EXTRA_PADDING 4
-#define PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT 5000
-
-/* The "background" areas of all rows/cells add up to cover the entire tree.
- * The background includes all inter-row and inter-cell spacing.
- * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
- * i.e. just the cells, no spacing.
- */
-
-#define BACKGROUND_HEIGHT(tree_view) (tree_view->priv->fixed_height)
-#define CELL_HEIGHT(tree_view, separator) ((BACKGROUND_HEIGHT (tree_view)) - (separator))
-
-/* Translate from bin_window coordinates to rbtree (tree coordinates) and
- * vice versa.
- */
-#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
-#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
-
-/* This is in bin_window coordinates */
-#define BACKGROUND_FIRST_PIXEL(tree_view,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, pspp_sheet_view_node_find_offset (tree_view, (node))))
-#define CELL_FIRST_PIXEL(tree_view,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,node) + separator/2)
-
-#define ROW_HEIGHT(tree_view) \
-  ((tree_view->priv->fixed_height > 0) ? (tree_view->priv->fixed_height) : (tree_view)->priv->expander_size)
-
-
-typedef struct _PsppSheetViewChild PsppSheetViewChild;
-struct _PsppSheetViewChild
-{
-  GtkWidget *widget;
-  PsppSheetViewColumn *column;
-  int node;
-};
-
-
-typedef struct _TreeViewDragInfo TreeViewDragInfo;
-struct _TreeViewDragInfo
-{
-  GdkModifierType start_button_mask;
-  GtkTargetList *_unused_source_target_list;
-  GdkDragAction source_actions;
-
-  GtkTargetList *_unused_dest_target_list;
-
-  guint source_set : 1;
-  guint dest_set : 1;
-};
-
-
-/* Signals */
-enum
-{
-  ROW_ACTIVATED,
-  COLUMNS_CHANGED,
-  CURSOR_CHANGED,
-  MOVE_CURSOR,
-  SELECT_ALL,
-  UNSELECT_ALL,
-  SELECT_CURSOR_ROW,
-  TOGGLE_CURSOR_ROW,
-  START_INTERACTIVE_SEARCH,
-  LAST_SIGNAL
-};
-
-/* Properties */
-enum {
-  PROP_0,
-  PROP_MODEL,
-  PROP_HADJUSTMENT,
-  PROP_VADJUSTMENT,
-  PROP_HSCROLL_POLICY,
-  PROP_VSCROLL_POLICY,
-  PROP_HEADERS_VISIBLE,
-  PROP_HEADERS_CLICKABLE,
-  PROP_REORDERABLE,
-  PROP_RULES_HINT,
-  PROP_ENABLE_SEARCH,
-  PROP_SEARCH_COLUMN,
-  PROP_HOVER_SELECTION,
-  PROP_RUBBER_BANDING,
-  PROP_ENABLE_GRID_LINES,
-  PROP_TOOLTIP_COLUMN,
-  PROP_SPECIAL_CELLS,
-  PROP_FIXED_HEIGHT,
-  PROP_FIXED_HEIGHT_SET
-};
-
-/* object signals */
-static void     pspp_sheet_view_finalize             (GObject          *object);
-static void     pspp_sheet_view_set_property         (GObject         *object,
-                                                   guint            prop_id,
-                                                   const GValue    *value,
-                                                   GParamSpec      *pspec);
-static void     pspp_sheet_view_get_property         (GObject         *object,
-                                                   guint            prop_id,
-                                                   GValue          *value,
-                                                   GParamSpec      *pspec);
-
-static void     pspp_sheet_view_dispose              (GObject        *object);
-
-/* gtkwidget signals */
-static void     pspp_sheet_view_realize              (GtkWidget        *widget);
-static void     pspp_sheet_view_unrealize            (GtkWidget        *widget);
-static void     pspp_sheet_view_map                  (GtkWidget        *widget);
-static void     pspp_sheet_view_size_request         (GtkWidget        *widget,
-                                                   GtkRequisition   *requisition);
-static void     pspp_sheet_view_size_allocate        (GtkWidget        *widget,
-                                                   GtkAllocation    *allocation);
-static gboolean pspp_sheet_view_draw               (GtkWidget        *widget,
-                                                   cairo_t *cr);
-static gboolean pspp_sheet_view_key_press            (GtkWidget        *widget,
-                                                   GdkEventKey      *event);
-static gboolean pspp_sheet_view_key_release          (GtkWidget        *widget,
-                                                   GdkEventKey      *event);
-static gboolean pspp_sheet_view_motion               (GtkWidget        *widget,
-                                                   GdkEventMotion   *event);
-static gboolean pspp_sheet_view_enter_notify         (GtkWidget        *widget,
-                                                   GdkEventCrossing *event);
-static gboolean pspp_sheet_view_leave_notify         (GtkWidget        *widget,
-                                                   GdkEventCrossing *event);
-static gboolean pspp_sheet_view_button_press         (GtkWidget        *widget,
-                                                   GdkEventButton   *event);
-static gboolean pspp_sheet_view_button_release       (GtkWidget        *widget,
-                                                   GdkEventButton   *event);
-static gboolean pspp_sheet_view_grab_broken          (GtkWidget          *widget,
-                                                   GdkEventGrabBroken *event);
-
-static void     pspp_sheet_view_set_focus_child      (GtkContainer     *container,
-                                                   GtkWidget        *child);
-static gint     pspp_sheet_view_focus_out            (GtkWidget        *widget,
-                                                   GdkEventFocus    *event);
-static gint     pspp_sheet_view_focus                (GtkWidget        *widget,
-                                                   GtkDirectionType  direction);
-static void     pspp_sheet_view_grab_focus           (GtkWidget        *widget);
-static void     pspp_sheet_view_style_updated        (GtkWidget        *widget);
-static void     pspp_sheet_view_grab_notify          (GtkWidget        *widget,
-                                                   gboolean          was_grabbed);
-static void     pspp_sheet_view_state_changed        (GtkWidget        *widget,
-                                                   GtkStateType      previous_state);
-
-/* container signals */
-static void     pspp_sheet_view_remove               (GtkContainer     *container,
-                                                   GtkWidget        *widget);
-static void     pspp_sheet_view_forall               (GtkContainer     *container,
-                                                   gboolean          include_internals,
-                                                   GtkCallback       callback,
-                                                   gpointer          callback_data);
-
-/* Source side drag signals */
-static void pspp_sheet_view_drag_begin       (GtkWidget        *widget,
-                                            GdkDragContext   *context);
-static void pspp_sheet_view_drag_end         (GtkWidget        *widget,
-                                            GdkDragContext   *context);
-static void pspp_sheet_view_drag_data_get    (GtkWidget        *widget,
-                                            GdkDragContext   *context,
-                                            GtkSelectionData *selection_data,
-                                            guint             info,
-                                            guint             time);
-static void pspp_sheet_view_drag_data_delete (GtkWidget        *widget,
-                                            GdkDragContext   *context);
-
-/* Target side drag signals */
-static void     pspp_sheet_view_drag_leave         (GtkWidget        *widget,
-                                                  GdkDragContext   *context,
-                                                  guint             time);
-static gboolean pspp_sheet_view_drag_motion        (GtkWidget        *widget,
-                                                  GdkDragContext   *context,
-                                                  gint              x,
-                                                  gint              y,
-                                                  guint             time);
-static gboolean pspp_sheet_view_drag_drop          (GtkWidget        *widget,
-                                                  GdkDragContext   *context,
-                                                  gint              x,
-                                                  gint              y,
-                                                  guint             time);
-static void     pspp_sheet_view_drag_data_received (GtkWidget        *widget,
-                                                  GdkDragContext   *context,
-                                                  gint              x,
-                                                  gint              y,
-                                                  GtkSelectionData *selection_data,
-                                                  guint             info,
-                                                  guint             time);
-
-/* tree_model signals */
-static void pspp_sheet_view_set_adjustments                 (PsppSheetView     *tree_view,
-                                                          GtkAdjustment   *hadj,
-                                                          GtkAdjustment   *vadj);
-static gboolean pspp_sheet_view_real_move_cursor            (PsppSheetView     *tree_view,
-                                                          GtkMovementStep  step,
-                                                          gint             count);
-static gboolean pspp_sheet_view_real_select_all             (PsppSheetView     *tree_view);
-static gboolean pspp_sheet_view_real_unselect_all           (PsppSheetView     *tree_view);
-static gboolean pspp_sheet_view_real_select_cursor_row      (PsppSheetView     *tree_view,
-                                                             gboolean         start_editing,
-                                                             PsppSheetSelectMode mode);
-static gboolean pspp_sheet_view_real_toggle_cursor_row      (PsppSheetView     *tree_view);
-static void pspp_sheet_view_row_changed                     (GtkTreeModel    *model,
-                                                          GtkTreePath     *path,
-                                                          GtkTreeIter     *iter,
-                                                          gpointer         data);
-static void pspp_sheet_view_row_inserted                    (GtkTreeModel    *model,
-                                                          GtkTreePath     *path,
-                                                          GtkTreeIter     *iter,
-                                                          gpointer         data);
-static void pspp_sheet_view_row_deleted                     (GtkTreeModel    *model,
-                                                          GtkTreePath     *path,
-                                                          gpointer         data);
-static void pspp_sheet_view_rows_reordered                  (GtkTreeModel    *model,
-                                                          GtkTreePath     *parent,
-                                                          GtkTreeIter     *iter,
-                                                          gint            *new_order,
-                                                          gpointer         data);
-
-/* Incremental reflow */
-static gint validate_row             (PsppSheetView *tree_view,
-                                         int node,
-                                         GtkTreeIter *iter,
-                                         GtkTreePath *path);
-static void     validate_visible_area    (PsppSheetView *tree_view);
-static gboolean validate_rows_handler    (PsppSheetView *tree_view);
-static gboolean presize_handler_callback (gpointer     data);
-static void     install_presize_handler  (PsppSheetView *tree_view);
-static void     install_scroll_sync_handler (PsppSheetView *tree_view);
-static void     pspp_sheet_view_set_top_row   (PsppSheetView *tree_view,
-                                            GtkTreePath *path,
-                                            gint         offset);
-static void    pspp_sheet_view_dy_to_top_row (PsppSheetView *tree_view);
-static void     pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view);
-static void     invalidate_empty_focus      (PsppSheetView *tree_view);
-
-/* Internal functions */
-static GtkAdjustment *pspp_sheet_view_do_get_hadjustment (PsppSheetView *);
-static GtkAdjustment *pspp_sheet_view_do_get_vadjustment (PsppSheetView *);
-static void pspp_sheet_view_do_set_hadjustment (PsppSheetView   *tree_view,
-                                              GtkAdjustment *adjustment);
-static void pspp_sheet_view_do_set_vadjustment (PsppSheetView   *tree_view,
-                                              GtkAdjustment *adjustment);
-static void     pspp_sheet_view_add_move_binding               (GtkBindingSet      *binding_set,
-                                                             guint               keyval,
-                                                             guint               modmask,
-                                                             gboolean            add_shifted_binding,
-                                                             GtkMovementStep     step,
-                                                             gint                count);
-static void     pspp_sheet_view_queue_draw_path                (PsppSheetView        *tree_view,
-                                                             GtkTreePath        *path,
-                                                             const GdkRectangle *clip_rect);
-static gint     pspp_sheet_view_new_column_width               (PsppSheetView        *tree_view,
-                                                             gint                i,
-                                                             gint               *x);
-static void     pspp_sheet_view_adjustment_changed             (GtkAdjustment      *adjustment,
-                                                             PsppSheetView        *tree_view);
-static void     pspp_sheet_view_clamp_node_visible             (PsppSheetView        *tree_view,
-                                                             int node);
-static void     pspp_sheet_view_clamp_column_visible           (PsppSheetView        *tree_view,
-                                                             PsppSheetViewColumn  *column,
-                                                             gboolean            focus_to_cell);
-static gboolean pspp_sheet_view_maybe_begin_dragging_row       (PsppSheetView        *tree_view,
-                                                             GdkEventMotion     *event);
-static void     pspp_sheet_view_focus_to_cursor                (PsppSheetView        *tree_view);
-static gboolean pspp_sheet_view_move_cursor_up_down            (PsppSheetView        *tree_view,
-                                                             gint                count,
-                                                                PsppSheetSelectMode mode);
-static void     pspp_sheet_view_move_cursor_page_up_down       (PsppSheetView        *tree_view,
-                                                             gint                count,
-                                                                PsppSheetSelectMode mode);
-static void     pspp_sheet_view_move_cursor_left_right         (PsppSheetView        *tree_view,
-                                                                gint                count,
-                                                                PsppSheetSelectMode mode);
-static void     pspp_sheet_view_move_cursor_line_start_end     (PsppSheetView        *tree_view,
-                                                               gint                count,
-                                                                PsppSheetSelectMode mode);
-static void     pspp_sheet_view_move_cursor_tab                (PsppSheetView        *tree_view,
-                                                             gint                count);
-static void     pspp_sheet_view_move_cursor_start_end          (PsppSheetView        *tree_view,
-                                                             gint                count,
-                                                                PsppSheetSelectMode mode);
-static void     pspp_sheet_view_real_set_cursor                (PsppSheetView        *tree_view,
-                                                             GtkTreePath        *path,
-                                                             gboolean            clear_and_select,
-                                                              gboolean            clamp_node,
-                                                              PsppSheetSelectMode mode);
-static gboolean pspp_sheet_view_has_special_cell               (PsppSheetView        *tree_view);
-static void     pspp_sheet_view_stop_rubber_band               (PsppSheetView        *tree_view);
-static void     update_prelight                              (PsppSheetView        *tree_view,
-                                                              int                 x,
-                                                              int                 y);
-static void initialize_fixed_height_mode (PsppSheetView *tree_view);
-
-/* interactive search */
-static void     pspp_sheet_view_ensure_interactive_directory (PsppSheetView *tree_view);
-static void     pspp_sheet_view_search_dialog_hide     (GtkWidget        *search_dialog,
-                                                        PsppSheetView      *tree_view);
-static void     pspp_sheet_view_search_position_func      (PsppSheetView      *tree_view,
-                                                        GtkWidget        *search_dialog,
-                                                        gpointer          user_data);
-static void     pspp_sheet_view_search_disable_popdown    (GtkEntry         *entry,
-                                                        GtkMenu          *menu,
-                                                        gpointer          data);
-static void     pspp_sheet_view_search_activate           (GtkEntry         *entry,
-                                                        PsppSheetView      *tree_view);
-static gboolean pspp_sheet_view_real_search_enable_popdown(gpointer          data);
-static void     pspp_sheet_view_search_enable_popdown     (GtkWidget        *widget,
-                                                        gpointer          data);
-static gboolean pspp_sheet_view_search_delete_event       (GtkWidget        *widget,
-                                                        GdkEventAny      *event,
-                                                        PsppSheetView      *tree_view);
-static gboolean pspp_sheet_view_search_button_press_event (GtkWidget        *widget,
-                                                        GdkEventButton   *event,
-                                                        PsppSheetView      *tree_view);
-static gboolean pspp_sheet_view_search_scroll_event       (GtkWidget        *entry,
-                                                        GdkEventScroll   *event,
-                                                        PsppSheetView      *tree_view);
-static gboolean pspp_sheet_view_search_key_press_event    (GtkWidget        *entry,
-                                                        GdkEventKey      *event,
-                                                        PsppSheetView      *tree_view);
-static gboolean pspp_sheet_view_search_move               (GtkWidget        *window,
-                                                        PsppSheetView      *tree_view,
-                                                        gboolean          up);
-static gboolean pspp_sheet_view_search_equal_func         (GtkTreeModel     *model,
-                                                        gint              column,
-                                                        const gchar      *key,
-                                                        GtkTreeIter      *iter,
-                                                        gpointer          search_data);
-static gboolean pspp_sheet_view_search_iter               (GtkTreeModel     *model,
-                                                        PsppSheetSelection *selection,
-                                                        GtkTreeIter      *iter,
-                                                        const gchar      *text,
-                                                        gint             *count,
-                                                        gint              n);
-static void     pspp_sheet_view_search_init               (GtkWidget        *entry,
-                                                        PsppSheetView      *tree_view);
-static void     pspp_sheet_view_put                       (PsppSheetView      *tree_view,
-                                                        GtkWidget        *child_widget,
-                                                        GtkTreePath *path,
-                                                        PsppSheetViewColumn *column);
-static gboolean pspp_sheet_view_start_editing             (PsppSheetView      *tree_view,
-                                                        GtkTreePath      *cursor_path);
-static gboolean pspp_sheet_view_editable_button_press_event (GtkWidget *,
-                                                             GdkEventButton *,
-                                                             PsppSheetView *);
-static void pspp_sheet_view_editable_clicked (GtkButton *, PsppSheetView *);
-static void pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
-                                             PsppSheetViewColumn *column,
-                                             GtkTreePath       *path,
-                                             GtkCellEditable   *cell_editable,
-                                             GdkRectangle      *cell_area,
-                                             GdkEvent          *event,
-                                             guint              flags);
-static gboolean pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view,
-                                                            gboolean     keybinding);
-static gboolean pspp_sheet_view_start_interactive_search      (PsppSheetView *tree_view);
-static PsppSheetViewColumn *pspp_sheet_view_get_drop_column (PsppSheetView       *tree_view,
-                                                        PsppSheetViewColumn *column,
-                                                        gint               drop_position);
-static void
-pspp_sheet_view_adjust_cell_area (PsppSheetView        *tree_view,
-                                  PsppSheetViewColumn  *column,
-                                  const GdkRectangle   *background_area,
-                                  gboolean              subtract_focus_rect,
-                                  GdkRectangle         *cell_area);
-static gint pspp_sheet_view_find_offset (PsppSheetView *tree_view,
-                                         gint height,
-                                         int *new_node);
-
-/* GtkBuildable */
-static void pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view,
-                                              GtkBuilder  *builder,
-                                              GObject     *child,
-                                              const gchar *type);
-static void pspp_sheet_view_buildable_init      (GtkBuildableIface *iface);
-
-
-static gboolean scroll_row_timeout                   (gpointer     data);
-static void     add_scroll_timeout                   (PsppSheetView *tree_view);
-static void     remove_scroll_timeout                (PsppSheetView *tree_view);
-
-static guint tree_view_signals [LAST_SIGNAL] = { 0 };
-
-static GtkBindingSet *edit_bindings;
-
-\f
-
-/* GType Methods
- */
-
-G_DEFINE_TYPE_WITH_CODE (PsppSheetView, pspp_sheet_view, GTK_TYPE_CONTAINER,
-                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
-                                               pspp_sheet_view_buildable_init)
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
-
-static void
-pspp_sheet_view_get_preferred_width (GtkWidget *widget,
-                               gint      *minimal_width,
-                               gint      *natural_width)
-{
-  GtkRequisition requisition;
-
-  pspp_sheet_view_size_request (widget, &requisition);
-
-  *minimal_width = *natural_width = requisition.width;
-}
-
-static void
-pspp_sheet_view_get_preferred_height (GtkWidget *widget,
-                                gint      *minimal_height,
-                                gint      *natural_height)
-{
-  GtkRequisition requisition;
-
-  pspp_sheet_view_size_request (widget, &requisition);
-
-  *minimal_height = *natural_height = requisition.height;
-}
-
-static void
-pspp_sheet_view_class_init (PsppSheetViewClass *class)
-{
-  GObjectClass *o_class;
-  GtkWidgetClass *widget_class;
-  GtkContainerClass *container_class;
-  GtkBindingSet *binding_set[2];
-  int i;
-
-  binding_set[0] = gtk_binding_set_by_class (class);
-
-  binding_set[1] = gtk_binding_set_new ("PsppSheetViewEditing");
-  edit_bindings = binding_set[1];
-
-  o_class = (GObjectClass *) class;
-  widget_class = (GtkWidgetClass *) class;
-  container_class = (GtkContainerClass *) class;
-
-  /* GObject signals */
-  o_class->set_property = pspp_sheet_view_set_property;
-  o_class->get_property = pspp_sheet_view_get_property;
-  o_class->finalize = pspp_sheet_view_finalize;
-  o_class->dispose = pspp_sheet_view_dispose;
-
-  /* GtkWidget signals */
-  widget_class->map = pspp_sheet_view_map;
-  widget_class->realize = pspp_sheet_view_realize;
-  widget_class->unrealize = pspp_sheet_view_unrealize;
-  widget_class->get_preferred_width = pspp_sheet_view_get_preferred_width;
-  widget_class->get_preferred_height = pspp_sheet_view_get_preferred_height;
-  widget_class->size_allocate = pspp_sheet_view_size_allocate;
-  widget_class->button_press_event = pspp_sheet_view_button_press;
-  widget_class->button_release_event = pspp_sheet_view_button_release;
-  widget_class->grab_broken_event = pspp_sheet_view_grab_broken;
-  /*widget_class->configure_event = pspp_sheet_view_configure;*/
-  widget_class->motion_notify_event = pspp_sheet_view_motion;
-  widget_class->draw = pspp_sheet_view_draw;
-  widget_class->key_press_event = pspp_sheet_view_key_press;
-  widget_class->key_release_event = pspp_sheet_view_key_release;
-  widget_class->enter_notify_event = pspp_sheet_view_enter_notify;
-  widget_class->leave_notify_event = pspp_sheet_view_leave_notify;
-  widget_class->focus_out_event = pspp_sheet_view_focus_out;
-  widget_class->drag_begin = pspp_sheet_view_drag_begin;
-  widget_class->drag_end = pspp_sheet_view_drag_end;
-  widget_class->drag_data_get = pspp_sheet_view_drag_data_get;
-  widget_class->drag_data_delete = pspp_sheet_view_drag_data_delete;
-  widget_class->drag_leave = pspp_sheet_view_drag_leave;
-  widget_class->drag_motion = pspp_sheet_view_drag_motion;
-  widget_class->drag_drop = pspp_sheet_view_drag_drop;
-  widget_class->drag_data_received = pspp_sheet_view_drag_data_received;
-  widget_class->focus = pspp_sheet_view_focus;
-  widget_class->grab_focus = pspp_sheet_view_grab_focus;
-  widget_class->style_updated = pspp_sheet_view_style_updated;
-  widget_class->grab_notify = pspp_sheet_view_grab_notify;
-  widget_class->state_changed = pspp_sheet_view_state_changed;
-
-  /* GtkContainer signals */
-  container_class->remove = pspp_sheet_view_remove;
-  container_class->forall = pspp_sheet_view_forall;
-  container_class->set_focus_child = pspp_sheet_view_set_focus_child;
-
-  class->set_scroll_adjustments = pspp_sheet_view_set_adjustments;
-  class->move_cursor = pspp_sheet_view_real_move_cursor;
-  class->select_all = pspp_sheet_view_real_select_all;
-  class->unselect_all = pspp_sheet_view_real_unselect_all;
-  class->select_cursor_row = pspp_sheet_view_real_select_cursor_row;
-  class->toggle_cursor_row = pspp_sheet_view_real_toggle_cursor_row;
-  class->start_interactive_search = pspp_sheet_view_start_interactive_search;
-
-  /* Properties */
-
-  g_object_class_install_property (o_class,
-                                   PROP_MODEL,
-                                   g_param_spec_object ("model",
-                                                       P_("TreeView Model"),
-                                                       P_("The model for the tree view"),
-                                                       GTK_TYPE_TREE_MODEL,
-                                                       GTK_PARAM_READWRITE));
-
-  g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
-  g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
-  g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
-  g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
-
-  g_object_class_install_property (o_class,
-                                   PROP_HEADERS_VISIBLE,
-                                   g_param_spec_boolean ("headers-visible",
-                                                        P_("Headers Visible"),
-                                                        P_("Show the column header buttons"),
-                                                        TRUE,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (o_class,
-                                   PROP_HEADERS_CLICKABLE,
-                                   g_param_spec_boolean ("headers-clickable",
-                                                        P_("Headers Clickable"),
-                                                        P_("Column headers respond to click events"),
-                                                        TRUE,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (o_class,
-                                   PROP_REORDERABLE,
-                                   g_param_spec_boolean ("reorderable",
-                                                        P_("Reorderable"),
-                                                        P_("View is reorderable"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (o_class,
-                                   PROP_RULES_HINT,
-                                   g_param_spec_boolean ("rules-hint",
-                                                        P_("Rules Hint"),
-                                                        P_("Set a hint to the theme engine to draw rows in alternating colors"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                    PROP_ENABLE_SEARCH,
-                                    g_param_spec_boolean ("enable-search",
-                                                          P_("Enable Search"),
-                                                          P_("View allows user to search through columns interactively"),
-                                                          TRUE,
-                                                          GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                    PROP_SEARCH_COLUMN,
-                                    g_param_spec_int ("search-column",
-                                                      P_("Search Column"),
-                                                      P_("Model column to search through during interactive search"),
-                                                      -1,
-                                                      G_MAXINT,
-                                                      -1,
-                                                      GTK_PARAM_READWRITE));
-
-    /**
-     * PsppSheetView:hover-selection:
-     *
-     * Enables of disables the hover selection mode of @tree_view.
-     * Hover selection makes the selected row follow the pointer.
-     * Currently, this works only for the selection modes
-     * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
-     *
-     * This mode is primarily intended for treeviews in popups, e.g.
-     * in #GtkComboBox or #GtkEntryCompletion.
-     *
-     * Since: 2.6
-     */
-    g_object_class_install_property (o_class,
-                                     PROP_HOVER_SELECTION,
-                                     g_param_spec_boolean ("hover-selection",
-                                                           P_("Hover Selection"),
-                                                           P_("Whether the selection should follow the pointer"),
-                                                           FALSE,
-                                                           GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                     PROP_RUBBER_BANDING,
-                                     g_param_spec_boolean ("rubber-banding",
-                                                           P_("Rubber Banding"),
-                                                           P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
-                                                           FALSE,
-                                                           GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                     PROP_ENABLE_GRID_LINES,
-                                     g_param_spec_enum ("enable-grid-lines",
-                                                       P_("Enable Grid Lines"),
-                                                       P_("Whether grid lines should be drawn in the tree view"),
-                                                       PSPP_TYPE_SHEET_VIEW_GRID_LINES,
-                                                       PSPP_SHEET_VIEW_GRID_LINES_NONE,
-                                                       GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                    PROP_TOOLTIP_COLUMN,
-                                    g_param_spec_int ("tooltip-column",
-                                                      P_("Tooltip Column"),
-                                                      P_("The column in the model containing the tooltip texts for the rows"),
-                                                      -1,
-                                                      G_MAXINT,
-                                                      -1,
-                                                      GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                     PROP_SPECIAL_CELLS,
-                                     g_param_spec_enum ("special-cells",
-                                                       P_("Special Cells"),
-                                                       P_("Whether rows have special cells."),
-                                                       PSPP_TYPE_SHEET_VIEW_SPECIAL_CELLS,
-                                                       PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT,
-                                                       GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                    PROP_FIXED_HEIGHT,
-                                    g_param_spec_int ("fixed-height",
-                                                      P_("Fixed Height"),
-                                                      P_("Height of a single row.  Normally the height of a row is determined automatically.  Writing this property sets fixed-height-set to true, preventing this property's value from changing."),
-                                                      -1,
-                                                      G_MAXINT,
-                                                      -1,
-                                                      GTK_PARAM_READWRITE));
-
-    g_object_class_install_property (o_class,
-                                     PROP_FIXED_HEIGHT_SET,
-                                     g_param_spec_boolean ("fixed-height-set",
-                                                           P_("Fixed Height Set"),
-                                                           P_("Whether fixed-height was set externally."),
-                                                           FALSE,
-                                                           GTK_PARAM_READWRITE));
-
-  /* Style properties */
-#define _TREE_VIEW_EXPANDER_SIZE 12
-#define _TREE_VIEW_VERTICAL_SEPARATOR 2
-#define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("expander-size",
-                                                            P_("Expander Size"),
-                                                            P_("Size of the expander arrow"),
-                                                            0,
-                                                            G_MAXINT,
-                                                            _TREE_VIEW_EXPANDER_SIZE,
-                                                            GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("vertical-separator",
-                                                            P_("Vertical Separator Width"),
-                                                            P_("Vertical space between cells.  Must be an even number"),
-                                                            0,
-                                                            G_MAXINT,
-                                                            _TREE_VIEW_VERTICAL_SEPARATOR,
-                                                            GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("horizontal-separator",
-                                                            P_("Horizontal Separator Width"),
-                                                            P_("Horizontal space between cells.  Must be an even number"),
-                                                            0,
-                                                            G_MAXINT,
-                                                            _TREE_VIEW_HORIZONTAL_SEPARATOR,
-                                                            GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_boolean ("allow-rules",
-                                                                P_("Allow Rules"),
-                                                                P_("Allow drawing of alternating color rows"),
-                                                                TRUE,
-                                                                GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                           g_param_spec_boxed ("even-row-color",
-                                                               P_("Even Row Color"),
-                                                               P_("Color to use for even rows"),
-                                                              GDK_TYPE_COLOR,
-                                                              GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                           g_param_spec_boxed ("odd-row-color",
-                                                               P_("Odd Row Color"),
-                                                               P_("Color to use for odd rows"),
-                                                              GDK_TYPE_COLOR,
-                                                              GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_boolean ("row-ending-details",
-                                                                P_("Row Ending details"),
-                                                                P_("Enable extended row background theming"),
-                                                                FALSE,
-                                                                GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("grid-line-width",
-                                                            P_("Grid line width"),
-                                                            P_("Width, in pixels, of the tree view grid lines"),
-                                                            0, G_MAXINT, 1,
-                                                            GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_int ("tree-line-width",
-                                                            P_("Tree line width"),
-                                                            P_("Width, in pixels, of the tree view lines"),
-                                                            0, G_MAXINT, 1,
-                                                            GTK_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                          g_param_spec_string ("tree-line-pattern",
-                                                               P_("Tree line pattern"),
-                                                               P_("Dash pattern used to draw the tree view lines"),
-                                                               "\1\1",
-                                                               GTK_PARAM_READABLE));
-
-  /* Signals */
-
-  /**
-   * PsppSheetView::row-activated:
-   * @tree_view: the object on which the signal is emitted
-   * @path: the #GtkTreePath for the activated row
-   * @column: the #PsppSheetViewColumn in which the activation occurred
-   *
-   * The "row-activated" signal is emitted when the method
-   * pspp_sheet_view_row_activated() is called or the user double clicks
-   * a treeview row. It is also emitted when a non-editable row is
-   * selected and one of the keys: Space, Shift+Space, Return or
-   * Enter is pressed.
-   *
-   * For selection handling refer to the <link linkend="TreeWidget">tree
-   * widget conceptual overview</link> as well as #PsppSheetSelection.
-   */
-  tree_view_signals[ROW_ACTIVATED] =
-    g_signal_new ("row-activated",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, row_activated),
-                 NULL, NULL,
-                  psppire_marshal_VOID__BOXED_OBJECT,
-                 G_TYPE_NONE, 2,
-                 GTK_TYPE_TREE_PATH,
-                 PSPP_TYPE_SHEET_VIEW_COLUMN);
-
-  /**
-   * PsppSheetView::columns-changed:
-   * @tree_view: the object on which the signal is emitted
-   *
-   * The number of columns of the treeview has changed.
-   */
-  tree_view_signals[COLUMNS_CHANGED] =
-    g_signal_new ("columns-changed",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, columns_changed),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-  /**
-   * PsppSheetView::cursor-changed:
-   * @tree_view: the object on which the signal is emitted
-   *
-   * The position of the cursor (focused cell) has changed.
-   */
-  tree_view_signals[CURSOR_CHANGED] =
-    g_signal_new ("cursor-changed",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, cursor_changed),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-  tree_view_signals[MOVE_CURSOR] =
-    g_signal_new ("move-cursor",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, move_cursor),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__ENUM_INT,
-                 G_TYPE_BOOLEAN, 2,
-                 GTK_TYPE_MOVEMENT_STEP,
-                 G_TYPE_INT);
-
-  tree_view_signals[SELECT_ALL] =
-    g_signal_new ("select-all",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, select_all),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__VOID,
-                 G_TYPE_BOOLEAN, 0);
-
-  tree_view_signals[UNSELECT_ALL] =
-    g_signal_new ("unselect-all",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, unselect_all),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__VOID,
-                 G_TYPE_BOOLEAN, 0);
-
-  tree_view_signals[SELECT_CURSOR_ROW] =
-    g_signal_new ("select-cursor-row",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_row),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__BOOLEAN,
-                 G_TYPE_BOOLEAN, 2,
-                 G_TYPE_BOOLEAN, G_TYPE_INT);
-
-  tree_view_signals[TOGGLE_CURSOR_ROW] =
-    g_signal_new ("toggle-cursor-row",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, toggle_cursor_row),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__VOID,
-                 G_TYPE_BOOLEAN, 0);
-
-  tree_view_signals[START_INTERACTIVE_SEARCH] =
-    g_signal_new ("start-interactive-search",
-                 G_TYPE_FROM_CLASS (o_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (PsppSheetViewClass, start_interactive_search),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__VOID,
-                 G_TYPE_BOOLEAN, 0);
-
-  /* Key bindings */
-  for (i = 0; i < 2; i++)
-    {
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Up, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Up, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Down, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Down, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_p, GDK_CONTROL_MASK, FALSE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_n, GDK_CONTROL_MASK, FALSE,
-                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Home, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Home, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_End, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_End, 0, TRUE,
-                                        GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Up, 0, TRUE,
-                                        GTK_MOVEMENT_PAGES, -1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Up, 0, TRUE,
-                                        GTK_MOVEMENT_PAGES, -1);
-
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Down, 0, TRUE,
-                                        GTK_MOVEMENT_PAGES, 1);
-      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Down, 0, TRUE,
-                                        GTK_MOVEMENT_PAGES, 1);
-
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Up, GDK_CONTROL_MASK, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Down, GDK_CONTROL_MASK, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Right, 0, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Left, 0, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, 0, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, GDK_SHIFT_MASK, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, 0, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, 0, "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Right, GDK_CONTROL_MASK,
-                                    "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_Left, GDK_CONTROL_MASK,
-                                    "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, GDK_CONTROL_MASK,
-                                    "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                                    G_TYPE_INT, 1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, GDK_CONTROL_MASK,
-                                    "move-cursor", 2,
-                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                                    G_TYPE_INT, -1);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
-
-      gtk_binding_entry_add_signal (binding_set[i], GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
-    }
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_a, GDK_CONTROL_MASK, "select-all", 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND);
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_space, 0, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, 0, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_Return, 0, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_ISO_Enter, 0, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Enter, 0, "select-cursor-row", 1,
-                               G_TYPE_BOOLEAN, TRUE,
-                                G_TYPE_INT, 0);
-
-  gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, 0, "select-cursor-parent", 0);
-  gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
-
-  g_type_class_add_private (o_class, sizeof (PsppSheetViewPrivate));
-}
-
-static void
-pspp_sheet_view_buildable_init (GtkBuildableIface *iface)
-{
-  iface->add_child = pspp_sheet_view_buildable_add_child;
-}
-
-static void
-pspp_sheet_view_init (PsppSheetView *tree_view)
-{
-  tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, PSPP_TYPE_SHEET_VIEW, PsppSheetViewPrivate);
-
-  gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
-  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
-
-  tree_view->priv->flags =  PSPP_SHEET_VIEW_DRAW_KEYFOCUS
-                            | PSPP_SHEET_VIEW_HEADERS_VISIBLE;
-
-  /* We need some padding */
-  tree_view->priv->selected = range_tower_create ();
-  tree_view->priv->dy = 0;
-  tree_view->priv->cursor_offset = 0;
-  tree_view->priv->n_columns = 0;
-  tree_view->priv->header_height = 1;
-  tree_view->priv->x_drag = 0;
-  tree_view->priv->drag_pos = -1;
-  tree_view->priv->header_has_focus = FALSE;
-  tree_view->priv->pressed_button = -1;
-  tree_view->priv->press_start_x = -1;
-  tree_view->priv->press_start_y = -1;
-  tree_view->priv->reorderable = FALSE;
-  tree_view->priv->presize_handler_timer = 0;
-  tree_view->priv->scroll_sync_timer = 0;
-  tree_view->priv->fixed_height = -1;
-  tree_view->priv->fixed_height_set = FALSE;
-  pspp_sheet_view_set_adjustments (tree_view, NULL, NULL);
-  tree_view->priv->selection = _pspp_sheet_selection_new_with_tree_view (tree_view);
-  tree_view->priv->enable_search = TRUE;
-  tree_view->priv->search_column = -1;
-  tree_view->priv->search_position_func = pspp_sheet_view_search_position_func;
-  tree_view->priv->search_equal_func = pspp_sheet_view_search_equal_func;
-  tree_view->priv->search_custom_entry_set = FALSE;
-  tree_view->priv->typeselect_flush_timeout = 0;
-  tree_view->priv->init_hadjust_value = TRUE;
-  tree_view->priv->width = 0;
-
-  tree_view->priv->hover_selection = FALSE;
-
-  tree_view->priv->rubber_banding_enable = FALSE;
-
-  tree_view->priv->grid_lines = PSPP_SHEET_VIEW_GRID_LINES_NONE;
-
-  tree_view->priv->tooltip_column = -1;
-
-  tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT;
-
-  tree_view->priv->post_validation_flag = FALSE;
-
-  tree_view->priv->last_button_x = -1;
-  tree_view->priv->last_button_y = -1;
-
-  tree_view->priv->event_last_x = -10000;
-  tree_view->priv->event_last_y = -10000;
-
-  tree_view->priv->prelight_node = -1;
-  tree_view->priv->rubber_band_start_node = -1;
-  tree_view->priv->rubber_band_end_node = -1;
-
-  tree_view->priv->anchor_column = NULL;
-
-  tree_view->priv->button_style = NULL;
-
-  tree_view->dispose_has_run = FALSE;
-
-  pspp_sheet_view_do_set_vadjustment (tree_view, NULL);
-  pspp_sheet_view_do_set_hadjustment (tree_view, NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
-                               GTK_STYLE_CLASS_VIEW);
-}
-
-\f
-
-/* GObject Methods
- */
-
-static void
-pspp_sheet_view_set_property (GObject         *object,
-                           guint            prop_id,
-                           const GValue    *value,
-                           GParamSpec      *pspec)
-{
-  PsppSheetView *tree_view;
-
-  tree_view = PSPP_SHEET_VIEW (object);
-
-  switch (prop_id)
-    {
-    case PROP_MODEL:
-      pspp_sheet_view_set_model (tree_view, g_value_get_object (value));
-      break;
-    case PROP_HADJUSTMENT:
-      pspp_sheet_view_do_set_hadjustment (tree_view, g_value_get_object (value));
-      break;
-    case PROP_VADJUSTMENT:
-      pspp_sheet_view_do_set_vadjustment (tree_view, g_value_get_object (value));
-      break;
-    case PROP_HSCROLL_POLICY:
-      tree_view->priv->hscroll_policy = g_value_get_enum (value);
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-      break;
-    case PROP_VSCROLL_POLICY:
-      tree_view->priv->vscroll_policy = g_value_get_enum (value);
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-      break;
-     case PROP_HEADERS_VISIBLE:
-      pspp_sheet_view_set_headers_visible (tree_view, g_value_get_boolean (value));
-      break;
-    case PROP_HEADERS_CLICKABLE:
-      pspp_sheet_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
-      break;
-    case PROP_REORDERABLE:
-      pspp_sheet_view_set_reorderable (tree_view, g_value_get_boolean (value));
-      break;
-    case PROP_RULES_HINT:
-      pspp_sheet_view_set_rules_hint (tree_view, g_value_get_boolean (value));
-      break;
-    case PROP_ENABLE_SEARCH:
-      pspp_sheet_view_set_enable_search (tree_view, g_value_get_boolean (value));
-      break;
-    case PROP_SEARCH_COLUMN:
-      pspp_sheet_view_set_search_column (tree_view, g_value_get_int (value));
-      break;
-    case PROP_HOVER_SELECTION:
-      tree_view->priv->hover_selection = g_value_get_boolean (value);
-      break;
-    case PROP_RUBBER_BANDING:
-      tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
-      break;
-    case PROP_ENABLE_GRID_LINES:
-      pspp_sheet_view_set_grid_lines (tree_view, g_value_get_enum (value));
-      break;
-    case PROP_TOOLTIP_COLUMN:
-      pspp_sheet_view_set_tooltip_column (tree_view, g_value_get_int (value));
-      break;
-    case PROP_SPECIAL_CELLS:
-      pspp_sheet_view_set_special_cells (tree_view, g_value_get_enum (value));
-      break;
-    case PROP_FIXED_HEIGHT:
-      pspp_sheet_view_set_fixed_height (tree_view, g_value_get_int (value));
-      break;
-    case PROP_FIXED_HEIGHT_SET:
-      if (g_value_get_boolean (value))
-        {
-          if (!tree_view->priv->fixed_height_set
-              && tree_view->priv->fixed_height >= 0)
-            {
-              tree_view->priv->fixed_height_set = true;
-              g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
-            }
-        }
-      else
-        {
-          if (tree_view->priv->fixed_height_set)
-            {
-              tree_view->priv->fixed_height_set = false;
-              g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
-              install_presize_handler (tree_view);
-            }
-        }
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-pspp_sheet_view_get_property (GObject    *object,
-                           guint       prop_id,
-                           GValue     *value,
-                           GParamSpec *pspec)
-{
-  PsppSheetView *tree_view;
-
-  tree_view = PSPP_SHEET_VIEW (object);
-
-  switch (prop_id)
-    {
-    case PROP_MODEL:
-      g_value_set_object (value, tree_view->priv->model);
-      break;
-    case PROP_HADJUSTMENT:
-      g_value_set_object (value, tree_view->priv->hadjustment);
-      break;
-    case PROP_VADJUSTMENT:
-      g_value_set_object (value, tree_view->priv->vadjustment);
-      break;
-    case PROP_HSCROLL_POLICY:
-      g_value_set_enum (value, tree_view->priv->hscroll_policy);
-      break;
-    case PROP_VSCROLL_POLICY:
-      g_value_set_enum (value, tree_view->priv->vscroll_policy);
-      break;
-    case PROP_HEADERS_VISIBLE:
-      g_value_set_boolean (value, pspp_sheet_view_get_headers_visible (tree_view));
-      break;
-    case PROP_HEADERS_CLICKABLE:
-      g_value_set_boolean (value, pspp_sheet_view_get_headers_clickable (tree_view));
-      break;
-    case PROP_REORDERABLE:
-      g_value_set_boolean (value, tree_view->priv->reorderable);
-      break;
-    case PROP_RULES_HINT:
-      g_value_set_boolean (value, tree_view->priv->has_rules);
-      break;
-    case PROP_ENABLE_SEARCH:
-      g_value_set_boolean (value, tree_view->priv->enable_search);
-      break;
-    case PROP_SEARCH_COLUMN:
-      g_value_set_int (value, tree_view->priv->search_column);
-      break;
-    case PROP_HOVER_SELECTION:
-      g_value_set_boolean (value, tree_view->priv->hover_selection);
-      break;
-    case PROP_RUBBER_BANDING:
-      g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
-      break;
-    case PROP_ENABLE_GRID_LINES:
-      g_value_set_enum (value, tree_view->priv->grid_lines);
-      break;
-    case PROP_TOOLTIP_COLUMN:
-      g_value_set_int (value, tree_view->priv->tooltip_column);
-      break;
-    case PROP_SPECIAL_CELLS:
-      g_value_set_enum (value, tree_view->priv->special_cells);
-      break;
-    case PROP_FIXED_HEIGHT:
-      g_value_set_int (value, pspp_sheet_view_get_fixed_height (tree_view));
-      break;
-    case PROP_FIXED_HEIGHT_SET:
-      g_value_set_boolean (value, tree_view->priv->fixed_height_set);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-pspp_sheet_view_dispose (GObject *object)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
-
-  if (tree_view->dispose_has_run)
-    return;
-
-  tree_view->dispose_has_run = TRUE;
-
-  if (tree_view->priv->selection != NULL)
-    {
-      _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL);
-      g_object_unref (tree_view->priv->selection);
-      tree_view->priv->selection = NULL;
-    }
-
-  if (tree_view->priv->hadjustment)
-    {
-      g_object_unref (tree_view->priv->hadjustment);
-      tree_view->priv->hadjustment = NULL;
-    }
-  if (tree_view->priv->vadjustment)
-    {
-      g_object_unref (tree_view->priv->vadjustment);
-      tree_view->priv->vadjustment = NULL;
-    }
-
-  if (tree_view->priv->button_style)
-    {
-      g_object_unref (tree_view->priv->button_style);
-      tree_view->priv->button_style = NULL;
-    }
-
-
-  G_OBJECT_CLASS (pspp_sheet_view_parent_class)->dispose (object);
-}
-
-\f
-
-static void
-pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view,
-                                  GtkBuilder  *builder,
-                                  GObject     *child,
-                                  const gchar *type)
-{
-  pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_COLUMN (child));
-}
-
-static void
-pspp_sheet_view_finalize (GObject *object)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
-
-  pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-  if (tree_view->priv->selected != NULL)
-    {
-      range_tower_destroy (tree_view->priv->selected);
-      tree_view->priv->selected = NULL;
-    }
-
-
-  tree_view->priv->prelight_node = -1;
-
-
-  if (tree_view->priv->scroll_to_path != NULL)
-    {
-      gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-      tree_view->priv->scroll_to_path = NULL;
-    }
-
-  if (tree_view->priv->drag_dest_row != NULL)
-    {
-      gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
-      tree_view->priv->drag_dest_row = NULL;
-    }
-
-  if (tree_view->priv->top_row != NULL)
-    {
-      gtk_tree_row_reference_free (tree_view->priv->top_row);
-      tree_view->priv->top_row = NULL;
-    }
-
-  if (tree_view->priv->column_drop_func_data &&
-      tree_view->priv->column_drop_func_data_destroy)
-    {
-      tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
-      tree_view->priv->column_drop_func_data = NULL;
-    }
-
-  if (tree_view->priv->destroy_count_destroy &&
-      tree_view->priv->destroy_count_data)
-    {
-      tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
-      tree_view->priv->destroy_count_data = NULL;
-    }
-
-  gtk_tree_row_reference_free (tree_view->priv->cursor);
-  tree_view->priv->cursor = NULL;
-
-  gtk_tree_row_reference_free (tree_view->priv->anchor);
-  tree_view->priv->anchor = NULL;
-
-  /* destroy interactive search dialog */
-  if (tree_view->priv->search_window)
-    {
-      gtk_widget_destroy (tree_view->priv->search_window);
-      tree_view->priv->search_window = NULL;
-      tree_view->priv->search_entry = NULL;
-      if (tree_view->priv->typeselect_flush_timeout)
-       {
-         g_source_remove (tree_view->priv->typeselect_flush_timeout);
-         tree_view->priv->typeselect_flush_timeout = 0;
-       }
-    }
-
-  if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
-    {
-      tree_view->priv->search_destroy (tree_view->priv->search_user_data);
-      tree_view->priv->search_user_data = NULL;
-    }
-
-  if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
-    {
-      tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
-      tree_view->priv->search_position_user_data = NULL;
-    }
-
-  pspp_sheet_view_set_model (tree_view, NULL);
-
-
-  G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object);
-}
-
-\f
-
-/* GtkWidget Methods
- */
-
-/* GtkWidget::map helper */
-static void
-pspp_sheet_view_map_buttons (PsppSheetView *tree_view)
-{
-  GList *list;
-
-  g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
-    {
-      PsppSheetViewColumn *column;
-
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         column = list->data;
-          if (column->button != NULL &&
-              gtk_widget_get_visible (column->button) &&
-              !gtk_widget_get_mapped (column->button))
-            gtk_widget_map (column->button);
-       }
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         column = list->data;
-         if (column->visible == FALSE || column->window == NULL)
-           continue;
-         if (column->resizable)
-           {
-             gdk_window_raise (column->window);
-             gdk_window_show (column->window);
-           }
-         else
-           gdk_window_hide (column->window);
-       }
-      gdk_window_show (tree_view->priv->header_window);
-    }
-}
-
-static void
-pspp_sheet_view_map (GtkWidget *widget)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *tmp_list;
-
-  gtk_widget_set_mapped (widget, TRUE);
-
-  tmp_list = tree_view->priv->children;
-  while (tmp_list)
-    {
-      PsppSheetViewChild *child = tmp_list->data;
-      tmp_list = tmp_list->next;
-
-      if (gtk_widget_get_visible (child->widget))
-       {
-         if (!gtk_widget_get_mapped (child->widget))
-           gtk_widget_map (child->widget);
-       }
-    }
-  gdk_window_show (tree_view->priv->bin_window);
-
-  pspp_sheet_view_map_buttons (tree_view);
-
-  gdk_window_show (gtk_widget_get_window (widget));
-}
-
-static void
-pspp_sheet_view_realize (GtkWidget *widget)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *tmp_list;
-  GdkWindow *window;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  GtkAllocation allocation;
-
-  gtk_widget_set_realized (widget, TRUE);
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  /* Make the main, clipping window */
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x =      allocation.x;
-  attributes.y =      allocation.y;
-  attributes.width =  allocation.width;
-  attributes.height = allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
-
-  window = gdk_window_new (gtk_widget_get_parent_window (widget),
-                           &attributes, attributes_mask);
-  gtk_widget_set_window (widget, window);
-
-  gtk_widget_register_window (widget, window);
-  gtk_widget_get_allocation (widget, &allocation);
-
-  /* Make the window for the tree */
-  attributes.x = 0;
-  attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
-  attributes.width = MAX (tree_view->priv->width, allocation.width);
-  attributes.height = allocation.height;
-  attributes.event_mask = (GDK_EXPOSURE_MASK |
-                           GDK_SCROLL_MASK |
-                           GDK_POINTER_MOTION_MASK |
-                           GDK_ENTER_NOTIFY_MASK |
-                           GDK_LEAVE_NOTIFY_MASK |
-                           GDK_BUTTON_PRESS_MASK |
-                           GDK_BUTTON_RELEASE_MASK |
-                           gtk_widget_get_events (widget));
-
-  tree_view->priv->bin_window = gdk_window_new (window,
-                                               &attributes, attributes_mask);
-  gtk_widget_register_window (widget, tree_view->priv->bin_window);
-  gtk_widget_get_allocation (widget, &allocation);
-
-  /* Make the column header window */
-  attributes.x = 0;
-  attributes.y = 0;
-  attributes.width = MAX (tree_view->priv->width, allocation.width);
-  attributes.height = tree_view->priv->header_height;
-  attributes.event_mask = (GDK_EXPOSURE_MASK |
-                           GDK_SCROLL_MASK |
-                           GDK_BUTTON_PRESS_MASK |
-                           GDK_BUTTON_RELEASE_MASK |
-                           GDK_KEY_PRESS_MASK |
-                           GDK_KEY_RELEASE_MASK |
-                           gtk_widget_get_events (widget));
-
-  tree_view->priv->header_window = gdk_window_new (window,
-                                                  &attributes, attributes_mask);
-  gtk_widget_register_window (widget, tree_view->priv->header_window);
-
-  { /* Ensure Background */
-    GtkStyleContext *context;
-
-    context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
-
-    gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
-    gtk_style_context_set_background (context, tree_view->priv->header_window);
-  }
-
-  tmp_list = tree_view->priv->children;
-  while (tmp_list)
-    {
-      PsppSheetViewChild *child = tmp_list->data;
-      tmp_list = tmp_list->next;
-
-      gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
-    }
-
-  for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
-    _pspp_sheet_view_column_realize_button (PSPP_SHEET_VIEW_COLUMN (tmp_list->data));
-
-  /* Need to call those here, since they create GCs */
-  pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
-
-  install_presize_handler (tree_view);
-}
-
-static void
-pspp_sheet_view_unrealize (GtkWidget *widget)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  PsppSheetViewPrivate *priv = tree_view->priv;
-  GList *list;
-
-  GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget);
-
-  if (priv->scroll_timeout != 0)
-    {
-      g_source_remove (priv->scroll_timeout);
-      priv->scroll_timeout = 0;
-    }
-
-  if (priv->open_dest_timeout != 0)
-    {
-      g_source_remove (priv->open_dest_timeout);
-      priv->open_dest_timeout = 0;
-    }
-
-  if (priv->presize_handler_timer != 0)
-    {
-      g_source_remove (priv->presize_handler_timer);
-      priv->presize_handler_timer = 0;
-    }
-
-  if (priv->validate_rows_timer != 0)
-    {
-      g_source_remove (priv->validate_rows_timer);
-      priv->validate_rows_timer = 0;
-    }
-
-  if (priv->scroll_sync_timer != 0)
-    {
-      g_source_remove (priv->scroll_sync_timer);
-      priv->scroll_sync_timer = 0;
-    }
-
-  if (priv->typeselect_flush_timeout)
-    {
-      g_source_remove (priv->typeselect_flush_timeout);
-      priv->typeselect_flush_timeout = 0;
-    }
-
-  for (list = priv->columns; list; list = list->next)
-    _pspp_sheet_view_column_unrealize_button (PSPP_SHEET_VIEW_COLUMN (list->data));
-
-  gdk_window_set_user_data (priv->bin_window, NULL);
-  gdk_window_destroy (priv->bin_window);
-  priv->bin_window = NULL;
-
-  gdk_window_set_user_data (priv->header_window, NULL);
-  gdk_window_destroy (priv->header_window);
-  priv->header_window = NULL;
-
-  if (priv->drag_window)
-    {
-      gdk_window_set_user_data (priv->drag_window, NULL);
-      gdk_window_destroy (priv->drag_window);
-      priv->drag_window = NULL;
-    }
-
-  if (priv->drag_highlight_window)
-    {
-      gdk_window_set_user_data (priv->drag_highlight_window, NULL);
-      gdk_window_destroy (priv->drag_highlight_window);
-      priv->drag_highlight_window = NULL;
-    }
-
-  if (tree_view->priv->columns != NULL)
-    {
-      list = tree_view->priv->columns;
-      while (list)
-       {
-         PsppSheetViewColumn *column;
-         column = PSPP_SHEET_VIEW_COLUMN (list->data);
-         list = list->next;
-         pspp_sheet_view_remove_column (tree_view, column);
-       }
-      tree_view->priv->columns = NULL;
-    }
-}
-
-/* GtkWidget::size_request helper */
-static void
-pspp_sheet_view_size_request_columns (PsppSheetView *tree_view)
-{
-  GList *list;
-
-  tree_view->priv->header_height = 0;
-
-  if (tree_view->priv->model)
-    {
-      for (list = tree_view->priv->columns; list; list = list->next)
-        {
-          GtkRequisition requisition;
-          PsppSheetViewColumn *column = list->data;
-
-          pspp_sheet_view_column_size_request (column, &requisition);
-         column->button_request = requisition.width;
-          tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
-        }
-    }
-}
-
-
-/* Called only by ::size_request */
-static void
-pspp_sheet_view_update_size (PsppSheetView *tree_view)
-{
-  GList *list;
-  PsppSheetViewColumn *column;
-  gint i;
-
-  if (tree_view->priv->model == NULL)
-    {
-      tree_view->priv->width = 0;
-      tree_view->priv->prev_width = 0;
-      tree_view->priv->height = 0;
-      return;
-    }
-
-  tree_view->priv->prev_width = tree_view->priv->width;
-  tree_view->priv->width = 0;
-
-  /* keep this in sync with size_allocate below */
-  for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
-    {
-      gint real_requested_width = 0;
-      column = list->data;
-      if (!column->visible)
-       continue;
-
-      if (column->use_resized_width)
-       {
-         real_requested_width = column->resized_width;
-       }
-      else
-       {
-         real_requested_width = column->fixed_width;
-       }
-
-      if (column->min_width != -1)
-       real_requested_width = MAX (real_requested_width, column->min_width);
-      if (column->max_width != -1)
-       real_requested_width = MIN (real_requested_width, column->max_width);
-
-      tree_view->priv->width += real_requested_width;
-    }
-
-  tree_view->priv->height = tree_view->priv->fixed_height * tree_view->priv->row_count;
-}
-
-static void
-pspp_sheet_view_size_request (GtkWidget      *widget,
-                           GtkRequisition *requisition)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *tmp_list;
-
-  /* we validate some rows initially just to make sure we have some size.
-   * In practice, with a lot of static lists, this should get a good width.
-   */
-  initialize_fixed_height_mode (tree_view);
-  pspp_sheet_view_size_request_columns (tree_view);
-  pspp_sheet_view_update_size (PSPP_SHEET_VIEW (widget));
-
-  requisition->width = tree_view->priv->width;
-  requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
-  tmp_list = tree_view->priv->children;
-
-  while (tmp_list)
-    {
-      PsppSheetViewChild *child = tmp_list->data;
-      GtkRequisition child_requisition;
-
-      tmp_list = tmp_list->next;
-
-      if (gtk_widget_get_visible (child->widget))
-       {
-         gtk_widget_get_preferred_size (child->widget, NULL, &child_requisition);
-       }
-    }
-}
-
-static void
-invalidate_column (PsppSheetView       *tree_view,
-                   PsppSheetViewColumn *column)
-{
-  gint column_offset = 0;
-  GList *list;
-  GtkWidget *widget = GTK_WIDGET (tree_view);
-  gboolean rtl;
-
-  if (!gtk_widget_get_realized (widget))
-    return;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-  for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-       list;
-       list = (rtl ? list->prev : list->next))
-    {
-      PsppSheetViewColumn *tmpcolumn = list->data;
-      if (tmpcolumn == column)
-       {
-         GdkRectangle invalid_rect;
-         GtkAllocation allocation;
-
-         gtk_widget_get_allocation (widget, &allocation);
-         invalid_rect.x = column_offset;
-         invalid_rect.y = 0;
-         invalid_rect.width = column->width;
-         invalid_rect.height = allocation.height;
-
-         gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
-         break;
-       }
-
-      column_offset += tmpcolumn->width;
-    }
-}
-
-static void
-invalidate_last_column (PsppSheetView *tree_view)
-{
-  GList *last_column;
-  gboolean rtl;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
-       last_column;
-       last_column = (rtl ? last_column->next : last_column->prev))
-    {
-      if (PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible)
-        {
-          invalidate_column (tree_view, last_column->data);
-          return;
-        }
-    }
-}
-
-static gint
-pspp_sheet_view_get_real_requested_width_from_column (PsppSheetView       *tree_view,
-                                                    PsppSheetViewColumn *column)
-{
-  gint real_requested_width;
-
-  if (column->use_resized_width)
-    {
-      real_requested_width = column->resized_width;
-    }
-  else
-    {
-      real_requested_width = column->fixed_width;
-    }
-
-  if (column->min_width != -1)
-    real_requested_width = MAX (real_requested_width, column->min_width);
-  if (column->max_width != -1)
-    real_requested_width = MIN (real_requested_width, column->max_width);
-
-  return real_requested_width;
-}
-
-static gboolean
-span_intersects (int a0, int a_width,
-                 int b0, int b_width)
-{
-  int a1 = a0 + a_width;
-  int b1 = b0 + b_width;
-  return (a0 >= b0 && a0 < b1) || (b0 >= a0 && b0 < a1);
-}
-
-/* GtkWidget::size_allocate helper */
-static void
-pspp_sheet_view_size_allocate_columns (GtkWidget *widget,
-                                    gboolean  *width_changed)
-{
-  PsppSheetView *tree_view;
-  GList *list, *first_column, *last_column;
-  PsppSheetViewColumn *column;
-  GtkAllocation col_allocation;
-  GtkAllocation allocation;
-  gint width = 0;
-  gint extra, extra_per_column;
-  gint full_requested_width = 0;
-  gint number_of_expand_columns = 0;
-  gboolean column_changed = FALSE;
-  gboolean rtl;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  for (last_column = g_list_last (tree_view->priv->columns);
-       last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
-       last_column = last_column->prev)
-    ;
-
-  if (last_column == NULL)
-    return;
-
-  for (first_column = g_list_first (tree_view->priv->columns);
-       first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
-       first_column = first_column->next)
-    ;
-
-  col_allocation.y = 0;
-  col_allocation.height = tree_view->priv->header_height;
-
-  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
-  /* find out how many extra space and expandable columns we have */
-  for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
-    {
-      column = (PsppSheetViewColumn *)list->data;
-
-      if (!column->visible)
-       continue;
-
-      full_requested_width += pspp_sheet_view_get_real_requested_width_from_column (tree_view, column);
-
-      if (column->expand)
-       number_of_expand_columns++;
-    }
-
-  gtk_widget_get_allocation (widget, &allocation);
-  extra = MAX (allocation.width - full_requested_width, 0);
-  if (number_of_expand_columns > 0)
-    extra_per_column = extra/number_of_expand_columns;
-  else
-    extra_per_column = 0;
-
-  for (list = (rtl ? last_column : first_column);
-       list != (rtl ? first_column->prev : last_column->next);
-       list = (rtl ? list->prev : list->next))
-    {
-      gint real_requested_width = 0;
-      gint old_width;
-
-      column = list->data;
-      old_width = column->width;
-
-      if (!column->visible)
-       continue;
-
-      /* We need to handle the dragged button specially.
-       */
-      if (column == tree_view->priv->drag_column)
-       {
-         GtkAllocation drag_allocation;
-         drag_allocation.width =  gdk_window_get_width (tree_view->priv->drag_window);
-         drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
-         drag_allocation.x = 0;
-         drag_allocation.y = 0;
-          pspp_sheet_view_column_size_allocate (tree_view->priv->drag_column,
-                                                &drag_allocation);
-         width += drag_allocation.width;
-         continue;
-       }
-
-      real_requested_width = pspp_sheet_view_get_real_requested_width_from_column (tree_view, column);
-
-      col_allocation.x = width;
-      column->width = real_requested_width;
-
-      if (column->expand)
-       {
-         if (number_of_expand_columns == 1)
-           {
-             /* We add the remander to the last column as
-              * */
-             column->width += extra;
-           }
-         else
-           {
-             column->width += extra_per_column;
-             extra -= extra_per_column;
-             number_of_expand_columns --;
-           }
-       }
-
-      if (column->width != old_width)
-        g_object_notify (G_OBJECT (column), "width");
-
-      col_allocation.width = column->width;
-      width += column->width;
-
-      if (column->width > old_width)
-        column_changed = TRUE;
-
-      pspp_sheet_view_column_size_allocate (column, &col_allocation);
-
-      if (column->window)
-       gdk_window_move_resize (column->window,
-                                col_allocation.x + (rtl ? 0 : col_allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
-                               col_allocation.y,
-                                TREE_VIEW_DRAG_WIDTH, col_allocation.height);
-    }
-
-  /* We change the width here.  The user might have been resizing columns,
-   * so the total width of the tree view changes.
-   */
-  tree_view->priv->width = width;
-  if (width_changed)
-    *width_changed = TRUE;
-
-  if (column_changed)
-    gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static void
-update_childrens_allocation (PsppSheetView *tree_view)
-{
-  GList *tmp_list;
-  for (tmp_list = tree_view->priv->children; tmp_list; tmp_list = tmp_list->next)
-    {
-      PsppSheetViewChild *child = tmp_list->data;
-      GtkAllocation allocation;
-      GtkTreePath *path;
-
-      /* totally ignore our child's requisition */
-      path = _pspp_sheet_view_find_path (tree_view, child->node);
-      pspp_sheet_view_get_cell_area (tree_view, path, child->column, &allocation);
-      gtk_tree_path_free (path);
-      gtk_widget_size_allocate (child->widget, &allocation);
-    }
-}
-
-static void
-pspp_sheet_view_size_allocate (GtkWidget     *widget,
-                            GtkAllocation *allocation)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *tmp_list;
-  gboolean width_changed = FALSE;
-  GtkAllocation old_allocation;
-  gtk_widget_get_allocation (widget, &old_allocation);
-
-  if (allocation->width != old_allocation.width)
-    width_changed = TRUE;
-
-  if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
-    allocation->x += allocation->width - tree_view->priv->width ;
-
-  gtk_widget_set_allocation (widget, allocation);
-
-  /* We size-allocate the columns first because the width of the
-   * tree view (used in updating the adjustments below) might change.
-   */
-  pspp_sheet_view_size_allocate_columns (widget, &width_changed);
-
-  gtk_adjustment_set_page_size (tree_view->priv->hadjustment, allocation->width);
-  gtk_adjustment_set_page_increment (tree_view->priv->hadjustment, allocation->width * 0.9);
-  gtk_adjustment_set_step_increment (tree_view->priv->hadjustment, allocation->width * 0.1);
-  gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
-  gtk_adjustment_set_upper (tree_view->priv->hadjustment, MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment), tree_view->priv->width));
-
-  if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
-    {
-      if (allocation->width < tree_view->priv->width)
-        {
-         if (tree_view->priv->init_hadjust_value)
-           {
-             gtk_adjustment_set_value (tree_view->priv->hadjustment, MAX (tree_view->priv->width - allocation->width, 0));
-             tree_view->priv->init_hadjust_value = FALSE;
-           }
-         else if (allocation->width != old_allocation.width)
-           {
-             gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_allocation.width, 0, tree_view->priv->width - allocation->width));
-           }
-         else
-           gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)), 0, tree_view->priv->width - allocation->width));
-       }
-      else
-        {
-         gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
-         tree_view->priv->init_hadjust_value = TRUE;
-       }
-    }
-  else
-    if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
-      gtk_adjustment_set_value (tree_view->priv->hadjustment, MAX (tree_view->priv->width - allocation->width, 0));
-
-  gtk_adjustment_changed (tree_view->priv->hadjustment);
-
-  gtk_adjustment_set_page_size (tree_view->priv->vadjustment, allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
-  gtk_adjustment_set_step_increment (tree_view->priv->vadjustment, gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
-  gtk_adjustment_set_page_increment (tree_view->priv->vadjustment, gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
-  gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
-  gtk_adjustment_set_upper (tree_view->priv->vadjustment, MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment), tree_view->priv->height));
-
-  gtk_adjustment_changed (tree_view->priv->vadjustment);
-
-  /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
-  if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
-    gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
-  else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
-    gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
-                              tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
-  else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
-    pspp_sheet_view_top_row_to_dy (tree_view);
-  else
-    pspp_sheet_view_dy_to_top_row (tree_view);
-
-  if (gtk_widget_get_realized (widget))
-    {
-      gdk_window_move_resize (gtk_widget_get_window (widget),
-                             allocation->x, allocation->y,
-                             allocation->width, allocation->height);
-      gdk_window_move_resize (tree_view->priv->header_window,
-                             - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
-                             0,
-                             MAX (tree_view->priv->width, allocation->width),
-                             tree_view->priv->header_height);
-      gdk_window_move_resize (tree_view->priv->bin_window,
-                             - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
-                             TREE_VIEW_HEADER_HEIGHT (tree_view),
-                             MAX (tree_view->priv->width, allocation->width),
-                             allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
-    }
-
-  if (tree_view->priv->row_count == 0)
-    invalidate_empty_focus (tree_view);
-
-  if (gtk_widget_get_realized (widget))
-    {
-      gboolean has_expand_column = FALSE;
-      for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
-       {
-         if (pspp_sheet_view_column_get_expand (PSPP_SHEET_VIEW_COLUMN (tmp_list->data)))
-           {
-             has_expand_column = TRUE;
-             break;
-           }
-       }
-
-      /* This little hack only works if we have an LTR locale, and no column has the  */
-      if (width_changed)
-       {
-         if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
-             ! has_expand_column)
-           invalidate_last_column (tree_view);
-         else
-           gtk_widget_queue_draw (widget);
-       }
-      update_childrens_allocation(tree_view);
-    }
-
-  tree_view->priv->resized = TRUE;
-}
-
-/* Grabs the focus and unsets the PSPP_SHEET_VIEW_DRAW_KEYFOCUS flag */
-static void
-grab_focus_and_unset_draw_keyfocus (PsppSheetView *tree_view)
-{
-  GtkWidget *widget = GTK_WIDGET (tree_view);
-
-  if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
-    gtk_widget_grab_focus (widget);
-  PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-}
-
-gboolean
-pspp_sheet_view_node_is_selected (PsppSheetView *tree_view,
-                                  int node)
-{
-  return node >= 0 && range_tower_contains (tree_view->priv->selected, node);
-}
-
-void
-pspp_sheet_view_node_select (PsppSheetView *tree_view,
-                             int node)
-{
-  range_tower_set1 (tree_view->priv->selected, node, 1);
-}
-
-void
-pspp_sheet_view_node_unselect (PsppSheetView *tree_view,
-                               int node)
-{
-  range_tower_set0 (tree_view->priv->selected, node, 1);
-}
-
-gint
-pspp_sheet_view_node_next (PsppSheetView *tree_view,
-                           gint node)
-{
-  return node + 1 < tree_view->priv->row_count ? node + 1 : -1;
-}
-
-gint
-pspp_sheet_view_node_prev (PsppSheetView *tree_view,
-                           gint node)
-{
-  return node > 0 ? node - 1 : -1;
-}
-
-static gboolean
-all_columns_selected (PsppSheetView *tree_view)
-{
-  GList *list;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column = list->data;
-      if (column->selectable && !column->selected)
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_row_head_clicked (PsppSheetView *tree_view,
-                                  gint node,
-                                  PsppSheetViewColumn *column,
-                                  GdkEventButton *event)
-{
-  PsppSheetSelection *selection;
-  PsppSheetSelectionMode mode;
-  GtkTreePath *path;
-  gboolean update_anchor;
-  gboolean handled;
-  guint modifiers;
-
-  g_return_val_if_fail (tree_view != NULL, FALSE);
-  g_return_val_if_fail (column != NULL, FALSE);
-
-  selection = tree_view->priv->selection;
-  mode = pspp_sheet_selection_get_mode (selection);
-  if (mode != PSPP_SHEET_SELECTION_RECTANGLE)
-    return FALSE;
-
-  if (!column->row_head)
-    return FALSE;
-
-  if (event)
-    {
-      modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
-      if (event->type != GDK_BUTTON_PRESS
-          || (modifiers != GDK_CONTROL_MASK && modifiers != GDK_SHIFT_MASK))
-        return FALSE;
-    }
-  else
-    modifiers = 0;
-
-  path = gtk_tree_path_new_from_indices (node, -1);
-  if (event == NULL)
-    {
-      pspp_sheet_selection_unselect_all (selection);
-      pspp_sheet_selection_select_path (selection, path);
-      pspp_sheet_selection_select_all_columns (selection);
-      update_anchor = TRUE;
-      handled = TRUE;
-    }
-  else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
-    {
-      if (pspp_sheet_selection_count_selected_rows (selection) <= 1
-          || !all_columns_selected (tree_view))
-        {
-          pspp_sheet_selection_unselect_all (selection);
-          pspp_sheet_selection_select_path (selection, path);
-          pspp_sheet_selection_select_all_columns (selection);
-          update_anchor = TRUE;
-          handled = FALSE;
-        }
-      else
-        update_anchor = handled = FALSE;
-    }
-  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
-           && modifiers == GDK_CONTROL_MASK)
-    {
-      if (!all_columns_selected (tree_view))
-        {
-          pspp_sheet_selection_unselect_all (selection);
-          pspp_sheet_selection_select_all_columns (selection);
-        }
-
-      if (pspp_sheet_selection_path_is_selected (selection, path))
-        pspp_sheet_selection_unselect_path (selection, path);
-      else
-        pspp_sheet_selection_select_path (selection, path);
-      update_anchor = TRUE;
-      handled = TRUE;
-    }
-  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
-           && modifiers == GDK_SHIFT_MASK)
-    {
-      GtkTreeRowReference *anchor = tree_view->priv->anchor;
-      GtkTreePath *anchor_path;
-
-      if (all_columns_selected (tree_view)
-          && gtk_tree_row_reference_valid (anchor))
-        {
-          update_anchor = FALSE;
-          anchor_path = gtk_tree_row_reference_get_path (anchor);
-        }
-      else
-        {
-          update_anchor = TRUE;
-          anchor_path = gtk_tree_path_copy (path);
-        }
-
-      pspp_sheet_selection_unselect_all (selection);
-      pspp_sheet_selection_select_range (selection, anchor_path, path);
-      pspp_sheet_selection_select_all_columns (selection);
-
-      gtk_tree_path_free (anchor_path);
-
-      handled = TRUE;
-    }
-  else
-    update_anchor = handled = FALSE;
-
-  if (update_anchor)
-    {
-      if (tree_view->priv->anchor)
-        gtk_tree_row_reference_free (tree_view->priv->anchor);
-      tree_view->priv->anchor =
-        gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
-                                          tree_view->priv->model,
-                                          path);
-    }
-
-  gtk_tree_path_free (path);
-  return handled;
-}
-
-static gboolean
-find_click (PsppSheetView *tree_view,
-            gint x, gint y,
-            gint *node,
-            PsppSheetViewColumn **column,
-            GdkRectangle *background_area,
-            GdkRectangle *cell_area)
-{
-  gint y_offset;
-  gboolean rtl;
-  GList *list;
-  gint new_y;
-
-  /* find the node that was clicked */
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, y);
-  if (new_y < 0)
-    new_y = 0;
-  y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, node);
-
-  if (*node < 0)
-    return FALSE;
-
-  background_area->y = y_offset + y;
-  background_area->height = ROW_HEIGHT (tree_view);
-  background_area->x = 0;
-
-  /* Let the column have a chance at selecting it. */
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-  for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-       list; list = (rtl ? list->prev : list->next))
-    {
-      PsppSheetViewColumn *candidate = list->data;
-
-      if (!candidate->visible)
-        continue;
-
-      background_area->width = candidate->width;
-      if ((background_area->x > x) ||
-          (background_area->x + background_area->width <= x))
-        {
-          background_area->x += background_area->width;
-          continue;
-        }
-
-      /* we found the focus column */
-
-      pspp_sheet_view_adjust_cell_area (tree_view, candidate, background_area,
-                                        TRUE, cell_area);
-      *column = candidate;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_button_press (GtkWidget      *widget,
-                           GdkEventButton *event)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *list;
-  PsppSheetViewColumn *column = NULL;
-  gint i;
-  GdkRectangle background_area;
-  GdkRectangle cell_area;
-  gboolean rtl;
-
-  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-  pspp_sheet_view_stop_editing (tree_view, FALSE);
-
-
-  /* Because grab_focus can cause reentrancy, we delay grab_focus until after
-   * we're done handling the button press.
-   */
-
-  if (event->window == tree_view->priv->bin_window)
-    {
-      int node;
-      GtkTreePath *path;
-      gint dval;
-      gint pre_val, aft_val;
-      PsppSheetViewColumn *column = NULL;
-      GtkCellRenderer *focus_cell = NULL;
-      gboolean row_double_click = FALSE;
-
-      /* Empty tree? */
-      if (tree_view->priv->row_count == 0)
-       {
-         grab_focus_and_unset_draw_keyfocus (tree_view);
-         return TRUE;
-       }
-
-      if (!find_click (tree_view, event->x, event->y, &node, &column,
-                       &background_area, &cell_area))
-        {
-         grab_focus_and_unset_draw_keyfocus (tree_view);
-          return FALSE;
-        }
-
-      tree_view->priv->focus_column = column;
-
-      if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event))
-        return TRUE;
-
-      /* select */
-      pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
-      path = _pspp_sheet_view_find_path (tree_view, node);
-
-      /* we only handle selection modifications on the first button press
-       */
-      if (event->type == GDK_BUTTON_PRESS)
-        {
-          PsppSheetSelectionMode mode = 0;
-
-          if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
-            mode |= PSPP_SHEET_SELECT_MODE_TOGGLE;
-          if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
-            mode |= PSPP_SHEET_SELECT_MODE_EXTEND;
-
-          focus_cell = _pspp_sheet_view_column_get_cell_at_pos (column, event->x - background_area.x);
-          if (focus_cell)
-            pspp_sheet_view_column_focus_cell (column, focus_cell);
-
-          if (event->state & GDK_CONTROL_MASK)
-            {
-              pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, mode);
-              pspp_sheet_view_real_toggle_cursor_row (tree_view);
-            }
-          else if (event->state & GDK_SHIFT_MASK)
-            {
-              pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode);
-              pspp_sheet_view_real_select_cursor_row (tree_view, FALSE, mode);
-            }
-          else
-            {
-              pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0);
-            }
-
-          if (tree_view->priv->anchor_column == NULL ||
-              !(event->state & GDK_SHIFT_MASK))
-            tree_view->priv->anchor_column = column;
-          pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
-          pspp_sheet_selection_select_column_range (tree_view->priv->selection,
-                                                    tree_view->priv->anchor_column,
-                                                    column);
-        }
-
-      /* the treeview may have been scrolled because of _set_cursor,
-       * correct here
-       */
-
-      aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
-      dval = pre_val - aft_val;
-
-      cell_area.y += dval;
-      background_area.y += dval;
-
-      /* Save press to possibly begin a drag
-       */
-      if (!tree_view->priv->in_grab &&
-         tree_view->priv->pressed_button < 0)
-        {
-          tree_view->priv->pressed_button = event->button;
-          tree_view->priv->press_start_x = event->x;
-          tree_view->priv->press_start_y = event->y;
-          tree_view->priv->press_start_node = node;
-
-         if (tree_view->priv->rubber_banding_enable
-             && (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-                  tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE))
-           {
-             tree_view->priv->press_start_y += tree_view->priv->dy;
-             tree_view->priv->rubber_band_x = event->x;
-             tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
-             tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
-
-             if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
-               tree_view->priv->rubber_band_ctrl = TRUE;
-             if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
-               tree_view->priv->rubber_band_shift = TRUE;
-
-           }
-        }
-
-      /* Test if a double click happened on the same row. */
-      if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
-        {
-          int double_click_time, double_click_distance;
-
-          g_object_get (gtk_settings_get_for_screen (
-                          gtk_widget_get_screen (widget)),
-                        "gtk-double-click-time", &double_click_time,
-                        "gtk-double-click-distance", &double_click_distance,
-                        NULL);
-
-          /* Same conditions as _gdk_event_button_generate */
-          if (tree_view->priv->last_button_x != -1 &&
-              (event->time < tree_view->priv->last_button_time + double_click_time) &&
-              (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
-              (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
-            {
-              /* We do no longer compare paths of this row and the
-               * row clicked previously.  We use the double click
-               * distance to decide whether this is a valid click,
-               * allowing the mouse to slightly move over another row.
-               */
-              row_double_click = TRUE;
-
-              tree_view->priv->last_button_time = 0;
-              tree_view->priv->last_button_x = -1;
-              tree_view->priv->last_button_y = -1;
-            }
-          else
-            {
-              tree_view->priv->last_button_time = event->time;
-              tree_view->priv->last_button_x = event->x;
-              tree_view->priv->last_button_y = event->y;
-            }
-        }
-
-      if (row_double_click)
-       {
-         gtk_grab_remove (widget);
-         pspp_sheet_view_row_activated (tree_view, path, column);
-
-          if (tree_view->priv->pressed_button == event->button)
-            tree_view->priv->pressed_button = -1;
-       }
-
-      gtk_tree_path_free (path);
-
-      /* If we activated the row through a double click we don't want to grab
-       * focus back, as moving focus to another widget is pretty common.
-       */
-      if (!row_double_click)
-       grab_focus_and_unset_draw_keyfocus (tree_view);
-
-      return TRUE;
-    }
-
-  /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
-   */
-  for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
-    {
-      column = list->data;
-      if (event->window == column->window &&
-         column->resizable &&
-         column->window)
-       {
-         gpointer drag_data;
-
-         if (GDK_GRAB_SUCCESS != gdk_device_grab (event->device,
-                                                  column->window,
-                                                  GDK_OWNERSHIP_NONE,
-                                                  FALSE,
-                                                  GDK_POINTER_MOTION_HINT_MASK |
-                                                  GDK_BUTTON1_MOTION_MASK |
-                                                  GDK_BUTTON_RELEASE_MASK,
-                                                  NULL, event->time))
-           return FALSE;
-
-         gtk_grab_add (widget);
-         PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE);
-         column->resized_width = column->width;
-
-         /* block attached dnd signal handler */
-         drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
-         if (drag_data)
-           g_signal_handlers_block_matched (widget,
-                                            G_SIGNAL_MATCH_DATA,
-                                            0, 0, NULL, NULL,
-                                            drag_data);
-
-         tree_view->priv->drag_pos = i;
-         tree_view->priv->x_drag = column->allocation.x + (rtl ? 0 : column->allocation.width);
-
-         if (!gtk_widget_has_focus (widget))
-           gtk_widget_grab_focus (widget);
-
-         return TRUE;
-       }
-    }
-  return FALSE;
-}
-
-/* GtkWidget::button_release_event helper */
-static gboolean
-pspp_sheet_view_button_release_drag_column (GtkWidget      *widget,
-                                         GdkEventButton *event)
-{
-  PsppSheetView *tree_view;
-  GList *l;
-  gboolean rtl;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-  gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
-  gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
-
-  /* Move the button back */
-  g_return_val_if_fail (tree_view->priv->drag_column->button, FALSE);
-
-  g_object_ref (tree_view->priv->drag_column->button);
-  gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
-  gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
-  gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
-  g_object_unref (tree_view->priv->drag_column->button);
-  gtk_widget_queue_resize (widget);
-  if (tree_view->priv->drag_column->resizable)
-    {
-      gdk_window_raise (tree_view->priv->drag_column->window);
-      gdk_window_show (tree_view->priv->drag_column->window);
-    }
-  else
-    gdk_window_hide (tree_view->priv->drag_column->window);
-
-  gtk_widget_grab_focus (tree_view->priv->drag_column->button);
-
-  if (rtl)
-    {
-      if (tree_view->priv->cur_reorder &&
-         tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
-       pspp_sheet_view_move_column_after (tree_view, tree_view->priv->drag_column,
-                                        tree_view->priv->cur_reorder->right_column);
-    }
-  else
-    {
-      if (tree_view->priv->cur_reorder &&
-         tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
-       pspp_sheet_view_move_column_after (tree_view, tree_view->priv->drag_column,
-                                        tree_view->priv->cur_reorder->left_column);
-    }
-  tree_view->priv->drag_column = NULL;
-  gdk_window_hide (tree_view->priv->drag_window);
-
-  for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
-    g_slice_free (PsppSheetViewColumnReorder, l->data);
-  g_list_free (tree_view->priv->column_drag_info);
-  tree_view->priv->column_drag_info = NULL;
-  tree_view->priv->cur_reorder = NULL;
-
-  if (tree_view->priv->drag_highlight_window)
-    gdk_window_hide (tree_view->priv->drag_highlight_window);
-
-  /* Reset our flags */
-  tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
-  PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG);
-
-  return TRUE;
-}
-
-/* GtkWidget::button_release_event helper */
-static gboolean
-pspp_sheet_view_button_release_column_resize (GtkWidget      *widget,
-                                           GdkEventButton *event)
-{
-  PsppSheetView *tree_view;
-  gpointer drag_data;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  tree_view->priv->drag_pos = -1;
-
-  /* unblock attached dnd signal handler */
-  drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
-  if (drag_data)
-    g_signal_handlers_unblock_matched (widget,
-                                      G_SIGNAL_MATCH_DATA,
-                                      0, 0, NULL, NULL,
-                                      drag_data);
-
-  PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE);
-  gtk_grab_remove (widget);
-  gdk_device_ungrab (event->device, event->time);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_button_release_edit (PsppSheetView *tree_view,
-                                     GdkEventButton *event)
-{
-  GtkCellEditable *cell_editable;
-  gchar *path_string;
-  GtkTreePath *path;
-  gint left, right;
-  GtkTreeIter iter;
-  PsppSheetViewColumn *column;
-  GdkRectangle background_area;
-  GdkRectangle cell_area;
-  GdkRectangle area;
-  guint modifiers;
-  guint flags;
-  int node;
-
-  if (event->window != tree_view->priv->bin_window)
-    return FALSE;
-
-  /* Ignore a released button, if that button wasn't depressed */
-  if (tree_view->priv->pressed_button != event->button)
-    return FALSE;
-
-  if (!find_click (tree_view, event->x, event->y, &node, &column, &background_area,
-                   &cell_area))
-    return FALSE;
-
-  /* decide if we edit */
-  path = _pspp_sheet_view_find_path (tree_view, node);
-  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
-  if (event->button != 1 || modifiers)
-    return FALSE;
-
-  gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
-  pspp_sheet_view_column_cell_set_cell_data (column,
-                                             tree_view->priv->model,
-                                             &iter);
-
-  if (!pspp_sheet_view_column_get_quick_edit (column)
-      && _pspp_sheet_view_column_has_editable_cell (column))
-    return FALSE;
-
-  flags = 0;                    /* FIXME: get the right flags */
-  path_string = gtk_tree_path_to_string (path);
-
-  if (!_pspp_sheet_view_column_cell_event (column,
-                                           &cell_editable,
-                                           (GdkEvent *)event,
-                                           path_string,
-                                           &background_area,
-                                           &cell_area, flags))
-    return FALSE;
-
-  if (cell_editable == NULL)
-    return FALSE;
-
-  pspp_sheet_view_real_set_cursor (tree_view, path,
-                                   TRUE, TRUE, 0); /* XXX mode? */
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
-  area = cell_area;
-  _pspp_sheet_view_column_get_neighbor_sizes (
-    column, _pspp_sheet_view_column_get_edited_cell (column), &left, &right);
-
-  area.x += left;
-  area.width -= right + left;
-
-  pspp_sheet_view_real_start_editing (tree_view,
-                                      column,
-                                      path,
-                                      cell_editable,
-                                      &area,
-                                      (GdkEvent *)event,
-                                      flags);
-  g_free (path_string);
-  gtk_tree_path_free (path);
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_button_release (GtkWidget      *widget,
-                             GdkEventButton *event)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  pspp_sheet_view_stop_editing (tree_view, FALSE);
-  if (tree_view->priv->rubber_band_status != RUBBER_BAND_ACTIVE
-      && pspp_sheet_view_button_release_edit (tree_view, event))
-    {
-      if (tree_view->priv->pressed_button == event->button)
-        tree_view->priv->pressed_button = -1;
-
-      tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
-      return TRUE;
-    }
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
-    return pspp_sheet_view_button_release_drag_column (widget, event);
-
-  if (tree_view->priv->rubber_band_status)
-    pspp_sheet_view_stop_rubber_band (tree_view);
-
-  if (tree_view->priv->pressed_button == event->button)
-    tree_view->priv->pressed_button = -1;
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
-    return pspp_sheet_view_button_release_column_resize (widget, event);
-
-  return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_grab_broken (GtkWidget          *widget,
-                          GdkEventGrabBroken *event)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
-    pspp_sheet_view_button_release_drag_column (widget, (GdkEventButton *)event);
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
-    pspp_sheet_view_button_release_column_resize (widget, (GdkEventButton *)event);
-
-  return TRUE;
-}
-
-/* GtkWidget::motion_event function set.
- */
-
-static void
-do_prelight (PsppSheetView *tree_view,
-             int node,
-            /* these are in bin_window coords */
-             gint         x,
-             gint         y)
-{
-  int prev_node = tree_view->priv->prelight_node;
-
-  if (prev_node != node)
-    {
-      tree_view->priv->prelight_node = node;
-
-      if (prev_node >= 0)
-        _pspp_sheet_view_queue_draw_node (tree_view, prev_node, NULL);
-
-      if (node >= 0)
-        _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
-    }
-}
-
-
-static void
-prelight_or_select (PsppSheetView *tree_view,
-                   int node,
-                   /* these are in bin_window coords */
-                   gint         x,
-                   gint         y)
-{
-  PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
-
-  if (tree_view->priv->hover_selection &&
-      (mode == PSPP_SHEET_SELECTION_SINGLE || mode == PSPP_SHEET_SELECTION_BROWSE) &&
-      !(tree_view->priv->edited_column &&
-       tree_view->priv->edited_column->editable_widget))
-    {
-      if (node >= 0)
-       {
-          if (!pspp_sheet_view_node_is_selected (tree_view, node))
-           {
-             GtkTreePath *path;
-
-             path = _pspp_sheet_view_find_path (tree_view, node);
-             pspp_sheet_selection_select_path (tree_view->priv->selection, path);
-              if (pspp_sheet_view_node_is_selected (tree_view, node))
-               {
-                 PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-                 pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, FALSE, 0); /* XXX mode? */
-               }
-             gtk_tree_path_free (path);
-           }
-       }
-
-      else if (mode == PSPP_SHEET_SELECTION_SINGLE)
-       pspp_sheet_selection_unselect_all (tree_view->priv->selection);
-    }
-
-    do_prelight (tree_view, node, x, y);
-}
-
-static void
-ensure_unprelighted (PsppSheetView *tree_view)
-{
-  do_prelight (tree_view,
-              -1,
-              -1000, -1000); /* coords not possibly over an arrow */
-
-  g_assert (tree_view->priv->prelight_node < 0);
-}
-
-static void
-update_prelight (PsppSheetView *tree_view,
-                 gint         x,
-                 gint         y)
-{
-  int new_y;
-  int node;
-
-  if (tree_view->priv->row_count == 0)
-    return;
-
-  if (x == -10000)
-    {
-      ensure_unprelighted (tree_view);
-      return;
-    }
-
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
-  if (new_y < 0)
-    new_y = 0;
-
-  pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
-  if (node >= 0)
-    prelight_or_select (tree_view, node, x, y);
-}
-
-
-
-
-/* Our motion arrow is either a box (in the case of the original spot)
- * or an arrow.  It is expander_size wide.
- */
-/*
- * 11111111111111
- * 01111111111110
- * 00111111111100
- * 00011111111000
- * 00001111110000
- * 00000111100000
- * 00000111100000
- * 00000111100000
- * ~ ~ ~ ~ ~ ~ ~
- * 00000111100000
- * 00000111100000
- * 00000111100000
- * 00001111110000
- * 00011111111000
- * 00111111111100
- * 01111111111110
- * 11111111111111
- */
-
-static void
-pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view)
-{
-}
-
-static gboolean
-pspp_sheet_view_motion_resize_column (GtkWidget      *widget,
-                                   GdkEventMotion *event)
-{
-  gint x;
-  gint new_width;
-  PsppSheetViewColumn *column;
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  column = pspp_sheet_view_get_column (tree_view, tree_view->priv->drag_pos);
-
-  if (event->is_hint || event->window != gtk_widget_get_window (widget))
-    gtk_widget_get_pointer (widget, &x, NULL);
-  else
-    x = event->x;
-
-  if (tree_view->priv->hadjustment)
-    x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
-
-  new_width = pspp_sheet_view_new_column_width (tree_view,
-                                             tree_view->priv->drag_pos, &x);
-  if (x != tree_view->priv->x_drag &&
-      (new_width != column->fixed_width))
-    {
-      column->use_resized_width = TRUE;
-      column->resized_width = new_width;
-#if 0
-      if (column->expand)
-       column->resized_width -= tree_view->priv->last_extra_space_per_column;
-#endif
-      gtk_widget_queue_resize (widget);
-    }
-
-  return FALSE;
-}
-
-
-static void
-pspp_sheet_view_update_current_reorder (PsppSheetView *tree_view)
-{
-  PsppSheetViewColumnReorder *reorder = NULL;
-  GList *list;
-  gint mouse_x;
-
-  gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
-  for (list = tree_view->priv->column_drag_info; list; list = list->next)
-    {
-      reorder = (PsppSheetViewColumnReorder *) list->data;
-      if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
-       break;
-      reorder = NULL;
-    }
-
-  /*  if (reorder && reorder == tree_view->priv->cur_reorder)
-      return;*/
-
-  tree_view->priv->cur_reorder = reorder;
-  pspp_sheet_view_motion_draw_column_motion_arrow (tree_view);
-}
-
-static void
-pspp_sheet_view_vertical_autoscroll (PsppSheetView *tree_view)
-{
-  GdkRectangle visible_rect;
-  gint y;
-  gint offset;
-  gfloat value;
-
-  gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
-  y += tree_view->priv->dy;
-
-  pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
-  /* see if we are near the edge. */
-  offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
-  if (offset > 0)
-    {
-      offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
-      if (offset < 0)
-       return;
-    }
-
-  value = CLAMP (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0,
-                gtk_adjustment_get_upper (tree_view->priv->vadjustment) - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
-  gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
-}
-
-static gboolean
-pspp_sheet_view_horizontal_autoscroll (PsppSheetView *tree_view)
-{
-  GdkRectangle visible_rect;
-  gint x;
-  gint offset;
-  gfloat value;
-
-  gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
-
-  pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
-  /* See if we are near the edge. */
-  offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
-  if (offset > 0)
-    {
-      offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
-      if (offset < 0)
-       return TRUE;
-    }
-  offset = offset/3;
-
-  value = CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset,
-                0.0, gtk_adjustment_get_upper (tree_view->priv->hadjustment) - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
-  gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
-
-  return TRUE;
-
-}
-
-static gboolean
-pspp_sheet_view_motion_drag_column (GtkWidget      *widget,
-                                 GdkEventMotion *event)
-{
-  PsppSheetView *tree_view = (PsppSheetView *) widget;
-  PsppSheetViewColumn *column = tree_view->priv->drag_column;
-  gint x, y;
-  GtkAllocation allocation;
-
-  /* Sanity Check */
-  if ((column == NULL) ||
-      (event->window != tree_view->priv->drag_window))
-    return FALSE;
-
-  /* Handle moving the header */
-  gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
-  gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-  x = CLAMP (x + (gint)event->x - column->drag_x, 0,
-            MAX (tree_view->priv->width, allocation.width) - column->allocation.width);
-  gdk_window_move (tree_view->priv->drag_window, x, y);
-
-  /* autoscroll, if needed */
-  pspp_sheet_view_horizontal_autoscroll (tree_view);
-  /* Update the current reorder position and arrow; */
-  pspp_sheet_view_update_current_reorder (tree_view);
-
-  return TRUE;
-}
-
-static void
-pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view)
-{
-  remove_scroll_timeout (tree_view);
-  gtk_grab_remove (GTK_WIDGET (tree_view));
-
-  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
-    {
-      GtkTreePath *tmp_path;
-
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
-      /* The anchor path should be set to the start path */
-      tmp_path = _pspp_sheet_view_find_path (tree_view,
-                                          tree_view->priv->rubber_band_start_node);
-
-      if (tree_view->priv->anchor)
-       gtk_tree_row_reference_free (tree_view->priv->anchor);
-
-      tree_view->priv->anchor =
-       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
-                                         tree_view->priv->model,
-                                         tmp_path);
-
-      gtk_tree_path_free (tmp_path);
-
-      /* ... and the cursor to the end path */
-      tmp_path = _pspp_sheet_view_find_path (tree_view,
-                                          tree_view->priv->rubber_band_end_node);
-      pspp_sheet_view_real_set_cursor (PSPP_SHEET_VIEW (tree_view), tmp_path, FALSE, FALSE, 0); /* XXX mode? */
-      gtk_tree_path_free (tmp_path);
-
-      _pspp_sheet_selection_emit_changed (tree_view->priv->selection);
-    }
-
-  /* Clear status variables */
-  tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
-  tree_view->priv->rubber_band_shift = 0;
-  tree_view->priv->rubber_band_ctrl = 0;
-
-  tree_view->priv->rubber_band_start_node = -1;
-  tree_view->priv->rubber_band_end_node = -1;
-}
-
-static void
-pspp_sheet_view_update_rubber_band_selection_range (PsppSheetView *tree_view,
-                                                int start_node,
-                                                int end_node,
-                                                gboolean     select,
-                                                gboolean     skip_start,
-                                                gboolean     skip_end)
-{
-  if (start_node == end_node)
-    return;
-
-  /* We skip the first node and jump inside the loop */
-  if (skip_start)
-    goto skip_first;
-
-  do
-    {
-      /* Small optimization by assuming insensitive nodes are never
-       * selected.
-       */
-      if (select)
-        {
-         if (tree_view->priv->rubber_band_shift)
-            pspp_sheet_view_node_select (tree_view, start_node);
-         else if (tree_view->priv->rubber_band_ctrl)
-           {
-             /* Toggle the selection state */
-              if (pspp_sheet_view_node_is_selected (tree_view, start_node))
-                pspp_sheet_view_node_unselect (tree_view, start_node);
-             else
-                pspp_sheet_view_node_select (tree_view, start_node);
-           }
-         else
-            pspp_sheet_view_node_select (tree_view, start_node);
-       }
-      else
-        {
-         /* Mirror the above */
-         if (tree_view->priv->rubber_band_shift)
-                pspp_sheet_view_node_unselect (tree_view, start_node);
-         else if (tree_view->priv->rubber_band_ctrl)
-           {
-             /* Toggle the selection state */
-              if (pspp_sheet_view_node_is_selected (tree_view, start_node))
-                pspp_sheet_view_node_unselect (tree_view, start_node);
-             else
-                pspp_sheet_view_node_select (tree_view, start_node);
-           }
-         else
-            pspp_sheet_view_node_unselect (tree_view, start_node);
-       }
-
-      _pspp_sheet_view_queue_draw_node (tree_view, start_node, NULL);
-
-      if (start_node == end_node)
-       break;
-
-skip_first:
-
-      start_node = pspp_sheet_view_node_next (tree_view, start_node);
-
-      if (start_node < 0)
-        /* Ran out of tree */
-        break;
-
-      if (skip_end && start_node == end_node)
-       break;
-    }
-  while (TRUE);
-}
-
-static gint
-pspp_sheet_view_node_find_offset (PsppSheetView *tree_view,
-                                  int node)
-{
-  return node * tree_view->priv->fixed_height;
-}
-
-static gint
-pspp_sheet_view_find_offset (PsppSheetView *tree_view,
-                             gint height,
-                             int *new_node)
-{
-  int fixed_height = tree_view->priv->fixed_height;
-  if (fixed_height <= 0
-      || height < 0
-      || height >= tree_view->priv->row_count * fixed_height)
-    {
-      *new_node = -1;
-      return 0;
-    }
-  else
-    {
-      *new_node = height / fixed_height;
-      return height % fixed_height;
-    }
-}
-
-static void
-pspp_sheet_view_update_rubber_band_selection (PsppSheetView *tree_view)
-{
-  int start_node;
-  int end_node;
-
-  pspp_sheet_view_find_offset (tree_view, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_node);
-  pspp_sheet_view_find_offset (tree_view, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_node);
-
-  /* Handle the start area first */
-  if (tree_view->priv->rubber_band_start_node < 0)
-    {
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      start_node,
-                                                      end_node,
-                                                      TRUE,
-                                                      FALSE,
-                                                      FALSE);
-    }
-  else if (start_node < tree_view->priv->rubber_band_start_node)
-    {
-      /* New node is above the old one; selection became bigger */
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      start_node,
-                                                      tree_view->priv->rubber_band_start_node,
-                                                      TRUE,
-                                                      FALSE,
-                                                      TRUE);
-    }
-  else if (start_node > tree_view->priv->rubber_band_start_node)
-    {
-      /* New node is below the old one; selection became smaller */
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      tree_view->priv->rubber_band_start_node,
-                                                      start_node,
-                                                      FALSE,
-                                                      FALSE,
-                                                      TRUE);
-    }
-
-  tree_view->priv->rubber_band_start_node = start_node;
-
-  /* Next, handle the end area */
-  if (tree_view->priv->rubber_band_end_node < 0)
-    {
-      /* In the event this happens, start_node was also -1; this case is
-       * handled above.
-       */
-    }
-  else if (end_node < 0)
-    {
-      /* Find the last node in the tree */
-      pspp_sheet_view_find_offset (tree_view, tree_view->priv->height - 1,
-                              &end_node);
-
-      /* Selection reached end of the tree */
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      tree_view->priv->rubber_band_end_node,
-                                                      end_node,
-                                                      TRUE,
-                                                      TRUE,
-                                                      FALSE);
-    }
-  else if (end_node > tree_view->priv->rubber_band_end_node)
-    {
-      /* New node is below the old one; selection became bigger */
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      tree_view->priv->rubber_band_end_node,
-                                                      end_node,
-                                                      TRUE,
-                                                      TRUE,
-                                                      FALSE);
-    }
-  else if (end_node < tree_view->priv->rubber_band_end_node)
-    {
-      /* New node is above the old one; selection became smaller */
-      pspp_sheet_view_update_rubber_band_selection_range (tree_view,
-                                                      end_node,
-                                                      tree_view->priv->rubber_band_end_node,
-                                                      FALSE,
-                                                      TRUE,
-                                                      FALSE);
-    }
-
-  tree_view->priv->rubber_band_end_node = end_node;
-}
-
-#define GDK_RECTANGLE_PTR(X) ((GdkRectangle *)(X))
-
-static void
-pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
-{
-  gint x, y;
-  cairo_rectangle_int_t old_area;
-  cairo_rectangle_int_t new_area;
-  cairo_rectangle_int_t common;
-  cairo_region_t *invalid_region;
-  PsppSheetViewColumn *column;
-
-  old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
-  old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
-  old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
-  old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
-
-  gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
-
-  x = MAX (x, 0);
-  y = MAX (y, 0) + tree_view->priv->dy;
-
-  new_area.x = MIN (tree_view->priv->press_start_x, x);
-  new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
-  new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
-  new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
-
-  invalid_region = cairo_region_create_rectangle (&old_area);
-  cairo_region_union_rectangle (invalid_region, &new_area);
-
-  gdk_rectangle_intersect (GDK_RECTANGLE_PTR (&old_area),
-                          GDK_RECTANGLE_PTR (&new_area), GDK_RECTANGLE_PTR (&common));
-  if (common.width > 2 && common.height > 2)
-    {
-      cairo_region_t *common_region;
-
-      /* make sure the border is invalidated */
-      common.x += 1;
-      common.y += 1;
-      common.width -= 2;
-      common.height -= 2;
-
-      common_region = cairo_region_create_rectangle (&common);
-
-      cairo_region_subtract (invalid_region, common_region);
-      cairo_region_destroy (common_region);
-    }
-
-#if GTK_MAJOR_VERSION == 3
-  gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
-#else
-  {
-    cairo_rectangle_int_t extents;
-    GdkRegion *ereg;
-    cairo_region_get_extents (invalid_region, &extents);
-    ereg = gdk_region_rectangle (GDK_RECTANGLE_PTR (&extents));
-    gdk_window_invalidate_region (tree_view->priv->bin_window, ereg, TRUE);
-    gdk_region_destroy (ereg);
-  }
-#endif
-
-  cairo_region_destroy (invalid_region);
-
-  tree_view->priv->rubber_band_x = x;
-  tree_view->priv->rubber_band_y = y;
-  pspp_sheet_view_get_path_at_pos (tree_view, x, y, NULL, &column, NULL, NULL);
-
-  pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
-  pspp_sheet_selection_select_column_range (tree_view->priv->selection,
-                                            tree_view->priv->anchor_column,
-                                            column);
-
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
-  pspp_sheet_view_update_rubber_band_selection (tree_view);
-}
-
-
-
-static gboolean
-pspp_sheet_view_motion_bin_window (GtkWidget      *widget,
-                                GdkEventMotion *event)
-{
-  PsppSheetView *tree_view;
-  int node;
-  gint new_y;
-
-  tree_view = (PsppSheetView *) widget;
-
-  if (tree_view->priv->row_count == 0)
-    return FALSE;
-
-  if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
-    {
-      GdkRectangle background_area, cell_area;
-      PsppSheetViewColumn *column;
-
-      if (find_click (tree_view, event->x, event->y, &node, &column,
-                      &background_area, &cell_area)
-          && tree_view->priv->focus_column == column
-          && tree_view->priv->press_start_node == node)
-        return FALSE;
-
-      gtk_grab_add (GTK_WIDGET (tree_view));
-      pspp_sheet_view_update_rubber_band (tree_view);
-
-      tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
-    }
-  else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
-    {
-      pspp_sheet_view_update_rubber_band (tree_view);
-
-      add_scroll_timeout (tree_view);
-    }
-
-  /* only check for an initiated drag when a button is pressed */
-  if (tree_view->priv->pressed_button >= 0
-      && !tree_view->priv->rubber_band_status)
-    pspp_sheet_view_maybe_begin_dragging_row (tree_view, event);
-
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
-  if (new_y < 0)
-    new_y = 0;
-
-  pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
-  tree_view->priv->event_last_x = event->x;
-  tree_view->priv->event_last_y = event->y;
-
-  prelight_or_select (tree_view, node, event->x, event->y);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_motion (GtkWidget      *widget,
-                     GdkEventMotion *event)
-{
-  PsppSheetView *tree_view;
-
-  tree_view = (PsppSheetView *) widget;
-
-  /* Resizing a column */
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
-    return pspp_sheet_view_motion_resize_column (widget, event);
-
-  /* Drag column */
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
-    return pspp_sheet_view_motion_drag_column (widget, event);
-
-  /* Sanity check it */
-  if (event->window == tree_view->priv->bin_window)
-    return pspp_sheet_view_motion_bin_window (widget, event);
-
-  return FALSE;
-}
-
-/* Invalidate the focus rectangle near the edge of the bin_window; used when
- * the tree is empty.
- */
-static void
-invalidate_empty_focus (PsppSheetView *tree_view)
-{
-  GdkRectangle area;
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  area.x = 0;
-  area.y = 0;
-  area.width = gdk_window_get_width (tree_view->priv->bin_window);
-  area.height = gdk_window_get_height (tree_view->priv->bin_window);
-  gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
-}
-
-/* Draws a focus rectangle near the edge of the bin_window; used when the tree
- * is empty.
- */
-static void
-draw_empty_focus (PsppSheetView *tree_view)
-{
-  GtkWidget *widget = GTK_WIDGET (tree_view);
-  gint w, h;
-  cairo_t *cr = gdk_cairo_create (tree_view->priv->bin_window);
-
-  if (!gtk_widget_has_focus (widget))
-    return;
-
-  w = gdk_window_get_width (tree_view->priv->bin_window);
-  h = gdk_window_get_height (tree_view->priv->bin_window);
-
-  w -= 2;
-  h -= 2;
-
-  if (w > 0 && h > 0)
-    gtk_paint_focus (gtk_widget_get_style (widget),
-                    cr,
-                    gtk_widget_get_state (widget),
-                    widget,
-                    NULL,
-                    1, 1, w, h);
-  cairo_destroy (cr);
-}
-
-static void
-pspp_sheet_view_draw_vertical_grid_lines (PsppSheetView    *tree_view,
-                                         cairo_t *cr,
-                                         gint n_visible_columns,
-                                         gint min_y,
-                                         gint max_y)
-{
-  GList *list = tree_view->priv->columns;
-  gint x = 0;
-
-  if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
-      && tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_BOTH)
-    return;
-
-  /* Only draw the lines for visible rows and columns */
-  gboolean rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-       list;
-       list = (rtl ? list->prev : list->next))
-    {
-      PsppSheetViewColumn *column = list->data;
-
-      if (! column->visible)
-       continue;
-
-      if (!rtl)
-       x += column->width;
-
-      cairo_set_line_width (cr, 1.0);
-      cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-      cairo_move_to (cr, x + 0.5, min_y);
-      cairo_line_to (cr, x + 0.5, max_y - min_y - 0.5);
-      cairo_stroke (cr);
-
-      if (rtl)
-       x += column->width;
-    }
-}
-
-/* Warning: Very scary function.
- * Modify at your own risk
- *
- * KEEP IN SYNC WITH pspp_sheet_view_create_row_drag_icon()!
- * FIXME: It's not...
- */
-static void
-pspp_sheet_view_draw_bin (GtkWidget      *widget,
-                         cairo_t *cr)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GtkTreePath *path;
-  GList *list;
-  int node;
-  int cursor = -1;
-  int drag_highlight = -1;
-  GtkTreeIter iter;
-  gint new_y;
-  gint y_offset, cell_offset;
-  gint max_height;
-  GdkRectangle background_area;
-  GdkRectangle cell_area;
-  guint flags;
-  gint bin_window_width;
-  gint bin_window_height;
-  GtkTreePath *cursor_path;
-  GtkTreePath *drag_dest_path;
-  GList *first_column, *last_column;
-  gint vertical_separator;
-  gint horizontal_separator;
-  gint focus_line_width;
-  gboolean allow_rules;
-  gboolean rtl;
-  gint n_visible_columns;
-  gint grid_line_width;
-  gboolean row_ending_details;
-  gboolean draw_vgrid_lines, draw_hgrid_lines;
-  gint min_y, max_y;
-  GtkStyleContext *context;
-  context = gtk_widget_get_style_context (widget);
-
-  GdkRectangle Zarea;
-  GtkAllocation allocation;
-  gtk_widget_get_allocation (widget, &allocation);
-
-  GdkRectangle exposed_rect;
-  gdk_cairo_get_clip_rectangle (cr, &exposed_rect);
-
-  Zarea.x =      0;
-  Zarea.y =      0;
-  Zarea.height = allocation.height;
-
-  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
-  gtk_widget_style_get (widget,
-                       "horizontal-separator", &horizontal_separator,
-                       "vertical-separator", &vertical_separator,
-                       "allow-rules", &allow_rules,
-                       "focus-line-width", &focus_line_width,
-                       "row-ending-details", &row_ending_details,
-                       NULL);
-
-  if (tree_view->priv->row_count == 0)
-    {
-      draw_empty_focus (tree_view);
-      return;
-    }
-
-  validate_visible_area (tree_view);
-
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, Zarea.y);
-
-  if (new_y < 0)
-    new_y = 0;
-  y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, &node);
-  bin_window_width =
-    gdk_window_get_width (tree_view->priv->bin_window);
-
-  bin_window_height =
-    gdk_window_get_height (tree_view->priv->bin_window);
-
-
-  if (tree_view->priv->height < bin_window_height)
-    {
-      gtk_paint_flat_box (gtk_widget_get_style (widget),
-                          cr,
-                          gtk_widget_get_state (widget),
-                          GTK_SHADOW_NONE,
-                          widget,
-                          "cell_even",
-                          0, tree_view->priv->height,
-                          bin_window_width,
-                          bin_window_height - tree_view->priv->height);
-    }
-
-  if (node < 0)
-    return;
-
-  /* find the path for the node */
-  path = _pspp_sheet_view_find_path ((PsppSheetView *)widget, node);
-  gtk_tree_model_get_iter (tree_view->priv->model,
-                          &iter,
-                          path);
-  gtk_tree_path_free (path);
-
-  cursor_path = NULL;
-  drag_dest_path = NULL;
-
-  if (tree_view->priv->cursor)
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-  if (cursor_path)
-    _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor);
-
-  if (tree_view->priv->drag_dest_row)
-    drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
-
-  if (drag_dest_path)
-    _pspp_sheet_view_find_node (tree_view, drag_dest_path,
-                                &drag_highlight);
-
-  draw_vgrid_lines =
-    tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
-    || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-  draw_hgrid_lines =
-    tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
-    || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-
-  if (draw_vgrid_lines || draw_hgrid_lines)
-    gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
-
-  n_visible_columns = 0;
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      if (! PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
-       continue;
-      n_visible_columns ++;
-    }
-
-  /* Find the last column */
-  for (last_column = g_list_last (tree_view->priv->columns);
-       last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
-       last_column = last_column->prev)
-    ;
-
-  /* and the first */
-  for (first_column = g_list_first (tree_view->priv->columns);
-       first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
-       first_column = first_column->next)
-    ;
-
-  /* Actually process the expose event.  To do this, we want to
-   * start at the first node of the event, and walk the tree in
-   * order, drawing each successive node.
-   */
-
-  min_y = y_offset;
-  do
-    {
-      gboolean parity;
-      gboolean is_first = FALSE;
-      gboolean is_last = FALSE;
-      gboolean done = FALSE;
-      gboolean selected;
-
-      max_height = ROW_HEIGHT (tree_view);
-
-      cell_offset = 0;
-
-      background_area.y = y_offset + Zarea.y;
-      background_area.height = max_height;
-      max_y = background_area.y + max_height;
-
-      flags = 0;
-
-      if (node == tree_view->priv->prelight_node)
-       flags |= GTK_CELL_RENDERER_PRELIT;
-
-      selected = pspp_sheet_view_node_is_selected (tree_view, node);
-
-      parity = node % 2;
-
-      for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-          list;
-          list = (rtl ? list->prev : list->next))
-       {
-         PsppSheetViewColumn *column = list->data;
-         const gchar *detail = NULL;
-          gboolean selected_column;
-         GtkStateType state;
-
-         if (!column->visible)
-            continue;
-
-          if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-            selected_column = column->selected && column->selectable;
-          else
-            selected_column = TRUE;
-
-          if (selected && selected_column)
-            flags |= GTK_CELL_RENDERER_SELECTED;
-          else
-            flags &= ~GTK_CELL_RENDERER_SELECTED;
-
-          if (column->show_sort_indicator)
-           flags |= GTK_CELL_RENDERER_SORTED;
-          else
-            flags &= ~GTK_CELL_RENDERER_SORTED;
-
-         if (cursor == node)
-            flags |= GTK_CELL_RENDERER_FOCUSED;
-          else
-            flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
-         background_area.x = cell_offset;
-         background_area.width = column->width;
-
-          cell_area = background_area;
-          cell_area.y += vertical_separator / 2;
-          cell_area.x += horizontal_separator / 2;
-          cell_area.height -= vertical_separator;
-         cell_area.width -= horizontal_separator;
-
-         if (draw_vgrid_lines)
-           {
-             if (list == first_column)
-               {
-                 cell_area.width -= grid_line_width / 2;
-               }
-             else if (list == last_column)
-               {
-                 cell_area.x += grid_line_width / 2;
-                 cell_area.width -= grid_line_width / 2;
-               }
-             else
-               {
-                 cell_area.x += grid_line_width / 2;
-                 cell_area.width -= grid_line_width;
-               }
-           }
-
-         if (draw_hgrid_lines)
-           {
-             cell_area.y += grid_line_width / 2;
-             cell_area.height -= grid_line_width;
-           }
-
-         if (!gdk_rectangle_intersect (&background_area, &exposed_rect, NULL))
-           {
-             cell_offset += column->width;
-             continue;
-           }
-
-
-         pspp_sheet_view_column_cell_set_cell_data (column,
-                                                     tree_view->priv->model,
-                                                     &iter);
-
-          /* Select the detail for drawing the cell.  relevant
-           * factors are parity, sortedness, and whether to
-           * display rules.
-           */
-          if (allow_rules && tree_view->priv->has_rules)
-            {
-              if ((flags & GTK_CELL_RENDERER_SORTED) &&
-                 n_visible_columns >= 3)
-                {
-                  if (parity)
-                    detail = "cell_odd_ruled_sorted";
-                  else
-                    detail = "cell_even_ruled_sorted";
-                }
-              else
-                {
-                  if (parity)
-                    detail = "cell_odd_ruled";
-                  else
-                    detail = "cell_even_ruled";
-                }
-            }
-          else
-            {
-              if ((flags & GTK_CELL_RENDERER_SORTED) &&
-                 n_visible_columns >= 3)
-                {
-                  if (parity)
-                    detail = "cell_odd_sorted";
-                  else
-                    detail = "cell_even_sorted";
-                }
-              else
-                {
-                  if (parity)
-                    detail = "cell_odd";
-                  else
-                    detail = "cell_even";
-                }
-            }
-
-          g_assert (detail);
-
-         gtk_style_context_save (context);
-         state = gtk_cell_renderer_get_state (NULL, widget, flags);
-          gtk_style_context_set_state (context, state);
-          gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
-
-         /* Draw background */
-          gtk_render_background (context, cr,
-                                 background_area.x,
-                                 background_area.y,
-                                 background_area.width,
-                                 background_area.height);
-
-          /* Draw frame */
-          gtk_render_frame (context, cr,
-                            background_area.x,
-                            background_area.y,
-                            background_area.width,
-                            background_area.height);
-
-         if (draw_hgrid_lines)
-           {
-             cairo_set_line_width (cr, 1.0);
-             cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-
-             if (background_area.y >= 0)
-               {
-                 cairo_move_to (cr, background_area.x, background_area.y - 0.5);
-                 cairo_line_to (cr, background_area.x + background_area.width,
-                                background_area.y - 0.5);
-               }
-
-             if (y_offset + max_height <= Zarea.height - 0.5)
-               {
-                 cairo_move_to (cr, background_area.x, background_area.y + max_height - 0.5);
-                 cairo_line_to (cr, background_area.x + background_area.width,
-                                background_area.y + max_height - 0.5);
-               }
-             cairo_stroke (cr);
-           }
-
-          _pspp_sheet_view_column_cell_render (column,
-                                               cr,
-                                               &background_area,
-                                               &cell_area,
-                                               flags);
-
-
-         cell_offset += column->width;
-         gtk_style_context_restore (context);
-       }
-
-      if (node == drag_highlight)
-        {
-          /* Draw indicator for the drop
-           */
-          gint highlight_y = -1;
-         int node = -1;
-         gint width;
-
-          switch (tree_view->priv->drag_dest_pos)
-            {
-            case PSPP_SHEET_VIEW_DROP_BEFORE:
-              highlight_y = background_area.y - 1;
-             if (highlight_y < 0)
-                     highlight_y = 0;
-              break;
-
-            case PSPP_SHEET_VIEW_DROP_AFTER:
-              highlight_y = background_area.y + background_area.height - 1;
-              break;
-
-            case PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE:
-            case PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER:
-             _pspp_sheet_view_find_node (tree_view, drag_dest_path, &node);
-
-             if (node < 0)
-               break;
-             width = gdk_window_get_width (tree_view->priv->bin_window);
-
-             if (row_ending_details)
-               gtk_paint_focus (gtk_widget_get_style (widget),
-                                cr,
-                                gtk_widget_get_state (widget),
-                                widget,
-                                (is_first
-                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
-                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
-                                0, BACKGROUND_FIRST_PIXEL (tree_view, node)
-                                - focus_line_width / 2,
-                                width, ROW_HEIGHT (tree_view)
-                              - focus_line_width + 1);
-             else
-               gtk_paint_focus (gtk_widget_get_style (widget),
-                                cr,
-                                gtk_widget_get_state (widget),
-                                widget,
-                                "treeview-drop-indicator",
-                                0, BACKGROUND_FIRST_PIXEL (tree_view, node)
-                                - focus_line_width / 2,
-                                width, ROW_HEIGHT (tree_view)
-                                - focus_line_width + 1);
-              break;
-            }
-
-        }
-
-      y_offset += max_height;
-
-      do
-        {
-          node = pspp_sheet_view_node_next (tree_view, node);
-          if (node >= 0)
-            {
-              gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
-              done = TRUE;
-
-              /* Sanity Check! */
-              TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
-            }
-          else
-            goto done;
-        }
-      while (!done);
-    }
-  while (y_offset < Zarea.height);
-
-done:
-  pspp_sheet_view_draw_vertical_grid_lines (tree_view, cr, n_visible_columns,
-                                   min_y, max_y);
-
-  if (cursor_path)
-    gtk_tree_path_free (cursor_path);
-
-  if (drag_dest_path)
-    gtk_tree_path_free (drag_dest_path);
-
-  return;
-}
-
-
-static gboolean
-pspp_sheet_view_draw (GtkWidget      *widget,
-                     cairo_t *cr)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GtkStyleContext *context;
-
-  context = gtk_widget_get_style_context (widget);
-
-  if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
-    {
-      GList *tmp_list;
-
-      cairo_save (cr);
-      gtk_cairo_transform_to_window(cr,widget,tree_view->priv->bin_window);
-      pspp_sheet_view_draw_bin (widget, cr);
-      cairo_restore (cr);
-
-      /* We can't just chain up to Container::expose as it will try to send the
-       * event to the headers, so we handle propagating it to our children
-       * (eg. widgets being edited) ourselves.
-       */
-      tmp_list = tree_view->priv->children;
-      while (tmp_list)
-       {
-         PsppSheetViewChild *child = tmp_list->data;
-         tmp_list = tmp_list->next;
-
-         gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
-        }
-    }
-  else
-    {
-      gtk_render_background (context, cr,
-                             0, 0,
-                             gtk_widget_get_allocated_width (widget),
-                             gtk_widget_get_allocated_height (widget));
-    }
-
-  gtk_style_context_save (context);
-  gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VIEW);
-
-  if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
-    {
-      gint n_visible_columns;
-      GList *list;
-
-      for (list = tree_view->priv->columns; list != NULL; list = list->next)
-       {
-         PsppSheetViewColumn *column = list->data;
-
-         if (column == tree_view->priv->drag_column || !column->visible)
-           continue;
-
-          if (span_intersects (column->allocation.x, column->allocation.width,
-                               (int) gtk_adjustment_get_value (tree_view->priv->hadjustment),
-                               (int) gtk_widget_get_allocated_width (widget))
-              && column->button != NULL)
-            gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
-                                         column->button, cr);
-       }
-
-      n_visible_columns = 0;
-      for (list = tree_view->priv->columns; list; list = list->next)
-        {
-          if (! PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
-            continue;
-          n_visible_columns ++;
-        }
-      cairo_save (cr);
-      gtk_cairo_transform_to_window(cr,widget,tree_view->priv->header_window);
-      pspp_sheet_view_draw_vertical_grid_lines (tree_view,
-                                               cr,
-                                               n_visible_columns,
-                                               0,
-                                               TREE_VIEW_HEADER_HEIGHT (tree_view));
-      cairo_restore (cr);
-    }
-  if (tree_view->priv->drag_window &&
-      gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
-    {
-      gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
-                                   tree_view->priv->drag_column->button,
-                                   cr);
-    }
-
-  gtk_style_context_restore (context);
-  return FALSE;
-}
-
-enum
-{
-  DROP_HOME,
-  DROP_RIGHT,
-  DROP_LEFT,
-  DROP_END
-};
-
-/* returns 0x1 when no column has been found -- yes it's hackish */
-static PsppSheetViewColumn *
-pspp_sheet_view_get_drop_column (PsppSheetView       *tree_view,
-                              PsppSheetViewColumn *column,
-                              gint               drop_position)
-{
-  PsppSheetViewColumn *left_column = NULL;
-  PsppSheetViewColumn *cur_column = NULL;
-  GList *tmp_list;
-
-  if (!column->reorderable)
-    return (PsppSheetViewColumn *)0x1;
-
-  switch (drop_position)
-    {
-      case DROP_HOME:
-       /* find first column where we can drop */
-       tmp_list = tree_view->priv->columns;
-       if (column == PSPP_SHEET_VIEW_COLUMN (tmp_list->data))
-         return (PsppSheetViewColumn *)0x1;
-
-       while (tmp_list)
-         {
-           g_assert (tmp_list);
-
-           cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-           tmp_list = tmp_list->next;
-
-           if (left_column && left_column->visible == FALSE)
-             continue;
-
-           if (!tree_view->priv->column_drop_func)
-             return left_column;
-
-           if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
-             {
-               left_column = cur_column;
-               continue;
-             }
-
-           return left_column;
-         }
-
-       if (!tree_view->priv->column_drop_func)
-         return left_column;
-
-       if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
-         return left_column;
-       else
-         return (PsppSheetViewColumn *)0x1;
-       break;
-
-      case DROP_RIGHT:
-       /* find first column after column where we can drop */
-       tmp_list = tree_view->priv->columns;
-
-       for (; tmp_list; tmp_list = tmp_list->next)
-         if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data) == column)
-           break;
-
-       if (!tmp_list || !tmp_list->next)
-         return (PsppSheetViewColumn *)0x1;
-
-       tmp_list = tmp_list->next;
-       left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-       tmp_list = tmp_list->next;
-
-       while (tmp_list)
-         {
-           g_assert (tmp_list);
-
-           cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-           tmp_list = tmp_list->next;
-
-           if (left_column && left_column->visible == FALSE)
-             {
-               left_column = cur_column;
-               if (tmp_list)
-                 tmp_list = tmp_list->next;
-               continue;
-             }
-
-           if (!tree_view->priv->column_drop_func)
-             return left_column;
-
-           if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
-             {
-               left_column = cur_column;
-               continue;
-             }
-
-           return left_column;
-         }
-
-       if (!tree_view->priv->column_drop_func)
-         return left_column;
-
-       if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
-         return left_column;
-       else
-         return (PsppSheetViewColumn *)0x1;
-       break;
-
-      case DROP_LEFT:
-       /* find first column before column where we can drop */
-       tmp_list = tree_view->priv->columns;
-
-       for (; tmp_list; tmp_list = tmp_list->next)
-         if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data) == column)
-           break;
-
-       if (!tmp_list || !tmp_list->prev)
-         return (PsppSheetViewColumn *)0x1;
-
-       tmp_list = tmp_list->prev;
-       cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-       tmp_list = tmp_list->prev;
-
-       while (tmp_list)
-         {
-           g_assert (tmp_list);
-
-           left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-
-           if (left_column && !left_column->visible)
-             {
-               /*if (!tmp_list->prev)
-                 return (PsppSheetViewColumn *)0x1;
-                 */
-/*
-               cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->prev->data);
-               tmp_list = tmp_list->prev->prev;
-               continue;*/
-
-               cur_column = left_column;
-               if (tmp_list)
-                 tmp_list = tmp_list->prev;
-               continue;
-             }
-
-           if (!tree_view->priv->column_drop_func)
-             return left_column;
-
-           if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
-             return left_column;
-
-           cur_column = left_column;
-           tmp_list = tmp_list->prev;
-         }
-
-       if (!tree_view->priv->column_drop_func)
-         return NULL;
-
-       if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
-         return NULL;
-       else
-         return (PsppSheetViewColumn *)0x1;
-       break;
-
-      case DROP_END:
-       /* same as DROP_HOME case, but doing it backwards */
-       tmp_list = g_list_last (tree_view->priv->columns);
-       cur_column = NULL;
-
-       if (column == PSPP_SHEET_VIEW_COLUMN (tmp_list->data))
-         return (PsppSheetViewColumn *)0x1;
-
-       while (tmp_list)
-         {
-           g_assert (tmp_list);
-
-           left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-
-           if (left_column && !left_column->visible)
-             {
-               cur_column = left_column;
-               tmp_list = tmp_list->prev;
-             }
-
-           if (!tree_view->priv->column_drop_func)
-             return left_column;
-
-           if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
-             return left_column;
-
-           cur_column = left_column;
-           tmp_list = tmp_list->prev;
-         }
-
-       if (!tree_view->priv->column_drop_func)
-         return NULL;
-
-       if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
-         return NULL;
-       else
-         return (PsppSheetViewColumn *)0x1;
-       break;
-    }
-
-  return (PsppSheetViewColumn *)0x1;
-}
-
-static gboolean
-pspp_sheet_view_key_press (GtkWidget   *widget,
-                        GdkEventKey *event)
-{
-  PsppSheetView *tree_view = (PsppSheetView *) widget;
-
-  if (tree_view->priv->rubber_band_status)
-    {
-      if (event->keyval == GDK_Escape)
-       pspp_sheet_view_stop_rubber_band (tree_view);
-
-      return TRUE;
-    }
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
-    {
-      if (event->keyval == GDK_Escape)
-       {
-         tree_view->priv->cur_reorder = NULL;
-         pspp_sheet_view_button_release_drag_column (widget, NULL);
-       }
-      return TRUE;
-    }
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
-    {
-      GList *focus_column;
-      gboolean rtl;
-
-      rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-      for (focus_column = tree_view->priv->columns;
-           focus_column;
-           focus_column = focus_column->next)
-        {
-          PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
-          if (column->button && gtk_widget_has_focus (column->button))
-            break;
-        }
-
-      if (focus_column &&
-          (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
-          (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-           || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
-        {
-          PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
-          if (!column->resizable)
-            {
-              gtk_widget_error_bell (widget);
-              return TRUE;
-            }
-
-          if (event->keyval == (rtl ? GDK_Right : GDK_Left)
-              || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
-            {
-              gint old_width = column->resized_width;
-
-              column->resized_width = MAX (column->resized_width,
-                                           column->width);
-              column->resized_width -= 2;
-              if (column->resized_width < 0)
-                column->resized_width = 0;
-
-              if (column->min_width == -1)
-                column->resized_width = MAX (column->button_request,
-                                             column->resized_width);
-              else
-                column->resized_width = MAX (column->min_width,
-                                             column->resized_width);
-
-              if (column->max_width != -1)
-                column->resized_width = MIN (column->resized_width,
-                                             column->max_width);
-
-              column->use_resized_width = TRUE;
-
-              if (column->resized_width != old_width)
-                gtk_widget_queue_resize (widget);
-              else
-                gtk_widget_error_bell (widget);
-            }
-          else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
-                   || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
-            {
-              gint old_width = column->resized_width;
-
-              column->resized_width = MAX (column->resized_width,
-                                           column->width);
-              column->resized_width += 2;
-
-              if (column->max_width != -1)
-                column->resized_width = MIN (column->resized_width,
-                                             column->max_width);
-
-              column->use_resized_width = TRUE;
-
-              if (column->resized_width != old_width)
-                gtk_widget_queue_resize (widget);
-              else
-                gtk_widget_error_bell (widget);
-            }
-
-          return TRUE;
-        }
-
-      if (focus_column &&
-          (event->state & GDK_MOD1_MASK) &&
-          (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-           || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
-           || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
-           || event->keyval == GDK_End || event->keyval == GDK_KP_End))
-        {
-          PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
-          if (event->keyval == (rtl ? GDK_Right : GDK_Left)
-              || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
-            {
-              PsppSheetViewColumn *col;
-              col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_LEFT);
-              if (col != (PsppSheetViewColumn *)0x1)
-                pspp_sheet_view_move_column_after (tree_view, column, col);
-              else
-                gtk_widget_error_bell (widget);
-            }
-          else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
-                   || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
-            {
-              PsppSheetViewColumn *col;
-              col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_RIGHT);
-              if (col != (PsppSheetViewColumn *)0x1)
-                pspp_sheet_view_move_column_after (tree_view, column, col);
-              else
-                gtk_widget_error_bell (widget);
-            }
-          else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
-            {
-              PsppSheetViewColumn *col;
-              col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_HOME);
-              if (col != (PsppSheetViewColumn *)0x1)
-                pspp_sheet_view_move_column_after (tree_view, column, col);
-              else
-                gtk_widget_error_bell (widget);
-            }
-          else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
-            {
-              PsppSheetViewColumn *col;
-              col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_END);
-              if (col != (PsppSheetViewColumn *)0x1)
-                pspp_sheet_view_move_column_after (tree_view, column, col);
-              else
-                gtk_widget_error_bell (widget);
-            }
-
-          return TRUE;
-        }
-    }
-
-  /* Chain up to the parent class.  It handles the keybindings. */
-  if (GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->key_press_event (widget, event))
-    return TRUE;
-
-  if (tree_view->priv->search_entry_avoid_unhandled_binding)
-    {
-      tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
-      return FALSE;
-    }
-
-  /* We pass the event to the search_entry.  If its text changes, then we start
-   * the typeahead find capabilities. */
-  if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
-      && tree_view->priv->enable_search
-      && !tree_view->priv->search_custom_entry_set)
-    {
-      GdkEvent *new_event;
-      char *old_text;
-      const char *new_text;
-      gboolean retval;
-      GdkScreen *screen;
-      gboolean text_modified;
-      gulong popup_menu_id;
-
-      pspp_sheet_view_ensure_interactive_directory (tree_view);
-
-      /* Make a copy of the current text */
-      old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
-      new_event = gdk_event_copy ((GdkEvent *) event);
-      g_object_unref (((GdkEventKey *) new_event)->window);
-      ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
-      gtk_widget_realize (tree_view->priv->search_window);
-
-      popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
-                                       "popup-menu", G_CALLBACK (gtk_true),
-                                        NULL);
-
-      /* Move the entry off screen */
-      screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
-      gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
-                      gdk_screen_get_width (screen) + 1,
-                      gdk_screen_get_height (screen) + 1);
-      gtk_widget_show (tree_view->priv->search_window);
-
-      /* Send the event to the window.  If the preedit_changed signal is emitted
-       * during this event, we will set priv->imcontext_changed  */
-      tree_view->priv->imcontext_changed = FALSE;
-      retval = gtk_widget_event (tree_view->priv->search_window, new_event);
-      gdk_event_free (new_event);
-      gtk_widget_hide (tree_view->priv->search_window);
-
-      g_signal_handler_disconnect (tree_view->priv->search_entry,
-                                  popup_menu_id);
-
-      /* We check to make sure that the entry tried to handle the text, and that
-       * the text has changed.
-       */
-      new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
-      text_modified = strcmp (old_text, new_text) != 0;
-      g_free (old_text);
-      if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
-         (retval && text_modified))               /* ...or the text was modified */
-       {
-         if (pspp_sheet_view_real_start_interactive_search (tree_view, FALSE))
-           {
-             gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-             return TRUE;
-           }
-         else
-           {
-             gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
-             return FALSE;
-           }
-       }
-    }
-
-  return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_key_release (GtkWidget   *widget,
-                          GdkEventKey *event)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (tree_view->priv->rubber_band_status)
-    return TRUE;
-
-  return GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->key_release_event (widget, event);
-}
-
-/* FIXME Is this function necessary? Can I get an enter_notify event
- * w/o either an expose event or a mouse motion event?
- */
-static gboolean
-pspp_sheet_view_enter_notify (GtkWidget        *widget,
-                           GdkEventCrossing *event)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  int node;
-  gint new_y;
-
-  /* Sanity check it */
-  if (event->window != tree_view->priv->bin_window)
-    return FALSE;
-
-  if (tree_view->priv->row_count == 0)
-    return FALSE;
-
-  if (event->mode == GDK_CROSSING_GRAB ||
-      event->mode == GDK_CROSSING_GTK_GRAB ||
-      event->mode == GDK_CROSSING_GTK_UNGRAB ||
-      event->mode == GDK_CROSSING_STATE_CHANGED)
-    return TRUE;
-
-  /* find the node internally */
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
-  if (new_y < 0)
-    new_y = 0;
-  pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
-  tree_view->priv->event_last_x = event->x;
-  tree_view->priv->event_last_y = event->y;
-
-  prelight_or_select (tree_view, node, event->x, event->y);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_leave_notify (GtkWidget        *widget,
-                           GdkEventCrossing *event)
-{
-  PsppSheetView *tree_view;
-
-  if (event->mode == GDK_CROSSING_GRAB)
-    return TRUE;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (tree_view->priv->prelight_node >= 0)
-    _pspp_sheet_view_queue_draw_node (tree_view,
-                                   tree_view->priv->prelight_node,
-                                   NULL);
-
-  tree_view->priv->event_last_x = -10000;
-  tree_view->priv->event_last_y = -10000;
-
-  prelight_or_select (tree_view,
-                     -1,
-                     -1000, -1000); /* coords not possibly over an arrow */
-
-  return TRUE;
-}
-
-
-static gint
-pspp_sheet_view_focus_out (GtkWidget     *widget,
-                        GdkEventFocus *event)
-{
-  PsppSheetView *tree_view;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  gtk_widget_queue_draw (widget);
-
-  /* destroy interactive search dialog */
-  if (tree_view->priv->search_window)
-    pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
-
-  return FALSE;
-}
-
-
-/* Incremental Reflow
- */
-
-static void
-pspp_sheet_view_node_queue_redraw (PsppSheetView *tree_view,
-                                int node)
-{
-  GtkAllocation allocation;
-  gint y = pspp_sheet_view_node_find_offset (tree_view, node)
-    - gtk_adjustment_get_value (tree_view->priv->vadjustment)
-    + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
-  gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
-  gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
-                             0, y,
-                             allocation.width,
-                              tree_view->priv->fixed_height);
-}
-
-static gboolean
-node_is_visible (PsppSheetView *tree_view,
-                int node)
-{
-  int y;
-  int height;
-
-  y = pspp_sheet_view_node_find_offset (tree_view, node);
-  height = ROW_HEIGHT (tree_view);
-
-  if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
-      y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
-                    + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
-    return TRUE;
-
-  return FALSE;
-}
-
-/* Returns the row height. */
-static gint
-validate_row (PsppSheetView *tree_view,
-             int node,
-             GtkTreeIter *iter,
-             GtkTreePath *path)
-{
-  PsppSheetViewColumn *column;
-  GList *list, *first_column, *last_column;
-  gint height = 0;
-  gint horizontal_separator;
-  gint vertical_separator;
-  gint focus_line_width;
-  gboolean draw_vgrid_lines, draw_hgrid_lines;
-  gint focus_pad;
-  gint grid_line_width;
-  gboolean wide_separators;
-  gint separator_height;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view),
-                       "focus-padding", &focus_pad,
-                       "focus-line-width", &focus_line_width,
-                       "horizontal-separator", &horizontal_separator,
-                       "vertical-separator", &vertical_separator,
-                       "grid-line-width", &grid_line_width,
-                        "wide-separators",  &wide_separators,
-                        "separator-height", &separator_height,
-                       NULL);
-
-  draw_vgrid_lines =
-    tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
-    || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-  draw_hgrid_lines =
-    tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
-    || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-
-  for (last_column = g_list_last (tree_view->priv->columns);
-       last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
-       last_column = last_column->prev)
-    ;
-
-  for (first_column = g_list_first (tree_view->priv->columns);
-       first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
-       first_column = first_column->next)
-    ;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      gint tmp_width;
-      gint tmp_height;
-
-      column = list->data;
-
-      if (! column->visible)
-       continue;
-
-      pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
-      pspp_sheet_view_column_cell_get_size (column,
-                                         NULL, NULL, NULL,
-                                         &tmp_width, &tmp_height);
-
-      tmp_height += vertical_separator;
-      height = MAX (height, tmp_height);
-
-      tmp_width = tmp_width + horizontal_separator;
-
-      if (draw_vgrid_lines)
-        {
-         if (list->data == first_column || list->data == last_column)
-           tmp_width += grid_line_width / 2.0;
-         else
-           tmp_width += grid_line_width;
-       }
-
-      if (tmp_width > column->requested_width)
-        column->requested_width = tmp_width;
-    }
-
-  if (draw_hgrid_lines)
-    height += grid_line_width;
-
-  tree_view->priv->post_validation_flag = TRUE;
-  return height;
-}
-
-
-static void
-validate_visible_area (PsppSheetView *tree_view)
-{
-  GtkTreePath *path = NULL;
-  GtkTreePath *above_path = NULL;
-  GtkTreeIter iter;
-  int node = -1;
-  gint total_height;
-  gint area_above = 0;
-  gint area_below = 0;
-  GtkAllocation allocation;
-
-  if (tree_view->priv->row_count == 0)
-    return;
-
-  if (tree_view->priv->scroll_to_path == NULL)
-    return;
-
-  gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
-  total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
-
-  if (total_height == 0)
-    return;
-
-  path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
-  if (path)
-    {
-      /* we are going to scroll, and will update dy */
-      _pspp_sheet_view_find_node (tree_view, path, &node);
-      gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
-
-      if (tree_view->priv->scroll_to_use_align)
-        {
-          gint height = ROW_HEIGHT (tree_view);
-          area_above = (total_height - height) *
-            tree_view->priv->scroll_to_row_align;
-          area_below = total_height - area_above - height;
-          area_above = MAX (area_above, 0);
-          area_below = MAX (area_below, 0);
-        }
-      else
-        {
-          /* two cases:
-           * 1) row not visible
-           * 2) row visible
-           */
-          gint dy;
-          gint height = ROW_HEIGHT (tree_view);
-
-          dy = pspp_sheet_view_node_find_offset (tree_view, node);
-
-          if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
-              dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
-                              + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
-            {
-              /* row visible: keep the row at the same position */
-              area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
-              area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
-                            gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
-                - dy - height;
-            }
-          else
-            {
-              /* row not visible */
-              if (dy >= 0
-                  && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
-                {
-                  /* row at the beginning -- fixed */
-                  area_above = dy;
-                  area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
-                    - area_above - height;
-                }
-              else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
-                              gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
-                {
-                  /* row at the end -- fixed */
-                  area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
-                                     gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
-                  area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
-                    area_above - height;
-
-                  if (area_below < 0)
-                    {
-                      area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
-                      area_below = 0;
-                    }
-                }
-              else
-                {
-                  /* row somewhere in the middle, bring it to the top
-                   * of the view
-                   */
-                  area_above = 0;
-                  area_below = total_height - height;
-                }
-            }
-        }
-    }
-  else
-    /* the scroll to isn't valid; ignore it.
-     */
-    {
-      gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-      tree_view->priv->scroll_to_path = NULL;
-      return;
-    }
-
-  above_path = gtk_tree_path_copy (path);
-
-  /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
-   * backwards is much slower then forward, as there is no iter_prev function.
-   * We go forwards first in case we run out of tree.  Then we go backwards to
-   * fill out the top.
-   */
-  while (node >= 0 && area_below > 0)
-    {
-      gboolean done = FALSE;
-      do
-        {
-          node = pspp_sheet_view_node_next (tree_view, node);
-          if (node >= 0)
-            {
-              gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
-              done = TRUE;
-              gtk_tree_path_next (path);
-
-              /* Sanity Check! */
-              TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
-            }
-          else
-            break;
-        }
-      while (!done);
-
-      if (node < 0)
-        break;
-
-      area_below -= ROW_HEIGHT (tree_view);
-    }
-  gtk_tree_path_free (path);
-
-  /* If we ran out of tree, and have extra area_below left, we need to add it
-   * to area_above */
-  if (area_below > 0)
-    area_above += area_below;
-
-  _pspp_sheet_view_find_node (tree_view, above_path, &node);
-
-  /* We walk backwards */
-  while (area_above > 0)
-    {
-      node = pspp_sheet_view_node_prev (tree_view, node);
-
-      /* Always find the new path in the tree.  We cannot just assume
-       * a gtk_tree_path_prev() is enough here, as there might be children
-       * in between this node and the previous sibling node.  If this
-       * appears to be a performance hotspot in profiles, we can look into
-       * intrigate logic for keeping path, node and iter in sync like
-       * we do for forward walks.  (Which will be hard because of the lacking
-       * iter_prev).
-       */
-
-      if (node < 0)
-       break;
-
-      gtk_tree_path_free (above_path);
-      above_path = _pspp_sheet_view_find_path (tree_view, node);
-
-      gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
-
-      area_above -= ROW_HEIGHT (tree_view);
-    }
-
-  /* set the dy here to scroll to the path,
-   * and sync the top row accordingly
-   */
-  pspp_sheet_view_set_top_row (tree_view, above_path, -area_above);
-  pspp_sheet_view_top_row_to_dy (tree_view);
-
-  gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-  tree_view->priv->scroll_to_path = NULL;
-
-  if (above_path)
-    gtk_tree_path_free (above_path);
-
-  if (tree_view->priv->scroll_to_column)
-    {
-      tree_view->priv->scroll_to_column = NULL;
-    }
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static void
-initialize_fixed_height_mode (PsppSheetView *tree_view)
-{
-  if (!tree_view->priv->row_count)
-    return;
-
-  if (tree_view->priv->fixed_height_set)
-    return;
-
-  if (tree_view->priv->fixed_height < 0)
-    {
-      GtkTreeIter iter;
-      GtkTreePath *path;
-
-      int node = 0;
-
-      path = _pspp_sheet_view_find_path (tree_view, node);
-      gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
-
-      tree_view->priv->fixed_height = validate_row (tree_view, node, &iter, path);
-
-      gtk_tree_path_free (path);
-
-      g_object_notify (G_OBJECT (tree_view), "fixed-height");
-    }
-}
-
-/* Our strategy for finding nodes to validate is a little convoluted.  We find
- * the left-most uninvalidated node.  We then try walking right, validating
- * nodes.  Once we find a valid node, we repeat the previous process of finding
- * the first invalid node.
- */
-
-static gboolean
-validate_rows_handler (PsppSheetView *tree_view)
-{
-  initialize_fixed_height_mode (tree_view);
-  if (tree_view->priv->validate_rows_timer)
-    {
-      g_source_remove (tree_view->priv->validate_rows_timer);
-      tree_view->priv->validate_rows_timer = 0;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-do_presize_handler (PsppSheetView *tree_view)
-{
-  GtkRequisition requisition;
-
-  validate_visible_area (tree_view);
-  tree_view->priv->presize_handler_timer = 0;
-
-  if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  gtk_widget_get_preferred_size (GTK_WIDGET (tree_view), NULL, &requisition);
-
-  gtk_adjustment_set_upper (tree_view->priv->hadjustment, MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), (gfloat)requisition.width));
-  gtk_adjustment_set_upper (tree_view->priv->vadjustment, MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), (gfloat)requisition.height));
-  gtk_adjustment_changed (tree_view->priv->hadjustment);
-  gtk_adjustment_changed (tree_view->priv->vadjustment);
-  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
-  return FALSE;
-}
-
-static gboolean
-presize_handler_callback (gpointer data)
-{
-  do_presize_handler (PSPP_SHEET_VIEW (data));
-
-  return FALSE;
-}
-
-static void
-install_presize_handler (PsppSheetView *tree_view)
-{
-  if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return;
-
-  if (! tree_view->priv->presize_handler_timer)
-    {
-      tree_view->priv->presize_handler_timer =
-       gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
-    }
-  if (! tree_view->priv->validate_rows_timer)
-    {
-      tree_view->priv->validate_rows_timer =
-       gdk_threads_add_idle_full (PSPP_SHEET_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
-    }
-}
-
-static gboolean
-scroll_sync_handler (PsppSheetView *tree_view)
-{
-  if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
-    gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
-  else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
-    pspp_sheet_view_top_row_to_dy (tree_view);
-  else
-    pspp_sheet_view_dy_to_top_row (tree_view);
-
-  tree_view->priv->scroll_sync_timer = 0;
-
-  return FALSE;
-}
-
-static void
-install_scroll_sync_handler (PsppSheetView *tree_view)
-{
-  if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return;
-
-  if (!tree_view->priv->scroll_sync_timer)
-    {
-      tree_view->priv->scroll_sync_timer =
-       gdk_threads_add_idle_full (PSPP_SHEET_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
-    }
-}
-
-static void
-pspp_sheet_view_set_top_row (PsppSheetView *tree_view,
-                          GtkTreePath *path,
-                          gint         offset)
-{
-  gtk_tree_row_reference_free (tree_view->priv->top_row);
-
-  if (!path)
-    {
-      tree_view->priv->top_row = NULL;
-      tree_view->priv->top_row_dy = 0;
-    }
-  else
-    {
-      tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
-      tree_view->priv->top_row_dy = offset;
-    }
-}
-
-/* Always call this iff dy is in the visible range.  If the tree is empty, then
- * it's set to be NULL, and top_row_dy is 0;
- */
-static void
-pspp_sheet_view_dy_to_top_row (PsppSheetView *tree_view)
-{
-  gint offset;
-  GtkTreePath *path;
-  int node;
-
-  if (tree_view->priv->row_count == 0)
-    {
-      pspp_sheet_view_set_top_row (tree_view, NULL, 0);
-    }
-  else
-    {
-      offset = pspp_sheet_view_find_offset (tree_view,
-                                            tree_view->priv->dy,
-                                            &node);
-
-      if (node < 0)
-        {
-         pspp_sheet_view_set_top_row (tree_view, NULL, 0);
-       }
-      else
-        {
-         path = _pspp_sheet_view_find_path (tree_view, node);
-         pspp_sheet_view_set_top_row (tree_view, path, offset);
-         gtk_tree_path_free (path);
-       }
-    }
-}
-
-static void
-pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view)
-{
-  GtkTreePath *path;
-  int node;
-  int new_dy;
-
-  /* Avoid recursive calls */
-  if (tree_view->priv->in_top_row_to_dy)
-    return;
-
-  if (tree_view->priv->top_row)
-    path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
-  else
-    path = NULL;
-
-  if (!path)
-    node = -1;
-  else
-    _pspp_sheet_view_find_node (tree_view, path, &node);
-
-  if (path)
-    gtk_tree_path_free (path);
-
-  if (node < 0)
-    {
-      /* keep dy and set new toprow */
-      gtk_tree_row_reference_free (tree_view->priv->top_row);
-      tree_view->priv->top_row = NULL;
-      tree_view->priv->top_row_dy = 0;
-      /* DO NOT install the idle handler */
-      pspp_sheet_view_dy_to_top_row (tree_view);
-      return;
-    }
-
-  if (ROW_HEIGHT (tree_view) < tree_view->priv->top_row_dy)
-    {
-      /* new top row -- do NOT install the idle handler */
-      pspp_sheet_view_dy_to_top_row (tree_view);
-      return;
-    }
-
-  new_dy = pspp_sheet_view_node_find_offset (tree_view, node);
-  new_dy += tree_view->priv->top_row_dy;
-
-  if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
-    new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
-
-  new_dy = MAX (0, new_dy);
-
-  tree_view->priv->in_top_row_to_dy = TRUE;
-  gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
-  tree_view->priv->in_top_row_to_dy = FALSE;
-}
-
-
-void
-_pspp_sheet_view_install_mark_rows_col_dirty (PsppSheetView *tree_view)
-{
-  install_presize_handler (tree_view);
-}
-
-/* Drag-and-drop */
-
-static void
-set_source_row (GdkDragContext *context,
-                GtkTreeModel   *model,
-                GtkTreePath    *source_row)
-{
-  g_object_set_data_full (G_OBJECT (context),
-                          "gtk-tree-view-source-row",
-                          source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
-                          (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
-}
-
-static GtkTreePath*
-get_source_row (GdkDragContext *context)
-{
-  GtkTreeRowReference *ref =
-    g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
-
-  if (ref)
-    return gtk_tree_row_reference_get_path (ref);
-  else
-    return NULL;
-}
-
-typedef struct
-{
-  GtkTreeRowReference *dest_row;
-  guint                path_down_mode   : 1;
-  guint                empty_view_drop  : 1;
-  guint                drop_append_mode : 1;
-}
-DestRow;
-
-static void
-dest_row_free (gpointer data)
-{
-  DestRow *dr = (DestRow *)data;
-
-  gtk_tree_row_reference_free (dr->dest_row);
-  g_slice_free (DestRow, dr);
-}
-
-static void
-set_dest_row (GdkDragContext *context,
-              GtkTreeModel   *model,
-              GtkTreePath    *dest_row,
-              gboolean        path_down_mode,
-              gboolean        empty_view_drop,
-              gboolean        drop_append_mode)
-{
-  DestRow *dr;
-
-  if (!dest_row)
-    {
-      g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
-                              NULL, NULL);
-      return;
-    }
-
-  dr = g_slice_new (DestRow);
-
-  dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
-  dr->path_down_mode = path_down_mode != FALSE;
-  dr->empty_view_drop = empty_view_drop != FALSE;
-  dr->drop_append_mode = drop_append_mode != FALSE;
-
-  g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
-                          dr, (GDestroyNotify) dest_row_free);
-}
-
-static GtkTreePath*
-get_dest_row (GdkDragContext *context,
-              gboolean       *path_down_mode)
-{
-  DestRow *dr =
-    g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
-
-  if (dr)
-    {
-      GtkTreePath *path = NULL;
-
-      if (path_down_mode)
-        *path_down_mode = dr->path_down_mode;
-
-      if (dr->dest_row)
-        path = gtk_tree_row_reference_get_path (dr->dest_row);
-      else if (dr->empty_view_drop)
-        path = gtk_tree_path_new_from_indices (0, -1);
-      else
-        path = NULL;
-
-      if (path && dr->drop_append_mode)
-        gtk_tree_path_next (path);
-
-      return path;
-    }
-  else
-    return NULL;
-}
-
-/* Get/set whether drag_motion requested the drag data and
- * drag_data_received should thus not actually insert the data,
- * since the data doesn't result from a drop.
- */
-static void
-set_status_pending (GdkDragContext *context,
-                    GdkDragAction   suggested_action)
-{
-  g_object_set_data (G_OBJECT (context),
-                     "gtk-tree-view-status-pending",
-                     GINT_TO_POINTER (suggested_action));
-}
-
-static GdkDragAction
-get_status_pending (GdkDragContext *context)
-{
-  return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
-                                             "gtk-tree-view-status-pending"));
-}
-
-static TreeViewDragInfo*
-get_info (PsppSheetView *tree_view)
-{
-  return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
-}
-
-static void
-destroy_info (TreeViewDragInfo *di)
-{
-  g_slice_free (TreeViewDragInfo, di);
-}
-
-static TreeViewDragInfo*
-ensure_info (PsppSheetView *tree_view)
-{
-  TreeViewDragInfo *di;
-
-  di = get_info (tree_view);
-
-  if (di == NULL)
-    {
-      di = g_slice_new0 (TreeViewDragInfo);
-
-      g_object_set_data_full (G_OBJECT (tree_view),
-                              "gtk-tree-view-drag-info",
-                              di,
-                              (GDestroyNotify) destroy_info);
-    }
-
-  return di;
-}
-
-static void
-remove_info (PsppSheetView *tree_view)
-{
-  g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
-}
-
-#if 0
-static gint
-drag_scan_timeout (gpointer data)
-{
-  PsppSheetView *tree_view;
-  gint x, y;
-  GdkModifierType state;
-  GtkTreePath *path = NULL;
-  PsppSheetViewColumn *column = NULL;
-  GdkRectangle visible_rect;
-
-  GDK_THREADS_ENTER ();
-
-  tree_view = PSPP_SHEET_VIEW (data);
-
-  gdk_window_get_pointer (tree_view->priv->bin_window,
-                          &x, &y, &state);
-
-  pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
-  /* See if we are near the edge. */
-  if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
-      (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
-      (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
-      (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
-    {
-      pspp_sheet_view_get_path_at_pos (tree_view,
-                                     tree_view->priv->bin_window,
-                                     x, y,
-                                     &path,
-                                     &column,
-                                     NULL,
-                                     NULL);
-
-      if (path != NULL)
-        {
-          pspp_sheet_view_scroll_to_cell (tree_view,
-                                        path,
-                                        column,
-                                       TRUE,
-                                        0.5, 0.5);
-
-          gtk_tree_path_free (path);
-        }
-    }
-
-  GDK_THREADS_LEAVE ();
-
-  return TRUE;
-}
-#endif /* 0 */
-
-static void
-add_scroll_timeout (PsppSheetView *tree_view)
-{
-  if (tree_view->priv->scroll_timeout == 0)
-    {
-      tree_view->priv->scroll_timeout =
-       gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
-    }
-}
-
-static void
-remove_scroll_timeout (PsppSheetView *tree_view)
-{
-  if (tree_view->priv->scroll_timeout != 0)
-    {
-      g_source_remove (tree_view->priv->scroll_timeout);
-      tree_view->priv->scroll_timeout = 0;
-    }
-}
-
-static gboolean
-check_model_dnd (GtkTreeModel *model,
-                 GType         required_iface,
-                 const gchar  *signal)
-{
-  if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
-    {
-      g_warning ("You must override the default '%s' handler "
-                 "on PsppSheetView when using models that don't support "
-                 "the %s interface and enabling drag-and-drop. The simplest way to do this "
-                 "is to connect to '%s' and call "
-                 "g_signal_stop_emission_by_name() in your signal handler to prevent "
-                 "the default handler from running. Look at the source code "
-                 "for the default handler in gtktreeview.c to get an idea what "
-                 "your handler should do. (gtktreeview.c is in the GTK source "
-                 "code.) If you're using GTK from a language other than C, "
-                 "there may be a more natural way to override default handlers, e.g. via derivation.",
-                 signal, g_type_name (required_iface), signal);
-      return FALSE;
-    }
-  else
-    return TRUE;
-}
-
-static gboolean
-scroll_row_timeout (gpointer data)
-{
-  PsppSheetView *tree_view = data;
-
-  pspp_sheet_view_horizontal_autoscroll (tree_view);
-  pspp_sheet_view_vertical_autoscroll (tree_view);
-
-  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
-    pspp_sheet_view_update_rubber_band (tree_view);
-
-  return TRUE;
-}
-
-/* Returns TRUE if event should not be propagated to parent widgets */
-static gboolean
-set_destination_row (PsppSheetView    *tree_view,
-                     GdkDragContext *context,
-                     /* coordinates relative to the widget */
-                     gint            x,
-                     gint            y,
-                     GdkDragAction  *suggested_action,
-                     GdkAtom        *target)
-{
-  GtkTreePath *path = NULL;
-  PsppSheetViewDropPosition pos;
-  PsppSheetViewDropPosition old_pos;
-  TreeViewDragInfo *di;
-  GtkWidget *widget;
-  GtkTreePath *old_dest_path = NULL;
-  gboolean can_drop = FALSE;
-
-  *suggested_action = 0;
-  *target = GDK_NONE;
-
-  widget = GTK_WIDGET (tree_view);
-
-  di = get_info (tree_view);
-
-  if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
-    {
-      /* someone unset us as a drag dest, note that if
-       * we return FALSE drag_leave isn't called
-       */
-
-      pspp_sheet_view_set_drag_dest_row (tree_view,
-                                       NULL,
-                                       PSPP_SHEET_VIEW_DROP_BEFORE);
-
-      remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-
-      return FALSE; /* no longer a drop site */
-    }
-
-  *target = gtk_drag_dest_find_target (widget, context,
-                                       gtk_drag_dest_get_target_list (widget));
-  if (*target == GDK_NONE)
-    {
-      return FALSE;
-    }
-
-  if (!pspp_sheet_view_get_dest_row_at_pos (tree_view,
-                                          x, y,
-                                          &path,
-                                          &pos))
-    {
-      gint n_children;
-      GtkTreeModel *model;
-
-      /* the row got dropped on empty space, let's setup a special case
-       */
-
-      if (path)
-       gtk_tree_path_free (path);
-
-      model = pspp_sheet_view_get_model (tree_view);
-
-      n_children = gtk_tree_model_iter_n_children (model, NULL);
-      if (n_children)
-        {
-          pos = PSPP_SHEET_VIEW_DROP_AFTER;
-          path = gtk_tree_path_new_from_indices (n_children - 1, -1);
-        }
-      else
-        {
-          pos = PSPP_SHEET_VIEW_DROP_BEFORE;
-          path = gtk_tree_path_new_from_indices (0, -1);
-        }
-
-      can_drop = TRUE;
-
-      goto out;
-    }
-
-  g_assert (path);
-
-  /* If we left the current row's "open" zone, unset the timeout for
-   * opening the row
-   */
-  pspp_sheet_view_get_drag_dest_row (tree_view,
-                                   &old_dest_path,
-                                   &old_pos);
-
-  if (old_dest_path)
-    gtk_tree_path_free (old_dest_path);
-
-  if (TRUE /* FIXME if the location droppable predicate */)
-    {
-      can_drop = TRUE;
-    }
-
-out:
-  if (can_drop)
-    {
-      GtkWidget *source_widget;
-
-      *suggested_action = gdk_drag_context_get_suggested_action (context);
-      source_widget = gtk_drag_get_source_widget (context);
-
-      if (source_widget == widget)
-        {
-          /* Default to MOVE, unless the user has
-           * pressed ctrl or shift to affect available actions
-           */
-          if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
-            *suggested_action = GDK_ACTION_MOVE;
-        }
-
-      pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
-                                       path, pos);
-    }
-  else
-    {
-      /* can't drop here */
-      pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
-                                       NULL,
-                                       PSPP_SHEET_VIEW_DROP_BEFORE);
-    }
-
-  if (path)
-    gtk_tree_path_free (path);
-
-  return TRUE;
-}
-
-static GtkTreePath*
-get_logical_dest_row (PsppSheetView *tree_view,
-                      gboolean    *path_down_mode,
-                      gboolean    *drop_append_mode)
-{
-  /* adjust path to point to the row the drop goes in front of */
-  GtkTreePath *path = NULL;
-  PsppSheetViewDropPosition pos;
-
-  g_return_val_if_fail (path_down_mode != NULL, NULL);
-  g_return_val_if_fail (drop_append_mode != NULL, NULL);
-
-  *path_down_mode = FALSE;
-  *drop_append_mode = 0;
-
-  pspp_sheet_view_get_drag_dest_row (tree_view, &path, &pos);
-
-  if (path == NULL)
-    return NULL;
-
-  if (pos == PSPP_SHEET_VIEW_DROP_BEFORE)
-    ; /* do nothing */
-  else if (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE ||
-           pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER)
-    *path_down_mode = TRUE;
-  else
-    {
-      GtkTreeIter iter;
-      GtkTreeModel *model = pspp_sheet_view_get_model (tree_view);
-
-      g_assert (pos == PSPP_SHEET_VIEW_DROP_AFTER);
-
-      if (!gtk_tree_model_get_iter (model, &iter, path) ||
-          !gtk_tree_model_iter_next (model, &iter))
-        *drop_append_mode = 1;
-      else
-        {
-          *drop_append_mode = 0;
-          gtk_tree_path_next (path);
-        }
-    }
-
-  return path;
-}
-
-static gboolean
-pspp_sheet_view_maybe_begin_dragging_row (PsppSheetView      *tree_view,
-                                        GdkEventMotion   *event)
-{
-  GtkWidget *widget = GTK_WIDGET (tree_view);
-  GdkDragContext *context;
-  TreeViewDragInfo *di;
-  GtkTreePath *path = NULL;
-  gint button;
-  gint cell_x, cell_y;
-  GtkTreeModel *model;
-  gboolean retval = FALSE;
-
-  di = get_info (tree_view);
-
-  if (di == NULL || !di->source_set)
-    goto out;
-
-  if (tree_view->priv->pressed_button < 0)
-    goto out;
-
-  if (!gtk_drag_check_threshold (widget,
-                                 tree_view->priv->press_start_x,
-                                 tree_view->priv->press_start_y,
-                                 event->x, event->y))
-    goto out;
-
-  model = pspp_sheet_view_get_model (tree_view);
-
-  if (model == NULL)
-    goto out;
-
-  button = tree_view->priv->pressed_button;
-  tree_view->priv->pressed_button = -1;
-
-  pspp_sheet_view_get_path_at_pos (tree_view,
-                                 tree_view->priv->press_start_x,
-                                 tree_view->priv->press_start_y,
-                                 &path,
-                                 NULL,
-                                 &cell_x,
-                                 &cell_y);
-
-  if (path == NULL)
-    goto out;
-
-  if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
-      !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
-                                          path))
-    goto out;
-
-  if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
-    goto out;
-
-  /* Now we can begin the drag */
-
-  retval = TRUE;
-
-  context = gtk_drag_begin (widget,
-                            gtk_drag_source_get_target_list (widget),
-                            di->source_actions,
-                            button,
-                            (GdkEvent*)event);
-
-  set_source_row (context, model, path);
-
- out:
-  if (path)
-    gtk_tree_path_free (path);
-
-  return retval;
-}
-
-
-
-static void
-pspp_sheet_view_drag_begin (GtkWidget      *widget,
-                          GdkDragContext *context)
-{
-}
-
-
-static void
-pspp_sheet_view_drag_end (GtkWidget      *widget,
-                        GdkDragContext *context)
-{
-  /* do nothing */
-}
-
-/* Default signal implementations for the drag signals */
-static void
-pspp_sheet_view_drag_data_get (GtkWidget        *widget,
-                             GdkDragContext   *context,
-                             GtkSelectionData *selection_data,
-                             guint             info,
-                             guint             time)
-{
-  PsppSheetView *tree_view;
-  GtkTreeModel *model;
-  TreeViewDragInfo *di;
-  GtkTreePath *source_row;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  model = pspp_sheet_view_get_model (tree_view);
-
-  if (model == NULL)
-    return;
-
-  di = get_info (PSPP_SHEET_VIEW (widget));
-
-  if (di == NULL)
-    return;
-
-  source_row = get_source_row (context);
-
-  if (source_row == NULL)
-    return;
-
-  /* We can implement the GTK_TREE_MODEL_ROW target generically for
-   * any model; for DragSource models there are some other targets
-   * we also support.
-   */
-
-  if (GTK_IS_TREE_DRAG_SOURCE (model) &&
-      gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
-                                          source_row,
-                                          selection_data))
-    goto done;
-
-  /* If drag_data_get does nothing, try providing row data. */
-  if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
-    {
-      gtk_tree_set_row_drag_data (selection_data,
-                                 model,
-                                 source_row);
-    }
-
- done:
-  gtk_tree_path_free (source_row);
-}
-
-
-static void
-pspp_sheet_view_drag_data_delete (GtkWidget      *widget,
-                                GdkDragContext *context)
-{
-  TreeViewDragInfo *di;
-  GtkTreeModel *model;
-  PsppSheetView *tree_view;
-  GtkTreePath *source_row;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-  model = pspp_sheet_view_get_model (tree_view);
-
-  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
-    return;
-
-  di = get_info (tree_view);
-
-  if (di == NULL)
-    return;
-
-  source_row = get_source_row (context);
-
-  if (source_row == NULL)
-    return;
-
-  gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
-                                         source_row);
-
-  gtk_tree_path_free (source_row);
-
-  set_source_row (context, NULL, NULL);
-}
-
-static void
-pspp_sheet_view_drag_leave (GtkWidget      *widget,
-                          GdkDragContext *context,
-                          guint             time)
-{
-  /* unset any highlight row */
-  pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
-                                   NULL,
-                                   PSPP_SHEET_VIEW_DROP_BEFORE);
-
-  remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-}
-
-
-static gboolean
-pspp_sheet_view_drag_motion (GtkWidget        *widget,
-                           GdkDragContext   *context,
-                          /* coordinates relative to the widget */
-                           gint              x,
-                           gint              y,
-                           guint             time)
-{
-  gboolean empty;
-  GtkTreePath *path = NULL;
-  PsppSheetViewDropPosition pos;
-  PsppSheetView *tree_view;
-  GdkDragAction suggested_action = 0;
-  GdkAtom target;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
-    return FALSE;
-
-  pspp_sheet_view_get_drag_dest_row (tree_view, &path, &pos);
-
-  /* we only know this *after* set_desination_row */
-  empty = tree_view->priv->empty_view_drop;
-
-  if (path == NULL && !empty)
-    {
-      /* Can't drop here. */
-      gdk_drag_status (context, 0, time);
-    }
-  else
-    {
-      if (tree_view->priv->open_dest_timeout == 0 &&
-          (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER ||
-           pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE))
-        {
-          /* Nothing. */
-        }
-      else
-        {
-         add_scroll_timeout (tree_view);
-       }
-
-      if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
-        {
-          /* Request data so we can use the source row when
-           * determining whether to accept the drop
-           */
-          set_status_pending (context, suggested_action);
-          gtk_drag_get_data (widget, context, target, time);
-        }
-      else
-        {
-          set_status_pending (context, 0);
-          gdk_drag_status (context, suggested_action, time);
-        }
-    }
-
-  if (path)
-    gtk_tree_path_free (path);
-
-  return TRUE;
-}
-
-
-static gboolean
-pspp_sheet_view_drag_drop (GtkWidget        *widget,
-                         GdkDragContext   *context,
-                        /* coordinates relative to the widget */
-                         gint              x,
-                         gint              y,
-                         guint             time)
-{
-  PsppSheetView *tree_view;
-  GtkTreePath *path;
-  GdkDragAction suggested_action = 0;
-  GdkAtom target = GDK_NONE;
-  TreeViewDragInfo *di;
-  GtkTreeModel *model;
-  gboolean path_down_mode;
-  gboolean drop_append_mode;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  model = pspp_sheet_view_get_model (tree_view);
-
-  remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-
-  di = get_info (tree_view);
-
-  if (di == NULL)
-    return FALSE;
-
-  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
-    return FALSE;
-
-  if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
-    return FALSE;
-
-  path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
-
-  if (target != GDK_NONE && path != NULL)
-    {
-      /* in case a motion had requested drag data, change things so we
-       * treat drag data receives as a drop.
-       */
-      set_status_pending (context, 0);
-      set_dest_row (context, model, path,
-                    path_down_mode, tree_view->priv->empty_view_drop,
-                    drop_append_mode);
-    }
-
-  if (path)
-    gtk_tree_path_free (path);
-
-  /* Unset this thing */
-  pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
-                                   NULL,
-                                   PSPP_SHEET_VIEW_DROP_BEFORE);
-
-  if (target != GDK_NONE)
-    {
-      gtk_drag_get_data (widget, context, target, time);
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
-
-static void
-pspp_sheet_view_drag_data_received (GtkWidget        *widget,
-                                  GdkDragContext   *context,
-                                 /* coordinates relative to the widget */
-                                  gint              x,
-                                  gint              y,
-                                  GtkSelectionData *selection_data,
-                                  guint             info,
-                                  guint             time)
-{
-  GtkTreePath *path;
-  TreeViewDragInfo *di;
-  gboolean accepted = FALSE;
-  GtkTreeModel *model;
-  PsppSheetView *tree_view;
-  GtkTreePath *dest_row;
-  GdkDragAction suggested_action;
-  gboolean path_down_mode;
-  gboolean drop_append_mode;
-
-  tree_view = PSPP_SHEET_VIEW (widget);
-
-  model = pspp_sheet_view_get_model (tree_view);
-
-  if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
-    return;
-
-  di = get_info (tree_view);
-
-  if (di == NULL)
-    return;
-
-  suggested_action = get_status_pending (context);
-
-  if (suggested_action)
-    {
-      /* We are getting this data due to a request in drag_motion,
-       * rather than due to a request in drag_drop, so we are just
-       * supposed to call drag_status, not actually paste in the
-       * data.
-       */
-      path = get_logical_dest_row (tree_view, &path_down_mode,
-                                   &drop_append_mode);
-
-      if (path == NULL)
-        suggested_action = 0;
-      else if (path_down_mode)
-        gtk_tree_path_down (path);
-
-      if (suggested_action)
-        {
-         if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
-                                                    path,
-                                                    selection_data))
-            {
-              if (path_down_mode)
-                {
-                  path_down_mode = FALSE;
-                  gtk_tree_path_up (path);
-
-                  if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
-                                                             path,
-                                                             selection_data))
-                    suggested_action = 0;
-                }
-              else
-               suggested_action = 0;
-            }
-        }
-
-      gdk_drag_status (context, suggested_action, time);
-
-      if (path)
-        gtk_tree_path_free (path);
-
-      /* If you can't drop, remove user drop indicator until the next motion */
-      if (suggested_action == 0)
-        pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
-                                         NULL,
-                                         PSPP_SHEET_VIEW_DROP_BEFORE);
-
-      return;
-    }
-
-  dest_row = get_dest_row (context, &path_down_mode);
-
-  if (dest_row == NULL)
-    return;
-
-  if (gtk_selection_data_get_length (selection_data) >= 0)
-    {
-      if (path_down_mode)
-        {
-          gtk_tree_path_down (dest_row);
-          if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
-                                                     dest_row, selection_data))
-            gtk_tree_path_up (dest_row);
-        }
-    }
-
-  if (gtk_selection_data_get_length (selection_data) >= 0)
-    {
-      if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
-                                                 dest_row,
-                                                 selection_data))
-        accepted = TRUE;
-    }
-
-  gtk_drag_finish (context,
-                   accepted,
-                   (gdk_drag_context_get_actions (context) == GDK_ACTION_MOVE),
-                   time);
-
-  if (gtk_tree_path_get_depth (dest_row) == 1
-      && gtk_tree_path_get_indices (dest_row)[0] == 0)
-    {
-      /* special special case drag to "0", scroll to first item */
-      if (!tree_view->priv->scroll_to_path)
-        pspp_sheet_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
-    }
-
-  gtk_tree_path_free (dest_row);
-
-  /* drop dest_row */
-  set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
-}
-
-
-
-/* GtkContainer Methods
- */
-
-
-static void
-pspp_sheet_view_remove (GtkContainer *container,
-                     GtkWidget    *widget)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
-  PsppSheetViewChild *child = NULL;
-  GList *tmp_list;
-
-  tmp_list = tree_view->priv->children;
-  while (tmp_list)
-    {
-      child = tmp_list->data;
-      if (child->widget == widget)
-       {
-         gtk_widget_unparent (widget);
-
-         tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
-         g_list_free_1 (tmp_list);
-         g_slice_free (PsppSheetViewChild, child);
-         return;
-       }
-
-      tmp_list = tmp_list->next;
-    }
-
-  tmp_list = tree_view->priv->columns;
-
-  while (tmp_list)
-    {
-      PsppSheetViewColumn *column;
-      column = tmp_list->data;
-      if (column->button == widget)
-       {
-         gtk_widget_unparent (widget);
-         return;
-       }
-      tmp_list = tmp_list->next;
-    }
-}
-
-static void
-pspp_sheet_view_forall (GtkContainer *container,
-                     gboolean      include_internals,
-                     GtkCallback   callback,
-                     gpointer      callback_data)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
-  PsppSheetViewChild *child = NULL;
-  PsppSheetViewColumn *column;
-  GList *tmp_list;
-
-  tmp_list = tree_view->priv->children;
-  while (tmp_list)
-    {
-      child = tmp_list->data;
-      tmp_list = tmp_list->next;
-
-      (* callback) (child->widget, callback_data);
-    }
-  if (include_internals == FALSE)
-    return;
-
-  for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
-    {
-      column = tmp_list->data;
-
-      if (column->button)
-       (* callback) (column->button, callback_data);
-    }
-}
-
-/* Returns TRUE if the treeview contains no "special" (editable or activatable)
- * cells. If so we draw one big row-spanning focus rectangle.
- */
-static gboolean
-pspp_sheet_view_has_special_cell (PsppSheetView *tree_view)
-{
-  GList *list;
-
-  if (tree_view->priv->special_cells != PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT)
-    return tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_YES;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      if (!((PsppSheetViewColumn *)list->data)->visible)
-       continue;
-      if (_pspp_sheet_view_column_count_special_cells (list->data))
-       return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_focus_column (PsppSheetView *tree_view,
-                              PsppSheetViewColumn *focus_column,
-                              gboolean clamp_column_visible)
-{
-  g_return_if_fail (focus_column != NULL);
-
-  tree_view->priv->focus_column = focus_column;
-
-  if (gtk_container_get_focus_child (GTK_CONTAINER (tree_view)) != focus_column->button)
-    gtk_widget_grab_focus (focus_column->button);
-
-  if (clamp_column_visible)
-    pspp_sheet_view_clamp_column_visible (tree_view, focus_column, FALSE);
-}
-
-/* Returns TRUE if the focus is within the headers, after the focus operation is
- * done
- */
-static gboolean
-pspp_sheet_view_header_focus (PsppSheetView      *tree_view,
-                           GtkDirectionType  dir,
-                           gboolean          clamp_column_visible)
-{
-  GtkWidget *focus_child;
-  PsppSheetViewColumn *focus_column;
-  GList *last_column, *first_column;
-  GList *tmp_list;
-  gboolean rtl;
-
-  if (! PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
-    return FALSE;
-
-  focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
-
-  first_column = tree_view->priv->columns;
-  while (first_column)
-    {
-      PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (first_column->data);
-
-      if (pspp_sheet_view_column_can_focus (c) && c->visible)
-       break;
-      first_column = first_column->next;
-    }
-
-  /* No headers are visible, or are focusable.  We can't focus in or out.
-   */
-  if (first_column == NULL)
-    return FALSE;
-
-  last_column = g_list_last (tree_view->priv->columns);
-  while (last_column)
-    {
-      PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (last_column->data);
-
-      if (pspp_sheet_view_column_can_focus (c) && c->visible)
-       break;
-      last_column = last_column->prev;
-    }
-
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  switch (dir)
-    {
-    case GTK_DIR_TAB_BACKWARD:
-    case GTK_DIR_TAB_FORWARD:
-    case GTK_DIR_UP:
-    case GTK_DIR_DOWN:
-      if (focus_child == NULL)
-       {
-         if (tree_view->priv->focus_column != NULL &&
-              pspp_sheet_view_column_can_focus (tree_view->priv->focus_column))
-           focus_column = tree_view->priv->focus_column;
-         else
-            focus_column = first_column->data;
-          pspp_sheet_view_focus_column (tree_view, focus_column,
-                                        clamp_column_visible);
-         return TRUE;
-       }
-      return FALSE;
-
-    case GTK_DIR_LEFT:
-    case GTK_DIR_RIGHT:
-      if (focus_child == NULL)
-       {
-         if (tree_view->priv->focus_column != NULL)
-           focus_column = tree_view->priv->focus_column;
-         else if (dir == GTK_DIR_LEFT)
-           focus_column = last_column->data;
-         else
-           focus_column = first_column->data;
-          pspp_sheet_view_focus_column (tree_view, focus_column,
-                                        clamp_column_visible);
-         return TRUE;
-       }
-
-      if (gtk_widget_child_focus (focus_child, dir))
-       {
-         /* The focus moves inside the button. */
-         /* This is probably a great example of bad UI */
-          if (clamp_column_visible)
-            pspp_sheet_view_clamp_column_visible (tree_view,
-                                                  tree_view->priv->focus_column,
-                                                  FALSE);
-         return TRUE;
-       }
-
-      /* We need to move the focus among the row of buttons. */
-      for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
-       if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data)->button == focus_child)
-         break;
-
-      if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
-         || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
-        {
-         gtk_widget_error_bell (GTK_WIDGET (tree_view));
-         return TRUE;
-       }
-
-      while (tmp_list)
-       {
-         PsppSheetViewColumn *column;
-
-         if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
-           tmp_list = tmp_list->next;
-         else
-           tmp_list = tmp_list->prev;
-
-         if (tmp_list == NULL)
-           {
-             g_warning ("Internal button not found");
-             break;
-           }
-         column = tmp_list->data;
-          if (column->visible &&
-             pspp_sheet_view_column_can_focus (column))
-            {
-              if (column->button)
-                {
-                  pspp_sheet_view_focus_column (tree_view, column,
-                                                clamp_column_visible);
-                  return TRUE;
-                }
-           }
-       }
-      return FALSE;
-
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  return FALSE;
-}
-
-/* This function returns in 'path' the first focusable path, if the given path
- * is already focusable, it's the returned one.
- *
- */
-static gboolean
-search_first_focusable_path (PsppSheetView  *tree_view,
-                            GtkTreePath **path,
-                            gboolean      search_forward,
-                            int *new_node)
-{
-  /* XXX this function is trivial given that the sheetview doesn't support
-     separator rows */
-  int node = -1;
-
-  if (!path || !*path)
-    return FALSE;
-
-  _pspp_sheet_view_find_node (tree_view, *path, &node);
-
-  if (node < 0)
-    return FALSE;
-
-  if (new_node)
-    *new_node = node;
-
-  return (*path != NULL);
-}
-
-static gint
-pspp_sheet_view_focus (GtkWidget        *widget,
-                    GtkDirectionType  direction)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GtkContainer *container = GTK_CONTAINER (widget);
-  GtkWidget *focus_child;
-
-  if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
-    return FALSE;
-
-  focus_child = gtk_container_get_focus_child (container);
-
-  pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (widget), FALSE);
-  /* Case 1.  Headers currently have focus. */
-  if (focus_child)
-    {
-      switch (direction)
-       {
-       case GTK_DIR_LEFT:
-       case GTK_DIR_RIGHT:
-         pspp_sheet_view_header_focus (tree_view, direction, TRUE);
-         return TRUE;
-       case GTK_DIR_TAB_BACKWARD:
-       case GTK_DIR_UP:
-         return FALSE;
-       case GTK_DIR_TAB_FORWARD:
-       case GTK_DIR_DOWN:
-         gtk_widget_grab_focus (widget);
-         return TRUE;
-       default:
-         g_assert_not_reached ();
-         return FALSE;
-       }
-    }
-
-  /* Case 2. We don't have focus at all. */
-  if (!gtk_widget_has_focus (widget))
-    {
-      if (!pspp_sheet_view_header_focus (tree_view, direction, FALSE))
-       gtk_widget_grab_focus (widget);
-      return TRUE;
-    }
-
-  /* Case 3. We have focus already. */
-  if (direction == GTK_DIR_TAB_BACKWARD)
-    return (pspp_sheet_view_header_focus (tree_view, direction, FALSE));
-  else if (direction == GTK_DIR_TAB_FORWARD)
-    return FALSE;
-
-  /* Other directions caught by the keybindings */
-  gtk_widget_grab_focus (widget);
-  return TRUE;
-}
-
-static void
-pspp_sheet_view_grab_focus (GtkWidget *widget)
-{
-  GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->grab_focus (widget);
-
-  pspp_sheet_view_focus_to_cursor (PSPP_SHEET_VIEW (widget));
-}
-
-static void
-pspp_sheet_view_style_updated (GtkWidget *widget)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  GList *list;
-  PsppSheetViewColumn *column;
-  GtkStyleContext *context;
-
-  GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->style_updated (widget);
-
-  if (gtk_widget_get_realized (widget))
-    {
-      context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
-      gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
-      gtk_style_context_set_background (context, tree_view->priv->header_window);
-      pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
-    }
-
-  gtk_widget_style_get (widget,
-                       "expander-size", &tree_view->priv->expander_size,
-                       NULL);
-  tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      column = list->data;
-      _pspp_sheet_view_column_cell_set_dirty (column);
-    }
-
-  tree_view->priv->fixed_height = -1;
-
-  /* Invalidate cached button style. */
-  if (tree_view->priv->button_style)
-    {
-      g_object_unref (tree_view->priv->button_style);
-      tree_view->priv->button_style = NULL;
-    }
-
-  gtk_widget_queue_resize (widget);
-}
-
-
-static void
-pspp_sheet_view_set_focus_child (GtkContainer *container,
-                              GtkWidget    *child)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
-  GList *list;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      if (PSPP_SHEET_VIEW_COLUMN (list->data)->button == child)
-       {
-         tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (list->data);
-         break;
-       }
-    }
-
-  GTK_CONTAINER_CLASS (pspp_sheet_view_parent_class)->set_focus_child (container, child);
-}
-
-static void
-pspp_sheet_view_set_adjustments (PsppSheetView   *tree_view,
-                              GtkAdjustment *hadj,
-                              GtkAdjustment *vadj)
-{
-  gboolean need_adjust = FALSE;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (hadj)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
-  else
-    hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-  if (vadj)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
-  else
-    vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-
-  if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
-    {
-      g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
-                                           pspp_sheet_view_adjustment_changed,
-                                           tree_view);
-      g_object_unref (tree_view->priv->hadjustment);
-    }
-
-  if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
-    {
-      g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
-                                           pspp_sheet_view_adjustment_changed,
-                                           tree_view);
-      g_object_unref (tree_view->priv->vadjustment);
-    }
-
-  if (tree_view->priv->hadjustment != hadj)
-    {
-      tree_view->priv->hadjustment = hadj;
-      g_object_ref_sink (tree_view->priv->hadjustment);
-
-      g_signal_connect (tree_view->priv->hadjustment, "value-changed",
-                       G_CALLBACK (pspp_sheet_view_adjustment_changed),
-                       tree_view);
-      need_adjust = TRUE;
-    }
-
-  if (tree_view->priv->vadjustment != vadj)
-    {
-      tree_view->priv->vadjustment = vadj;
-      g_object_ref_sink (tree_view->priv->vadjustment);
-
-      g_signal_connect (tree_view->priv->vadjustment, "value-changed",
-                       G_CALLBACK (pspp_sheet_view_adjustment_changed),
-                       tree_view);
-      need_adjust = TRUE;
-    }
-
-  if (need_adjust)
-    pspp_sheet_view_adjustment_changed (NULL, tree_view);
-}
-
-
-static gboolean
-pspp_sheet_view_real_move_cursor (PsppSheetView       *tree_view,
-                               GtkMovementStep    step,
-                               gint               count)
-{
-  PsppSheetSelectMode mode;
-  GdkModifierType state;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-  g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
-                       step == GTK_MOVEMENT_VISUAL_POSITIONS ||
-                       step == GTK_MOVEMENT_DISPLAY_LINES ||
-                       step == GTK_MOVEMENT_PAGES ||
-                       step == GTK_MOVEMENT_BUFFER_ENDS ||
-                       step == GTK_MOVEMENT_DISPLAY_LINE_ENDS, FALSE);
-
-  if (tree_view->priv->row_count == 0)
-    return FALSE;
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  pspp_sheet_view_stop_editing (tree_view, FALSE);
-  PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-  mode = 0;
-  if (gtk_get_current_event_state (&state))
-    {
-      if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
-        mode |= PSPP_SHEET_SELECT_MODE_TOGGLE;
-      if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
-        mode |= PSPP_SHEET_SELECT_MODE_EXTEND;
-    }
-  /* else we assume not pressed */
-
-  switch (step)
-    {
-    case GTK_MOVEMENT_LOGICAL_POSITIONS:
-      pspp_sheet_view_move_cursor_tab (tree_view, count);
-      break;
-    case GTK_MOVEMENT_VISUAL_POSITIONS:
-      pspp_sheet_view_move_cursor_left_right (tree_view, count, mode);
-      break;
-    case GTK_MOVEMENT_DISPLAY_LINES:
-      pspp_sheet_view_move_cursor_up_down (tree_view, count, mode);
-      break;
-    case GTK_MOVEMENT_PAGES:
-      pspp_sheet_view_move_cursor_page_up_down (tree_view, count, mode);
-      break;
-    case GTK_MOVEMENT_BUFFER_ENDS:
-      pspp_sheet_view_move_cursor_start_end (tree_view, count, mode);
-      break;
-    case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
-      pspp_sheet_view_move_cursor_line_start_end (tree_view, count, mode);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-
-  return TRUE;
-}
-
-static void
-pspp_sheet_view_put (PsppSheetView *tree_view,
-                    GtkWidget   *child_widget,
-                    GtkTreePath *path,
-                    PsppSheetViewColumn *column)
-{
-  PsppSheetViewChild *child;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (GTK_IS_WIDGET (child_widget));
-
-  child = g_slice_new (PsppSheetViewChild);
-
-  child->widget = child_widget;
-  _pspp_sheet_view_find_node (tree_view, path, &child->node);
-  if (child->node < 0)
-    {
-      g_assert_not_reached ();
-    }
-  child->column = column;
-
-  tree_view->priv->children = g_list_append (tree_view->priv->children, child);
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
-
-  gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
-}
-
-/* TreeModel Callbacks
- */
-
-static void
-pspp_sheet_view_row_changed (GtkTreeModel *model,
-                          GtkTreePath  *path,
-                          GtkTreeIter  *iter,
-                          gpointer      data)
-{
-  PsppSheetView *tree_view = (PsppSheetView *)data;
-  int node;
-  gboolean free_path = FALSE;
-  GtkTreePath *cursor_path;
-
-  g_return_if_fail (path != NULL || iter != NULL);
-
-  if (tree_view->priv->cursor != NULL)
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  else
-    cursor_path = NULL;
-
-  if (tree_view->priv->edited_column &&
-      (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
-    pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-  if (cursor_path != NULL)
-    gtk_tree_path_free (cursor_path);
-
-  if (path == NULL)
-    {
-      path = gtk_tree_model_get_path (model, iter);
-      free_path = TRUE;
-    }
-  else if (iter == NULL)
-    gtk_tree_model_get_iter (model, iter, path);
-
-  _pspp_sheet_view_find_node (tree_view,
-                              path,
-                              &node);
-
-  if (node >= 0)
-    {
-      if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-        pspp_sheet_view_node_queue_redraw (tree_view, node);
-    }
-
-  if (free_path)
-    gtk_tree_path_free (path);
-}
-
-static void
-pspp_sheet_view_row_inserted (GtkTreeModel *model,
-                           GtkTreePath  *path,
-                           GtkTreeIter  *iter,
-                           gpointer      data)
-{
-  PsppSheetView *tree_view = (PsppSheetView *) data;
-  gint *indices;
-  int tmpnode = -1;
-  gint height = tree_view->priv->fixed_height;
-  gboolean free_path = FALSE;
-  gboolean node_visible = TRUE;
-
-  g_return_if_fail (path != NULL || iter != NULL);
-
-  if (path == NULL)
-    {
-      path = gtk_tree_model_get_path (model, iter);
-      free_path = TRUE;
-    }
-  else if (iter == NULL)
-    gtk_tree_model_get_iter (model, iter, path);
-
-  tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL);
-
-  /* Update all row-references */
-  gtk_tree_row_reference_inserted (G_OBJECT (data), path);
-  indices = gtk_tree_path_get_indices (path);
-  tmpnode = indices[0];
-
-  range_tower_insert0 (tree_view->priv->selected, tmpnode, 1);
-
-  if (height > 0)
-    {
-      if (node_visible && node_is_visible (tree_view, tmpnode))
-       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-      else
-       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
-    }
-  else
-    install_presize_handler (tree_view);
-  if (free_path)
-    gtk_tree_path_free (path);
-}
-
-static void
-pspp_sheet_view_row_deleted (GtkTreeModel *model,
-                          GtkTreePath  *path,
-                          gpointer      data)
-{
-  PsppSheetView *tree_view = (PsppSheetView *)data;
-  int node;
-
-  g_return_if_fail (path != NULL);
-
-  gtk_tree_row_reference_deleted (G_OBJECT (data), path);
-
-  _pspp_sheet_view_find_node (tree_view, path, &node);
-
-  if (node < 0)
-    return;
-
-  range_tower_delete (tree_view->priv->selected, node, 1);
-
-  /* Ensure we don't have a dangling pointer to a dead node */
-  ensure_unprelighted (tree_view);
-
-  /* Cancel editting if we've started */
-  pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-  if (tree_view->priv->destroy_count_func)
-    {
-      gint child_count = 0;
-      tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
-    }
-
-  tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL);
-
-  if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
-    {
-      gtk_tree_row_reference_free (tree_view->priv->top_row);
-      tree_view->priv->top_row = NULL;
-    }
-
-  install_scroll_sync_handler (tree_view);
-
-  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
-#if 0
-  if (helper_data.changed)
-    g_signal_emit_by_name (tree_view->priv->selection, "changed");
-#endif
-}
-
-static void
-pspp_sheet_view_rows_reordered (GtkTreeModel *model,
-                             GtkTreePath  *parent,
-                             GtkTreeIter  *iter,
-                             gint         *new_order,
-                             gpointer      data)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (data);
-  gint len;
-
-  /* XXX need to adjust selection */
-  len = gtk_tree_model_iter_n_children (model, iter);
-
-  if (len < 2)
-    return;
-
-  gtk_tree_row_reference_reordered (G_OBJECT (data),
-                                   parent,
-                                   iter,
-                                   new_order);
-
-  if (gtk_tree_path_get_depth (parent) != 0)
-    return;
-
-  if (tree_view->priv->edited_column)
-    pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-  /* we need to be unprelighted */
-  ensure_unprelighted (tree_view);
-
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
-  pspp_sheet_view_dy_to_top_row (tree_view);
-}
-
-
-/* Internal tree functions
- */
-
-
-static void
-pspp_sheet_view_get_background_xrange (PsppSheetView       *tree_view,
-                                     PsppSheetViewColumn *column,
-                                     gint              *x1,
-                                     gint              *x2)
-{
-  PsppSheetViewColumn *tmp_column = NULL;
-  gint total_width;
-  GList *list;
-  gboolean rtl;
-
-  if (x1)
-    *x1 = 0;
-
-  if (x2)
-    *x2 = 0;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  total_width = 0;
-  for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-       list;
-       list = (rtl ? list->prev : list->next))
-    {
-      tmp_column = list->data;
-
-      if (tmp_column == column)
-        break;
-
-      if (tmp_column->visible)
-        total_width += tmp_column->width;
-    }
-
-  if (tmp_column != column)
-    {
-      g_warning (G_STRLOC": passed-in column isn't in the tree");
-      return;
-    }
-
-  if (x1)
-    *x1 = total_width;
-
-  if (x2)
-    {
-      if (column->visible)
-        *x2 = total_width + column->width;
-      else
-        *x2 = total_width; /* width of 0 */
-    }
-}
-
-/* Make sure the node is visible vertically */
-static void
-pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view,
-                                    int node)
-{
-  gint node_dy, height;
-  GtkTreePath *path = NULL;
-
-  if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return;
-
-  /* just return if the node is visible, avoiding a costly expose */
-  node_dy = pspp_sheet_view_node_find_offset (tree_view, node);
-  height = ROW_HEIGHT (tree_view);
-  if (node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
-      && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
-                              + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
-    return;
-
-  path = _pspp_sheet_view_find_path (tree_view, node);
-  if (path)
-    {
-      /* We process updates because we want to clear old selected items when we scroll.
-       * if this is removed, we get a "selection streak" at the bottom. */
-      gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
-      pspp_sheet_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
-      gtk_tree_path_free (path);
-    }
-}
-
-static void
-pspp_sheet_view_clamp_column_visible (PsppSheetView       *tree_view,
-                                   PsppSheetViewColumn *column,
-                                   gboolean           focus_to_cell)
-{
-  gint x, width;
-
-  if (column == NULL)
-    return;
-
-  x = column->allocation.x;
-  width = column->allocation.width;
-
-  if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
-    {
-      /* The column is larger than the horizontal page size.  If the
-       * column has cells which can be focussed individually, then we make
-       * sure the cell which gets focus is fully visible (if even the
-       * focus cell is bigger than the page size, we make sure the
-       * left-hand side of the cell is visible).
-       *
-       * If the column does not have those so-called special cells, we
-       * make sure the left-hand side of the column is visible.
-       */
-
-      if (focus_to_cell && pspp_sheet_view_has_special_cell (tree_view))
-        {
-         GtkTreePath *cursor_path;
-         GdkRectangle background_area, cell_area, focus_area;
-
-         cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-         pspp_sheet_view_get_cell_area (tree_view,
-                                      cursor_path, column, &cell_area);
-         pspp_sheet_view_get_background_area (tree_view,
-                                            cursor_path, column,
-                                            &background_area);
-
-         gtk_tree_path_free (cursor_path);
-
-         _pspp_sheet_view_column_get_focus_area (column,
-                                               &background_area,
-                                               &cell_area,
-                                               &focus_area);
-
-         x = focus_area.x;
-         width = focus_area.width;
-
-         if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
-           {
-             if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
-               gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                         x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
-             else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
-               gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
-           }
-       }
-
-      gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                               CLAMP (x,
-                                      gtk_adjustment_get_lower (tree_view->priv->hadjustment),
-                                      gtk_adjustment_get_upper (tree_view->priv->hadjustment)
-                                      - gtk_adjustment_get_page_size (tree_view->priv->hadjustment)));
-    }
-  else
-    {
-      if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
-         gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                   x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
-      else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
-       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
-  }
-}
-
-GtkTreePath *
-_pspp_sheet_view_find_path (PsppSheetView *tree_view,
-                            int node)
-{
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new ();
-  if (node >= 0)
-    gtk_tree_path_append_index (path, node);
-  return path;
-}
-
-void
-_pspp_sheet_view_find_node (PsppSheetView  *tree_view,
-                         GtkTreePath  *path,
-                         int *node)
-{
-  gint *indices = gtk_tree_path_get_indices (path);
-  gint depth = gtk_tree_path_get_depth (path);
-
-  *node = -1;
-  if (depth == 0 || indices[0] < 0 || indices[0] >= tree_view->priv->row_count)
-    return;
-  *node = indices[0];
-}
-
-static void
-pspp_sheet_view_add_move_binding (GtkBindingSet  *binding_set,
-                               guint           keyval,
-                               guint           modmask,
-                               gboolean        add_shifted_binding,
-                               GtkMovementStep step,
-                               gint            count)
-{
-
-  gtk_binding_entry_add_signal (binding_set, keyval, modmask,
-                                "move-cursor", 2,
-                                G_TYPE_ENUM, step,
-                                G_TYPE_INT, count);
-
-  if (add_shifted_binding)
-    gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
-                                 "move-cursor", 2,
-                                 G_TYPE_ENUM, step,
-                                 G_TYPE_INT, count);
-
-  if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
-   return;
-
-  gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "move-cursor", 2,
-                                G_TYPE_ENUM, step,
-                                G_TYPE_INT, count);
-
-  gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                                G_TYPE_ENUM, step,
-                                G_TYPE_INT, count);
-}
-
-static void
-pspp_sheet_view_set_column_drag_info (PsppSheetView       *tree_view,
-                                   PsppSheetViewColumn *column)
-{
-  PsppSheetViewColumn *left_column;
-  PsppSheetViewColumn *cur_column = NULL;
-  PsppSheetViewColumnReorder *reorder;
-  gboolean rtl;
-  GList *tmp_list;
-  gint left;
-
-  /* We want to precalculate the motion list such that we know what column slots
-   * are available.
-   */
-  left_column = NULL;
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  /* First, identify all possible drop spots */
-  if (rtl)
-    tmp_list = g_list_last (tree_view->priv->columns);
-  else
-    tmp_list = g_list_first (tree_view->priv->columns);
-
-  while (tmp_list)
-    {
-      cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-      tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
-
-      if (cur_column->visible == FALSE)
-       continue;
-
-      /* If it's not the column moving and func tells us to skip over the column, we continue. */
-      if (left_column != column && cur_column != column &&
-         tree_view->priv->column_drop_func &&
-         ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
-       {
-         left_column = cur_column;
-         continue;
-       }
-      reorder = g_slice_new0 (PsppSheetViewColumnReorder);
-      reorder->left_column = left_column;
-      left_column = reorder->right_column = cur_column;
-
-      tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
-    }
-
-  /* Add the last one */
-  if (tree_view->priv->column_drop_func == NULL ||
-      ((left_column != column) &&
-       tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
-    {
-      reorder = g_slice_new0 (PsppSheetViewColumnReorder);
-      reorder->left_column = left_column;
-      reorder->right_column = NULL;
-      tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
-    }
-
-  /* We quickly check to see if it even makes sense to reorder columns. */
-  /* If there is nothing that can be moved, then we return */
-
-  if (tree_view->priv->column_drag_info == NULL)
-    return;
-
-  /* We know there are always 2 slots possbile, as you can always return column. */
-  /* If that's all there is, return */
-  if (tree_view->priv->column_drag_info->next == NULL ||
-      (tree_view->priv->column_drag_info->next->next == NULL &&
-       ((PsppSheetViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
-       ((PsppSheetViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
-    {
-      for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
-       g_slice_free (PsppSheetViewColumnReorder, tmp_list->data);
-      g_list_free (tree_view->priv->column_drag_info);
-      tree_view->priv->column_drag_info = NULL;
-      return;
-    }
-  /* We fill in the ranges for the columns, now that we've isolated them */
-  left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
-
-  for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
-    {
-      reorder = (PsppSheetViewColumnReorder *) tmp_list->data;
-
-      reorder->left_align = left;
-      if (tmp_list->next != NULL)
-       {
-         g_assert (tmp_list->next->data);
-         left = reorder->right_align = (reorder->right_column->allocation.x +
-                                        reorder->right_column->allocation.width +
-                                        ((PsppSheetViewColumnReorder *)tmp_list->next->data)->left_column->allocation.x)/2;
-       }
-      else
-       {
-         gint width = gdk_window_get_width (tree_view->priv->header_window);
-         reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
-       }
-    }
-}
-
-void
-_pspp_sheet_view_column_start_drag (PsppSheetView       *tree_view,
-                                 PsppSheetViewColumn *column)
-{
-  GdkEvent *send_event;
-  GtkAllocation allocation;
-  gint x, y;
-  GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
-  GdkDisplay *display = gdk_screen_get_display (screen);
-
-  g_return_if_fail (tree_view->priv->column_drag_info == NULL);
-  g_return_if_fail (tree_view->priv->cur_reorder == NULL);
-  g_return_if_fail (column->button);
-
-  pspp_sheet_view_set_column_drag_info (tree_view, column);
-
-  if (tree_view->priv->column_drag_info == NULL)
-    return;
-
-  if (tree_view->priv->drag_window == NULL)
-    {
-      GdkWindowAttr attributes;
-      guint attributes_mask;
-
-      attributes.window_type = GDK_WINDOW_CHILD;
-      attributes.wclass = GDK_INPUT_OUTPUT;
-      attributes.x = column->allocation.x;
-      attributes.y = 0;
-      attributes.width = column->allocation.width;
-      attributes.height = column->allocation.height;
-      attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
-      attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
-      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL ;
-
-      tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
-                                                    &attributes,
-                                                    attributes_mask);
-      gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
-    }
-
-  gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
-  gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
-
-  gtk_grab_remove (column->button);
-
-  send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
-  send_event->crossing.send_event = TRUE;
-  send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (column->button)));
-  send_event->crossing.subwindow = NULL;
-  send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
-  send_event->crossing.time = GDK_CURRENT_TIME;
-
-  gtk_propagate_event (column->button, send_event);
-  gdk_event_free (send_event);
-
-  send_event = gdk_event_new (GDK_BUTTON_RELEASE);
-  send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
-  send_event->button.send_event = TRUE;
-  send_event->button.time = GDK_CURRENT_TIME;
-  send_event->button.x = -1;
-  send_event->button.y = -1;
-  send_event->button.axes = NULL;
-  send_event->button.state = 0;
-  send_event->button.button = 1;
-  send_event->button.device =
-    gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
-
-  send_event->button.x_root = 0;
-  send_event->button.y_root = 0;
-
-  gtk_propagate_event (column->button, send_event);
-  gdk_event_free (send_event);
-
-  /* Kids, don't try this at home */
-  g_object_ref (column->button);
-  gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
-  gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
-  gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
-  g_object_unref (column->button);
-
-  tree_view->priv->drag_column_x = column->allocation.x;
-  allocation = column->allocation;
-  allocation.x = 0;
-  gtk_widget_size_allocate (column->button, &allocation);
-  gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
-
-  tree_view->priv->drag_column = column;
-  gdk_window_show (tree_view->priv->drag_window);
-
-  gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
-
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-  while (gtk_events_pending ())
-    gtk_main_iteration ();
-
-  PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG);
-  gdk_pointer_grab (tree_view->priv->drag_window,
-                   FALSE,
-                   GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
-                   NULL, NULL, GDK_CURRENT_TIME);
-  gdk_keyboard_grab (tree_view->priv->drag_window,
-                    FALSE,
-                    GDK_CURRENT_TIME);
-}
-
-void
-_pspp_sheet_view_queue_draw_node (PsppSheetView        *tree_view,
-                               int node,
-                               const GdkRectangle *clip_rect)
-{
-  GdkRectangle rect;
-  GtkAllocation allocation;
-
-  if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return;
-
-  gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-  rect.x = 0;
-  rect.width = MAX (tree_view->priv->width, allocation.width);
-
-  rect.y = BACKGROUND_FIRST_PIXEL (tree_view, node);
-  rect.height = ROW_HEIGHT (tree_view);
-
-  if (clip_rect)
-    {
-      GdkRectangle new_rect;
-
-      gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
-
-      gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
-    }
-  else
-    {
-      gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
-    }
-}
-
-static void
-pspp_sheet_view_queue_draw_path (PsppSheetView        *tree_view,
-                               GtkTreePath        *path,
-                               const GdkRectangle *clip_rect)
-{
-  int node = -1;
-
-  _pspp_sheet_view_find_node (tree_view, path, &node);
-
-  if (node)
-    _pspp_sheet_view_queue_draw_node (tree_view, node, clip_rect);
-}
-
-static void
-pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
-
-{
-  GtkTreePath *cursor_path;
-
-  if ((tree_view->priv->row_count == 0) ||
-      (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
-    return;
-
-  cursor_path = NULL;
-  if (tree_view->priv->cursor)
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-  if (cursor_path == NULL)
-    {
-      /* There's no cursor.  Move the cursor to the first selected row, if any
-       * are selected, otherwise to the first row in the sheetview.
-       */
-      GList *selected_rows;
-      GtkTreeModel *model;
-      PsppSheetSelection *selection;
-
-      selection = pspp_sheet_view_get_selection (tree_view);
-      selected_rows = pspp_sheet_selection_get_selected_rows (selection, &model);
-
-      if (selected_rows)
-       {
-          /* XXX we could avoid doing O(n) work to get this result */
-          cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
-         g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
-         g_list_free (selected_rows);
-        }
-      else
-       {
-         cursor_path = gtk_tree_path_new_first ();
-         search_first_focusable_path (tree_view, &cursor_path,
-                                      TRUE, NULL);
-       }
-
-      gtk_tree_row_reference_free (tree_view->priv->cursor);
-      tree_view->priv->cursor = NULL;
-
-      if (cursor_path)
-       {
-         if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-              tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
-           pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE, 0);
-         else
-           pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, 0);
-       }
-    }
-
-  if (cursor_path)
-    {
-      /* Now find a column for the cursor. */
-      PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-
-      pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
-      gtk_tree_path_free (cursor_path);
-
-      if (tree_view->priv->focus_column == NULL)
-       {
-         GList *list;
-         for (list = tree_view->priv->columns; list; list = list->next)
-           {
-             if (PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
-               {
-                 tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (list->data);
-                  pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
-                  pspp_sheet_selection_select_column (tree_view->priv->selection, tree_view->priv->focus_column);
-                 break;
-               }
-           }
-
-       }
-    }
-}
-
-static gboolean
-pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view,
-                                  gint         count,
-                                   PsppSheetSelectMode mode)
-{
-  gint selection_count;
-  int cursor_node = -1;
-  int new_cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-  gboolean grab_focus = TRUE;
-
-  if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  cursor_path = NULL;
-  if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    /* FIXME: we lost the cursor; should we get the first? */
-    return FALSE;
-
-  cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-
-  if (cursor_node < 0)
-    /* FIXME: we lost the cursor; should we get the first? */
-    return FALSE;
-
-  selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection);
-
-  if (selection_count == 0
-      && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE
-      && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE))
-    {
-      /* Don't move the cursor, but just select the current node */
-      new_cursor_node = cursor_node;
-    }
-  else
-    {
-      if (count == -1)
-       new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node);
-      else
-       new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
-    }
-
-  gtk_tree_path_free (cursor_path);
-
-  if (new_cursor_node)
-    {
-      cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node);
-
-      search_first_focusable_path (tree_view, &cursor_path,
-                                  (count != -1),
-                                  &new_cursor_node);
-
-      if (cursor_path)
-       gtk_tree_path_free (cursor_path);
-    }
-
-  /*
-   * If the list has only one item and multi-selection is set then select
-   * the row (if not yet selected).
-   */
-  if ((tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
-       tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) &&
-      new_cursor_node < 0)
-    {
-      if (count == -1)
-        new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
-      else
-        new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node);
-
-      if (new_cursor_node < 0
-         && !pspp_sheet_view_node_is_selected (tree_view, cursor_node))
-        {
-          new_cursor_node = cursor_node;
-        }
-      else
-        {
-          new_cursor_node = -1;
-        }
-    }
-
-  if (new_cursor_node >= 0)
-    {
-      cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node);
-      pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE, mode);
-      gtk_tree_path_free (cursor_path);
-    }
-  else
-    {
-      pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
-      if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND))
-        {
-          if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
-                                          count < 0 ?
-                                          GTK_DIR_UP : GTK_DIR_DOWN))
-            {
-              GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
-
-              if (toplevel)
-                gtk_widget_child_focus (toplevel,
-                                        count < 0 ?
-                                        GTK_DIR_TAB_BACKWARD :
-                                        GTK_DIR_TAB_FORWARD);
-
-              grab_focus = FALSE;
-            }
-        }
-      else
-        {
-          gtk_widget_error_bell (GTK_WIDGET (tree_view));
-        }
-    }
-
-  if (grab_focus)
-    gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-  return new_cursor_node >= 0;
-}
-
-static void
-pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view,
-                                          gint         count,
-                                          PsppSheetSelectMode mode)
-{
-  int cursor_node = -1;
-  GtkTreePath *old_cursor_path = NULL;
-  GtkTreePath *cursor_path = NULL;
-  int start_cursor_node = -1;
-  gint y;
-  gint window_y;
-  gint vertical_separator;
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  else
-    /* This is sorta weird.  Focus in should give us a cursor */
-    return;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
-  _pspp_sheet_view_find_node (tree_view, old_cursor_path, &cursor_node);
-
-  if (cursor_node < 0)
-    {
-      /* FIXME: we lost the cursor.  Should we try to get one? */
-      gtk_tree_path_free (old_cursor_path);
-      return;
-    }
-
-  y = pspp_sheet_view_node_find_offset (tree_view, cursor_node);
-  window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
-  y += tree_view->priv->cursor_offset;
-  y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
-  y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
-
-  if (y >= tree_view->priv->height)
-    y = tree_view->priv->height - 1;
-
-  tree_view->priv->cursor_offset =
-    pspp_sheet_view_find_offset (tree_view, y, &cursor_node);
-
-  if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (tree_view))
-    {
-      cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
-      tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (tree_view);
-    }
-
-  y -= tree_view->priv->cursor_offset;
-  cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node);
-
-  start_cursor_node = cursor_node;
-
-  if (! search_first_focusable_path (tree_view, &cursor_path,
-                                    (count != -1),
-                                    &cursor_node))
-    {
-      /* It looks like we reached the end of the view without finding
-       * a focusable row.  We will step backwards to find the last
-       * focusable row.
-       */
-      cursor_node = start_cursor_node;
-      cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node);
-
-      search_first_focusable_path (tree_view, &cursor_path,
-                                  (count == -1),
-                                  &cursor_node);
-    }
-
-  if (!cursor_path)
-    goto cleanup;
-
-  /* update y */
-  y = pspp_sheet_view_node_find_offset (tree_view, cursor_node);
-
-  pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, mode);
-
-  y -= window_y;
-  pspp_sheet_view_scroll_to_point (tree_view, -1, y);
-  pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-  _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-
-  if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
-    gtk_widget_error_bell (GTK_WIDGET (tree_view));
-
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-cleanup:
-  gtk_tree_path_free (old_cursor_path);
-  gtk_tree_path_free (cursor_path);
-}
-
-static void
-pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view,
-                                        gint         count,
-                                        PsppSheetSelectMode mode)
-{
-  int cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-  PsppSheetViewColumn *column;
-  GtkTreeIter iter;
-  GList *list;
-  gboolean found_column = FALSE;
-  gboolean rtl;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  else
-    return;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-  if (cursor_node < 0)
-    return;
-  if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
-    {
-      gtk_tree_path_free (cursor_path);
-      return;
-    }
-  gtk_tree_path_free (cursor_path);
-
-  list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
-  if (tree_view->priv->focus_column)
-    {
-      for (; list; list = (rtl ? list->prev : list->next))
-       {
-         if (list->data == tree_view->priv->focus_column)
-           break;
-       }
-    }
-
-  while (list)
-    {
-      gboolean left, right;
-
-      column = list->data;
-      if (column->visible == FALSE || column->row_head)
-       goto loop_end;
-
-      pspp_sheet_view_column_cell_set_cell_data (column,
-                                              tree_view->priv->model,
-                                              &iter);
-
-      if (rtl)
-        {
-         right = list->prev ? TRUE : FALSE;
-         left = list->next ? TRUE : FALSE;
-       }
-      else
-        {
-         left = list->prev ? TRUE : FALSE;
-         right = list->next ? TRUE : FALSE;
-        }
-
-      if (_pspp_sheet_view_column_cell_focus (column, count, left, right))
-       {
-         tree_view->priv->focus_column = column;
-         found_column = TRUE;
-         break;
-       }
-    loop_end:
-      if (count == 1)
-       list = rtl ? list->prev : list->next;
-      else
-       list = rtl ? list->next : list->prev;
-    }
-
-  if (found_column)
-    {
-      _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-      g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
-      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-    }
-  else
-    {
-      gtk_widget_error_bell (GTK_WIDGET (tree_view));
-    }
-
-  pspp_sheet_view_clamp_column_visible (tree_view,
-                                     tree_view->priv->focus_column, TRUE);
-}
-
-static void
-pspp_sheet_view_move_cursor_line_start_end (PsppSheetView *tree_view,
-                                            gint         count,
-                                            PsppSheetSelectMode mode)
-{
-  int cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-  PsppSheetViewColumn *column;
-  PsppSheetViewColumn *found_column;
-  GtkTreeIter iter;
-  GList *list;
-  gboolean rtl;
-
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  else
-    return;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-  if (cursor_node < 0)
-    return;
-  if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
-    {
-      gtk_tree_path_free (cursor_path);
-      return;
-    }
-  gtk_tree_path_free (cursor_path);
-
-  list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
-  if (tree_view->priv->focus_column)
-    {
-      for (; list; list = (rtl ? list->prev : list->next))
-       {
-         if (list->data == tree_view->priv->focus_column)
-           break;
-       }
-    }
-
-  found_column = NULL;
-  while (list)
-    {
-      gboolean left, right;
-
-      column = list->data;
-      if (column->visible == FALSE || column->row_head)
-       goto loop_end;
-
-      pspp_sheet_view_column_cell_set_cell_data (column,
-                                              tree_view->priv->model,
-                                              &iter);
-
-      if (rtl)
-        {
-         right = list->prev ? TRUE : FALSE;
-         left = list->next ? TRUE : FALSE;
-       }
-      else
-        {
-         left = list->prev ? TRUE : FALSE;
-         right = list->next ? TRUE : FALSE;
-        }
-
-      if (column->tabbable
-          && _pspp_sheet_view_column_cell_focus (column, count, left, right))
-        found_column = column;
-
-    loop_end:
-      if (count == 1)
-       list = rtl ? list->prev : list->next;
-      else
-       list = rtl ? list->next : list->prev;
-    }
-
-  if (found_column)
-    {
-      tree_view->priv->focus_column = found_column;
-      _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-      g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
-      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-    }
-
-  pspp_sheet_view_clamp_column_visible (tree_view,
-                                     tree_view->priv->focus_column, TRUE);
-}
-
-static gboolean
-try_move_cursor_tab (PsppSheetView *tree_view,
-                     gboolean start_at_focus_column,
-                     gint count)
-{
-  PsppSheetViewColumn *column;
-  GtkTreeIter iter;
-  int cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-  gboolean rtl;
-  GList *list;
-
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-  else
-    return TRUE;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-  if (cursor_node < 0)
-    return TRUE;
-  if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
-    {
-      gtk_tree_path_free (cursor_path);
-      return TRUE;
-    }
-  gtk_tree_path_free (cursor_path);
-
-  rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
-  if (start_at_focus_column)
-    {
-      list = (rtl
-              ? g_list_last (tree_view->priv->columns)
-              : g_list_first (tree_view->priv->columns));
-      if (tree_view->priv->focus_column)
-        {
-          for (; list; list = (rtl ? list->prev : list->next))
-            {
-              if (list->data == tree_view->priv->focus_column)
-                break;
-            }
-        }
-    }
-  else
-    {
-      list = (rtl ^ (count == 1)
-              ? g_list_first (tree_view->priv->columns)
-              : g_list_last (tree_view->priv->columns));
-    }
-
-  while (list)
-    {
-      gboolean left, right;
-
-      column = list->data;
-      if (column->visible == FALSE || !column->tabbable)
-       goto loop_end;
-
-      pspp_sheet_view_column_cell_set_cell_data (column,
-                                                 tree_view->priv->model,
-                                                 &iter);
-
-      if (rtl)
-        {
-         right = list->prev ? TRUE : FALSE;
-         left = list->next ? TRUE : FALSE;
-       }
-      else
-        {
-         left = list->prev ? TRUE : FALSE;
-         right = list->next ? TRUE : FALSE;
-        }
-
-      if (column->tabbable
-          && _pspp_sheet_view_column_cell_focus (column, count, left, right))
-       {
-         tree_view->priv->focus_column = column;
-          _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-          g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
-          gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-          return TRUE;
-       }
-    loop_end:
-      if (count == 1)
-       list = rtl ? list->prev : list->next;
-      else
-       list = rtl ? list->next : list->prev;
-    }
-
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_move_cursor_tab (PsppSheetView *tree_view,
-                                 gint         count)
-{
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  if (!try_move_cursor_tab (tree_view, TRUE, count))
-    {
-      if (pspp_sheet_view_move_cursor_up_down (tree_view, count, 0)
-          && !try_move_cursor_tab (tree_view, FALSE, count))
-        gtk_widget_error_bell (GTK_WIDGET (tree_view));
-    }
-
-  pspp_sheet_view_clamp_column_visible (tree_view,
-                                        tree_view->priv->focus_column, TRUE);
-}
-
-static void
-pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view,
-                                       gint         count,
-                                       PsppSheetSelectMode mode)
-{
-  int cursor_node;
-  GtkTreePath *path;
-  GtkTreePath *old_path;
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return;
-
-  g_return_if_fail (tree_view->priv->row_count > 0);
-
-  pspp_sheet_view_get_cursor (tree_view, &old_path, NULL);
-
-  if (count == -1)
-    {
-      /* Now go forward to find the first focusable row. */
-      path = _pspp_sheet_view_find_path (tree_view, 0);
-      search_first_focusable_path (tree_view, &path,
-                                  TRUE, &cursor_node);
-    }
-  else
-    {
-      /* Now go backwards to find last focusable row. */
-      path = _pspp_sheet_view_find_path (tree_view, tree_view->priv->row_count - 1);
-      search_first_focusable_path (tree_view, &path,
-                                  FALSE, &cursor_node);
-    }
-
-  if (!path)
-    goto cleanup;
-
-  if (gtk_tree_path_compare (old_path, path))
-    {
-      pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode);
-      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-    }
-  else
-    {
-      gtk_widget_error_bell (GTK_WIDGET (tree_view));
-    }
-
-cleanup:
-  gtk_tree_path_free (old_path);
-  gtk_tree_path_free (path);
-}
-
-static gboolean
-pspp_sheet_view_real_select_all (PsppSheetView *tree_view)
-{
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
-      tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
-    return FALSE;
-
-  pspp_sheet_selection_select_all (tree_view->priv->selection);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_unselect_all (PsppSheetView *tree_view)
-{
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
-      tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
-    return FALSE;
-
-  pspp_sheet_selection_unselect_all (tree_view->priv->selection);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view,
-                                        gboolean     start_editing,
-                                        PsppSheetSelectMode mode)
-{
-  int new_node = -1;
-  int cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  if (tree_view->priv->cursor)
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-  if (cursor_path == NULL)
-    return FALSE;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path,
-                              &cursor_node);
-
-  if (cursor_node < 0)
-    {
-      gtk_tree_path_free (cursor_path);
-      return FALSE;
-    }
-
-  if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND) && start_editing &&
-      tree_view->priv->focus_column)
-    {
-      if (pspp_sheet_view_start_editing (tree_view, cursor_path))
-       {
-         gtk_tree_path_free (cursor_path);
-         return TRUE;
-       }
-    }
-
-  _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
-                                           cursor_node,
-                                           cursor_path,
-                                            mode,
-                                           FALSE);
-
-  /* We bail out if the original (tree, node) don't exist anymore after
-   * handling the selection-changed callback.  We do return TRUE because
-   * the key press has been handled at this point.
-   */
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node);
-
-  if (cursor_node != new_node)
-    return FALSE;
-
-  pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-  _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-
-  if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND))
-    pspp_sheet_view_row_activated (tree_view, cursor_path,
-                                 tree_view->priv->focus_column);
-
-  gtk_tree_path_free (cursor_path);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view)
-{
-  int new_node = -1;
-  int cursor_node = -1;
-  GtkTreePath *cursor_path = NULL;
-
-  if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  cursor_path = NULL;
-  if (tree_view->priv->cursor)
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-  if (cursor_path == NULL)
-    return FALSE;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-  if (cursor_node < 0)
-    {
-      gtk_tree_path_free (cursor_path);
-      return FALSE;
-    }
-
-  _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
-                                           cursor_node,
-                                           cursor_path,
-                                            PSPP_SHEET_SELECT_MODE_TOGGLE,
-                                           FALSE);
-
-  /* We bail out if the original (tree, node) don't exist anymore after
-   * handling the selection-changed callback.  We do return TRUE because
-   * the key press has been handled at this point.
-   */
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node);
-
-  if (cursor_node != new_node)
-    return FALSE;
-
-  pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-  pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
-  gtk_tree_path_free (cursor_path);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_entry_flush_timeout (PsppSheetView *tree_view)
-{
-  pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
-  tree_view->priv->typeselect_flush_timeout = 0;
-
-  return FALSE;
-}
-
-/* Cut and paste from gtkwindow.c */
-static void
-send_focus_change (GtkWidget *widget,
-                  gboolean   in)
-{
-  GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
-  fevent->focus_change.type = GDK_FOCUS_CHANGE;
-  fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
-  fevent->focus_change.in = in;
-
-  gtk_widget_send_focus_change (widget, fevent);
-  gdk_event_free (fevent);
-}
-
-static void
-pspp_sheet_view_ensure_interactive_directory (PsppSheetView *tree_view)
-{
-  GtkWidget *frame, *vbox, *toplevel;
-  GdkScreen *screen;
-
-  if (tree_view->priv->search_custom_entry_set)
-    return;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
-  screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
-
-   if (tree_view->priv->search_window != NULL)
-     {
-       if (gtk_window_get_group (GTK_WINDOW (toplevel)))
-        gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-                                     GTK_WINDOW (tree_view->priv->search_window));
-       else if (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)))
-        gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
-                                        GTK_WINDOW (tree_view->priv->search_window));
-       gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
-       return;
-     }
-
-  tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
-  gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
-
-  if (gtk_window_get_group (GTK_WINDOW (toplevel)))
-    gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-                                GTK_WINDOW (tree_view->priv->search_window));
-
-  gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
-                           GDK_WINDOW_TYPE_HINT_UTILITY);
-  gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
-  g_signal_connect (tree_view->priv->search_window, "delete-event",
-                   G_CALLBACK (pspp_sheet_view_search_delete_event),
-                   tree_view);
-  g_signal_connect (tree_view->priv->search_window, "key-press-event",
-                   G_CALLBACK (pspp_sheet_view_search_key_press_event),
-                   tree_view);
-  g_signal_connect (tree_view->priv->search_window, "button-press-event",
-                   G_CALLBACK (pspp_sheet_view_search_button_press_event),
-                   tree_view);
-  g_signal_connect (tree_view->priv->search_window, "scroll-event",
-                   G_CALLBACK (pspp_sheet_view_search_scroll_event),
-                   tree_view);
-
-  frame = gtk_frame_new (NULL);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-  gtk_widget_show (frame);
-  gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
-
-  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_widget_show (vbox);
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-  gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
-
-  /* add entry */
-  tree_view->priv->search_entry = gtk_entry_new ();
-  gtk_widget_show (tree_view->priv->search_entry);
-  g_signal_connect (tree_view->priv->search_entry, "populate-popup",
-                   G_CALLBACK (pspp_sheet_view_search_disable_popdown),
-                   tree_view);
-  g_signal_connect (tree_view->priv->search_entry,
-                   "activate", G_CALLBACK (pspp_sheet_view_search_activate),
-                   tree_view);
-
-  gtk_container_add (GTK_CONTAINER (vbox),
-                    tree_view->priv->search_entry);
-
-  gtk_widget_realize (tree_view->priv->search_entry);
-}
-
-/* Pops up the interactive search entry.  If keybinding is TRUE then the user
- * started this by typing the start_interactive_search keybinding.  Otherwise, it came from
- */
-static gboolean
-pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view,
-                                            gboolean     keybinding)
-{
-  /* We only start interactive search if we have focus or the columns
-   * have focus.  If one of our children have focus, we don't want to
-   * start the search.
-   */
-  GList *list;
-  gboolean found_focus = FALSE;
-  GtkWidgetClass *entry_parent_class;
-
-  if (!tree_view->priv->enable_search && !keybinding)
-    return FALSE;
-
-  if (tree_view->priv->search_custom_entry_set)
-    return FALSE;
-
-  if (tree_view->priv->search_window != NULL &&
-      gtk_widget_get_visible (tree_view->priv->search_window))
-    return TRUE;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      PsppSheetViewColumn *column;
-
-      column = list->data;
-      if (! column->visible)
-       continue;
-
-      if (column->button && gtk_widget_has_focus (column->button))
-       {
-         found_focus = TRUE;
-         break;
-       }
-    }
-
-  if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
-    found_focus = TRUE;
-
-  if (!found_focus)
-    return FALSE;
-
-  if (tree_view->priv->search_column < 0)
-    return FALSE;
-
-  pspp_sheet_view_ensure_interactive_directory (tree_view);
-
-  if (keybinding)
-    gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
-
-  /* done, show it */
-  tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
-  gtk_widget_show (tree_view->priv->search_window);
-  if (tree_view->priv->search_entry_changed_id == 0)
-    {
-      tree_view->priv->search_entry_changed_id =
-       g_signal_connect (tree_view->priv->search_entry, "changed",
-                         G_CALLBACK (pspp_sheet_view_search_init),
-                         tree_view);
-    }
-
-  tree_view->priv->typeselect_flush_timeout =
-    gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
-                  (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
-                  tree_view);
-
-  /* Grab focus will select all the text.  We don't want that to happen, so we
-   * call the parent instance and bypass the selection change.  This is probably
-   * really non-kosher. */
-  entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
-  (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
-
-  /* send focus-in event */
-  send_focus_change (tree_view->priv->search_entry, TRUE);
-
-  /* search first matching iter */
-  pspp_sheet_view_search_init (tree_view->priv->search_entry, tree_view);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_start_interactive_search (PsppSheetView *tree_view)
-{
-  return pspp_sheet_view_real_start_interactive_search (tree_view, TRUE);
-}
-
-/* this function returns the new width of the column being resized given
- * the column and x position of the cursor; the x cursor position is passed
- * in as a pointer and automagicly corrected if it's beyond min/max limits
- */
-static gint
-pspp_sheet_view_new_column_width (PsppSheetView *tree_view,
-                               gint       i,
-                               gint      *x)
-{
-  PsppSheetViewColumn *column;
-  gint width;
-  gboolean rtl;
-
-  /* first translate the x position from gtk_widget_get_window (widget)
-   * to clist->clist_window
-   */
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-  column = g_list_nth (tree_view->priv->columns, i)->data;
-  width = rtl ? (column->allocation.x + column->allocation.width - *x) : (*x - column->allocation.x);
-
-  /* Clamp down the value */
-  if (column->min_width == -1)
-    width = MAX (column->button_request, width);
-  else
-    width = MAX (column->min_width, width);
-  if (column->max_width != -1)
-    width = MIN (width, column->max_width);
-
-  *x = rtl ? (column->allocation.x + column->allocation.width - width) : (column->allocation.x + width);
-
-  return width;
-}
-
-void
-pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
-
-/* Callbacks */
-static void
-pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment,
-                                 PsppSheetView   *tree_view)
-{
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    {
-      gint dy;
-
-      gdk_window_move (tree_view->priv->bin_window,
-                      - gtk_adjustment_get_value (tree_view->priv->hadjustment),
-                      TREE_VIEW_HEADER_HEIGHT (tree_view));
-      gdk_window_move (tree_view->priv->header_window,
-                      - gtk_adjustment_get_value (tree_view->priv->hadjustment),
-                      0);
-      dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
-      gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
-
-      if (dy != 0)
-        {
-          /* update our dy and top_row */
-          tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
-         update_prelight (tree_view,
-                           tree_view->priv->event_last_x,
-                           tree_view->priv->event_last_y);
-
-          if (!tree_view->priv->in_top_row_to_dy)
-            pspp_sheet_view_dy_to_top_row (tree_view);
-       }
-
-      update_childrens_allocation(tree_view);
-    }
-}
-
-/* Public methods
- */
-
-/**
- * pspp_sheet_view_new:
- *
- * Creates a new #PsppSheetView widget.
- *
- * Return value: A newly created #PsppSheetView widget.
- **/
-GtkWidget *
-pspp_sheet_view_new (void)
-{
-  return g_object_new (PSPP_TYPE_SHEET_VIEW, NULL);
-}
-
-/**
- * pspp_sheet_view_new_with_model:
- * @model: the model.
- *
- * Creates a new #PsppSheetView widget with the model initialized to @model.
- *
- * Return value: A newly created #PsppSheetView widget.
- **/
-GtkWidget *
-pspp_sheet_view_new_with_model (GtkTreeModel *model)
-{
-  return g_object_new (PSPP_TYPE_SHEET_VIEW, "model", model, NULL);
-}
-
-/* Public Accessors
- */
-
-/**
- * pspp_sheet_view_get_model:
- * @tree_view: a #PsppSheetView
- *
- * Returns the model the #PsppSheetView is based on.  Returns %NULL if the
- * model is unset.
- *
- * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
- **/
-GtkTreeModel *
-pspp_sheet_view_get_model (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return tree_view->priv->model;
-}
-
-/**
- * pspp_sheet_view_set_model:
- * @tree_view: A #GtkTreeNode.
- * @model: (allow-none): The model.
- *
- * Sets the model for a #PsppSheetView.  If the @tree_view already has a model
- * set, it will remove it before setting the new model.  If @model is %NULL,
- * then it will unset the old model.
- **/
-void
-pspp_sheet_view_set_model (PsppSheetView  *tree_view,
-                        GtkTreeModel *model)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
-
-  if (model == tree_view->priv->model)
-    return;
-
-  if (tree_view->priv->scroll_to_path)
-    {
-      gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-      tree_view->priv->scroll_to_path = NULL;
-    }
-
-  if (tree_view->priv->model)
-    {
-      GList *tmplist = tree_view->priv->columns;
-
-      if (tree_view->priv->selected)
-        range_tower_set0 (tree_view->priv->selected, 0, ULONG_MAX);
-      pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-      g_signal_handlers_disconnect_by_func (tree_view->priv->model,
-                                           pspp_sheet_view_row_changed,
-                                           tree_view);
-      g_signal_handlers_disconnect_by_func (tree_view->priv->model,
-                                           pspp_sheet_view_row_inserted,
-                                           tree_view);
-      g_signal_handlers_disconnect_by_func (tree_view->priv->model,
-                                           pspp_sheet_view_row_deleted,
-                                           tree_view);
-      g_signal_handlers_disconnect_by_func (tree_view->priv->model,
-                                           pspp_sheet_view_rows_reordered,
-                                           tree_view);
-
-      for (; tmplist; tmplist = tmplist->next)
-       _pspp_sheet_view_column_unset_model (tmplist->data,
-                                          tree_view->priv->model);
-
-      tree_view->priv->prelight_node = -1;
-
-      gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
-      tree_view->priv->drag_dest_row = NULL;
-      gtk_tree_row_reference_free (tree_view->priv->cursor);
-      tree_view->priv->cursor = NULL;
-      gtk_tree_row_reference_free (tree_view->priv->anchor);
-      tree_view->priv->anchor = NULL;
-      gtk_tree_row_reference_free (tree_view->priv->top_row);
-      tree_view->priv->top_row = NULL;
-      gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-      tree_view->priv->scroll_to_path = NULL;
-
-      tree_view->priv->scroll_to_column = NULL;
-
-      g_object_unref (tree_view->priv->model);
-
-      tree_view->priv->search_column = -1;
-      tree_view->priv->fixed_height = -1;
-      tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
-      tree_view->priv->last_button_x = -1;
-      tree_view->priv->last_button_y = -1;
-    }
-
-  tree_view->priv->model = model;
-
-  if (tree_view->priv->model)
-    {
-      gint i;
-
-      if (tree_view->priv->search_column == -1)
-       {
-         for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
-           {
-             GType type = gtk_tree_model_get_column_type (model, i);
-
-             if (g_value_type_transformable (type, G_TYPE_STRING))
-               {
-                 tree_view->priv->search_column = i;
-                 break;
-               }
-           }
-       }
-
-      g_object_ref (tree_view->priv->model);
-      g_signal_connect (tree_view->priv->model,
-                       "row-changed",
-                       G_CALLBACK (pspp_sheet_view_row_changed),
-                       tree_view);
-      g_signal_connect (tree_view->priv->model,
-                       "row-inserted",
-                       G_CALLBACK (pspp_sheet_view_row_inserted),
-                       tree_view);
-      g_signal_connect (tree_view->priv->model,
-                       "row-deleted",
-                       G_CALLBACK (pspp_sheet_view_row_deleted),
-                       tree_view);
-      g_signal_connect (tree_view->priv->model,
-                       "rows-reordered",
-                       G_CALLBACK (pspp_sheet_view_rows_reordered),
-                       tree_view);
-
-      tree_view->priv->row_count = gtk_tree_model_iter_n_children (tree_view->priv->model, NULL);
-
-      /*  FIXME: do I need to do this? pspp_sheet_view_create_buttons (tree_view); */
-      install_presize_handler (tree_view);
-    }
-
-  g_object_notify (G_OBJECT (tree_view), "model");
-
-  if (tree_view->priv->selection)
-    _pspp_sheet_selection_emit_changed (tree_view->priv->selection);
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-}
-
-/**
- * pspp_sheet_view_get_selection:
- * @tree_view: A #PsppSheetView.
- *
- * Gets the #PsppSheetSelection associated with @tree_view.
- *
- * Return value: A #PsppSheetSelection object.
- **/
-PsppSheetSelection *
-pspp_sheet_view_get_selection (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return tree_view->priv->selection;
-}
-
-/**
- * pspp_sheet_view_get_hadjustment:
- * @tree_view: A #PsppSheetView
- *
- * Gets the #GtkAdjustment currently being used for the horizontal aspect.
- *
- * Return value: A #GtkAdjustment object, or %NULL if none is currently being
- * used.
- **/
-GtkAdjustment *
-pspp_sheet_view_get_hadjustment (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return pspp_sheet_view_do_get_hadjustment (tree_view);
-}
-
-static GtkAdjustment *
-pspp_sheet_view_do_get_hadjustment (PsppSheetView *tree_view)
-{
-  return tree_view->priv->hadjustment;
-}
-
-/**
- * pspp_sheet_view_set_hadjustment:
- * @tree_view: A #PsppSheetView
- * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
- *
- * Sets the #GtkAdjustment for the current horizontal aspect.
- **/
-void
-pspp_sheet_view_set_hadjustment (PsppSheetView   *tree_view,
-                              GtkAdjustment *adjustment)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  pspp_sheet_view_set_adjustments (tree_view,
-                                adjustment,
-                                tree_view->priv->vadjustment);
-
-  g_object_notify (G_OBJECT (tree_view), "hadjustment");
-}
-
-static void
-pspp_sheet_view_do_set_hadjustment (PsppSheetView   *tree_view,
-                                  GtkAdjustment *adjustment)
-{
-  PsppSheetViewPrivate *priv = tree_view->priv;
-
-  if (adjustment && priv->hadjustment == adjustment)
-    return;
-
-  if (priv->hadjustment != NULL)
-    {
-      g_signal_handlers_disconnect_by_func (priv->hadjustment,
-                                            pspp_sheet_view_adjustment_changed,
-                                            tree_view);
-      g_object_unref (priv->hadjustment);
-    }
-
-  if (adjustment == NULL)
-    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
-                                     0.0, 0.0, 0.0);
-
-  g_signal_connect (adjustment, "value-changed",
-                    G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
-  priv->hadjustment = g_object_ref_sink (adjustment);
-  /* FIXME: Adjustment should probably be populated here with fresh values, but
-   * internal details are too complicated for me to decipher right now.
-   */
-  pspp_sheet_view_adjustment_changed (NULL, tree_view);
-
-  g_object_notify (G_OBJECT (tree_view), "hadjustment");
-}
-
-/**
- * pspp_sheet_view_get_vadjustment:
- * @tree_view: A #PsppSheetView
- *
- * Gets the #GtkAdjustment currently being used for the vertical aspect.
- *
- * Return value: (transfer none): A #GtkAdjustment object, or %NULL
- *     if none is currently being used.
- *
- * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
- **/
-GtkAdjustment *
-pspp_sheet_view_get_vadjustment (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return pspp_sheet_view_do_get_vadjustment (tree_view);
-}
-
-static GtkAdjustment *
-pspp_sheet_view_do_get_vadjustment (PsppSheetView *tree_view)
-{
-  return tree_view->priv->vadjustment;
-}
-
-/**
- * pspp_sheet_view_set_vadjustment:
- * @tree_view: A #PsppSheetView
- * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
- *
- * Sets the #GtkAdjustment for the current vertical aspect.
- *
- * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
- **/
-void
-pspp_sheet_view_set_vadjustment (PsppSheetView   *tree_view,
-                               GtkAdjustment *adjustment)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
-
-  pspp_sheet_view_do_set_vadjustment (tree_view, adjustment);
-}
-
-static void
-pspp_sheet_view_do_set_vadjustment (PsppSheetView   *tree_view,
-                                  GtkAdjustment *adjustment)
-{
-  PsppSheetViewPrivate *priv = tree_view->priv;
-
-  if (adjustment && priv->vadjustment == adjustment)
-    return;
-
-  if (priv->vadjustment != NULL)
-    {
-      g_signal_handlers_disconnect_by_func (priv->vadjustment,
-                                            pspp_sheet_view_adjustment_changed,
-                                            tree_view);
-      g_object_unref (priv->vadjustment);
-    }
-
-  if (adjustment == NULL)
-    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
-                                     0.0, 0.0, 0.0);
-
-  g_signal_connect (adjustment, "value-changed",
-                    G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
-  priv->vadjustment = g_object_ref_sink (adjustment);
-  /* FIXME: Adjustment should probably be populated here with fresh values, but
-   * internal details are too complicated for me to decipher right now.
-   */
-  pspp_sheet_view_adjustment_changed (NULL, tree_view);
-  g_object_notify (G_OBJECT (tree_view), "vadjustment");
-}
-
-/* Column and header operations */
-
-/**
- * pspp_sheet_view_get_headers_visible:
- * @tree_view: A #PsppSheetView.
- *
- * Returns %TRUE if the headers on the @tree_view are visible.
- *
- * Return value: Whether the headers are visible or not.
- **/
-gboolean
-pspp_sheet_view_get_headers_visible (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  return PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
-}
-
-/**
- * pspp_sheet_view_set_headers_visible:
- * @tree_view: A #PsppSheetView.
- * @headers_visible: %TRUE if the headers are visible
- *
- * Sets the visibility state of the headers.
- **/
-void
-pspp_sheet_view_set_headers_visible (PsppSheetView *tree_view,
-                                  gboolean     headers_visible)
-{
-  gint x, y;
-  GList *list;
-  PsppSheetViewColumn *column;
-  GtkAllocation allocation;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
-  headers_visible = !! headers_visible;
-
-  if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE) == headers_visible)
-    return;
-
-  if (headers_visible)
-    PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
-  else
-    PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    {
-      gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
-      if (headers_visible)
-       {
-         gdk_window_move_resize (tree_view->priv->bin_window, x, y  + TREE_VIEW_HEADER_HEIGHT (tree_view),
-                                 tree_view->priv->width, allocation.height -  + TREE_VIEW_HEADER_HEIGHT (tree_view));
-
-          if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
-            pspp_sheet_view_map_buttons (tree_view);
-       }
-      else
-       {
-         gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
-
-         for (list = tree_view->priv->columns; list; list = list->next)
-           {
-             column = list->data;
-              if (column->button)
-                gtk_widget_unmap (column->button);
-           }
-         gdk_window_hide (tree_view->priv->header_window);
-       }
-    }
-
-  gtk_adjustment_set_page_size (tree_view->priv->vadjustment, allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view));
-  gtk_adjustment_set_page_increment (tree_view->priv->vadjustment, (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2);
-  gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
-  gtk_adjustment_set_upper (tree_view->priv->vadjustment, tree_view->priv->height);
-  gtk_adjustment_changed (tree_view->priv->vadjustment);
-
-  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
-  g_object_notify (G_OBJECT (tree_view), "headers-visible");
-}
-
-/**
- * pspp_sheet_view_columns_autosize:
- * @tree_view: A #PsppSheetView.
- *
- * Resizes all columns to their optimal width. Only works after the
- * treeview has been realized.
- **/
-void
-pspp_sheet_view_columns_autosize (PsppSheetView *tree_view)
-{
-  gboolean dirty = FALSE;
-  GList *list;
-  PsppSheetViewColumn *column;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      column = list->data;
-      _pspp_sheet_view_column_cell_set_dirty (column);
-      dirty = TRUE;
-    }
-
-  if (dirty)
-    gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-}
-
-/**
- * pspp_sheet_view_set_headers_clickable:
- * @tree_view: A #PsppSheetView.
- * @setting: %TRUE if the columns are clickable.
- *
- * Allow the column title buttons to be clicked.
- **/
-void
-pspp_sheet_view_set_headers_clickable (PsppSheetView *tree_view,
-                                    gboolean   setting)
-{
-  GList *list;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    pspp_sheet_view_column_set_clickable (PSPP_SHEET_VIEW_COLUMN (list->data), setting);
-
-  g_object_notify (G_OBJECT (tree_view), "headers-clickable");
-}
-
-
-/**
- * pspp_sheet_view_get_headers_clickable:
- * @tree_view: A #PsppSheetView.
- *
- * Returns whether all header columns are clickable.
- *
- * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
- *
- * Since: 2.10
- **/
-gboolean
-pspp_sheet_view_get_headers_clickable (PsppSheetView *tree_view)
-{
-  GList *list;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    if (!PSPP_SHEET_VIEW_COLUMN (list->data)->clickable)
-      return FALSE;
-
-  return TRUE;
-}
-
-/**
- * pspp_sheet_view_set_rules_hint
- * @tree_view: a #PsppSheetView
- * @setting: %TRUE if the tree requires reading across rows
- *
- * This function tells GTK+ that the user interface for your
- * application requires users to read across tree rows and associate
- * cells with one another. By default, GTK+ will then render the tree
- * with alternating row colors. Do <emphasis>not</emphasis> use it
- * just because you prefer the appearance of the ruled tree; that's a
- * question for the theme. Some themes will draw tree rows in
- * alternating colors even when rules are turned off, and users who
- * prefer that appearance all the time can choose those themes. You
- * should call this function only as a <emphasis>semantic</emphasis>
- * hint to the theme engine that your tree makes alternating colors
- * useful from a functional standpoint (since it has lots of columns,
- * generally).
- *
- **/
-void
-pspp_sheet_view_set_rules_hint (PsppSheetView  *tree_view,
-                              gboolean      setting)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  setting = setting != FALSE;
-
-  if (tree_view->priv->has_rules != setting)
-    {
-      tree_view->priv->has_rules = setting;
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-    }
-
-  g_object_notify (G_OBJECT (tree_view), "rules-hint");
-}
-
-/**
- * pspp_sheet_view_get_rules_hint
- * @tree_view: a #PsppSheetView
- *
- * Gets the setting set by pspp_sheet_view_set_rules_hint().
- *
- * Return value: %TRUE if rules are useful for the user of this tree
- **/
-gboolean
-pspp_sheet_view_get_rules_hint (PsppSheetView  *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  return tree_view->priv->has_rules;
-}
-
-/* Public Column functions
- */
-
-/**
- * pspp_sheet_view_append_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to add.
- *
- * Appends @column to the list of columns.
- *
- * Return value: The number of columns in @tree_view after appending.
- **/
-gint
-pspp_sheet_view_append_column (PsppSheetView       *tree_view,
-                            PsppSheetViewColumn *column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
-  g_return_val_if_fail (column->tree_view == NULL, -1);
-
-  return pspp_sheet_view_insert_column (tree_view, column, -1);
-}
-
-
-/**
- * pspp_sheet_view_remove_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to remove.
- *
- * Removes @column from @tree_view.
- *
- * Return value: The number of columns in @tree_view after removing.
- **/
-gint
-pspp_sheet_view_remove_column (PsppSheetView       *tree_view,
-                             PsppSheetViewColumn *column)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
-  g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
-
-  if (tree_view->priv->focus_column == column)
-    tree_view->priv->focus_column = NULL;
-
-  if (tree_view->priv->edited_column == column)
-    {
-      pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-      /* no need to, but just to be sure ... */
-      tree_view->priv->edited_column = NULL;
-    }
-
-  _pspp_sheet_view_column_unset_tree_view (column);
-
-  tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
-  tree_view->priv->n_columns--;
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    {
-      GList *list;
-
-      _pspp_sheet_view_column_unrealize_button (column);
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         PsppSheetViewColumn *tmp_column;
-
-         tmp_column = PSPP_SHEET_VIEW_COLUMN (list->data);
-         if (tmp_column->visible)
-           _pspp_sheet_view_column_cell_set_dirty (tmp_column);
-       }
-
-      if (tree_view->priv->n_columns == 0 &&
-         pspp_sheet_view_get_headers_visible (tree_view) &&
-         tree_view->priv->header_window)
-       gdk_window_hide (tree_view->priv->header_window);
-
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-    }
-
-  g_object_unref (column);
-  g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-
-  return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to be inserted.
- * @position: The position to insert @column in.
- *
- * This inserts the @column into the @tree_view at @position.  If @position is
- * -1, then the column is inserted at the end.
- *
- * Return value: The number of columns in @tree_view after insertion.
- **/
-gint
-pspp_sheet_view_insert_column (PsppSheetView       *tree_view,
-                             PsppSheetViewColumn *column,
-                             gint               position)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
-  g_return_val_if_fail (column->tree_view == NULL, -1);
-
-  g_object_ref_sink (column);
-
-  if (tree_view->priv->n_columns == 0 &&
-      gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
-      pspp_sheet_view_get_headers_visible (tree_view))
-    {
-      gdk_window_show (tree_view->priv->header_window);
-    }
-
-  tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
-                                           column, position);
-  tree_view->priv->n_columns++;
-
-  _pspp_sheet_view_column_set_tree_view (column, tree_view);
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    {
-      GList *list;
-
-      _pspp_sheet_view_column_realize_button (column);
-
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         column = PSPP_SHEET_VIEW_COLUMN (list->data);
-         if (column->visible)
-           _pspp_sheet_view_column_cell_set_dirty (column);
-       }
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-    }
-
-  g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-
-  return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column_with_attributes:
- * @tree_view: A #PsppSheetView
- * @position: The position to insert the new column in.
- * @title: The title to set the header to.
- * @cell: The #GtkCellRenderer.
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Creates a new #PsppSheetViewColumn and inserts it into the @tree_view at
- * @position.  If @position is -1, then the newly created column is inserted at
- * the end.  The column is initialized with the attributes given.
- *
- * Return value: The number of columns in @tree_view after insertion.
- **/
-gint
-pspp_sheet_view_insert_column_with_attributes (PsppSheetView     *tree_view,
-                                            gint             position,
-                                            const gchar     *title,
-                                            GtkCellRenderer *cell,
-                                            ...)
-{
-  PsppSheetViewColumn *column;
-  gchar *attribute;
-  va_list args;
-  gint column_id;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
-  column = pspp_sheet_view_column_new ();
-  pspp_sheet_view_column_set_title (column, title);
-  pspp_sheet_view_column_pack_start (column, cell, TRUE);
-
-  va_start (args, cell);
-
-  attribute = va_arg (args, gchar *);
-
-  while (attribute != NULL)
-    {
-      column_id = va_arg (args, gint);
-      pspp_sheet_view_column_add_attribute (column, cell, attribute, column_id);
-      attribute = va_arg (args, gchar *);
-    }
-
-  va_end (args);
-
-  pspp_sheet_view_insert_column (tree_view, column, position);
-
-  return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column_with_data_func:
- * @tree_view: a #PsppSheetView
- * @position: Position to insert, -1 for append
- * @title: column title
- * @cell: cell renderer for column
- * @func: function to set attributes of cell renderer
- * @data: data for @func
- * @dnotify: destroy notifier for @data
- *
- * Convenience function that inserts a new column into the #PsppSheetView
- * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
- * attributes (normally using data from the model). See also
- * pspp_sheet_view_column_set_cell_data_func(), pspp_sheet_view_column_pack_start().
- *
- * Return value: number of columns in the tree view post-insert
- **/
-gint
-pspp_sheet_view_insert_column_with_data_func  (PsppSheetView               *tree_view,
-                                             gint                       position,
-                                             const gchar               *title,
-                                             GtkCellRenderer           *cell,
-                                             PsppSheetCellDataFunc        func,
-                                             gpointer                   data,
-                                             GDestroyNotify             dnotify)
-{
-  PsppSheetViewColumn *column;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
-  column = pspp_sheet_view_column_new ();
-  pspp_sheet_view_column_set_title (column, title);
-  pspp_sheet_view_column_pack_start (column, cell, TRUE);
-  pspp_sheet_view_column_set_cell_data_func (column, cell, func, data, dnotify);
-
-  pspp_sheet_view_insert_column (tree_view, column, position);
-
-  return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_get_column:
- * @tree_view: A #PsppSheetView.
- * @n: The position of the column, counting from 0.
- *
- * Gets the #PsppSheetViewColumn at the given position in the #tree_view.
- *
- * Return value: The #PsppSheetViewColumn, or %NULL if the position is outside the
- * range of columns.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_get_column (PsppSheetView *tree_view,
-                         gint         n)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  if (n < 0 || n >= tree_view->priv->n_columns)
-    return NULL;
-
-  if (tree_view->priv->columns == NULL)
-    return NULL;
-
-  return PSPP_SHEET_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
-}
-
-/**
- * pspp_sheet_view_get_columns:
- * @tree_view: A #PsppSheetView
- *
- * Returns a #GList of all the #PsppSheetViewColumn s currently in @tree_view.
- * The returned list must be freed with g_list_free ().
- *
- * Return value: (element-type PsppSheetViewColumn) (transfer container): A list of #PsppSheetViewColumn s
- **/
-GList *
-pspp_sheet_view_get_columns (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return g_list_copy (tree_view->priv->columns);
-}
-
-/**
- * pspp_sheet_view_move_column_after:
- * @tree_view: A #PsppSheetView
- * @column: The #PsppSheetViewColumn to be moved.
- * @base_column: (allow-none): The #PsppSheetViewColumn to be moved relative to, or %NULL.
- *
- * Moves @column to be after to @base_column.  If @base_column is %NULL, then
- * @column is placed in the first position.
- **/
-void
-pspp_sheet_view_move_column_after (PsppSheetView       *tree_view,
-                                PsppSheetViewColumn *column,
-                                PsppSheetViewColumn *base_column)
-{
-  GList *column_list_el, *base_el = NULL;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  column_list_el = g_list_find (tree_view->priv->columns, column);
-  g_return_if_fail (column_list_el != NULL);
-
-  if (base_column)
-    {
-      base_el = g_list_find (tree_view->priv->columns, base_column);
-      g_return_if_fail (base_el != NULL);
-    }
-
-  if (column_list_el->prev == base_el)
-    return;
-
-  tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
-  if (base_el == NULL)
-    {
-      column_list_el->prev = NULL;
-      column_list_el->next = tree_view->priv->columns;
-      if (column_list_el->next)
-       column_list_el->next->prev = column_list_el;
-      tree_view->priv->columns = column_list_el;
-    }
-  else
-    {
-      column_list_el->prev = base_el;
-      column_list_el->next = base_el->next;
-      if (column_list_el->next)
-       column_list_el->next->prev = column_list_el;
-      base_el->next = column_list_el;
-    }
-
-  if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    {
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-      pspp_sheet_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
-    }
-
-  g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-}
-
-/**
- * pspp_sheet_view_set_column_drag_function:
- * @tree_view: A #PsppSheetView.
- * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
- * @user_data: (allow-none): User data to be passed to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
- *
- * Sets a user function for determining where a column may be dropped when
- * dragged.  This function is called on every column pair in turn at the
- * beginning of a column drag to determine where a drop can take place.  The
- * arguments passed to @func are: the @tree_view, the #PsppSheetViewColumn being
- * dragged, the two #PsppSheetViewColumn s determining the drop spot, and
- * @user_data.  If either of the #PsppSheetViewColumn arguments for the drop spot
- * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
- * @tree_view reverts to the default behavior of allowing all columns to be
- * dropped everywhere.
- **/
-void
-pspp_sheet_view_set_column_drag_function (PsppSheetView               *tree_view,
-                                       PsppSheetViewColumnDropFunc  func,
-                                       gpointer                   user_data,
-                                       GDestroyNotify             destroy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (tree_view->priv->column_drop_func_data_destroy)
-    tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
-
-  tree_view->priv->column_drop_func = func;
-  tree_view->priv->column_drop_func_data = user_data;
-  tree_view->priv->column_drop_func_data_destroy = destroy;
-}
-
-/**
- * pspp_sheet_view_scroll_to_point:
- * @tree_view: a #PsppSheetView
- * @tree_x: X coordinate of new top-left pixel of visible area, or -1
- * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
- *
- * Scrolls the tree view such that the top-left corner of the visible
- * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
- * in tree coordinates.  The @tree_view must be realized before
- * this function is called.  If it isn't, you probably want to be
- * using pspp_sheet_view_scroll_to_cell().
- *
- * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
- **/
-void
-pspp_sheet_view_scroll_to_point (PsppSheetView *tree_view,
-                               gint         tree_x,
-                               gint         tree_y)
-{
-  GtkAdjustment *hadj;
-  GtkAdjustment *vadj;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
-
-  hadj = tree_view->priv->hadjustment;
-  vadj = tree_view->priv->vadjustment;
-
-  if (tree_x != -1)
-    gtk_adjustment_set_value (hadj, CLAMP (tree_x, gtk_adjustment_get_lower (hadj), gtk_adjustment_get_upper (hadj) - gtk_adjustment_get_page_size (hadj)));
-  if (tree_y != -1)
-    gtk_adjustment_set_value (vadj, CLAMP (tree_y, gtk_adjustment_get_lower (vadj), gtk_adjustment_get_upper (vadj) - gtk_adjustment_get_page_size (vadj)));
-}
-
-/**
- * pspp_sheet_view_scroll_to_cell:
- * @tree_view: A #PsppSheetView.
- * @path: (allow-none): The path of the row to move to, or %NULL.
- * @column: (allow-none): The #PsppSheetViewColumn to move horizontally to, or %NULL.
- * @use_align: whether to use alignment arguments, or %FALSE.
- * @row_align: The vertical alignment of the row specified by @path.
- * @col_align: The horizontal alignment of the column specified by @column.
- *
- * Moves the alignments of @tree_view to the position specified by @column and
- * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
- * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
- * or @path need to be non-%NULL.  @row_align determines where the row is
- * placed, and @col_align determines where @column is placed.  Both are expected
- * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
- * right/bottom alignment, 0.5 means center.
- *
- * If @use_align is %FALSE, then the alignment arguments are ignored, and the
- * tree does the minimum amount of work to scroll the cell onto the screen.
- * This means that the cell will be scrolled to the edge closest to its current
- * position.  If the cell is currently visible on the screen, nothing is done.
- *
- * This function only works if the model is set, and @path is a valid row on the
- * model.  If the model changes before the @tree_view is realized, the centered
- * path will be modified to reflect this change.
- **/
-void
-pspp_sheet_view_scroll_to_cell (PsppSheetView       *tree_view,
-                              GtkTreePath       *path,
-                              PsppSheetViewColumn *column,
-                             gboolean           use_align,
-                              gfloat             row_align,
-                              gfloat             col_align)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (tree_view->priv->model != NULL);
-  g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
-  g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
-  g_return_if_fail (path != NULL || column != NULL);
-
-#if 0
-  g_print ("pspp_sheet_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
-          gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
-#endif
-  row_align = CLAMP (row_align, 0.0, 1.0);
-  col_align = CLAMP (col_align, 0.0, 1.0);
-
-
-  /* Note: Despite the benefits that come from having one code path for the
-   * scrolling code, we short-circuit validate_visible_area's immplementation as
-   * it is much slower than just going to the point.
-   */
-  if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
-      !gtk_widget_get_realized (GTK_WIDGET (tree_view))
-      /* XXX || GTK_WIDGET_ALLOC_NEEDED (tree_view) */)
-    {
-      if (tree_view->priv->scroll_to_path)
-       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-
-      tree_view->priv->scroll_to_path = NULL;
-      tree_view->priv->scroll_to_column = NULL;
-
-      if (path)
-       tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
-      if (column)
-       tree_view->priv->scroll_to_column = column;
-      tree_view->priv->scroll_to_use_align = use_align;
-      tree_view->priv->scroll_to_row_align = row_align;
-      tree_view->priv->scroll_to_col_align = col_align;
-
-      install_presize_handler (tree_view);
-    }
-  else
-    {
-      GdkRectangle cell_rect;
-      GdkRectangle vis_rect;
-      gint dest_x, dest_y;
-
-      pspp_sheet_view_get_background_area (tree_view, path, column, &cell_rect);
-      pspp_sheet_view_get_visible_rect (tree_view, &vis_rect);
-
-      cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
-
-      dest_x = vis_rect.x;
-      dest_y = vis_rect.y;
-
-      if (column)
-       {
-         if (use_align)
-           {
-             dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
-           }
-         else
-           {
-             if (cell_rect.x < vis_rect.x)
-               dest_x = cell_rect.x;
-             if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
-               dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
-           }
-       }
-
-      if (path)
-       {
-         if (use_align)
-           {
-             dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
-             dest_y = MAX (dest_y, 0);
-           }
-         else
-           {
-             if (cell_rect.y < vis_rect.y)
-               dest_y = cell_rect.y;
-             if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
-               dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
-           }
-       }
-
-      pspp_sheet_view_scroll_to_point (tree_view, dest_x, dest_y);
-    }
-}
-
-/**
- * pspp_sheet_view_row_activated:
- * @tree_view: A #PsppSheetView
- * @path: The #GtkTreePath to be activated.
- * @column: The #PsppSheetViewColumn to be activated.
- *
- * Activates the cell determined by @path and @column.
- **/
-void
-pspp_sheet_view_row_activated (PsppSheetView       *tree_view,
-                            GtkTreePath       *path,
-                            PsppSheetViewColumn *column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
-}
-
-
-/**
- * pspp_sheet_view_get_reorderable:
- * @tree_view: a #PsppSheetView
- *
- * Retrieves whether the user can reorder the tree via drag-and-drop. See
- * pspp_sheet_view_set_reorderable().
- *
- * Return value: %TRUE if the tree can be reordered.
- **/
-gboolean
-pspp_sheet_view_get_reorderable (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  return tree_view->priv->reorderable;
-}
-
-/**
- * pspp_sheet_view_set_reorderable:
- * @tree_view: A #PsppSheetView.
- * @reorderable: %TRUE, if the tree can be reordered.
- *
- * This function is a convenience function to allow you to reorder
- * models that support the #GtkDragSourceIface and the
- * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
- * these.  If @reorderable is %TRUE, then the user can reorder the
- * model by dragging and dropping rows. The developer can listen to
- * these changes by connecting to the model's row_inserted and
- * row_deleted signals. The reordering is implemented by setting up
- * the tree view as a drag source and destination. Therefore, drag and
- * drop can not be used in a reorderable view for any other purpose.
- *
- * This function does not give you any degree of control over the order -- any
- * reordering is allowed.  If more control is needed, you should probably
- * handle drag and drop manually.
- **/
-void
-pspp_sheet_view_set_reorderable (PsppSheetView *tree_view,
-                              gboolean     reorderable)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  reorderable = reorderable != FALSE;
-
-  if (tree_view->priv->reorderable == reorderable)
-    return;
-
-  if (reorderable)
-    {
-      const GtkTargetEntry row_targets[] = {
-        { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
-      };
-
-      pspp_sheet_view_enable_model_drag_source (tree_view,
-                                             GDK_BUTTON1_MASK,
-                                             row_targets,
-                                             G_N_ELEMENTS (row_targets),
-                                             GDK_ACTION_MOVE);
-      pspp_sheet_view_enable_model_drag_dest (tree_view,
-                                           row_targets,
-                                           G_N_ELEMENTS (row_targets),
-                                           GDK_ACTION_MOVE);
-    }
-  else
-    {
-      pspp_sheet_view_unset_rows_drag_source (tree_view);
-      pspp_sheet_view_unset_rows_drag_dest (tree_view);
-    }
-
-  tree_view->priv->reorderable = reorderable;
-
-  g_object_notify (G_OBJECT (tree_view), "reorderable");
-}
-
-/* If CLEAR_AND_SELECT is true, then the row will be selected and, unless Shift
-   is pressed, other rows will be unselected.
-
-   If CLAMP_NODE is true, then the sheetview will scroll to make the row
-   visible. */
-static void
-pspp_sheet_view_real_set_cursor (PsppSheetView     *tree_view,
-                              GtkTreePath     *path,
-                              gboolean         clear_and_select,
-                               gboolean         clamp_node,
-                               PsppSheetSelectMode mode)
-{
-  int node = -1;
-
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    {
-      GtkTreePath *cursor_path;
-      cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-      pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
-      gtk_tree_path_free (cursor_path);
-    }
-
-  gtk_tree_row_reference_free (tree_view->priv->cursor);
-  tree_view->priv->cursor = NULL;
-
-  _pspp_sheet_view_find_node (tree_view, path, &node);
-  tree_view->priv->cursor =
-    gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
-                                      tree_view->priv->model,
-                                      path);
-
-  if (tree_view->priv->row_count > 0)
-    {
-      int new_node = -1;
-
-      if (clear_and_select && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE))
-        _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
-                                                    node, path, mode,
-                                                    FALSE);
-
-      /* We have to re-find tree and node here again, somebody might have
-       * cleared the node or the whole tree in the PsppSheetSelection::changed
-       * callback. If the nodes differ we bail out here.
-       */
-      _pspp_sheet_view_find_node (tree_view, path, &new_node);
-
-      if (node != new_node)
-        return;
-
-      if (clamp_node)
-        {
-         pspp_sheet_view_clamp_node_visible (tree_view, node);
-         _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
-       }
-    }
-
-  g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
-}
-
-/**
- * pspp_sheet_view_get_cursor:
- * @tree_view: A #PsppSheetView
- * @path: (allow-none): A pointer to be filled with the current cursor path, or %NULL
- * @focus_column: (allow-none): A pointer to be filled with the current focus column, or %NULL
- *
- * Fills in @path and @focus_column with the current path and focus column.  If
- * the cursor isn't currently set, then *@path will be %NULL.  If no column
- * currently has focus, then *@focus_column will be %NULL.
- *
- * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
- * you are done with it.
- **/
-void
-pspp_sheet_view_get_cursor (PsppSheetView        *tree_view,
-                         GtkTreePath       **path,
-                         PsppSheetViewColumn **focus_column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (path)
-    {
-      if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-       *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-      else
-       *path = NULL;
-    }
-
-  if (focus_column)
-    {
-      *focus_column = tree_view->priv->focus_column;
-    }
-}
-
-/**
- * pspp_sheet_view_set_cursor:
- * @tree_view: A #PsppSheetView
- * @path: A #GtkTreePath
- * @focus_column: (allow-none): A #PsppSheetViewColumn, or %NULL
- * @start_editing: %TRUE if the specified cell should start being edited.
- *
- * Sets the current keyboard focus to be at @path, and selects it.  This is
- * useful when you want to focus the user's attention on a particular row.  If
- * @focus_column is not %NULL, then focus is given to the column specified by
- * it. Additionally, if @focus_column is specified, and @start_editing is
- * %TRUE, then editing should be started in the specified cell.
- * This function is often followed by @gtk_widget_grab_focus (@tree_view)
- * in order to give keyboard focus to the widget.  Please note that editing
- * can only happen when the widget is realized.
- *
- * If @path is invalid for @model, the current cursor (if any) will be unset
- * and the function will return without failing.
- **/
-void
-pspp_sheet_view_set_cursor (PsppSheetView       *tree_view,
-                         GtkTreePath       *path,
-                         PsppSheetViewColumn *focus_column,
-                         gboolean           start_editing)
-{
-  pspp_sheet_view_set_cursor_on_cell (tree_view, path, focus_column,
-                                   NULL, start_editing);
-}
-
-/**
- * pspp_sheet_view_set_cursor_on_cell:
- * @tree_view: A #PsppSheetView
- * @path: A #GtkTreePath
- * @focus_column: (allow-none): A #PsppSheetViewColumn, or %NULL
- * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
- * @start_editing: %TRUE if the specified cell should start being edited.
- *
- * Sets the current keyboard focus to be at @path, and selects it.  This is
- * useful when you want to focus the user's attention on a particular row.  If
- * @focus_column is not %NULL, then focus is given to the column specified by
- * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
- * contains 2 or more editable or activatable cells, then focus is given to
- * the cell specified by @focus_cell. Additionally, if @focus_column is
- * specified, and @start_editing is %TRUE, then editing should be started in
- * the specified cell.  This function is often followed by
- * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
- * widget.  Please note that editing can only happen when the widget is
- * realized.
- *
- * If @path is invalid for @model, the current cursor (if any) will be unset
- * and the function will return without failing.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_view_set_cursor_on_cell (PsppSheetView       *tree_view,
-                                 GtkTreePath       *path,
-                                 PsppSheetViewColumn *focus_column,
-                                 GtkCellRenderer   *focus_cell,
-                                 gboolean           start_editing)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (path != NULL);
-  g_return_if_fail (focus_column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (focus_column));
-
-  if (!tree_view->priv->model)
-    return;
-
-  if (focus_cell)
-    {
-      g_return_if_fail (focus_column);
-      g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
-    }
-
-  /* cancel the current editing, if it exists */
-  if (tree_view->priv->edited_column &&
-      tree_view->priv->edited_column->editable_widget)
-    pspp_sheet_view_stop_editing (tree_view, TRUE);
-
-  pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0);
-
-  if (focus_column && focus_column->visible)
-    {
-      GList *list;
-      gboolean column_in_tree = FALSE;
-
-      for (list = tree_view->priv->columns; list; list = list->next)
-       if (list->data == focus_column)
-         {
-           column_in_tree = TRUE;
-           break;
-         }
-      g_return_if_fail (column_in_tree);
-      tree_view->priv->focus_column = focus_column;
-      if (focus_cell)
-       pspp_sheet_view_column_focus_cell (focus_column, focus_cell);
-      if (start_editing)
-       pspp_sheet_view_start_editing (tree_view, path);
-
-      pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
-      pspp_sheet_selection_select_column (tree_view->priv->selection, focus_column);
-
-    }
-}
-
-/**
- * pspp_sheet_view_get_bin_window:
- * @tree_view: A #PsppSheetView
- *
- * Returns the window that @tree_view renders to.  This is used primarily to
- * compare to <literal>event->window</literal> to confirm that the event on
- * @tree_view is on the right window.
- *
- * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
- **/
-GdkWindow *
-pspp_sheet_view_get_bin_window (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return tree_view->priv->bin_window;
-}
-
-/**
- * pspp_sheet_view_get_path_at_pos:
- * @tree_view: A #PsppSheetView.
- * @x: The x position to be identified (relative to bin_window).
- * @y: The y position to be identified (relative to bin_window).
- * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
- * @column: (out) (allow-none): A pointer to a #PsppSheetViewColumn pointer to be filled in, or %NULL
- * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
- * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
- *
- * Finds the path at the point (@x, @y), relative to bin_window coordinates
- * (please see pspp_sheet_view_get_bin_window()).
- * That is, @x and @y are relative to an events coordinates. @x and @y must
- * come from an event on the @tree_view only where <literal>event->window ==
- * pspp_sheet_view_get_bin_window (<!-- -->)</literal>. It is primarily for
- * things like popup menus. If @path is non-%NULL, then it will be filled
- * with the #GtkTreePath at that point.  This path should be freed with
- * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
- * with the column at that point.  @cell_x and @cell_y return the coordinates
- * relative to the cell background (i.e. the @background_area passed to
- * gtk_cell_renderer_render()).  This function is only meaningful if
- * @tree_view is realized.  Therefore this function will always return %FALSE
- * if @tree_view is not realized or does not have a model.
- *
- * For converting widget coordinates (eg. the ones you get from
- * GtkWidget::query-tooltip), please see
- * pspp_sheet_view_convert_widget_to_bin_window_coords().
- *
- * Return value: %TRUE if a row exists at that coordinate.
- **/
-gboolean
-pspp_sheet_view_get_path_at_pos (PsppSheetView        *tree_view,
-                              gint                x,
-                              gint                y,
-                              GtkTreePath       **path,
-                              PsppSheetViewColumn **column,
-                               gint               *cell_x,
-                               gint               *cell_y)
-{
-  int node;
-  gint y_offset;
-
-  g_return_val_if_fail (tree_view != NULL, FALSE);
-
-  if (path)
-    *path = NULL;
-  if (column)
-    *column = NULL;
-
-  if (tree_view->priv->bin_window == NULL)
-    return FALSE;
-
-  if (tree_view->priv->row_count == 0)
-    return FALSE;
-
-  if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
-    return FALSE;
-
-  if (x < 0 || y < 0)
-    return FALSE;
-
-  if (column || cell_x)
-    {
-      PsppSheetViewColumn *tmp_column;
-      PsppSheetViewColumn *last_column = NULL;
-      GList *list;
-      gint remaining_x = x;
-      gboolean found = FALSE;
-      gboolean rtl;
-
-      rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-      for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
-          list;
-          list = (rtl ? list->prev : list->next))
-       {
-         tmp_column = list->data;
-
-         if (tmp_column->visible == FALSE)
-           continue;
-
-         last_column = tmp_column;
-         if (remaining_x <= tmp_column->width)
-           {
-              found = TRUE;
-
-              if (column)
-                *column = tmp_column;
-
-              if (cell_x)
-                *cell_x = remaining_x;
-
-             break;
-           }
-         remaining_x -= tmp_column->width;
-       }
-
-      /* If found is FALSE and there is a last_column, then it the remainder
-       * space is in that area
-       */
-      if (!found)
-        {
-         if (last_column)
-           {
-             if (column)
-               *column = last_column;
-
-             if (cell_x)
-               *cell_x = last_column->width + remaining_x;
-           }
-         else
-           {
-             return FALSE;
-           }
-       }
-    }
-
-  y_offset = pspp_sheet_view_find_offset (tree_view,
-                                          TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
-                                          &node);
-
-  if (node < 0)
-    return FALSE;
-
-  if (cell_y)
-    *cell_y = y_offset;
-
-  if (path)
-    *path = _pspp_sheet_view_find_path (tree_view, node);
-
-  return TRUE;
-}
-
-/* Computes 'cell_area' from 'background_area', which must be the background
-   area for a cell.  Set 'subtract_focus_rect' to TRUE to compute the cell area
-   as passed to a GtkCellRenderer's "render" function, or to FALSE to compute
-   the cell area as passed to _pspp_sheet_view_column_cell_render().
-
-   'column' is required to properly adjust 'cell_area->x' and
-   'cell_area->width'.  It may be set to NULL if these values are not of
-   interest.  In this case 'cell_area->x' and 'cell_area->width' will be
-   returned as 0. */
-static void
-pspp_sheet_view_adjust_cell_area (PsppSheetView        *tree_view,
-                                  PsppSheetViewColumn  *column,
-                                  const GdkRectangle   *background_area,
-                                  gboolean              subtract_focus_rect,
-                                  GdkRectangle         *cell_area)
-{
-  gint vertical_separator;
-  gint horizontal_separator;
-
-  *cell_area = *background_area;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view),
-                       "vertical-separator", &vertical_separator,
-                       "horizontal-separator", &horizontal_separator,
-                       NULL);
-  cell_area->x += horizontal_separator / 2;
-  cell_area->y += vertical_separator / 2;
-  cell_area->width -= horizontal_separator;
-  cell_area->height -= vertical_separator;
-
-  if (subtract_focus_rect)
-    {
-      int focus_line_width;
-
-      gtk_widget_style_get (GTK_WIDGET (tree_view),
-                            "focus-line-width", &focus_line_width,
-                            NULL);
-      cell_area->x += focus_line_width;
-      cell_area->y += focus_line_width;
-      cell_area->width -= 2 * focus_line_width;
-      cell_area->height -= 2 * focus_line_width;
-    }
-
-  if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE)
-    {
-      gint grid_line_width;
-      gtk_widget_style_get (GTK_WIDGET (tree_view),
-                            "grid-line-width", &grid_line_width,
-                            NULL);
-
-      if ((tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
-           || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
-          && column != NULL)
-        {
-          PsppSheetViewColumn *first_column, *last_column;
-          GList *list;
-
-          /* Find the last visible column. */
-          last_column = NULL;
-          for (list = g_list_last (tree_view->priv->columns);
-               list;
-               list = list->prev)
-            {
-              PsppSheetViewColumn *c = list->data;
-              if (c->visible)
-                {
-                  last_column = c;
-                  break;
-                }
-            }
-
-          /* Find the first visible column. */
-          first_column = NULL;
-          for (list = g_list_first (tree_view->priv->columns);
-               list;
-               list = list->next)
-            {
-              PsppSheetViewColumn *c = list->data;
-              if (c->visible)
-                {
-                  first_column = c;
-                  break;
-                }
-            }
-
-          if (column == first_column)
-            {
-              cell_area->width -= grid_line_width / 2;
-            }
-          else if (column == last_column)
-            {
-              cell_area->x += grid_line_width / 2;
-              cell_area->width -= grid_line_width / 2;
-            }
-          else
-            {
-              cell_area->x += grid_line_width / 2;
-              cell_area->width -= grid_line_width;
-            }
-        }
-
-      if (tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
-          || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
-        {
-          cell_area->y += grid_line_width / 2;
-          cell_area->height -= grid_line_width;
-        }
-    }
-
-  if (column == NULL)
-    {
-      cell_area->x = 0;
-      cell_area->width = 0;
-    }
-}
-
-/**
- * pspp_sheet_view_get_cell_area:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
- * @column: (allow-none): a #PsppSheetViewColumn for the column, or %NULL to get only vertical coordinates
- * @rect: rectangle to fill with cell rect
- *
- * Fills the bounding rectangle in bin_window coordinates for the cell at the
- * row specified by @path and the column specified by @column.  If @path is
- * %NULL, or points to a path not currently displayed, the @y and @height fields
- * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
- * fields will be filled with 0.  The sum of all cell rects does not cover the
- * entire tree; there are extra pixels in between rows, for example. The
- * returned rectangle is equivalent to the @cell_area passed to
- * gtk_cell_renderer_render().  This function is only valid if @tree_view is
- * realized.
- **/
-void
-pspp_sheet_view_get_cell_area (PsppSheetView        *tree_view,
-                             GtkTreePath        *path,
-                             PsppSheetViewColumn  *column,
-                             GdkRectangle       *rect)
-{
-  GdkRectangle background_area;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
-  g_return_if_fail (rect != NULL);
-  g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
-  g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
-
-  pspp_sheet_view_get_background_area (tree_view, path, column,
-                                       &background_area);
-  pspp_sheet_view_adjust_cell_area (tree_view, column, &background_area,
-                                    FALSE, rect);
-}
-
-/**
- * pspp_sheet_view_get_background_area:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
- * @column: (allow-none): a #PsppSheetViewColumn for the column, or %NULL to get only vertical coordiantes
- * @rect: rectangle to fill with cell background rect
- *
- * Fills the bounding rectangle in bin_window coordinates for the cell at the
- * row specified by @path and the column specified by @column.  If @path is
- * %NULL, or points to a node not found in the tree, the @y and @height fields of
- * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
- * fields will be filled with 0.  The returned rectangle is equivalent to the
- * @background_area passed to gtk_cell_renderer_render().  These background
- * areas tile to cover the entire bin window.  Contrast with the @cell_area,
- * returned by pspp_sheet_view_get_cell_area(), which returns only the cell
- * itself, excluding surrounding borders.
- *
- **/
-void
-pspp_sheet_view_get_background_area (PsppSheetView        *tree_view,
-                                   GtkTreePath        *path,
-                                   PsppSheetViewColumn  *column,
-                                   GdkRectangle       *rect)
-{
-  int node = -1;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
-  g_return_if_fail (rect != NULL);
-
-  rect->x = 0;
-  rect->y = 0;
-  rect->width = 0;
-  rect->height = 0;
-
-  if (path)
-    {
-      /* Get vertical coords */
-
-      _pspp_sheet_view_find_node (tree_view, path, &node);
-      if (node < 0)
-       return;
-
-      rect->y = BACKGROUND_FIRST_PIXEL (tree_view, node);
-
-      rect->height = ROW_HEIGHT (tree_view);
-    }
-
-  if (column)
-    {
-      gint x2 = 0;
-
-      pspp_sheet_view_get_background_xrange (tree_view, column, &rect->x, &x2);
-      rect->width = x2 - rect->x;
-    }
-}
-
-/**
- * pspp_sheet_view_get_visible_rect:
- * @tree_view: a #PsppSheetView
- * @visible_rect: rectangle to fill
- *
- * Fills @visible_rect with the currently-visible region of the
- * buffer, in tree coordinates. Convert to bin_window coordinates with
- * pspp_sheet_view_convert_tree_to_bin_window_coords().
- * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
- * scrollable area of the tree.
- **/
-void
-pspp_sheet_view_get_visible_rect (PsppSheetView  *tree_view,
-                                GdkRectangle *visible_rect)
-{
-  GtkWidget *widget;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  widget = GTK_WIDGET (tree_view);
-
-  if (visible_rect)
-    {
-      GtkAllocation allocation;
-      gtk_widget_get_allocation (widget, &allocation);
-      visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
-      visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
-      visible_rect->width  = allocation.width;
-      visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
-    }
-}
-
-/**
- * pspp_sheet_view_widget_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to bin_window
- * @wy: Y coordinate relative to bin_window
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts bin_window coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Deprecated: 2.12: Due to historial reasons the name of this function is
- * incorrect.  For converting coordinates relative to the widget to
- * bin_window coordinates, please see
- * pspp_sheet_view_convert_widget_to_bin_window_coords().
- *
- **/
-void
-pspp_sheet_view_widget_to_tree_coords (PsppSheetView *tree_view,
-                                     gint         wx,
-                                     gint         wy,
-                                     gint        *tx,
-                                     gint        *ty)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (tx)
-    *tx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
-  if (ty)
-    *ty = wy + tree_view->priv->dy;
-}
-
-/**
- * pspp_sheet_view_tree_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @tx: tree X coordinate
- * @ty: tree Y coordinate
- * @wx: return location for X coordinate relative to bin_window
- * @wy: return location for Y coordinate relative to bin_window
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to bin_window coordinates.
- *
- * Deprecated: 2.12: Due to historial reasons the name of this function is
- * incorrect.  For converting bin_window coordinates to coordinates relative
- * to bin_window, please see
- * pspp_sheet_view_convert_bin_window_to_widget_coords().
- *
- **/
-void
-pspp_sheet_view_tree_to_widget_coords (PsppSheetView *tree_view,
-                                     gint         tx,
-                                     gint         ty,
-                                     gint        *wx,
-                                     gint        *wy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (wx)
-    *wx = tx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
-  if (wy)
-    *wy = ty - tree_view->priv->dy;
-}
-
-
-/**
- * pspp_sheet_view_convert_widget_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to the widget
- * @wy: Y coordinate relative to the widget
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts widget coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_widget_to_tree_coords (PsppSheetView *tree_view,
-                                             gint         wx,
-                                             gint         wy,
-                                             gint        *tx,
-                                             gint        *ty)
-{
-  gint x, y;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
-                                                    wx, wy,
-                                                    &x, &y);
-  pspp_sheet_view_convert_bin_window_to_tree_coords (tree_view,
-                                                  x, y,
-                                                  tx, ty);
-}
-
-/**
- * pspp_sheet_view_convert_tree_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @tx: X coordinate relative to the tree
- * @ty: Y coordinate relative to the tree
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to widget coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_tree_to_widget_coords (PsppSheetView *tree_view,
-                                             gint         tx,
-                                             gint         ty,
-                                             gint        *wx,
-                                             gint        *wy)
-{
-  gint x, y;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  pspp_sheet_view_convert_tree_to_bin_window_coords (tree_view,
-                                                  tx, ty,
-                                                  &x, &y);
-  pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
-                                                    x, y,
-                                                    wx, wy);
-}
-
-/**
- * pspp_sheet_view_convert_widget_to_bin_window_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to the widget
- * @wy: Y coordinate relative to the widget
- * @bx: return location for bin_window X coordinate
- * @by: return location for bin_window Y coordinate
- *
- * Converts widget coordinates to coordinates for the bin_window
- * (see pspp_sheet_view_get_bin_window()).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_widget_to_bin_window_coords (PsppSheetView *tree_view,
-                                                   gint         wx,
-                                                   gint         wy,
-                                                   gint        *bx,
-                                                   gint        *by)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (bx)
-    *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
-  if (by)
-    *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
-}
-
-/**
- * pspp_sheet_view_convert_bin_window_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @bx: bin_window X coordinate
- * @by: bin_window Y coordinate
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
- *
- * Converts bin_window coordinates (see pspp_sheet_view_get_bin_window())
- * to widget relative coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_bin_window_to_widget_coords (PsppSheetView *tree_view,
-                                                   gint         bx,
-                                                   gint         by,
-                                                   gint        *wx,
-                                                   gint        *wy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (wx)
-    *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
-  if (wy)
-    *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
-}
-
-/**
- * pspp_sheet_view_convert_tree_to_bin_window_coords:
- * @tree_view: a #PsppSheetView
- * @tx: tree X coordinate
- * @ty: tree Y coordinate
- * @bx: return location for X coordinate relative to bin_window
- * @by: return location for Y coordinate relative to bin_window
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to bin_window coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_tree_to_bin_window_coords (PsppSheetView *tree_view,
-                                                 gint         tx,
-                                                 gint         ty,
-                                                 gint        *bx,
-                                                 gint        *by)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (bx)
-    *bx = tx;
-  if (by)
-    *by = ty - tree_view->priv->dy;
-}
-
-/**
- * pspp_sheet_view_convert_bin_window_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @bx: X coordinate relative to bin_window
- * @by: Y coordinate relative to bin_window
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts bin_window coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_bin_window_to_tree_coords (PsppSheetView *tree_view,
-                                                 gint         bx,
-                                                 gint         by,
-                                                 gint        *tx,
-                                                 gint        *ty)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (tx)
-    *tx = bx;
-  if (ty)
-    *ty = by + tree_view->priv->dy;
-}
-
-
-
-/**
- * pspp_sheet_view_get_visible_range:
- * @tree_view: A #PsppSheetView
- * @start_path: (allow-none): Return location for start of region, or %NULL.
- * @end_path: (allow-none): Return location for end of region, or %NULL.
- *
- * Sets @start_path and @end_path to be the first and last visible path.
- * Note that there may be invisible paths in between.
- *
- * The paths should be freed with gtk_tree_path_free() after use.
- *
- * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
- *
- * Since: 2.8
- **/
-gboolean
-pspp_sheet_view_get_visible_range (PsppSheetView  *tree_view,
-                                 GtkTreePath **start_path,
-                                 GtkTreePath **end_path)
-{
-  int node;
-  gboolean retval;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  if (!tree_view->priv->row_count)
-    return FALSE;
-
-  retval = TRUE;
-
-  if (start_path)
-    {
-      pspp_sheet_view_find_offset (tree_view,
-                                   TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
-                                   &node);
-      if (node >= 0)
-        *start_path = _pspp_sheet_view_find_path (tree_view, node);
-      else
-        retval = FALSE;
-    }
-
-  if (end_path)
-    {
-      gint y;
-
-      if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
-        y = tree_view->priv->height - 1;
-      else
-        y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
-
-      pspp_sheet_view_find_offset (tree_view, y, &node);
-      if (node >= 0)
-        *end_path = _pspp_sheet_view_find_path (tree_view, node);
-      else
-        retval = FALSE;
-    }
-
-  return retval;
-}
-
-static void
-unset_reorderable (PsppSheetView *tree_view)
-{
-  if (tree_view->priv->reorderable)
-    {
-      tree_view->priv->reorderable = FALSE;
-      g_object_notify (G_OBJECT (tree_view), "reorderable");
-    }
-}
-
-/**
- * pspp_sheet_view_enable_model_drag_source:
- * @tree_view: a #PsppSheetView
- * @start_button_mask: Mask of allowed buttons to start drag
- * @targets: the table of targets that the drag will support
- * @n_targets: the number of items in @targets
- * @actions: the bitmask of possible actions for a drag from this
- *    widget
- *
- * Turns @tree_view into a drag source for automatic DND. Calling this
- * method sets #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_enable_model_drag_source (PsppSheetView              *tree_view,
-                                       GdkModifierType           start_button_mask,
-                                       const GtkTargetEntry     *targets,
-                                       gint                      n_targets,
-                                       GdkDragAction             actions)
-{
-  TreeViewDragInfo *di;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  gtk_drag_source_set (GTK_WIDGET (tree_view),
-                      0,
-                      targets,
-                      n_targets,
-                      actions);
-
-  di = ensure_info (tree_view);
-
-  di->start_button_mask = start_button_mask;
-  di->source_actions = actions;
-  di->source_set = TRUE;
-
-  unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_enable_model_drag_dest:
- * @tree_view: a #PsppSheetView
- * @targets: the table of targets that the drag will support
- * @n_targets: the number of items in @targets
- * @actions: the bitmask of possible actions for a drag from this
- *    widget
- *
- * Turns @tree_view into a drop destination for automatic DND. Calling
- * this method sets #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_enable_model_drag_dest (PsppSheetView              *tree_view,
-                                     const GtkTargetEntry     *targets,
-                                     gint                      n_targets,
-                                     GdkDragAction             actions)
-{
-  TreeViewDragInfo *di;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  gtk_drag_dest_set (GTK_WIDGET (tree_view),
-                     0,
-                     targets,
-                     n_targets,
-                     actions);
-
-  di = ensure_info (tree_view);
-  di->dest_set = TRUE;
-
-  unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_unset_rows_drag_source:
- * @tree_view: a #PsppSheetView
- *
- * Undoes the effect of
- * pspp_sheet_view_enable_model_drag_source(). Calling this method sets
- * #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_unset_rows_drag_source (PsppSheetView *tree_view)
-{
-  TreeViewDragInfo *di;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  di = get_info (tree_view);
-
-  if (di)
-    {
-      if (di->source_set)
-        {
-          gtk_drag_source_unset (GTK_WIDGET (tree_view));
-          di->source_set = FALSE;
-        }
-
-      if (!di->dest_set && !di->source_set)
-        remove_info (tree_view);
-    }
-
-  unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_unset_rows_drag_dest:
- * @tree_view: a #PsppSheetView
- *
- * Undoes the effect of
- * pspp_sheet_view_enable_model_drag_dest(). Calling this method sets
- * #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_unset_rows_drag_dest (PsppSheetView *tree_view)
-{
-  TreeViewDragInfo *di;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  di = get_info (tree_view);
-
-  if (di)
-    {
-      if (di->dest_set)
-        {
-          gtk_drag_dest_unset (GTK_WIDGET (tree_view));
-          di->dest_set = FALSE;
-        }
-
-      if (!di->dest_set && !di->source_set)
-        remove_info (tree_view);
-    }
-
-  unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_set_drag_dest_row:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): The path of the row to highlight, or %NULL.
- * @pos: Specifies whether to drop before, after or into the row
- *
- * Sets the row that is highlighted for feedback.
- **/
-void
-pspp_sheet_view_set_drag_dest_row (PsppSheetView            *tree_view,
-                                 GtkTreePath            *path,
-                                 PsppSheetViewDropPosition pos)
-{
-  GtkTreePath *current_dest;
-
-  /* Note; this function is exported to allow a custom DND
-   * implementation, so it can't touch TreeViewDragInfo
-   */
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  current_dest = NULL;
-
-  if (tree_view->priv->drag_dest_row)
-    {
-      current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
-      gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
-    }
-
-  /* special case a drop on an empty model */
-  tree_view->priv->empty_view_drop = 0;
-
-  if (pos == PSPP_SHEET_VIEW_DROP_BEFORE && path
-      && gtk_tree_path_get_depth (path) == 1
-      && gtk_tree_path_get_indices (path)[0] == 0)
-    {
-      gint n_children;
-
-      n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
-                                                   NULL);
-
-      if (!n_children)
-        tree_view->priv->empty_view_drop = 1;
-    }
-
-  tree_view->priv->drag_dest_pos = pos;
-
-  if (path)
-    {
-      tree_view->priv->drag_dest_row =
-        gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
-      pspp_sheet_view_queue_draw_path (tree_view, path, NULL);
-    }
-  else
-    tree_view->priv->drag_dest_row = NULL;
-
-  if (current_dest)
-    {
-      int node, new_node;
-
-      _pspp_sheet_view_find_node (tree_view, current_dest, &node);
-      _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
-
-      if (node >= 0)
-       {
-         new_node = pspp_sheet_view_node_next (tree_view, node);
-         if (new_node >= 0)
-           _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL);
-
-         new_node = pspp_sheet_view_node_prev (tree_view, node);
-         if (new_node >= 0)
-           _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL);
-       }
-      gtk_tree_path_free (current_dest);
-    }
-}
-
-/**
- * pspp_sheet_view_get_drag_dest_row:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): Return location for the path of the highlighted row, or %NULL.
- * @pos: (allow-none): Return location for the drop position, or %NULL
- *
- * Gets information about the row that is highlighted for feedback.
- **/
-void
-pspp_sheet_view_get_drag_dest_row (PsppSheetView              *tree_view,
-                                 GtkTreePath             **path,
-                                 PsppSheetViewDropPosition  *pos)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (path)
-    {
-      if (tree_view->priv->drag_dest_row)
-        *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
-      else
-        {
-          if (tree_view->priv->empty_view_drop)
-            *path = gtk_tree_path_new_from_indices (0, -1);
-          else
-            *path = NULL;
-        }
-    }
-
-  if (pos)
-    *pos = tree_view->priv->drag_dest_pos;
-}
-
-/**
- * pspp_sheet_view_get_dest_row_at_pos:
- * @tree_view: a #PsppSheetView
- * @drag_x: the position to determine the destination row for
- * @drag_y: the position to determine the destination row for
- * @path: (allow-none): Return location for the path of the highlighted row, or %NULL.
- * @pos: (allow-none): Return location for the drop position, or %NULL
- *
- * Determines the destination row for a given position.  @drag_x and
- * @drag_y are expected to be in widget coordinates.  This function is only
- * meaningful if @tree_view is realized.  Therefore this function will always
- * return %FALSE if @tree_view is not realized or does not have a model.
- *
- * Return value: whether there is a row at the given position, %TRUE if this
- * is indeed the case.
- **/
-gboolean
-pspp_sheet_view_get_dest_row_at_pos (PsppSheetView             *tree_view,
-                                   gint                     drag_x,
-                                   gint                     drag_y,
-                                   GtkTreePath            **path,
-                                   PsppSheetViewDropPosition *pos)
-{
-  gint cell_y;
-  gint bin_x, bin_y;
-  gdouble offset_into_row;
-  gdouble third;
-  GdkRectangle cell;
-  PsppSheetViewColumn *column = NULL;
-  GtkTreePath *tmp_path = NULL;
-
-  /* Note; this function is exported to allow a custom DND
-   * implementation, so it can't touch TreeViewDragInfo
-   */
-
-  g_return_val_if_fail (tree_view != NULL, FALSE);
-  g_return_val_if_fail (drag_x >= 0, FALSE);
-  g_return_val_if_fail (drag_y >= 0, FALSE);
-
-  if (path)
-    *path = NULL;
-
-  if (tree_view->priv->bin_window == NULL)
-    return FALSE;
-
-  if (tree_view->priv->row_count == 0)
-    return FALSE;
-
-  /* If in the top third of a row, we drop before that row; if
-   * in the bottom third, drop after that row; if in the middle,
-   * and the row has children, drop into the row.
-   */
-  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
-                                                    &bin_x, &bin_y);
-
-  if (!pspp_sheet_view_get_path_at_pos (tree_view,
-                                     bin_x,
-                                     bin_y,
-                                      &tmp_path,
-                                      &column,
-                                      NULL,
-                                      &cell_y))
-    return FALSE;
-
-  pspp_sheet_view_get_background_area (tree_view, tmp_path, column,
-                                     &cell);
-
-  offset_into_row = cell_y;
-
-  if (path)
-    *path = tmp_path;
-  else
-    gtk_tree_path_free (tmp_path);
-
-  tmp_path = NULL;
-
-  third = cell.height / 3.0;
-
-  if (pos)
-    {
-      if (offset_into_row < third)
-        {
-          *pos = PSPP_SHEET_VIEW_DROP_BEFORE;
-        }
-      else if (offset_into_row < (cell.height / 2.0))
-        {
-          *pos = PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE;
-        }
-      else if (offset_into_row < third * 2.0)
-        {
-          *pos = PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER;
-        }
-      else
-        {
-          *pos = PSPP_SHEET_VIEW_DROP_AFTER;
-        }
-    }
-
-  return TRUE;
-}
-
-
-
-/**
- * pspp_sheet_view_set_destroy_count_func:
- * @tree_view: A #PsppSheetView
- * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
- * @data: (allow-none): User data to be passed to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @data, or %NULL
- *
- * This function should almost never be used.  It is meant for private use by
- * ATK for determining the number of visible children that are removed when a row is deleted.
- **/
-void
-pspp_sheet_view_set_destroy_count_func (PsppSheetView             *tree_view,
-                                     PsppSheetDestroyCountFunc  func,
-                                     gpointer                 data,
-                                     GDestroyNotify           destroy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (tree_view->priv->destroy_count_destroy)
-    tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
-
-  tree_view->priv->destroy_count_func = func;
-  tree_view->priv->destroy_count_data = data;
-  tree_view->priv->destroy_count_destroy = destroy;
-}
-
-
-/*
- * Interactive search
- */
-
-/**
- * pspp_sheet_view_set_enable_search:
- * @tree_view: A #PsppSheetView
- * @enable_search: %TRUE, if the user can search interactively
- *
- * If @enable_search is set, then the user can type in text to search through
- * the tree interactively (this is sometimes called "typeahead find").
- *
- * Note that even if this is %FALSE, the user can still initiate a search
- * using the "start-interactive-search" key binding.
- */
-void
-pspp_sheet_view_set_enable_search (PsppSheetView *tree_view,
-                                gboolean     enable_search)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  enable_search = !!enable_search;
-
-  if (tree_view->priv->enable_search != enable_search)
-    {
-       tree_view->priv->enable_search = enable_search;
-       g_object_notify (G_OBJECT (tree_view), "enable-search");
-    }
-}
-
-/**
- * pspp_sheet_view_get_enable_search:
- * @tree_view: A #PsppSheetView
- *
- * Returns whether or not the tree allows to start interactive searching
- * by typing in text.
- *
- * Return value: whether or not to let the user search interactively
- */
-gboolean
-pspp_sheet_view_get_enable_search (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  return tree_view->priv->enable_search;
-}
-
-
-/**
- * pspp_sheet_view_get_search_column:
- * @tree_view: A #PsppSheetView
- *
- * Gets the column searched on by the interactive search code.
- *
- * Return value: the column the interactive search code searches in.
- */
-gint
-pspp_sheet_view_get_search_column (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
-  return (tree_view->priv->search_column);
-}
-
-/**
- * pspp_sheet_view_set_search_column:
- * @tree_view: A #PsppSheetView
- * @column: the column of the model to search in, or -1 to disable searching
- *
- * Sets @column as the column where the interactive search code should
- * search in for the current model.
- *
- * If the search column is set, users can use the "start-interactive-search"
- * key binding to bring up search popup. The enable-search property controls
- * whether simply typing text will also start an interactive search.
- *
- * Note that @column refers to a column of the current model. The search
- * column is reset to -1 when the model is changed.
- */
-void
-pspp_sheet_view_set_search_column (PsppSheetView *tree_view,
-                                gint         column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (column >= -1);
-
-  if (tree_view->priv->search_column == column)
-    return;
-
-  tree_view->priv->search_column = column;
-  g_object_notify (G_OBJECT (tree_view), "search-column");
-}
-
-/**
- * pspp_sheet_view_get_search_equal_func:
- * @tree_view: A #PsppSheetView
- *
- * Returns the compare function currently in use.
- *
- * Return value: the currently used compare function for the search code.
- */
-
-PsppSheetViewSearchEqualFunc
-pspp_sheet_view_get_search_equal_func (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return tree_view->priv->search_equal_func;
-}
-
-/**
- * pspp_sheet_view_set_search_equal_func:
- * @tree_view: A #PsppSheetView
- * @search_equal_func: the compare function to use during the search
- * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
- * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
- *
- * Sets the compare function for the interactive search capabilities; note
- * that somewhat like strcmp() returning 0 for equality
- * #PsppSheetViewSearchEqualFunc returns %FALSE on matches.
- **/
-void
-pspp_sheet_view_set_search_equal_func (PsppSheetView                *tree_view,
-                                    PsppSheetViewSearchEqualFunc  search_equal_func,
-                                    gpointer                    search_user_data,
-                                    GDestroyNotify              search_destroy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (search_equal_func != NULL);
-
-  if (tree_view->priv->search_destroy)
-    tree_view->priv->search_destroy (tree_view->priv->search_user_data);
-
-  tree_view->priv->search_equal_func = search_equal_func;
-  tree_view->priv->search_user_data = search_user_data;
-  tree_view->priv->search_destroy = search_destroy;
-  if (tree_view->priv->search_equal_func == NULL)
-    tree_view->priv->search_equal_func = pspp_sheet_view_search_equal_func;
-}
-
-/**
- * pspp_sheet_view_get_search_entry:
- * @tree_view: A #PsppSheetView
- *
- * Returns the #GtkEntry which is currently in use as interactive search
- * entry for @tree_view.  In case the built-in entry is being used, %NULL
- * will be returned.
- *
- * Return value: the entry currently in use as search entry.
- *
- * Since: 2.10
- */
-GtkEntry *
-pspp_sheet_view_get_search_entry (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  if (tree_view->priv->search_custom_entry_set)
-    return GTK_ENTRY (tree_view->priv->search_entry);
-
-  return NULL;
-}
-
-/**
- * pspp_sheet_view_set_search_entry:
- * @tree_view: A #PsppSheetView
- * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
- *
- * Sets the entry which the interactive search code will use for this
- * @tree_view.  This is useful when you want to provide a search entry
- * in our interface at all time at a fixed position.  Passing %NULL for
- * @entry will make the interactive search code use the built-in popup
- * entry again.
- *
- * Since: 2.10
- */
-void
-pspp_sheet_view_set_search_entry (PsppSheetView *tree_view,
-                               GtkEntry    *entry)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
-
-  if (tree_view->priv->search_custom_entry_set)
-    {
-      if (tree_view->priv->search_entry_changed_id)
-        {
-         g_signal_handler_disconnect (tree_view->priv->search_entry,
-                                      tree_view->priv->search_entry_changed_id);
-         tree_view->priv->search_entry_changed_id = 0;
-       }
-      g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
-                                           G_CALLBACK (pspp_sheet_view_search_key_press_event),
-                                           tree_view);
-
-      g_object_unref (tree_view->priv->search_entry);
-    }
-  else if (tree_view->priv->search_window)
-    {
-      gtk_widget_destroy (tree_view->priv->search_window);
-
-      tree_view->priv->search_window = NULL;
-    }
-
-  if (entry)
-    {
-      tree_view->priv->search_entry = g_object_ref (entry);
-      tree_view->priv->search_custom_entry_set = TRUE;
-
-      if (tree_view->priv->search_entry_changed_id == 0)
-        {
-          tree_view->priv->search_entry_changed_id =
-           g_signal_connect (tree_view->priv->search_entry, "changed",
-                             G_CALLBACK (pspp_sheet_view_search_init),
-                             tree_view);
-       }
-
-        g_signal_connect (tree_view->priv->search_entry, "key-press-event",
-                         G_CALLBACK (pspp_sheet_view_search_key_press_event),
-                         tree_view);
-
-       pspp_sheet_view_search_init (tree_view->priv->search_entry, tree_view);
-    }
-  else
-    {
-      tree_view->priv->search_entry = NULL;
-      tree_view->priv->search_custom_entry_set = FALSE;
-    }
-}
-
-/**
- * pspp_sheet_view_set_search_position_func:
- * @tree_view: A #PsppSheetView
- * @func: (allow-none): the function to use to position the search dialog, or %NULL
- *    to use the default search position function
- * @data: (allow-none): user data to pass to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @data, or %NULL
- *
- * Sets the function to use when positioning the search dialog.
- *
- * Since: 2.10
- **/
-void
-pspp_sheet_view_set_search_position_func (PsppSheetView                   *tree_view,
-                                       PsppSheetViewSearchPositionFunc  func,
-                                       gpointer                       user_data,
-                                       GDestroyNotify                 destroy)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (tree_view->priv->search_position_destroy)
-    tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
-
-  tree_view->priv->search_position_func = func;
-  tree_view->priv->search_position_user_data = user_data;
-  tree_view->priv->search_position_destroy = destroy;
-  if (tree_view->priv->search_position_func == NULL)
-    tree_view->priv->search_position_func = pspp_sheet_view_search_position_func;
-}
-
-/**
- * pspp_sheet_view_get_search_position_func:
- * @tree_view: A #PsppSheetView
- *
- * Returns the positioning function currently in use.
- *
- * Return value: the currently used function for positioning the search dialog.
- *
- * Since: 2.10
- */
-PsppSheetViewSearchPositionFunc
-pspp_sheet_view_get_search_position_func (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
-  return tree_view->priv->search_position_func;
-}
-
-
-static void
-pspp_sheet_view_search_dialog_hide (GtkWidget   *search_dialog,
-                                 PsppSheetView *tree_view)
-{
-  if (tree_view->priv->disable_popdown)
-    return;
-
-  if (tree_view->priv->search_entry_changed_id)
-    {
-      g_signal_handler_disconnect (tree_view->priv->search_entry,
-                                  tree_view->priv->search_entry_changed_id);
-      tree_view->priv->search_entry_changed_id = 0;
-    }
-  if (tree_view->priv->typeselect_flush_timeout)
-    {
-      g_source_remove (tree_view->priv->typeselect_flush_timeout);
-      tree_view->priv->typeselect_flush_timeout = 0;
-    }
-
-  if (gtk_widget_get_visible (search_dialog))
-    {
-      /* send focus-in event */
-      send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
-      gtk_widget_hide (search_dialog);
-      gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
-      send_focus_change (GTK_WIDGET (tree_view), TRUE);
-    }
-}
-
-static void
-pspp_sheet_view_search_position_func (PsppSheetView *tree_view,
-                                   GtkWidget   *search_dialog,
-                                   gpointer     user_data)
-{
-  gint x, y;
-  gint tree_x, tree_y;
-  gint tree_width, tree_height;
-  GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
-  GdkScreen *screen = gdk_window_get_screen (tree_window);
-  GtkRequisition requisition;
-  gint monitor_num;
-  GdkRectangle monitor;
-
-  monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-
-  gtk_widget_realize (search_dialog);
-
-  gdk_window_get_origin (tree_window, &tree_x, &tree_y);
-  tree_width = gdk_window_get_width (tree_window);
-  tree_height = gdk_window_get_height (tree_window);
-
-  gtk_widget_size_request (search_dialog, &requisition);
-
-  if (tree_x + tree_width > gdk_screen_get_width (screen))
-    x = gdk_screen_get_width (screen) - requisition.width;
-  else if (tree_x + tree_width - requisition.width < 0)
-    x = 0;
-  else
-    x = tree_x + tree_width - requisition.width;
-
-  if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
-    y = gdk_screen_get_height (screen) - requisition.height;
-  else if (tree_y + tree_height < 0) /* isn't really possible ... */
-    y = 0;
-  else
-    y = tree_y + tree_height;
-
-  gtk_window_move (GTK_WINDOW (search_dialog), x, y);
-}
-
-static void
-pspp_sheet_view_search_disable_popdown (GtkEntry *entry,
-                                     GtkMenu  *menu,
-                                     gpointer  data)
-{
-  PsppSheetView *tree_view = (PsppSheetView *)data;
-
-  tree_view->priv->disable_popdown = 1;
-  g_signal_connect (menu, "hide",
-                   G_CALLBACK (pspp_sheet_view_search_enable_popdown), data);
-}
-
-
-static void
-pspp_sheet_view_search_activate (GtkEntry    *entry,
-                              PsppSheetView *tree_view)
-{
-  GtkTreePath *path;
-  int node;
-
-  pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window,
-                                   tree_view);
-
-  /* If we have a row selected and it's the cursor row, we activate
-   * the row XXX */
-  if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    {
-      path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
-      _pspp_sheet_view_find_node (tree_view, path, &node);
-
-      if (node >= 0 && pspp_sheet_view_node_is_selected (tree_view, node))
-       pspp_sheet_view_row_activated (tree_view, path, tree_view->priv->focus_column);
-
-      gtk_tree_path_free (path);
-    }
-}
-
-static gboolean
-pspp_sheet_view_real_search_enable_popdown (gpointer data)
-{
-  PsppSheetView *tree_view = (PsppSheetView *)data;
-
-  tree_view->priv->disable_popdown = 0;
-
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_search_enable_popdown (GtkWidget *widget,
-                                    gpointer   data)
-{
-  gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, pspp_sheet_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
-}
-
-static gboolean
-pspp_sheet_view_search_delete_event (GtkWidget *widget,
-                                  GdkEventAny *event,
-                                  PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-
-  pspp_sheet_view_search_dialog_hide (widget, tree_view);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_button_press_event (GtkWidget *widget,
-                                        GdkEventButton *event,
-                                        PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-
-  pspp_sheet_view_search_dialog_hide (widget, tree_view);
-
-  if (event->window == tree_view->priv->bin_window)
-    pspp_sheet_view_button_press (GTK_WIDGET (tree_view), event);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_scroll_event (GtkWidget *widget,
-                                  GdkEventScroll *event,
-                                  PsppSheetView *tree_view)
-{
-  gboolean retval = FALSE;
-
-  if (event->direction == GDK_SCROLL_UP)
-    {
-      pspp_sheet_view_search_move (widget, tree_view, TRUE);
-      retval = TRUE;
-    }
-  else if (event->direction == GDK_SCROLL_DOWN)
-    {
-      pspp_sheet_view_search_move (widget, tree_view, FALSE);
-      retval = TRUE;
-    }
-
-  /* renew the flush timeout */
-  if (retval && tree_view->priv->typeselect_flush_timeout
-      && !tree_view->priv->search_custom_entry_set)
-    {
-      g_source_remove (tree_view->priv->typeselect_flush_timeout);
-      tree_view->priv->typeselect_flush_timeout =
-       gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
-                      (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
-                      tree_view);
-    }
-
-  return retval;
-}
-
-static gboolean
-pspp_sheet_view_search_key_press_event (GtkWidget *widget,
-                                     GdkEventKey *event,
-                                     PsppSheetView *tree_view)
-{
-  gboolean retval = FALSE;
-
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  /* close window and cancel the search */
-  if (!tree_view->priv->search_custom_entry_set
-      && (event->keyval == GDK_Escape ||
-          event->keyval == GDK_Tab ||
-           event->keyval == GDK_KP_Tab ||
-           event->keyval == GDK_ISO_Left_Tab))
-    {
-      pspp_sheet_view_search_dialog_hide (widget, tree_view);
-      return TRUE;
-    }
-
-  /* select previous matching iter */
-  if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
-    {
-      if (!pspp_sheet_view_search_move (widget, tree_view, TRUE))
-        gtk_widget_error_bell (widget);
-
-      retval = TRUE;
-    }
-
-  if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
-      && (event->keyval == GDK_g || event->keyval == GDK_G))
-    {
-      if (!pspp_sheet_view_search_move (widget, tree_view, TRUE))
-        gtk_widget_error_bell (widget);
-
-      retval = TRUE;
-    }
-
-  /* select next matching iter */
-  if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
-    {
-      if (!pspp_sheet_view_search_move (widget, tree_view, FALSE))
-        gtk_widget_error_bell (widget);
-
-      retval = TRUE;
-    }
-
-  if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
-      && (event->keyval == GDK_g || event->keyval == GDK_G))
-    {
-      if (!pspp_sheet_view_search_move (widget, tree_view, FALSE))
-        gtk_widget_error_bell (widget);
-
-      retval = TRUE;
-    }
-
-  /* renew the flush timeout */
-  if (retval && tree_view->priv->typeselect_flush_timeout
-      && !tree_view->priv->search_custom_entry_set)
-    {
-      g_source_remove (tree_view->priv->typeselect_flush_timeout);
-      tree_view->priv->typeselect_flush_timeout =
-       gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
-                      (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
-                      tree_view);
-    }
-
-  return retval;
-}
-
-/*  this function returns FALSE if there is a search string but
- *  nothing was found, and TRUE otherwise.
- */
-static gboolean
-pspp_sheet_view_search_move (GtkWidget   *window,
-                          PsppSheetView *tree_view,
-                          gboolean     up)
-{
-  gboolean ret;
-  gint len;
-  gint count = 0;
-  const gchar *text;
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-  PsppSheetSelection *selection;
-
-  text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
-
-  g_return_val_if_fail (text != NULL, FALSE);
-
-  len = strlen (text);
-
-  if (up && tree_view->priv->selected_iter == 1)
-    return strlen (text) < 1;
-
-  len = strlen (text);
-
-  if (len < 1)
-    return TRUE;
-
-  model = pspp_sheet_view_get_model (tree_view);
-  selection = pspp_sheet_view_get_selection (tree_view);
-
-  /* search */
-  pspp_sheet_selection_unselect_all (selection);
-  if (!gtk_tree_model_get_iter_first (model, &iter))
-    return TRUE;
-
-  ret = pspp_sheet_view_search_iter (model, selection, &iter, text,
-                                  &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
-
-  if (ret)
-    {
-      /* found */
-      tree_view->priv->selected_iter += up?(-1):(1);
-      return TRUE;
-    }
-  else
-    {
-      /* return to old iter */
-      count = 0;
-      gtk_tree_model_get_iter_first (model, &iter);
-      pspp_sheet_view_search_iter (model, selection,
-                                &iter, text,
-                                &count, tree_view->priv->selected_iter);
-      return FALSE;
-    }
-}
-
-static gboolean
-pspp_sheet_view_search_equal_func (GtkTreeModel *model,
-                                gint          column,
-                                const gchar  *key,
-                                GtkTreeIter  *iter,
-                                gpointer      search_data)
-{
-  gboolean retval = TRUE;
-  const gchar *str;
-  gchar *normalized_string;
-  gchar *normalized_key;
-  gchar *case_normalized_string = NULL;
-  gchar *case_normalized_key = NULL;
-  GValue value = {0,};
-  GValue transformed = {0,};
-
-  gtk_tree_model_get_value (model, iter, column, &value);
-
-  g_value_init (&transformed, G_TYPE_STRING);
-
-  if (!g_value_transform (&value, &transformed))
-    {
-      g_value_unset (&value);
-      return TRUE;
-    }
-
-  g_value_unset (&value);
-
-  str = g_value_get_string (&transformed);
-  if (!str)
-    {
-      g_value_unset (&transformed);
-      return TRUE;
-    }
-
-  normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
-  normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
-
-  if (normalized_string && normalized_key)
-    {
-      case_normalized_string = g_utf8_casefold (normalized_string, -1);
-      case_normalized_key = g_utf8_casefold (normalized_key, -1);
-
-      if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
-        retval = FALSE;
-    }
-
-  g_value_unset (&transformed);
-  g_free (normalized_key);
-  g_free (normalized_string);
-  g_free (case_normalized_key);
-  g_free (case_normalized_string);
-
-  return retval;
-}
-
-static gboolean
-pspp_sheet_view_search_iter (GtkTreeModel     *model,
-                             PsppSheetSelection *selection,
-                             GtkTreeIter      *iter,
-                             const gchar      *text,
-                             gint             *count,
-                             gint              n)
-{
-  int node = -1;
-  GtkTreePath *path;
-
-  PsppSheetView *tree_view = pspp_sheet_selection_get_tree_view (selection);
-
-  path = gtk_tree_model_get_path (model, iter);
-  _pspp_sheet_view_find_node (tree_view, path, &node);
-
-  do
-    {
-      gboolean done = FALSE;
-
-      if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
-        {
-          (*count)++;
-          if (*count == n)
-            {
-              pspp_sheet_view_scroll_to_cell (tree_view, path, NULL,
-                                              TRUE, 0.5, 0.0);
-              pspp_sheet_selection_select_iter (selection, iter);
-              pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0);
-
-             if (path)
-               gtk_tree_path_free (path);
-
-              return TRUE;
-            }
-        }
-
-
-      do
-        {
-          node = pspp_sheet_view_node_next (tree_view, node);
-
-          if (node >= 0)
-            {
-              gboolean has_next;
-
-              has_next = gtk_tree_model_iter_next (model, iter);
-
-              done = TRUE;
-              gtk_tree_path_next (path);
-
-              /* sanity check */
-              TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
-            }
-          else
-            {
-              if (path)
-                gtk_tree_path_free (path);
-
-              /* we've run out of tree, done with this func */
-              return FALSE;
-            }
-        }
-      while (!done);
-    }
-  while (1);
-
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_search_init (GtkWidget   *entry,
-                          PsppSheetView *tree_view)
-{
-  gint ret;
-  gint count = 0;
-  const gchar *text;
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-  PsppSheetSelection *selection;
-
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  text = gtk_entry_get_text (GTK_ENTRY (entry));
-
-  model = pspp_sheet_view_get_model (tree_view);
-  selection = pspp_sheet_view_get_selection (tree_view);
-
-  /* search */
-  pspp_sheet_selection_unselect_all (selection);
-  if (tree_view->priv->typeselect_flush_timeout
-      && !tree_view->priv->search_custom_entry_set)
-    {
-      g_source_remove (tree_view->priv->typeselect_flush_timeout);
-      tree_view->priv->typeselect_flush_timeout =
-       gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
-                      (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
-                      tree_view);
-    }
-
-  if (*text == '\0')
-    return;
-
-  if (!gtk_tree_model_get_iter_first (model, &iter))
-    return;
-
-  ret = pspp_sheet_view_search_iter (model, selection,
-                                  &iter, text,
-                                  &count, 1);
-
-  if (ret)
-    tree_view->priv->selected_iter = 1;
-}
-
-static void
-pspp_sheet_view_remove_widget (GtkCellEditable *cell_editable,
-                            PsppSheetView     *tree_view)
-{
-  if (tree_view->priv->edited_column == NULL)
-    return;
-
-  _pspp_sheet_view_column_stop_editing (tree_view->priv->edited_column);
-  tree_view->priv->edited_column = NULL;
-
-  if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
-    gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-  g_signal_handlers_disconnect_by_func (cell_editable,
-                                       pspp_sheet_view_remove_widget,
-                                       tree_view);
-  g_signal_handlers_disconnect_by_func (cell_editable,
-                                       pspp_sheet_view_editable_button_press_event,
-                                       tree_view);
-  g_signal_handlers_disconnect_by_func (cell_editable,
-                                       pspp_sheet_view_editable_clicked,
-                                       tree_view);
-
-  gtk_container_remove (GTK_CONTAINER (tree_view),
-                       GTK_WIDGET (cell_editable));
-
-  /* FIXME should only redraw a single node */
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static gboolean
-pspp_sheet_view_start_editing (PsppSheetView *tree_view,
-                            GtkTreePath *cursor_path)
-{
-  GtkTreeIter iter;
-  GdkRectangle background_area;
-  GdkRectangle cell_area;
-  GtkCellEditable *editable_widget = NULL;
-  gchar *path_string;
-  guint flags = 0; /* can be 0, as the flags are primarily for rendering */
-  gint retval = FALSE;
-  int cursor_node;
-
-  g_assert (tree_view->priv->focus_column);
-
-  if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
-    return FALSE;
-
-  _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-  if (cursor_node < 0)
-    return FALSE;
-
-  path_string = gtk_tree_path_to_string (cursor_path);
-  gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
-
-  pspp_sheet_view_column_cell_set_cell_data (tree_view->priv->focus_column,
-                                          tree_view->priv->model,
-                                          &iter);
-  pspp_sheet_view_get_background_area (tree_view,
-                                    cursor_path,
-                                    tree_view->priv->focus_column,
-                                    &background_area);
-  pspp_sheet_view_get_cell_area (tree_view,
-                              cursor_path,
-                              tree_view->priv->focus_column,
-                              &cell_area);
-
-  if (_pspp_sheet_view_column_cell_event (tree_view->priv->focus_column,
-                                       &editable_widget,
-                                       NULL,
-                                       path_string,
-                                       &background_area,
-                                       &cell_area,
-                                       flags))
-    {
-      retval = TRUE;
-      if (editable_widget != NULL)
-       {
-         gint left, right;
-         GdkRectangle area;
-         GtkCellRenderer *cell;
-
-         area = cell_area;
-         cell = _pspp_sheet_view_column_get_edited_cell (tree_view->priv->focus_column);
-
-         _pspp_sheet_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
-
-         area.x += left;
-         area.width -= right + left;
-
-         pspp_sheet_view_real_start_editing (tree_view,
-                                           tree_view->priv->focus_column,
-                                           cursor_path,
-                                           editable_widget,
-                                           &area,
-                                           NULL,
-                                           flags);
-       }
-
-    }
-  g_free (path_string);
-  return retval;
-}
-
-static gboolean
-pspp_sheet_view_editable_button_press_event (GtkWidget *widget,
-                                             GdkEventButton *event,
-                                             PsppSheetView *sheet_view)
-{
-  gint node;
-
-  node = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
-                                             "pspp-sheet-view-node"));
-  return pspp_sheet_view_row_head_clicked (sheet_view,
-                                           node,
-                                           sheet_view->priv->edited_column,
-                                           event);
-}
-
-static void
-pspp_sheet_view_editable_clicked (GtkButton *button,
-                                  PsppSheetView *sheet_view)
-{
-  pspp_sheet_view_editable_button_press_event (GTK_WIDGET (button), NULL,
-                                               sheet_view);
-}
-
-static gboolean
-is_all_selected (GtkWidget *widget)
-{
-  GtkEntryBuffer *buffer;
-  gint start_pos, end_pos;
-
-  if (!GTK_IS_ENTRY (widget))
-    return FALSE;
-
-  buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
-  return (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget),
-                                             &start_pos, &end_pos)
-          && start_pos == 0
-          && end_pos == gtk_entry_buffer_get_length (buffer));
-}
-
-static gboolean
-is_at_left (GtkWidget *widget)
-{
-  return (GTK_IS_ENTRY (widget)
-          && gtk_editable_get_position (GTK_EDITABLE (widget)) == 0);
-}
-
-static gboolean
-is_at_right (GtkWidget *widget)
-{
-  GtkEntryBuffer *buffer;
-  gint length;
-
-  if (!GTK_IS_ENTRY (widget))
-    return FALSE;
-
-  buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
-  length = gtk_entry_buffer_get_length (buffer);
-  return gtk_editable_get_position (GTK_EDITABLE (widget)) == length;
-}
-
-static gboolean
-pspp_sheet_view_event (GtkWidget *widget,
-                       GdkEventKey *event,
-                       PsppSheetView *tree_view)
-{
-  PsppSheetViewColumn *column;
-  GtkTreePath *path;
-  gboolean handled;
-  gboolean cancel;
-  guint keyval;
-  gint row;
-
-  /* Intercept only key press events.
-     It would make sense to use "key-press-event" instead of "event", but
-     GtkEntry attaches its own signal handler to "key-press-event" that runs
-     before ours and overrides our desired behavior for GDK_Up and GDK_Down.
-  */
-  if (event->type != GDK_KEY_PRESS)
-    return FALSE;
-
-  keyval = event->keyval;
-  cancel = FALSE;
-  switch (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK))
-    {
-    case 0:
-      switch (event->keyval)
-        {
-        case GDK_Left:      case GDK_KP_Left:
-        case GDK_Home:      case GDK_KP_Home:
-          if (!is_all_selected (widget) && !is_at_left (widget))
-            return FALSE;
-          break;
-
-        case GDK_Right:     case GDK_KP_Right:
-        case GDK_End:       case GDK_KP_End:
-          if (!is_all_selected (widget) && !is_at_right (widget))
-            return FALSE;
-          break;
-
-        case GDK_Up:        case GDK_KP_Up:
-        case GDK_Down:      case GDK_KP_Down:
-          break;
-
-        case GDK_Page_Up:   case GDK_KP_Page_Up:
-        case GDK_Page_Down: case GDK_KP_Page_Down:
-          break;
-
-        case GDK_Escape:
-          cancel = TRUE;
-          break;
-
-        case GDK_Return:
-          keyval = GDK_Down;
-          break;
-
-        case GDK_Tab:       case GDK_KP_Tab:
-        case GDK_ISO_Left_Tab:
-          keyval = GDK_Tab;
-          break;
-
-        default:
-          return FALSE;
-        }
-      break;
-
-    case GDK_SHIFT_MASK:
-      switch (event->keyval)
-        {
-        case GDK_Tab:
-        case GDK_ISO_Left_Tab:
-          keyval = GDK_Tab;
-          break;
-
-        default:
-          return FALSE;
-        }
-      break;
-
-    case GDK_CONTROL_MASK:
-      switch (event->keyval)
-        {
-        case GDK_Left:      case GDK_KP_Left:
-          if (!is_all_selected (widget) && !is_at_left (widget))
-            return FALSE;
-          break;
-
-        case GDK_Right:     case GDK_KP_Right:
-          if (!is_all_selected (widget) && !is_at_right (widget))
-            return FALSE;
-          break;
-
-        case GDK_Up:        case GDK_KP_Up:
-        case GDK_Down:      case GDK_KP_Down:
-          break;
-
-        default:
-          return FALSE;
-        }
-      break;
-
-    default:
-      return FALSE;
-    }
-
-  row = tree_view->priv->edited_row;
-  column = tree_view->priv->edited_column;
-  path = gtk_tree_path_new_from_indices (row, -1);
-
-  pspp_sheet_view_stop_editing (tree_view, cancel);
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-  pspp_sheet_view_set_cursor (tree_view, path, column, FALSE);
-  gtk_tree_path_free (path);
-
-  handled = gtk_binding_set_activate (edit_bindings, keyval, event->state,
-                                      G_OBJECT (tree_view));
-  if (handled)
-    g_signal_stop_emission_by_name (widget, "event");
-
-  pspp_sheet_view_get_cursor (tree_view, &path, NULL);
-  pspp_sheet_view_start_editing (tree_view, path);
-  gtk_tree_path_free (path);
-
-  return handled;
-}
-
-static void
-pspp_sheet_view_override_cell_keypresses (GtkWidget *widget,
-                                          gpointer data)
-{
-  PsppSheetView *sheet_view = data;
-
-  g_signal_connect (widget, "event",
-                    G_CALLBACK (pspp_sheet_view_event),
-                    sheet_view);
-
-  if (GTK_IS_CONTAINER (widget))
-    gtk_container_foreach (GTK_CONTAINER (widget),
-                           pspp_sheet_view_override_cell_keypresses,
-                           data);
-}
-
-static void
-pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
-                                 PsppSheetViewColumn *column,
-                                 GtkTreePath       *path,
-                                 GtkCellEditable   *cell_editable,
-                                 GdkRectangle      *cell_area,
-                                 GdkEvent          *event,
-                                 guint              flags)
-{
-  PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
-  gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
-  gint row;
-
-  g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
-
-  tree_view->priv->edited_column = column;
-  _pspp_sheet_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
-
-  row = gtk_tree_path_get_indices (path)[0];
-  tree_view->priv->edited_row = row;
-  pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0);
-  cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
-  pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
-  pspp_sheet_selection_select_column (tree_view->priv->selection, column);
-  tree_view->priv->anchor_column = column;
-
-  PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-
-  pspp_sheet_view_put (tree_view,
-                      GTK_WIDGET (cell_editable),
-                      path,
-                      column);
-
-  gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
-                                  (GdkEvent *)event);
-
-  gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
-  g_signal_connect (cell_editable, "remove-widget",
-                   G_CALLBACK (pspp_sheet_view_remove_widget), tree_view);
-  if (mode == PSPP_SHEET_SELECTION_RECTANGLE && column->row_head &&
-      GTK_IS_BUTTON (cell_editable))
-    {
-      g_signal_connect (cell_editable, "button-press-event",
-                        G_CALLBACK (pspp_sheet_view_editable_button_press_event),
-                        tree_view);
-      g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node",
-                         GINT_TO_POINTER (row));
-      g_signal_connect (cell_editable, "clicked",
-                        G_CALLBACK (pspp_sheet_view_editable_clicked),
-                        tree_view);
-    }
-
-  pspp_sheet_view_override_cell_keypresses (GTK_WIDGET (cell_editable),
-                                            tree_view);
-}
-
-void
-pspp_sheet_view_stop_editing (PsppSheetView *tree_view,
-                              gboolean     cancel_editing)
-{
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *cell;
-
-  if (tree_view->priv->edited_column == NULL)
-    return;
-
-  /*
-   * This is very evil. We need to do this, because
-   * gtk_cell_editable_editing_done may trigger pspp_sheet_view_row_changed
-   * later on. If pspp_sheet_view_row_changed notices
-   * tree_view->priv->edited_column != NULL, it'll call
-   * pspp_sheet_view_stop_editing again. Bad things will happen then.
-   *
-   * Please read that again if you intend to modify anything here.
-   */
-
-  column = tree_view->priv->edited_column;
-  tree_view->priv->edited_column = NULL;
-
-  cell = _pspp_sheet_view_column_get_edited_cell (column);
-  gtk_cell_renderer_stop_editing (cell, cancel_editing);
-
-  if (!cancel_editing)
-    gtk_cell_editable_editing_done (column->editable_widget);
-
-  tree_view->priv->edited_column = column;
-
-  gtk_cell_editable_remove_widget (column->editable_widget);
-}
-
-
-/**
- * pspp_sheet_view_set_hover_selection:
- * @tree_view: a #PsppSheetView
- * @hover: %TRUE to enable hover selection mode
- *
- * Enables of disables the hover selection mode of @tree_view.
- * Hover selection makes the selected row follow the pointer.
- * Currently, this works only for the selection modes
- * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
- *
- * Since: 2.6
- **/
-void
-pspp_sheet_view_set_hover_selection (PsppSheetView *tree_view,
-                                  gboolean     hover)
-{
-  hover = hover != FALSE;
-
-  if (hover != tree_view->priv->hover_selection)
-    {
-      tree_view->priv->hover_selection = hover;
-
-      g_object_notify (G_OBJECT (tree_view), "hover-selection");
-    }
-}
-
-/**
- * pspp_sheet_view_get_hover_selection:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether hover selection mode is turned on for @tree_view.
- *
- * Return value: %TRUE if @tree_view is in hover selection mode
- *
- * Since: 2.6
- **/
-gboolean
-pspp_sheet_view_get_hover_selection (PsppSheetView *tree_view)
-{
-  return tree_view->priv->hover_selection;
-}
-
-/**
- * pspp_sheet_view_set_rubber_banding:
- * @tree_view: a #PsppSheetView
- * @enable: %TRUE to enable rubber banding
- *
- * Enables or disables rubber banding in @tree_view.  If the selection mode is
- * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, rubber
- * banding will allow the user to select multiple rows by dragging the mouse.
- *
- * Since: 2.10
- **/
-void
-pspp_sheet_view_set_rubber_banding (PsppSheetView *tree_view,
-                                 gboolean     enable)
-{
-  enable = enable != FALSE;
-
-  if (enable != tree_view->priv->rubber_banding_enable)
-    {
-      tree_view->priv->rubber_banding_enable = enable;
-
-      g_object_notify (G_OBJECT (tree_view), "rubber-banding");
-    }
-}
-
-/**
- * pspp_sheet_view_get_rubber_banding:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether rubber banding is turned on for @tree_view.  If the
- * selection mode is #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE, rubber banding will allow the user to
- * select multiple rows by dragging the mouse.
- *
- * Return value: %TRUE if rubber banding in @tree_view is enabled.
- *
- * Since: 2.10
- **/
-gboolean
-pspp_sheet_view_get_rubber_banding (PsppSheetView *tree_view)
-{
-  return tree_view->priv->rubber_banding_enable;
-}
-
-/**
- * pspp_sheet_view_is_rubber_banding_active:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether a rubber banding operation is currently being done
- * in @tree_view.
- *
- * Return value: %TRUE if a rubber banding operation is currently being
- * done in @tree_view.
- *
- * Since: 2.12
- **/
-gboolean
-pspp_sheet_view_is_rubber_banding_active (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
-  if (tree_view->priv->rubber_banding_enable
-      && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
-    return TRUE;
-
-  return FALSE;
-}
-
-static void
-pspp_sheet_view_grab_notify (GtkWidget *widget,
-                          gboolean   was_grabbed)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  tree_view->priv->in_grab = !was_grabbed;
-
-  if (!was_grabbed)
-    {
-      tree_view->priv->pressed_button = -1;
-
-      if (tree_view->priv->rubber_band_status)
-       pspp_sheet_view_stop_rubber_band (tree_view);
-    }
-}
-
-static void
-pspp_sheet_view_state_changed (GtkWidget      *widget,
-                            GtkStateType    previous_state)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (gtk_widget_get_realized (widget))
-    {
-      GtkStyle *style = gtk_widget_get_style (widget);
-      gdk_window_set_background (tree_view->priv->bin_window, &style->base[gtk_widget_get_state (widget)]);
-    }
-
-  gtk_widget_queue_draw (widget);
-}
-
-/**
- * pspp_sheet_view_get_grid_lines:
- * @tree_view: a #PsppSheetView
- *
- * Returns which grid lines are enabled in @tree_view.
- *
- * Return value: a #PsppSheetViewGridLines value indicating which grid lines
- * are enabled.
- *
- * Since: 2.10
- */
-PsppSheetViewGridLines
-pspp_sheet_view_get_grid_lines (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
-  return tree_view->priv->grid_lines;
-}
-
-/**
- * pspp_sheet_view_set_grid_lines:
- * @tree_view: a #PsppSheetView
- * @grid_lines: a #PsppSheetViewGridLines value indicating which grid lines to
- * enable.
- *
- * Sets which grid lines to draw in @tree_view.
- *
- * Since: 2.10
- */
-void
-pspp_sheet_view_set_grid_lines (PsppSheetView           *tree_view,
-                             PsppSheetViewGridLines   grid_lines)
-{
-  PsppSheetViewPrivate *priv;
-  PsppSheetViewGridLines old_grid_lines;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  priv = tree_view->priv;
-
-  old_grid_lines = priv->grid_lines;
-  priv->grid_lines = grid_lines;
-
-  if (old_grid_lines != grid_lines)
-    {
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
-      g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
-    }
-}
-
-/**
- * pspp_sheet_view_get_special_cells:
- * @tree_view: a #PsppSheetView
- *
- * Returns which grid lines are enabled in @tree_view.
- *
- * Return value: a #PsppSheetViewSpecialCells value indicating whether rows in
- * the sheet view contain special cells.
- */
-PsppSheetViewSpecialCells
-pspp_sheet_view_get_special_cells (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
-  return tree_view->priv->special_cells;
-}
-
-/**
- * pspp_sheet_view_set_special_cells:
- * @tree_view: a #PsppSheetView
- * @special_cells: a #PsppSheetViewSpecialCells value indicating whether rows in
- * the sheet view contain special cells.
- *
- * Sets whether rows in the sheet view contain special cells, controlling the
- * rendering of row selections.
- */
-void
-pspp_sheet_view_set_special_cells (PsppSheetView           *tree_view,
-                             PsppSheetViewSpecialCells   special_cells)
-{
-  PsppSheetViewPrivate *priv;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  priv = tree_view->priv;
-
-  if (priv->special_cells != special_cells)
-    {
-      priv->special_cells = special_cells;
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-      g_object_notify (G_OBJECT (tree_view), "special-cells");
-    }
-}
-
-int
-pspp_sheet_view_get_fixed_height (const PsppSheetView *tree_view)
-{
-  /* XXX (re)calculate fixed_height if necessary */
-  return tree_view->priv->fixed_height;
-}
-
-void
-pspp_sheet_view_set_fixed_height (PsppSheetView *tree_view,
-                                  int fixed_height)
-{
-  g_return_if_fail (fixed_height > 0);
-
-  if (tree_view->priv->fixed_height != fixed_height)
-    {
-      tree_view->priv->fixed_height = fixed_height;
-      g_object_notify (G_OBJECT (tree_view), "fixed-height");
-    }
-  if (!tree_view->priv->fixed_height_set)
-    {
-      tree_view->priv->fixed_height_set = TRUE;
-      g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
-    }
-}
-
-/**
- * pspp_sheet_view_set_tooltip_row:
- * @tree_view: a #PsppSheetView
- * @tooltip: a #GtkTooltip
- * @path: a #GtkTreePath
- *
- * Sets the tip area of @tooltip to be the area covered by the row at @path.
- * See also pspp_sheet_view_set_tooltip_column() for a simpler alternative.
- * See also gtk_tooltip_set_tip_area().
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_row (PsppSheetView *tree_view,
-                              GtkTooltip  *tooltip,
-                              GtkTreePath *path)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
-
-  pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
-}
-
-/**
- * pspp_sheet_view_set_tooltip_cell:
- * @tree_view: a #PsppSheetView
- * @tooltip: a #GtkTooltip
- * @path: (allow-none): a #GtkTreePath or %NULL
- * @column: (allow-none): a #PsppSheetViewColumn or %NULL
- * @cell: (allow-none): a #GtkCellRenderer or %NULL
- *
- * Sets the tip area of @tooltip to the area @path, @column and @cell have
- * in common.  For example if @path is %NULL and @column is set, the tip
- * area will be set to the full area covered by @column.  See also
- * gtk_tooltip_set_tip_area().
- *
- * See also pspp_sheet_view_set_tooltip_column() for a simpler alternative.
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_cell (PsppSheetView       *tree_view,
-                               GtkTooltip        *tooltip,
-                               GtkTreePath       *path,
-                               PsppSheetViewColumn *column,
-                               GtkCellRenderer   *cell)
-{
-  GdkRectangle rect;
-
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
-  g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
-  g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
-
-  /* Determine x values. */
-  if (column && cell)
-    {
-      GdkRectangle tmp;
-      gint start, width;
-
-      pspp_sheet_view_get_cell_area (tree_view, path, column, &tmp);
-      pspp_sheet_view_column_cell_get_position (column, cell, &start, &width);
-
-      pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
-                                                        tmp.x + start, 0,
-                                                        &rect.x, NULL);
-      rect.width = width;
-    }
-  else if (column)
-    {
-      GdkRectangle tmp;
-
-      pspp_sheet_view_get_background_area (tree_view, NULL, column, &tmp);
-      pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
-                                                        tmp.x, 0,
-                                                        &rect.x, NULL);
-      rect.width = tmp.width;
-    }
-  else
-    {
-      GtkAllocation allocation;
-      gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-      rect.x = 0;
-      rect.width = allocation.width;
-    }
-
-  /* Determine y values. */
-  if (path)
-    {
-      GdkRectangle tmp;
-
-      pspp_sheet_view_get_background_area (tree_view, path, NULL, &tmp);
-      pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
-                                                        0, tmp.y,
-                                                        NULL, &rect.y);
-      rect.height = tmp.height;
-    }
-  else
-    {
-      rect.y = 0;
-      rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
-    }
-
-  gtk_tooltip_set_tip_area (tooltip, &rect);
-}
-
-/**
- * pspp_sheet_view_get_tooltip_context:
- * @tree_view: a #PsppSheetView
- * @x: the x coordinate (relative to widget coordinates)
- * @y: the y coordinate (relative to widget coordinates)
- * @keyboard_tip: whether this is a keyboard tooltip or not
- * @model: (allow-none): a pointer to receive a #GtkTreeModel or %NULL
- * @path: (allow-none): a pointer to receive a #GtkTreePath or %NULL
- * @iter: (allow-none): a pointer to receive a #GtkTreeIter or %NULL
- *
- * This function is supposed to be used in a #GtkWidget::query-tooltip
- * signal handler for #PsppSheetView.  The @x, @y and @keyboard_tip values
- * which are received in the signal handler, should be passed to this
- * function without modification.
- *
- * The return value indicates whether there is a tree view row at the given
- * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
- * tooltips the row returned will be the cursor row.  When %TRUE, then any of
- * @model, @path and @iter which have been provided will be set to point to
- * that row and the corresponding model.  @x and @y will always be converted
- * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
- *
- * Return value: whether or not the given tooltip context points to a row.
- *
- * Since: 2.12
- */
-gboolean
-pspp_sheet_view_get_tooltip_context (PsppSheetView   *tree_view,
-                                  gint          *x,
-                                  gint          *y,
-                                  gboolean       keyboard_tip,
-                                  GtkTreeModel **model,
-                                  GtkTreePath  **path,
-                                  GtkTreeIter   *iter)
-{
-  GtkTreePath *tmppath = NULL;
-
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-  g_return_val_if_fail (x != NULL, FALSE);
-  g_return_val_if_fail (y != NULL, FALSE);
-
-  if (keyboard_tip)
-    {
-      pspp_sheet_view_get_cursor (tree_view, &tmppath, NULL);
-
-      if (!tmppath)
-       return FALSE;
-    }
-  else
-    {
-      pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
-                                                        x, y);
-
-      if (!pspp_sheet_view_get_path_at_pos (tree_view, *x, *y,
-                                         &tmppath, NULL, NULL, NULL))
-       return FALSE;
-    }
-
-  if (model)
-    *model = pspp_sheet_view_get_model (tree_view);
-
-  if (iter)
-    gtk_tree_model_get_iter (pspp_sheet_view_get_model (tree_view),
-                            iter, tmppath);
-
-  if (path)
-    *path = tmppath;
-  else
-    gtk_tree_path_free (tmppath);
-
-  return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_set_tooltip_query_cb (GtkWidget  *widget,
-                                   gint        x,
-                                   gint        y,
-                                   gboolean    keyboard_tip,
-                                   GtkTooltip *tooltip,
-                                   gpointer    data)
-{
-  GValue value = { 0, };
-  GValue transformed = { 0, };
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  GtkTreeModel *model;
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (!pspp_sheet_view_get_tooltip_context (PSPP_SHEET_VIEW (widget),
-                                         &x, &y,
-                                         keyboard_tip,
-                                         &model, &path, &iter))
-    return FALSE;
-
-  gtk_tree_model_get_value (model, &iter,
-                            tree_view->priv->tooltip_column, &value);
-
-  g_value_init (&transformed, G_TYPE_STRING);
-
-  if (!g_value_transform (&value, &transformed))
-    {
-      g_value_unset (&value);
-      gtk_tree_path_free (path);
-
-      return FALSE;
-    }
-
-  g_value_unset (&value);
-
-  if (!g_value_get_string (&transformed))
-    {
-      g_value_unset (&transformed);
-      gtk_tree_path_free (path);
-
-      return FALSE;
-    }
-
-  gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
-  pspp_sheet_view_set_tooltip_row (tree_view, tooltip, path);
-
-  gtk_tree_path_free (path);
-  g_value_unset (&transformed);
-
-  return TRUE;
-}
-
-/**
- * pspp_sheet_view_set_tooltip_column:
- * @tree_view: a #PsppSheetView
- * @column: an integer, which is a valid column number for @tree_view's model
- *
- * If you only plan to have simple (text-only) tooltips on full rows, you
- * can use this function to have #PsppSheetView handle these automatically
- * for you. @column should be set to the column in @tree_view's model
- * containing the tooltip texts, or -1 to disable this feature.
- *
- * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
- * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
- *
- * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
- * so &amp;, &lt;, etc have to be escaped in the text.
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_column (PsppSheetView *tree_view,
-                                 gint         column)
-{
-  g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
-  if (column == tree_view->priv->tooltip_column)
-    return;
-
-  if (column == -1)
-    {
-      g_signal_handlers_disconnect_by_func (tree_view,
-                                           pspp_sheet_view_set_tooltip_query_cb,
-                                           NULL);
-      gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
-    }
-  else
-    {
-      if (tree_view->priv->tooltip_column == -1)
-        {
-          g_signal_connect (tree_view, "query-tooltip",
-                           G_CALLBACK (pspp_sheet_view_set_tooltip_query_cb), NULL);
-          gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
-        }
-    }
-
-  tree_view->priv->tooltip_column = column;
-  g_object_notify (G_OBJECT (tree_view), "tooltip-column");
-}
-
-/**
- * pspp_sheet_view_get_tooltip_column:
- * @tree_view: a #PsppSheetView
- *
- * Returns the column of @tree_view's model which is being used for
- * displaying tooltips on @tree_view's rows.
- *
- * Return value: the index of the tooltip column that is currently being
- * used, or -1 if this is disabled.
- *
- * Since: 2.12
- */
-gint
-pspp_sheet_view_get_tooltip_column (PsppSheetView *tree_view)
-{
-  g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
-  return tree_view->priv->tooltip_column;
-}
-
-gboolean
-_gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
-                                  GValue                *return_accu,
-                                  const GValue          *handler_return,
-                                  gpointer               dummy)
-{
-  gboolean continue_emission;
-  gboolean signal_handled;
-
-  signal_handled = g_value_get_boolean (handler_return);
-  g_value_set_boolean (return_accu, signal_handled);
-  continue_emission = !signal_handled;
-
-  return continue_emission;
-}
-
-
-GType
-pspp_sheet_view_grid_lines_get_type (void)
-{
-    static GType etype = 0;
-    if (G_UNLIKELY(etype == 0)) {
-        static const GEnumValue values[] = {
-            { PSPP_SHEET_VIEW_GRID_LINES_NONE, "PSPP_SHEET_VIEW_GRID_LINES_NONE", "none" },
-            { PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL, "PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL", "horizontal" },
-            { PSPP_SHEET_VIEW_GRID_LINES_VERTICAL, "PSPP_SHEET_VIEW_GRID_LINES_VERTICAL", "vertical" },
-            { PSPP_SHEET_VIEW_GRID_LINES_BOTH, "PSPP_SHEET_VIEW_GRID_LINES_BOTH", "both" },
-            { 0, NULL, NULL }
-        };
-        etype = g_enum_register_static (g_intern_static_string ("PsppSheetViewGridLines"), values);
-    }
-    return etype;
-}
-
-GType
-pspp_sheet_view_special_cells_get_type (void)
-{
-    static GType etype = 0;
-    if (G_UNLIKELY(etype == 0)) {
-        static const GEnumValue values[] = {
-            { PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT, "PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT", "detect" },
-            { PSPP_SHEET_VIEW_SPECIAL_CELLS_YES, "PSPP_SHEET_VIEW_SPECIAL_CELLS_YES", "yes" },
-            { PSPP_SHEET_VIEW_SPECIAL_CELLS_NO, "PSPP_SHEET_VIEW_SPECIAL_CELLS_NO", "no" },
-            { 0, NULL, NULL }
-        };
-        etype = g_enum_register_static (g_intern_static_string ("PsppSheetViewSpecialCells"), values);
-    }
-    return etype;
-}
diff --git a/src/ui/gui/pspp-sheet-view.h b/src/ui/gui/pspp-sheet-view.h
deleted file mode 100644 (file)
index 8941b89..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-/* gtktreeview.h
- * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __PSPP_SHEET_VIEW_H__
-#define __PSPP_SHEET_VIEW_H__
-
-#include <gtk/gtk.h>
-#include "ui/gui/pspp-sheet-view-column.h"
-
-G_BEGIN_DECLS
-
-
-typedef enum
-{
-  PSPP_SHEET_VIEW_GRID_LINES_NONE,
-  PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL,
-  PSPP_SHEET_VIEW_GRID_LINES_VERTICAL,
-  PSPP_SHEET_VIEW_GRID_LINES_BOTH
-} PsppSheetViewGridLines;
-
-GType pspp_sheet_view_grid_lines_get_type (void) G_GNUC_CONST;
-#define PSPP_TYPE_SHEET_VIEW_GRID_LINES (pspp_sheet_view_grid_lines_get_type ())
-
-/* A "special cell" is a cell that is editable or activatable.  When a row that
- * contains a special cell is selected, the cursor is drawn around a single
- * cell; when other rows are selected, the cursor is drawn around the entire
- * row.
- *
- * With the default of "detect", whether a given row contains a special cell is
- * detected automatically.  This is the best choice most of the time.  For
- * sheet views that contain more than 100 columns, an explicit "yes" or "no"
- * improves performance. */
-typedef enum
-{
-  PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT,
-  PSPP_SHEET_VIEW_SPECIAL_CELLS_YES,
-  PSPP_SHEET_VIEW_SPECIAL_CELLS_NO,
-} PsppSheetViewSpecialCells;
-
-GType pspp_sheet_view_special_cells_get_type (void) G_GNUC_CONST;
-#define PSPP_TYPE_SHEET_VIEW_SPECIAL_CELLS (pspp_sheet_view_special_cells_get_type ())
-
-typedef enum
-{
-  /* drop before/after this row */
-  PSPP_SHEET_VIEW_DROP_BEFORE,
-  PSPP_SHEET_VIEW_DROP_AFTER,
-  /* drop as a child of this row (with fallback to before or after
-   * if into is not possible)
-   */
-  PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE,
-  PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER
-} PsppSheetViewDropPosition;
-
-typedef enum
-{
-  PSPP_SHEET_SELECT_MODE_TOGGLE = 1 << 0,
-  PSPP_SHEET_SELECT_MODE_EXTEND = 1 << 1
-}
-PsppSheetSelectMode;
-
-#define PSPP_TYPE_SHEET_VIEW           (pspp_sheet_view_get_type ())
-#define PSPP_SHEET_VIEW(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_VIEW, PsppSheetView))
-#define PSPP_SHEET_VIEW_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_VIEW, PsppSheetViewClass))
-#define PSPP_IS_SHEET_VIEW(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_VIEW))
-#define PSPP_IS_SHEET_VIEW_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_VIEW))
-#define PSPP_SHEET_VIEW_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_VIEW, PsppSheetViewClass))
-
-typedef struct _PsppSheetView           PsppSheetView;
-typedef struct _PsppSheetViewClass      PsppSheetViewClass;
-typedef struct _PsppSheetViewPrivate    PsppSheetViewPrivate;
-typedef struct _PsppSheetSelection      PsppSheetSelection;
-typedef struct _PsppSheetSelectionClass PsppSheetSelectionClass;
-
-struct _PsppSheetView
-{
-  GtkContainer parent;
-
-  PsppSheetViewPrivate *PSEAL (priv);
-
-  gboolean dispose_has_run ;
-};
-
-struct _PsppSheetViewClass
-{
-  GtkContainerClass parent_class;
-
-  void     (* set_scroll_adjustments)     (PsppSheetView       *tree_view,
-                                          GtkAdjustment     *hadjustment,
-                                          GtkAdjustment     *vadjustment);
-  void     (* row_activated)              (PsppSheetView       *tree_view,
-                                          GtkTreePath       *path,
-                                          PsppSheetViewColumn *column);
-  void     (* columns_changed)            (PsppSheetView       *tree_view);
-  void     (* cursor_changed)             (PsppSheetView       *tree_view);
-
-  /* Key Binding signals */
-  gboolean (* move_cursor)                (PsppSheetView       *tree_view,
-                                          GtkMovementStep    step,
-                                          gint               count);
-  gboolean (* select_all)                 (PsppSheetView       *tree_view);
-  gboolean (* unselect_all)               (PsppSheetView       *tree_view);
-  gboolean (* select_cursor_row)          (PsppSheetView       *tree_view,
-                                          gboolean           start_editing,
-                                           PsppSheetSelectMode mode);
-  gboolean (* toggle_cursor_row)          (PsppSheetView       *tree_view);
-  gboolean (* select_cursor_parent)       (PsppSheetView       *tree_view);
-  gboolean (* start_interactive_search)   (PsppSheetView       *tree_view);
-
-  /* Padding for future expansion */
-  void (*_gtk_reserved0) (void);
-  void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
-};
-
-
-typedef gboolean (* PsppSheetViewColumnDropFunc) (PsppSheetView             *tree_view,
-                                               PsppSheetViewColumn       *column,
-                                               PsppSheetViewColumn       *prev_column,
-                                               PsppSheetViewColumn       *next_column,
-                                               gpointer                 data);
-typedef void     (* PsppSheetViewMappingFunc)    (PsppSheetView             *tree_view,
-                                               GtkTreePath             *path,
-                                               gpointer                 user_data);
-typedef gboolean (*PsppSheetViewSearchEqualFunc) (GtkTreeModel            *model,
-                                               gint                     column,
-                                               const gchar             *key,
-                                               GtkTreeIter             *iter,
-                                               gpointer                 search_data);
-typedef void     (*PsppSheetViewSearchPositionFunc) (PsppSheetView  *tree_view,
-                                                  GtkWidget    *search_dialog,
-                                                  gpointer      user_data);
-
-
-/* Creators */
-GType                  pspp_sheet_view_get_type                      (void) G_GNUC_CONST;
-GtkWidget             *pspp_sheet_view_new                           (void);
-GtkWidget             *pspp_sheet_view_new_with_model                (GtkTreeModel              *model);
-
-/* Accessors */
-GtkTreeModel          *pspp_sheet_view_get_model                     (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_set_model                     (PsppSheetView               *tree_view,
-                                                                   GtkTreeModel              *model);
-PsppSheetSelection      *pspp_sheet_view_get_selection                 (PsppSheetView               *tree_view);
-GtkAdjustment         *pspp_sheet_view_get_hadjustment               (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_set_hadjustment               (PsppSheetView               *tree_view,
-                                                                   GtkAdjustment             *adjustment);
-GtkAdjustment         *pspp_sheet_view_get_vadjustment               (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_set_vadjustment               (PsppSheetView               *tree_view,
-                                                                   GtkAdjustment             *adjustment);
-gboolean               pspp_sheet_view_get_headers_visible           (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_set_headers_visible           (PsppSheetView               *tree_view,
-                                                                   gboolean                   headers_visible);
-void                   pspp_sheet_view_columns_autosize              (PsppSheetView               *tree_view);
-gboolean               pspp_sheet_view_get_headers_clickable         (PsppSheetView *tree_view);
-void                   pspp_sheet_view_set_headers_clickable         (PsppSheetView               *tree_view,
-                                                                   gboolean                   setting);
-void                   pspp_sheet_view_set_rules_hint                (PsppSheetView               *tree_view,
-                                                                   gboolean                   setting);
-gboolean               pspp_sheet_view_get_rules_hint                (PsppSheetView               *tree_view);
-
-/* Column funtions */
-gint                   pspp_sheet_view_append_column                 (PsppSheetView               *tree_view,
-                                                                   PsppSheetViewColumn         *column);
-gint                   pspp_sheet_view_remove_column                 (PsppSheetView               *tree_view,
-                                                                   PsppSheetViewColumn         *column);
-gint                   pspp_sheet_view_insert_column                 (PsppSheetView               *tree_view,
-                                                                   PsppSheetViewColumn         *column,
-                                                                   gint                       position);
-gint                   pspp_sheet_view_insert_column_with_attributes (PsppSheetView               *tree_view,
-                                                                   gint                       position,
-                                                                   const gchar               *title,
-                                                                   GtkCellRenderer           *cell,
-                                                                   ...) G_GNUC_NULL_TERMINATED;
-gint                   pspp_sheet_view_insert_column_with_data_func  (PsppSheetView               *tree_view,
-                                                                   gint                       position,
-                                                                   const gchar               *title,
-                                                                   GtkCellRenderer           *cell,
-                                                                    PsppSheetCellDataFunc        func,
-                                                                    gpointer                   data,
-                                                                    GDestroyNotify             dnotify);
-PsppSheetViewColumn     *pspp_sheet_view_get_column                    (PsppSheetView               *tree_view,
-                                                                   gint                       n);
-GList                 *pspp_sheet_view_get_columns                   (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_move_column_after             (PsppSheetView               *tree_view,
-                                                                   PsppSheetViewColumn         *column,
-                                                                   PsppSheetViewColumn         *base_column);
-void                   pspp_sheet_view_set_column_drag_function      (PsppSheetView               *tree_view,
-                                                                   PsppSheetViewColumnDropFunc  func,
-                                                                   gpointer                   user_data,
-                                                                   GDestroyNotify             destroy);
-
-/* Actions */
-void                   pspp_sheet_view_scroll_to_point               (PsppSheetView               *tree_view,
-                                                                   gint                       tree_x,
-                                                                   gint                       tree_y);
-void                   pspp_sheet_view_scroll_to_cell                (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *column,
-                                                                   gboolean                   use_align,
-                                                                   gfloat                     row_align,
-                                                                   gfloat                     col_align);
-void                   pspp_sheet_view_row_activated                 (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *column);
-void                   pspp_sheet_view_set_reorderable               (PsppSheetView               *tree_view,
-                                                                   gboolean                   reorderable);
-gboolean               pspp_sheet_view_get_reorderable               (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_set_cursor                    (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *focus_column,
-                                                                   gboolean                   start_editing);
-void                   pspp_sheet_view_set_cursor_on_cell            (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *focus_column,
-                                                                   GtkCellRenderer           *focus_cell,
-                                                                   gboolean                   start_editing);
-void                   pspp_sheet_view_get_cursor                    (PsppSheetView               *tree_view,
-                                                                   GtkTreePath              **path,
-                                                                   PsppSheetViewColumn        **focus_column);
-
-
-/* Layout information */
-GdkWindow             *pspp_sheet_view_get_bin_window                (PsppSheetView               *tree_view);
-gboolean               pspp_sheet_view_get_path_at_pos               (PsppSheetView               *tree_view,
-                                                                   gint                       x,
-                                                                   gint                       y,
-                                                                   GtkTreePath              **path,
-                                                                   PsppSheetViewColumn        **column,
-                                                                   gint                      *cell_x,
-                                                                   gint                      *cell_y);
-void                   pspp_sheet_view_get_cell_area                 (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *column,
-                                                                   GdkRectangle              *rect);
-void                   pspp_sheet_view_get_background_area           (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewColumn         *column,
-                                                                   GdkRectangle              *rect);
-void                   pspp_sheet_view_get_visible_rect              (PsppSheetView               *tree_view,
-                                                                   GdkRectangle              *visible_rect);
-
-#ifndef GTK_DISABLE_DEPRECATED
-void                   pspp_sheet_view_widget_to_tree_coords         (PsppSheetView               *tree_view,
-                                                                   gint                       wx,
-                                                                   gint                       wy,
-                                                                   gint                      *tx,
-                                                                   gint                      *ty);
-void                   pspp_sheet_view_tree_to_widget_coords         (PsppSheetView               *tree_view,
-                                                                   gint                       tx,
-                                                                   gint                       ty,
-                                                                   gint                      *wx,
-                                                                   gint                      *wy);
-#endif /* !GTK_DISABLE_DEPRECATED */
-gboolean               pspp_sheet_view_get_visible_range             (PsppSheetView               *tree_view,
-                                                                   GtkTreePath              **start_path,
-                                                                   GtkTreePath              **end_path);
-
-/* Drag-and-Drop support */
-void                   pspp_sheet_view_enable_model_drag_source      (PsppSheetView               *tree_view,
-                                                                   GdkModifierType            start_button_mask,
-                                                                   const GtkTargetEntry      *targets,
-                                                                   gint                       n_targets,
-                                                                   GdkDragAction              actions);
-void                   pspp_sheet_view_enable_model_drag_dest        (PsppSheetView               *tree_view,
-                                                                   const GtkTargetEntry      *targets,
-                                                                   gint                       n_targets,
-                                                                   GdkDragAction              actions);
-void                   pspp_sheet_view_unset_rows_drag_source        (PsppSheetView               *tree_view);
-void                   pspp_sheet_view_unset_rows_drag_dest          (PsppSheetView               *tree_view);
-
-
-/* These are useful to implement your own custom stuff. */
-void                   pspp_sheet_view_set_drag_dest_row             (PsppSheetView               *tree_view,
-                                                                   GtkTreePath               *path,
-                                                                   PsppSheetViewDropPosition    pos);
-void                   pspp_sheet_view_get_drag_dest_row             (PsppSheetView               *tree_view,
-                                                                   GtkTreePath              **path,
-                                                                   PsppSheetViewDropPosition   *pos);
-gboolean               pspp_sheet_view_get_dest_row_at_pos           (PsppSheetView               *tree_view,
-                                                                   gint                       drag_x,
-                                                                   gint                       drag_y,
-                                                                   GtkTreePath              **path,
-                                                                   PsppSheetViewDropPosition   *pos);
-
-/* Interactive search */
-void                       pspp_sheet_view_set_enable_search     (PsppSheetView                *tree_view,
-                                                               gboolean                    enable_search);
-gboolean                   pspp_sheet_view_get_enable_search     (PsppSheetView                *tree_view);
-gint                       pspp_sheet_view_get_search_column     (PsppSheetView                *tree_view);
-void                       pspp_sheet_view_set_search_column     (PsppSheetView                *tree_view,
-                                                               gint                        column);
-PsppSheetViewSearchEqualFunc pspp_sheet_view_get_search_equal_func (PsppSheetView                *tree_view);
-void                       pspp_sheet_view_set_search_equal_func (PsppSheetView                *tree_view,
-                                                               PsppSheetViewSearchEqualFunc  search_equal_func,
-                                                               gpointer                    search_user_data,
-                                                               GDestroyNotify              search_destroy);
-
-GtkEntry                     *pspp_sheet_view_get_search_entry         (PsppSheetView                   *tree_view);
-void                          pspp_sheet_view_set_search_entry         (PsppSheetView                   *tree_view,
-                                                                     GtkEntry                      *entry);
-PsppSheetViewSearchPositionFunc pspp_sheet_view_get_search_position_func (PsppSheetView                   *tree_view);
-void                          pspp_sheet_view_set_search_position_func (PsppSheetView                   *tree_view,
-                                                                     PsppSheetViewSearchPositionFunc  func,
-                                                                     gpointer                       data,
-                                                                     GDestroyNotify                 destroy);
-
-/* Convert between the different coordinate systems */
-void pspp_sheet_view_convert_widget_to_tree_coords       (PsppSheetView *tree_view,
-                                                       gint         wx,
-                                                       gint         wy,
-                                                       gint        *tx,
-                                                       gint        *ty);
-void pspp_sheet_view_convert_tree_to_widget_coords       (PsppSheetView *tree_view,
-                                                       gint         tx,
-                                                       gint         ty,
-                                                       gint        *wx,
-                                                       gint        *wy);
-void pspp_sheet_view_convert_widget_to_bin_window_coords (PsppSheetView *tree_view,
-                                                       gint         wx,
-                                                       gint         wy,
-                                                       gint        *bx,
-                                                       gint        *by);
-void pspp_sheet_view_convert_bin_window_to_widget_coords (PsppSheetView *tree_view,
-                                                       gint         bx,
-                                                       gint         by,
-                                                       gint        *wx,
-                                                       gint        *wy);
-void pspp_sheet_view_convert_tree_to_bin_window_coords   (PsppSheetView *tree_view,
-                                                       gint         tx,
-                                                       gint         ty,
-                                                       gint        *bx,
-                                                       gint        *by);
-void pspp_sheet_view_convert_bin_window_to_tree_coords   (PsppSheetView *tree_view,
-                                                       gint         bx,
-                                                       gint         by,
-                                                       gint        *tx,
-                                                       gint        *ty);
-
-/* This function should really never be used.  It is just for use by ATK.
- */
-typedef void (* PsppSheetDestroyCountFunc)  (PsppSheetView             *tree_view,
-                                          GtkTreePath             *path,
-                                          gint                     children,
-                                          gpointer                 user_data);
-void pspp_sheet_view_set_destroy_count_func (PsppSheetView             *tree_view,
-                                          PsppSheetDestroyCountFunc  func,
-                                          gpointer                 data,
-                                          GDestroyNotify           destroy);
-
-void     pspp_sheet_view_set_hover_selection   (PsppSheetView          *tree_view,
-                                             gboolean              hover);
-gboolean pspp_sheet_view_get_hover_selection   (PsppSheetView          *tree_view);
-void     pspp_sheet_view_set_rubber_banding    (PsppSheetView          *tree_view,
-                                             gboolean              enable);
-gboolean pspp_sheet_view_get_rubber_banding    (PsppSheetView          *tree_view);
-
-gboolean pspp_sheet_view_is_rubber_banding_active (PsppSheetView       *tree_view);
-
-PsppSheetViewGridLines        pspp_sheet_view_get_grid_lines         (PsppSheetView                *tree_view);
-void                        pspp_sheet_view_set_grid_lines         (PsppSheetView                *tree_view,
-                                                                 PsppSheetViewGridLines        grid_lines);
-
-PsppSheetViewSpecialCells pspp_sheet_view_get_special_cells (PsppSheetView                *tree_view);
-void                        pspp_sheet_view_set_special_cells (PsppSheetView                *tree_view,
-                                                               PsppSheetViewSpecialCells);
-
-int           pspp_sheet_view_get_fixed_height (const PsppSheetView *);
-void          pspp_sheet_view_set_fixed_height (PsppSheetView *,
-                                                int fixed_height);
-
-/* Convenience functions for setting tooltips */
-void          pspp_sheet_view_set_tooltip_row    (PsppSheetView       *tree_view,
-                                               GtkTooltip        *tooltip,
-                                               GtkTreePath       *path);
-void          pspp_sheet_view_set_tooltip_cell   (PsppSheetView       *tree_view,
-                                               GtkTooltip        *tooltip,
-                                               GtkTreePath       *path,
-                                               PsppSheetViewColumn *column,
-                                               GtkCellRenderer   *cell);
-gboolean      pspp_sheet_view_get_tooltip_context(PsppSheetView       *tree_view,
-                                               gint              *x,
-                                               gint              *y,
-                                               gboolean           keyboard_tip,
-                                               GtkTreeModel     **model,
-                                               GtkTreePath      **path,
-                                               GtkTreeIter       *iter);
-void          pspp_sheet_view_set_tooltip_column (PsppSheetView       *tree_view,
-                                               gint               column);
-gint          pspp_sheet_view_get_tooltip_column (PsppSheetView       *tree_view);
-
-void pspp_sheet_view_stop_editing (PsppSheetView *tree_view,
-                                   gboolean     cancel_editing);
-
-G_END_DECLS
-
-
-#endif /* __PSPP_SHEET_VIEW_H__ */
diff --git a/src/ui/gui/pspp-widget-facade.c b/src/ui/gui/pspp-widget-facade.c
deleted file mode 100644 (file)
index a95040b..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2014 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "pspp-widget-facade.h"
-
-#include <math.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-
-static void
-inset_rectangle (const GdkRectangle *src,
-                 const GtkBorder *inset,
-                 GdkRectangle *dst)
-{
-  dst->x = src->x + inset->left;
-  dst->y = src->y + inset->top;
-  dst->width = MAX (1, src->width - inset->left - inset->right);
-  dst->height = MAX (1, src->height - inset->top - inset->bottom);
-}
-
-static void
-thicken_border (gint x, gint y, GtkBorder *border)
-{
-  border->left += x;
-  border->right += x;
-  border->top += y;
-  border->bottom += y;
-}
-
-GtkStyle *
-facade_get_style (GtkWidget *base,
-                  GType type1,
-                  ...)
-{
-  GString path, class_path;
-  GType final_type;
-  GtkStyle *style;
-  va_list args;
-  GType type;
-
-  gtk_widget_path (base, NULL, &path.str, NULL);
-  path.len = path.allocated_len = strlen (path.str);
-
-  gtk_widget_class_path (base, NULL, &class_path.str, NULL);
-  class_path.len = class_path.allocated_len = strlen (class_path.str);
-
-  va_start (args, type1);
-  for (type = final_type = type1; type != 0; type = va_arg (args, GType))
-    {
-      const gchar *type_name = g_type_name (type);
-      g_string_append_printf (&path, ".%s", type_name);
-      g_string_append_printf (&class_path, ".%s", type_name);
-      final_type = type;
-    }
-  va_end (args);
-
-  style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (base),
-                                     path.str, class_path.str, final_type);
-
-  free (path.str);
-  free (class_path.str);
-
-  return style;
-}
-
-void
-facade_hbox_get_base_size_request (gint border_width,
-                                   gint spacing,
-                                   gint n_children,
-                                   GtkRequisition *request)
-{
-  request->width = border_width * 2;
-  if (n_children > 1)
-    request->width += spacing * (n_children - 1);
-
-  request->height = border_width * 2;
-}
-
-void
-facade_hbox_add_child_size_request (gint hbox_border_width,
-                                    const GtkRequisition *child_request,
-                                    gint child_padding,
-                                    GtkRequisition *request)
-{
-  request->width += child_request->width + child_padding * 2;
-  request->height = MAX (request->height,
-                         hbox_border_width * 2 + child_request->height);
-}
-
-void
-facade_arrow_get_size_request (gint xpad,
-                               gint ypad,
-                               GtkRequisition *request)
-{
-#define MIN_ARROW_SIZE 15
-  request->width = MIN_ARROW_SIZE + xpad * 2;
-  request->height = MIN_ARROW_SIZE + ypad * 2;
-}
-
-void
-facade_alignment_get_size_request (gint border_width,
-                                   gint padding_left,
-                                   gint padding_right,
-                                   gint padding_top,
-                                   gint padding_bottom,
-                                   const GtkRequisition *child_request,
-                                   GtkRequisition *request)
-{
-  request->width = (border_width * 2 + padding_left + padding_right
-                    + child_request->width);
-  request->height = (border_width * 2 + padding_top + padding_bottom
-                     + child_request->height);
-}
-
-void
-facade_label_get_size_request (gint xpad,
-                               gint ypad,
-                               GtkWidget *base,
-                               const char *text,
-                               GtkRequisition *request)
-{
-  PangoLayout *layout;
-
-  layout = facade_label_get_layout (base, text);
-  facade_label_get_size_request_from_layout (xpad, ypad, layout, request);
-  g_object_unref (layout);
-}
-
-void
-facade_label_get_size_request_from_layout (gint xpad,
-                                           gint ypad,
-                                           PangoLayout *layout,
-                                           GtkRequisition *request)
-{
-  PangoRectangle logical_rect;
-
-  pango_layout_get_extents (layout, NULL, &logical_rect);
-  request->width = xpad * 2 + PANGO_PIXELS (logical_rect.width);
-  request->height = ypad * 2 + PANGO_PIXELS (logical_rect.height);
-}
-
-PangoLayout *
-facade_label_get_layout (GtkWidget *base,
-                         const char *text)
-{
-  PangoAlignment alignment;
-  PangoLayout *layout;
-  gboolean rtl;
-
-  rtl = gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL;
-  alignment = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-
-  layout = gtk_widget_create_pango_layout (base, text);
-  pango_layout_set_alignment (layout, alignment);
-
-  return layout;
-}
-
-static void
-facade_button_get_inner_border (GtkStyle *button_style,
-                                GtkBorder *inner_border)
-{
-  GtkBorder *tmp_border;
-
-  gtk_style_get (button_style, GTK_TYPE_BUTTON,
-                 "inner-border", &tmp_border,
-                 NULL);
-
-  if (tmp_border)
-    {
-      *inner_border = *tmp_border;
-      gtk_border_free (tmp_border);
-    }
-  else
-    {
-      static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
-      *inner_border = default_inner_border;
-    }
-}
-
-void
-facade_button_get_size_request (gint border_width,
-                                GtkWidget *base,
-                                GtkStyle *button_style,
-                                const GtkRequisition *child_request,
-                                GtkRequisition *request)
-{
-  GtkBorder inner_border;
-  gint common_width;
-  gint focus_width;
-  gint focus_pad;
-
-  gtk_style_get (button_style, GTK_TYPE_BUTTON,
-                 "focus-line-width", &focus_width,
-                 "focus-padding", &focus_pad,
-                 NULL);
-  facade_button_get_inner_border (button_style, &inner_border);
-
-  common_width = 2 * (border_width + focus_width + focus_pad);
-  request->width = (common_width
-                    + 2 * button_style->xthickness
-                    + inner_border.left + inner_border.right
-                    + child_request->width);
-  request->height = (common_width
-                     + 2 * button_style->ythickness
-                     + inner_border.top + inner_border.bottom
-                     + child_request->height);
-}
-
-void
-facade_button_get_focus_inset (gint border_width,
-                               GtkWidget *base,
-                               GtkStyle *button_style,
-                               GtkBorder *focus_inset)
-{
-  facade_button_get_inner_border (button_style, focus_inset);
-  thicken_border (border_width + button_style->xthickness,
-                  border_width + button_style->ythickness,
-                  focus_inset);
-}
-
-static void
-facade_button_get_label_inset (gint border_width,
-                               GtkWidget *base,
-                               GtkStyle *button_style,
-                               GtkBorder *label_inset)
-{
-  gint focus_width;
-  gint focus_pad;
-
-  facade_button_get_focus_inset (border_width, base, button_style,
-                                 label_inset);
-
-  gtk_style_get (button_style, GTK_TYPE_BUTTON,
-                 "focus-line-width", &focus_width,
-                 "focus-padding", &focus_pad,
-                 NULL);
-  thicken_border (focus_width + focus_pad,
-                  focus_width + focus_pad,
-                  label_inset);
-}
-
-static void
-get_layout_location (GtkWidget *base,
-                     const GdkRectangle *label_area,
-                     PangoLayout *layout,
-                     gint xpad,
-                     gint ypad,
-                     gfloat xalign,
-                     gfloat yalign,
-                     gint *x,
-                     gint *y)
-{
-  PangoRectangle logical;
-  GtkRequisition req;
-
-  if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL)
-    xalign = 1.0 - xalign;
-
-  pango_layout_get_pixel_extents (layout, NULL, &logical);
-
-  facade_label_get_size_request_from_layout (xpad, ypad, layout, &req);
-
-  *x = floor (label_area->x + xpad + xalign * (label_area->width - req.width));
-
-  if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_LTR)
-    *x = MAX (*x, label_area->x + xpad);
-  else
-    *x = MIN (*x, label_area->x + label_area->width - xpad);
-  *x -= logical.x;
-
-  /* bgo#315462 - For single-line labels, *do* align the requisition with
-   * respect to the allocation, even if we are under-allocated.  For multi-line
-   * labels, always show the top of the text when they are under-allocated.
-   * The rationale is this:
-   *
-   * - Single-line labels appear in GtkButtons, and it is very easy to get them
-   *   to be smaller than their requisition.  The button may clip the label,
-   *   but the label will still be able to show most of itself and the focus
-   *   rectangle.  Also, it is fairly easy to read a single line of clipped
-   *   text.
-   *
-   * - Multi-line labels should not be clipped to showing "something in the
-   *   middle".  You want to read the first line, at least, to get some
-   *   context.
-   */
-  if (pango_layout_get_line_count (layout) == 1)
-    *y = floor (label_area->y + ypad
-                + (label_area->height - req.height) * yalign);
-  else
-    *y = floor (label_area->y + ypad
-                + MAX (((label_area->height - req.height) * yalign),
-                       0));
-}
-
-void
-facade_button_render (GtkWidget *base,
-                      cairo_t *cr,
-                      const GdkRectangle *button_area,
-                      gint border_width,
-                      GtkStyle *button_style,
-                      GtkStateType state_type,
-
-                      GtkStyle *label_style,
-                      const gchar *label,
-                      gint xpad,
-                      gint ypad,
-                      gfloat xalign,
-                      gfloat yalign)
-{
-  GdkRectangle label_area;
-  PangoLayout *layout;
-  GtkBorder inset;
-  gint x, y;
-
-  /* Paint the button. */
-  gtk_paint_box (button_style, cr,
-                 state_type,
-                 GTK_SHADOW_OUT, base, "button",
-                 button_area->x + border_width,
-                 button_area->y + border_width,
-                 button_area->width - border_width * 2,
-                 button_area->height - border_width * 2);
-
-  /* Figure out where the label should go. */
-  facade_button_get_label_inset (border_width, base, button_style, &inset);
-  inset_rectangle (button_area, &inset, &label_area);
-
-  /* Paint the label. */
-  layout = facade_label_get_layout (base, label);
-  get_layout_location (base, &label_area, layout, xpad, ypad, xalign, yalign,
-                       &x, &y);
-
-  gtk_paint_layout (label_style, cr, state_type, FALSE,
-                    base, "label", x, y, layout);
-
-  g_object_unref (layout);
-}
-
diff --git a/src/ui/gui/pspp-widget-facade.h b/src/ui/gui/pspp-widget-facade.h
deleted file mode 100644 (file)
index 6705185..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef FACADE_WIDGET_FACADE_H
-#define FACADE_WIDGET_FACADE_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-GtkStyle *facade_get_style (GtkWidget *base, GType, ...);
-
-void facade_hbox_get_base_size_request (gint border_width,
-                                        gint spacing,
-                                        gint n_children,
-                                        GtkRequisition *);
-void facade_hbox_add_child_size_request (gint hbox_border_width,
-                                         const GtkRequisition *child_request,
-                                         gint child_padding,
-                                         GtkRequisition *);
-
-void facade_arrow_get_size_request (gint xpad,
-                                    gint ypad,
-                                    GtkRequisition *);
-
-
-void facade_alignment_get_size_request (gint border_width,
-                                        gint padding_left,
-                                        gint padding_right,
-                                        gint padding_top,
-                                        gint padding_bottom,
-                                        const GtkRequisition *child_request,
-                                        GtkRequisition *);
-
-void facade_label_get_size_request (gint xpad,
-                                    gint ypad,
-                                    GtkWidget *base,
-                                    const char *text,
-                                    GtkRequisition *);
-void facade_label_get_size_request_from_layout (gint xpad,
-                                                gint ypad,
-                                                PangoLayout *,
-                                                GtkRequisition *);
-PangoLayout *facade_label_get_layout (GtkWidget *base,
-                                      const char *text);
-
-void facade_button_get_size_request (gint border_width,
-                                     GtkWidget *base,
-                                     GtkStyle *button_style,
-                                     const GtkRequisition *child_request,
-                                     GtkRequisition *);
-void facade_button_render (GtkWidget *base,
-                           cairo_t *cr,
-                           const GdkRectangle *button_area,
-                           gint border_width,
-                           GtkStyle *button_style,
-                           GtkStateType state_type,
-
-                           GtkStyle *label_style,
-                           const gchar *label,
-                           gint xpad,
-                           gint ypad,
-                           gfloat xalign,
-                           gfloat yalign);
-void facade_button_get_focus_inset (gint border_width,
-                                    GtkWidget *base,
-                                    GtkStyle *button_style,
-                                    GtkBorder *focus_inset);
-
-G_END_DECLS
-
-#endif /* FACADE_WIDGET_FACADE_H */
diff --git a/src/ui/gui/psppire-button-editable.c b/src/ui/gui/psppire-button-editable.c
deleted file mode 100644 (file)
index f77e3ce..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2016 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "ui/gui/psppire-button-editable.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-#define P_(STRING) STRING
-
-/* GtkCellEditable interface. */
-static void gtk_cell_editable_interface_init (GtkCellEditableIface *iface);
-static void button_editable_editing_done (GtkCellEditable *cell_editable);
-static void button_editable_remove_widget (GtkCellEditable *cell_editable);
-static void button_editable_start_editing (GtkCellEditable *cell_editable,
-                                           GdkEvent        *event);
-
-G_DEFINE_TYPE_EXTENDED (PsppireButtonEditable,
-                        psppire_button_editable,
-                        GTK_TYPE_BUTTON,
-                        0,
-                        G_IMPLEMENT_INTERFACE (
-                          GTK_TYPE_CELL_EDITABLE,
-                          gtk_cell_editable_interface_init));
-
-enum
-  {
-    PROP_0,
-    PROP_PATH,
-    PROP_EDITING_CANCELED
-  };
-
-static void
-psppire_button_editable_set_property (GObject      *object,
-                                      guint         prop_id,
-                                      const GValue *value,
-                                      GParamSpec   *pspec)
-{
-  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
-
-  switch (prop_id)
-    {
-    case PROP_PATH:
-      g_free (obj->path);
-      obj->path = g_value_dup_string (value);
-      break;
-
-    case PROP_EDITING_CANCELED:
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_button_editable_get_property (GObject      *object,
-                                      guint         prop_id,
-                                      GValue       *value,
-                                      GParamSpec   *pspec)
-{
-  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
-
-  switch (prop_id)
-    {
-    case PROP_PATH:
-      g_value_set_string (value, obj->path);
-      break;
-
-    case PROP_EDITING_CANCELED:
-      g_value_set_boolean (value, FALSE);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_button_editable_finalize (GObject *gobject)
-{
-  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (gobject);
-
-  g_free (obj->path);
-
-  G_OBJECT_CLASS (psppire_button_editable_parent_class)->finalize (gobject);
-}
-
-static gboolean
-psppire_button_editable_button_release (GtkWidget      *widget,
-                                        GdkEventButton *event)
-{
-  if (event->button == 1)
-    {
-      g_signal_emit_by_name (widget, "released", event, NULL);
-    }
-
-  return TRUE;
-}
-
-static void
-psppire_button_editable_class_init (PsppireButtonEditableClass *class)
-{
-  GObjectClass *gobject_class;
-  GtkWidgetClass *widget_class;
-
-  gobject_class = G_OBJECT_CLASS (class);
-  widget_class = GTK_WIDGET_CLASS (class);
-
-  gobject_class->set_property = psppire_button_editable_set_property;
-  gobject_class->get_property = psppire_button_editable_get_property;
-  gobject_class->finalize = psppire_button_editable_finalize;
-
-  widget_class->button_release_event = psppire_button_editable_button_release;
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_PATH,
-                                   g_param_spec_string ("path",
-                                                       P_("TreeView path"),
-                                                       P_("The path to the row in the GtkTreeView, as a string"),
-                                                       "",
-                                                       G_PARAM_READWRITE));
-
-  g_object_class_override_property (gobject_class,
-                                   PROP_EDITING_CANCELED,
-                                    "editing-canceled");
-}
-
-static void
-psppire_button_editable_init (PsppireButtonEditable *obj)
-{
-  obj->path = g_strdup ("");
-}
-
-PsppireButtonEditable *
-psppire_button_editable_new (void)
-{
-  return PSPPIRE_BUTTON_EDITABLE (g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE, NULL));
-}
-
-\f
-/* GtkCellEditable interface. */
-
-static void
-gtk_cell_editable_interface_init (GtkCellEditableIface *iface)
-{
-  g_return_if_fail (iface != NULL);
-
-  iface->editing_done = button_editable_editing_done;
-  iface->remove_widget = button_editable_remove_widget;
-  iface->start_editing = button_editable_start_editing;
-}
-
-static void
-button_editable_editing_done (GtkCellEditable *cell_editable)
-{
-}
-
-static void
-button_editable_remove_widget (GtkCellEditable *cell_editable)
-{
-}
-
-static void
-button_editable_start_editing (GtkCellEditable *cell_editable,
-                               GdkEvent        *event)
-{
-}
diff --git a/src/ui/gui/psppire-button-editable.h b/src/ui/gui/psppire-button-editable.h
deleted file mode 100644 (file)
index 80b6180..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef PSPPIRE_BUTTON_EDITABLE_H
-#define PSPPIRE_BUTTON_EDITABLE_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_BUTTON_EDITABLE             (psppire_button_editable_get_type())
-#define PSPPIRE_BUTTON_EDITABLE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditable))
-#define PSPPIRE_BUTTON_EDITABLE_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
-#define PSPPIRE_IS_BUTTON_EDITABLE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE))
-#define PSPPIRE_IS_BUTTON_EDITABLE_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_BUTTON_EDITABLE))
-#define PSPPIRE_BUTTON_EDITABLE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
-
-typedef struct _PsppireButtonEditable      PsppireButtonEditable;
-typedef struct _PsppireButtonEditableClass PsppireButtonEditableClass;
-
-struct _PsppireButtonEditable {
-  GtkButton parent;
-  gchar *path;
-};
-
-struct _PsppireButtonEditableClass {
-  GtkButtonClass parent_class;
-};
-
-GType psppire_button_editable_get_type (void) G_GNUC_CONST;
-PsppireButtonEditable* psppire_button_editable_new (void);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_BUTTON_EDITABLE_H */
diff --git a/src/ui/gui/psppire-cell-renderer-button.c b/src/ui/gui/psppire-cell-renderer-button.c
deleted file mode 100644 (file)
index e801cc6..0000000
+++ /dev/null
@@ -1,580 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "ui/gui/psppire-cell-renderer-button.h"
-
-#include <math.h>
-#include <string.h>
-
-#include "ui/gui/psppire-button-editable.h"
-#include "ui/gui/pspp-widget-facade.h"
-
-#include "gl/configmake.h"
-#include "gl/relocatable.h"
-
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-
-#define P_(msgid) (msgid)
-
-static void psppire_cell_renderer_button_dispose (GObject *);
-static void psppire_cell_renderer_button_finalize (GObject *);
-
-static void update_style_cache (PsppireCellRendererButton *button,
-                                GtkWidget                 *widget);
-
-static void psppire_cell_renderer_button_load_gtkrc (void);
-
-
-G_DEFINE_TYPE_EXTENDED (PsppireCellRendererButton,
-                        psppire_cell_renderer_button,
-                        GTK_TYPE_CELL_RENDERER,
-                        0,
-                        psppire_cell_renderer_button_load_gtkrc ());
-
-static void
-psppire_cell_renderer_button_load_gtkrc (void)
-{
-  const char *gtkrc_file;
-
-  gtkrc_file = relocate (PKGDATADIR "/psppire.gtkrc");
-  gtk_rc_add_default_file (gtkrc_file);
-  gtk_rc_parse (gtkrc_file);
-}
-
-enum
-  {
-    PROP_0,
-    PROP_EDITABLE,
-    PROP_LABEL,
-    PROP_SLASH
-  };
-
-static void
-psppire_cell_renderer_button_set_property (GObject      *object,
-                                           guint         prop_id,
-                                           const GValue *value,
-                                           GParamSpec   *pspec)
-{
-  PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
-  switch (prop_id)
-    {
-    case PROP_EDITABLE:
-      obj->editable = g_value_get_boolean (value);
-      if (obj->editable)
-       g_object_set (obj, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
-      else
-       g_object_set (obj, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
-      break;
-
-    case PROP_LABEL:
-      g_free (obj->label);
-      obj->label = g_value_dup_string (value);
-      break;
-
-    case PROP_SLASH:
-      psppire_cell_renderer_button_set_slash (obj,
-                                              g_value_get_boolean (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_cell_renderer_button_get_property (GObject      *object,
-                                           guint         prop_id,
-                                           GValue       *value,
-                                           GParamSpec   *pspec)
-{
-  PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
-
-  switch (prop_id)
-    {
-    case PROP_EDITABLE:
-      g_value_set_boolean (value, obj->editable);
-      break;
-
-    case PROP_LABEL:
-      g_value_set_string (value, obj->label);
-      break;
-
-    case PROP_SLASH:
-      g_value_set_boolean (value,
-                           psppire_cell_renderer_button_get_slash (obj));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-on_style_set (GtkWidget                 *base,
-              GtkStyle                  *previous_style,
-              PsppireCellRendererButton *button)
-{
-  update_style_cache (button, NULL);
-}
-
-static void
-update_style_cache (PsppireCellRendererButton *button,
-                    GtkWidget                 *widget)
-{
-  if (button->base == widget)
-    return;
-
-  /* Clear old cache. */
-  if (button->button_style)
-    {
-      g_object_unref (button->button_style);
-      button->button_style = NULL;
-    }
-  if (button->label_style)
-    {
-      g_object_unref (button->label_style);
-      button->label_style = NULL;
-    }
-  if (button->base != NULL)
-    {
-      if (button->style_set_handler)
-        {
-          g_signal_handler_disconnect (button->base,
-                                       button->style_set_handler);
-          button->style_set_handler = 0;
-        }
-      g_object_unref (button->base);
-      button->base = NULL;
-    }
-
-  /* Populate cache. */
-  if (widget)
-    {
-      button->button_style = facade_get_style (widget, GTK_TYPE_BUTTON, 0);
-      button->label_style = facade_get_style (widget, GTK_TYPE_BUTTON,
-                                              GTK_TYPE_LABEL, 0);
-      button->base = widget;
-      button->style_set_handler = g_signal_connect (widget, "style-set",
-                                                    G_CALLBACK (on_style_set),
-                                                    button);
-      g_object_ref (widget);
-      g_object_ref (button->button_style);
-      g_object_ref (button->label_style);
-    }
-}
-
-static void
-psppire_cell_renderer_button_render (GtkCellRenderer      *cell,
-                                     cairo_t              *cr,
-                                     GtkWidget            *widget,
-                                     const GdkRectangle         *background_area,
-                                     const GdkRectangle         *cell_area,
-                                     GtkCellRendererState  flags)
-{
-  GtkStateType state_type;
-  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
-  gfloat xalign, yalign;
-
-  if (!button->editable || ! gtk_cell_renderer_get_sensitive (cell))
-    state_type = GTK_STATE_INSENSITIVE;
-  else if (flags & GTK_CELL_RENDERER_SELECTED)
-    {
-      if (gtk_widget_has_focus (widget))
-        state_type = GTK_STATE_SELECTED;
-      else
-        state_type = GTK_STATE_ACTIVE;
-    }
-  else if (flags & GTK_CELL_RENDERER_PRELIT)
-    state_type = GTK_STATE_PRELIGHT;
-  else
-    {
-      if (gtk_widget_get_state_flags (widget) == GTK_STATE_FLAG_INSENSITIVE)
-        state_type = GTK_STATE_INSENSITIVE;
-      else
-        state_type = GTK_STATE_NORMAL;
-    }
-
-  gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
-
-
-  update_style_cache (button, widget);
-
-  facade_button_render (widget, cr,
-                        cell_area, button->border_width, button->button_style,
-                        state_type,
-                        button->label_style, button->label, button->xpad,
-                        button->ypad, xalign, yalign);
-
-  if (button->slash)
-    {
-      cairo_set_line_width (cr, 1.0);
-      cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-      cairo_move_to (cr,
-                    cell_area->x,
-                    cell_area->y + cell_area->height);
-
-      cairo_line_to (cr,
-                    cell_area->x + cell_area->width,
-                    cell_area->y);
-      cairo_stroke (cr);
-    }
-}
-
-static void
-psppire_cell_renderer_button_get_size (GtkCellRenderer      *cell,
-                                       GtkWidget            *widget,
-                                       const GdkRectangle   *cell_area,
-                                       gint                 *x_offset,
-                                       gint                 *y_offset,
-                                       gint                 *width,
-                                       gint                 *height)
-{
-  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
-
-  update_style_cache (button, widget);
-  if (cell_area != NULL)
-    {
-      /* The caller is really asking for the placement of the focus rectangle.
-         The focus rectangle should surround the whole label area, so calculate
-         that area. */
-      GtkBorder inset;
-
-      facade_button_get_focus_inset (button->border_width, widget,
-                                     button->button_style, &inset);
-
-      if (x_offset)
-        *x_offset = inset.left;
-      if (y_offset)
-        *y_offset = inset.top;
-      if (width)
-        *width = MAX (1, cell_area->width - inset.left - inset.right);
-      if (height)
-        *height = MAX (1, cell_area->height - inset.top - inset.bottom);
-    }
-  else
-    {
-      /* The caller is asking for the preferred size of the cell. */
-      GtkRequisition label_req;
-      GtkRequisition request;
-
-      facade_label_get_size_request (button->xpad, button->ypad,
-                                     widget, button->label, &label_req);
-      facade_button_get_size_request (button->border_width, widget,
-                                      button->button_style, &label_req,
-                                      &request);
-
-      if (x_offset)
-        *x_offset = 0;
-      if (y_offset)
-        *y_offset = 0;
-      if (width)
-        *width = request.width;
-      if (height)
-        *height = request.height;
-    }
-}
-
-static void
-psppire_cell_renderer_button_clicked (GtkButton *button,
-                                      gpointer   data)
-{
-  PsppireCellRendererButton *cell_button = data;
-  gchar *path;
-
-  g_object_get (button, "path", &path, NULL);
-  g_signal_emit_by_name (cell_button, "clicked", path);
-  g_free (path);
-}
-
-#define IDLE_ID_STRING "psppire-cell-renderer-button-idle-id"
-
-static gboolean
-psppire_cell_renderer_button_initial_click (gpointer data)
-{
-  GtkButton *button = data;
-
-  g_object_steal_data (G_OBJECT (button), IDLE_ID_STRING);
-  gtk_button_clicked (button);
-  return FALSE;
-}
-
-static void
-psppire_cell_renderer_button_on_destroy (GObject *object, gpointer user_data)
-{
-  guint idle_id;
-
-  idle_id = GPOINTER_TO_INT (g_object_steal_data (object, IDLE_ID_STRING));
-  if (idle_id != 0)
-    g_source_remove (idle_id);
-}
-
-static void
-psppire_cell_renderer_button_double_click (GtkButton *button,
-                                           PsppireCellRendererButton *cell_button)
-{
-  gchar *path;
-
-  if (g_object_get_data (G_OBJECT (button), IDLE_ID_STRING))
-    psppire_cell_renderer_button_initial_click (button);
-
-  g_object_get (button, "path", &path, NULL);
-  g_signal_emit_by_name (cell_button, "double-clicked", path);
-  g_free (path);
-}
-
-static gboolean
-psppire_cell_renderer_button_press_event (GtkButton      *button,
-                                          GdkEventButton *event,
-                                          gpointer        data)
-{
-  PsppireCellRendererButton *cell_button = data;
-
-  if (event->button == 3)
-    {
-      /* Allow right-click events to propagate upward in the widget hierarchy.
-         Otherwise right-click menus, that trigger on a button-press-event on
-         the containing PsppSheetView, will pop up if the button is rendered as
-         a facade but not if the button widget exists.
-
-         We have to translate the event's data by hand to be relative to the
-         parent window, because the normal GObject signal propagation mechanism
-         won't do it for us.  (This might be a hint that we're doing this
-         wrong.) */
-      gint x, y;
-
-      gdk_window_get_position (event->window, &x, &y);
-      event->x += x;
-      event->y += y;
-      g_signal_stop_emission_by_name (button, "button-press-event");
-      return FALSE;
-    }
-
-  if (cell_button->click_time != 0)
-    {
-      GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
-      GtkSettings *settings = gtk_settings_get_for_screen (screen);
-      gint double_click_distance;
-      gint double_click_time;
-
-      g_object_get (settings,
-                    "gtk-double-click-time", &double_click_time,
-                    "gtk-double-click-distance", &double_click_distance,
-                    NULL);
-
-      if (event->type == GDK_BUTTON_PRESS
-          && event->button == 1
-          && event->time <= cell_button->click_time + double_click_time
-          && ABS (event->x_root - cell_button->click_x) <= double_click_distance
-          && ABS (event->y_root - cell_button->click_y) <= double_click_distance)
-        {
-          psppire_cell_renderer_button_double_click (button, cell_button);
-          return TRUE;
-        }
-
-      cell_button->click_time = 0;
-    }
-
-  if (event->type == GDK_2BUTTON_PRESS)
-    {
-      psppire_cell_renderer_button_double_click (button, cell_button);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static GtkCellEditable *
-psppire_cell_renderer_button_start_editing (GtkCellRenderer      *cell,
-                                            GdkEvent             *event,
-                                            GtkWidget            *widget,
-                                            const gchar          *path,
-                                            const GdkRectangle   *background_area,
-                                            const GdkRectangle   *cell_area,
-                                            GtkCellRendererState  flags)
-{
-  PsppireCellRendererButton *cell_button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
-  gfloat xalign, yalign;
-
-  gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
-  cell_button->button = g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE,
-                                      "label", cell_button->label,
-                                      "xalign", xalign,
-                                      "yalign", yalign,
-                                      "path", path,
-                                      NULL);
-
-  g_signal_connect (G_OBJECT (cell_button->button), "clicked",
-                    G_CALLBACK (psppire_cell_renderer_button_clicked),
-                    cell);
-  g_signal_connect (G_OBJECT (cell_button->button), "button-press-event",
-                    G_CALLBACK (psppire_cell_renderer_button_press_event),
-                    cell);
-
-  gtk_widget_show (cell_button->button);
-
-  if (event != NULL && event->any.type == GDK_BUTTON_RELEASE)
-    {
-      guint idle_id;
-
-      cell_button->click_time = event->button.time;
-      cell_button->click_x = event->button.x_root;
-      cell_button->click_y = event->button.y_root;
-      idle_id = g_idle_add (psppire_cell_renderer_button_initial_click,
-                            cell_button->button);
-      g_object_set_data (G_OBJECT (cell_button->button), IDLE_ID_STRING,
-                         GINT_TO_POINTER (idle_id));
-      g_signal_connect (G_OBJECT (cell_button->button), "destroy",
-                        G_CALLBACK (psppire_cell_renderer_button_on_destroy),
-                        NULL);
-    }
-  else
-    {
-      cell_button->click_time = 0;
-      cell_button->click_x = 0;
-      cell_button->click_y = 0;
-    }
-
-  return GTK_CELL_EDITABLE (cell_button->button);
-}
-
-static void
-psppire_cell_renderer_button_class_init (PsppireCellRendererButtonClass *class)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
-
-  gobject_class->set_property = psppire_cell_renderer_button_set_property;
-  gobject_class->get_property = psppire_cell_renderer_button_get_property;
-  gobject_class->finalize = psppire_cell_renderer_button_finalize;
-  gobject_class->dispose = psppire_cell_renderer_button_dispose;
-
-  cell_class->get_size = psppire_cell_renderer_button_get_size;
-  cell_class->render = psppire_cell_renderer_button_render;
-  cell_class->start_editing = psppire_cell_renderer_button_start_editing;
-
-  g_signal_new ("clicked",
-                G_TYPE_FROM_CLASS (gobject_class),
-                G_SIGNAL_RUN_LAST,
-                0,
-                NULL, NULL,
-                g_cclosure_marshal_VOID__STRING,
-                G_TYPE_NONE,
-                1, G_TYPE_STRING);
-
-  g_signal_new ("double-clicked",
-                G_TYPE_FROM_CLASS (gobject_class),
-                G_SIGNAL_RUN_LAST,
-                0,
-                NULL, NULL,
-                g_cclosure_marshal_VOID__STRING,
-                G_TYPE_NONE,
-                1, G_TYPE_STRING);
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_EDITABLE,
-                                   g_param_spec_boolean ("editable",
-                                                         P_("Editable"),
-                                                         P_("Whether the button may be clicked."),
-                                                         FALSE,
-                                                         G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_LABEL,
-                                   g_param_spec_string ("label",
-                                                        P_("Label"),
-                                                        P_("Text to appear in button."),
-                                                        "",
-                                                        G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_SLASH,
-                                   g_param_spec_boolean ("slash",
-                                                         P_("Diagonal slash"),
-                                                         P_("Whether to draw a diagonal slash across the button."),
-                                                         FALSE,
-                                                         G_PARAM_READWRITE));
-
-}
-
-static void
-psppire_cell_renderer_button_init (PsppireCellRendererButton *obj)
-{
-  obj->editable = FALSE;
-  obj->label = g_strdup ("");
-  obj->border_width = 0;
-  obj->xpad = 0;
-  obj->ypad = 0;
-
-  obj->slash = FALSE;
-
-  obj->button = NULL;
-
-  obj->button_style = NULL;
-  obj->label_style = NULL;
-  obj->base = NULL;
-  obj->style_set_handler = 0;
-  obj->dispose_has_run = FALSE;
-}
-
-static void
-psppire_cell_renderer_button_finalize (GObject *obj)
-{
-  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
-
-  g_free (button->label);
-}
-
-static void
-psppire_cell_renderer_button_dispose (GObject *obj)
-{
-  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
-
-  if (button->dispose_has_run)
-    return;
-
-  button->dispose_has_run = TRUE;
-
-  /* When called with NULL, as we are doing here, update_style_cache
-     does nothing more than to drop references */
-  update_style_cache (button, NULL);
-
-  G_OBJECT_CLASS (psppire_cell_renderer_button_parent_class)->dispose (obj);
-}
-
-GtkCellRenderer *
-psppire_cell_renderer_button_new (void)
-{
-  return GTK_CELL_RENDERER (g_object_new (PSPPIRE_TYPE_CELL_RENDERER_BUTTON, NULL));
-}
-
-void
-psppire_cell_renderer_button_set_slash (PsppireCellRendererButton *button,
-                                        gboolean slash)
-{
-  g_return_if_fail (button != NULL);
-  button->slash = slash;
-}
-
-gboolean
-psppire_cell_renderer_button_get_slash (const PsppireCellRendererButton *button)
-{
-  g_return_val_if_fail (button != NULL, FALSE);
-  return button->slash;
-}
diff --git a/src/ui/gui/psppire-cell-renderer-button.h b/src/ui/gui/psppire-cell-renderer-button.h
deleted file mode 100644 (file)
index 28d5dd1..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef PSPPIRE_CELL_RENDERER_BUTTON_H
-#define PSPPIRE_CELL_RENDERER_BUTTON_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_CELL_RENDERER_BUTTON             (psppire_cell_renderer_button_get_type())
-#define PSPPIRE_CELL_RENDERER_BUTTON(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButton))
-#define PSPPIRE_CELL_RENDERER_BUTTON_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
-#define PSPPIRE_IS_CELL_RENDERER_BUTTON(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
-#define PSPPIRE_IS_CELL_RENDERER_BUTTON_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
-#define PSPPIRE_CELL_RENDERER_BUTTON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
-
-typedef struct _PsppireCellRendererButton      PsppireCellRendererButton;
-typedef struct _PsppireCellRendererButtonClass PsppireCellRendererButtonClass;
-
-struct _PsppireCellRendererButton
-{
-  GtkCellRenderer parent;
-
-  gboolean editable;
-  gchar *label;
-  gint border_width;
-  gint xpad;
-  gint ypad;
-
-  gboolean slash;
-
-  GtkWidget *button;
-  guint32 click_time;
-  gdouble click_x;
-  gdouble click_y;
-
-  /* Style caching. */
-  GtkStyle *button_style;
-  GtkStyle *label_style;
-  GtkWidget *base;
-  gulong style_set_handler;
-  gboolean dispose_has_run;
-};
-
-struct _PsppireCellRendererButtonClass {
-  GtkCellRendererClass parent_class;
-};
-
-GType psppire_cell_renderer_button_get_type (void) G_GNUC_CONST;
-GtkCellRenderer* psppire_cell_renderer_button_new (void);
-
-void psppire_cell_renderer_button_set_slash (PsppireCellRendererButton *,
-                                             gboolean slash);
-gboolean psppire_cell_renderer_button_get_slash (const PsppireCellRendererButton *);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_CELL_RENDERER_BUTTON_H */
index ab3a5f0668767b1b9734f870190dcf243ed827f7..f1712ad4b7f683b74110ebbdc641dd8af13840a8 100644 (file)
@@ -1,5 +1,6 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011, 2012, 2016,
+   2017 Free Software Foundation, Inc.
 
    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
 #include "ui/gui/psppire-data-editor.h"
 
 #include <gtk/gtk.h>
-#include <gtk-contrib/gtkxpaned.h>
 
 #include "data/datasheet.h"
 #include "data/value-labels.h"
 #include "libpspp/range-set.h"
 #include "libpspp/str.h"
+
 #include "ui/gui/helper.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-data-sheet.h"
+#include "ui/gui/var-display.h"
+#include "ui/gui/val-labs-dialog.h"
+#include "ui/gui/missing-val-dialog.h"
+#include "ui/gui/var-type-dialog.h"
+#include "ui/gui/psppire-dict.h"
 #include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-data-window.h"
 #include "ui/gui/psppire-value-entry.h"
-#include "ui/gui/psppire-var-sheet.h"
 #include "ui/gui/psppire-conf.h"
+#include "ui/gui/psppire-variable-sheet.h"
+#include "ui/gui/psppire-data-sheet.h"
+
+
+#include <ssw-sheet.h>
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 
-#define FOR_EACH_DATA_SHEET(DATA_SHEET, IDX, DATA_EDITOR)       \
-  for ((IDX) = 0;                                               \
-       (IDX) < 4                                                \
-         && ((DATA_SHEET) = PSPPIRE_DATA_SHEET (                \
-               (DATA_EDITOR)->data_sheets[IDX])) != NULL;       \
-       (IDX)++)
-
 static void psppire_data_editor_class_init          (PsppireDataEditorClass *klass);
 static void psppire_data_editor_init                (PsppireDataEditor      *de);
 
-static void disconnect_data_sheets (PsppireDataEditor *);
 static void refresh_entry (PsppireDataEditor *);
 
 GType
@@ -83,8 +84,6 @@ psppire_data_editor_dispose (GObject *obj)
 {
   PsppireDataEditor *de = (PsppireDataEditor *) obj;
 
-  disconnect_data_sheets (de);
-
   if (de->data_store)
     {
       g_object_unref (de->data_store);
@@ -119,15 +118,9 @@ enum
 static void
 psppire_data_editor_refresh_model (PsppireDataEditor *de)
 {
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (de->var_sheet);
-  PsppireDataSheet *data_sheet;
-  int i;
-
-  FOR_EACH_DATA_SHEET (data_sheet, i, de)
-    psppire_data_sheet_set_data_store (data_sheet, de->data_store);
-  psppire_var_sheet_set_dictionary (var_sheet, de->dict);
 }
 
+
 static void
 psppire_data_editor_set_property (GObject         *object,
                                  guint            prop_id,
@@ -135,13 +128,13 @@ psppire_data_editor_set_property (GObject         *object,
                                  GParamSpec      *pspec)
 {
   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
-  PsppireDataSheet *data_sheet;
-  int i;
 
   switch (prop_id)
     {
     case PROP_SPLIT_WINDOW:
-      psppire_data_editor_split_window (de, g_value_get_boolean (value));
+      de->split = g_value_get_boolean (value);
+      g_object_set (de->data_sheet, "split", de->split, NULL);
+      g_object_set (de->var_sheet, "split", de->split, NULL);
       break;
     case PROP_DATA_STORE:
       if ( de->data_store)
@@ -154,8 +147,14 @@ psppire_data_editor_set_property (GObject         *object,
 
       de->data_store = g_value_get_pointer (value);
       g_object_ref (de->data_store);
+
+      g_object_set (de->data_sheet, "data-model", de->data_store, NULL);
       psppire_data_editor_refresh_model (de);
 
+      g_signal_connect_swapped (de->data_sheet, "selection-changed",
+                               G_CALLBACK (refresh_entry),
+                               de);
+
       g_signal_connect_swapped (de->data_store, "case-changed",
                                 G_CALLBACK (refresh_entry), de);
 
@@ -166,13 +165,18 @@ psppire_data_editor_set_property (GObject         *object,
       de->dict = g_value_get_pointer (value);
       g_object_ref (de->dict);
 
-      psppire_var_sheet_set_dictionary (PSPPIRE_VAR_SHEET (de->var_sheet),
-                                        de->dict);
+      g_object_set (de->var_sheet, "data-model", de->dict, NULL);
       break;
+
     case PROP_VALUE_LABELS:
-      FOR_EACH_DATA_SHEET (data_sheet, i, de)
-        psppire_data_sheet_set_value_labels (data_sheet,
-                                          g_value_get_boolean (value));
+      {
+       gboolean l = g_value_get_boolean (value);
+       g_object_set (de->data_sheet, "forward-conversion",
+                     l ?
+                     psppire_data_store_value_to_string_with_labels :
+                     psppire_data_store_value_to_string,
+                     NULL);
+      }
       break;
 
     default:
@@ -201,9 +205,6 @@ psppire_data_editor_get_property (GObject         *object,
       g_value_set_pointer (value, de->dict);
       break;
     case PROP_VALUE_LABELS:
-      g_value_set_boolean (value,
-                           psppire_data_sheet_get_value_labels (
-                             PSPPIRE_DATA_SHEET (de->data_sheets[0])));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -292,393 +293,156 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass)
   g_object_class_install_property (object_class,
                                    PROP_SPLIT_WINDOW,
                                    split_window_spec);
-
 }
 
-static gboolean
-on_data_sheet_var_double_clicked (PsppireDataSheet *data_sheet,
-                                  gint dict_index,
-                                  PsppireDataEditor *de)
+
+static void
+on_var_sheet_var_double_clicked (void *var_sheet, gint dict_index,
+                                 PsppireDataEditor *de)
 {
   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
-                                 PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
-
-  psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
-                                   dict_index);
+                                 PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
-  return TRUE;
+  ssw_sheet_scroll_to (SSW_SHEET (de->data_sheet), dict_index, -1);
 }
 
-static gboolean
-on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
+
+static void
+on_data_sheet_var_double_clicked (SswSheet *data_sheet, gint dict_index,
                                  PsppireDataEditor *de)
 {
-  PsppireDataSheet *data_sheet;
 
   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
-                                 PSPPIRE_DATA_EDITOR_DATA_VIEW);
-
-  data_sheet = psppire_data_editor_get_active_data_sheet (de);
-  psppire_data_sheet_goto_variable (data_sheet, dict_index);
+                                 PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
 
-  return TRUE;
+  ssw_sheet_scroll_to (SSW_SHEET (de->var_sheet), -1, dict_index);
 }
 
+
+
 /* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
    active cell or cells. */
 static void
 refresh_entry (PsppireDataEditor *de)
 {
-  PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-
-  gchar *ref_cell_text;
-  GList *selected_columns, *iter;
-  struct variable *var;
-  gint n_cases;
-  gint n_vars;
-
-  selected_columns = pspp_sheet_selection_get_selected_columns (selection);
-  n_vars = 0;
-  var = NULL;
-  for (iter = selected_columns; iter != NULL; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
-      if (v != NULL)
-        {
-          var = v;
-          n_vars++;
-        }
-    }
-  g_list_free (selected_columns);
-
-  n_cases = pspp_sheet_selection_count_selected_rows (selection);
-  if (n_cases > 0)
-    {
-      /* The final row is selectable but it isn't a case (it's just used to add
-         more cases), so don't count it. */
-      GtkTreePath *path;
-      gint case_count;
-
-      case_count = psppire_data_store_get_case_count (de->data_store);
-      path = gtk_tree_path_new_from_indices (case_count, -1);
-      if (pspp_sheet_selection_path_is_selected (selection, path))
-        n_cases--;
-      gtk_tree_path_free (path);
-    }
-
-  ref_cell_text = NULL;
-  if (n_cases == 1 && n_vars == 1)
+  gint row, col;
+  if (ssw_sheet_get_active_cell (SSW_SHEET (de->data_sheet), &col, &row))
     {
-      PsppireValueEntry *value_entry = PSPPIRE_VALUE_ENTRY (de->datum_entry);
-      struct range_set *selected_rows;
-      gboolean show_value_labels;
-      union value value;
-      int width;
-      gint row;
-
-      selected_rows = pspp_sheet_selection_get_range_set (selection);
-      row = range_set_scan (selected_rows, 0);
-      range_set_destroy (selected_rows);
-
-      ref_cell_text = g_strdup_printf ("%d : %s", row + 1, var_get_name (var));
+      union value val;
+      const struct variable *var = psppire_dict_get_variable (de->dict, col);
+      if (var == NULL)
+       return;
 
-      show_value_labels = psppire_data_sheet_get_value_labels (data_sheet);
+      psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry), var);
 
-      psppire_value_entry_set_variable (value_entry, var);
-      psppire_value_entry_set_show_value_label (value_entry,
-                                                show_value_labels);
+      int width = var_get_width (var);
+      if (! psppire_data_store_get_value (PSPPIRE_DATA_STORE (de->data_store),
+                                         row, var, &val))
+       return;
 
-      width = var_get_width (var);
-      value_init (&value, width);
-      datasheet_get_value (de->data_store->datasheet,
-                           row, var_get_case_index (var), &value);
-      psppire_value_entry_set_value (value_entry, &value, width);
-      value_destroy (&value, width);
-
-      gtk_widget_set_sensitive (de->datum_entry, TRUE);
+      psppire_value_entry_set_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
+                                    &val, width);
+      value_destroy (&val, width);
     }
-  else
-    {
-      if (n_cases == 0 || n_vars == 0)
-        {
-          ref_cell_text = NULL;
-        }
-      else
-        {
-          struct string s;
-
-          /* The glib string library does not understand the ' printf modifier
-             on all platforms, but the "struct string" library does (because
-             Gnulib fixes that problem), so use the latter.  */
-          ds_init_empty (&s);
-          ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
-                         n_cases);
-          ds_put_byte (&s, ' ');
-          ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
-          ds_put_byte (&s, ' ');
-          ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
-                                       n_vars),
-                         n_vars);
-          ref_cell_text = ds_steal_cstr (&s);
-        }
-
-      psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry),
-                                        NULL);
-      gtk_entry_set_text (
-        GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))), "");
-      gtk_widget_set_sensitive (de->datum_entry, FALSE);
-    }
-
-  gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
-                       ref_cell_text ? ref_cell_text : "");
-  g_free (ref_cell_text);
 }
 
 static void
 on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
 {
-  PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
-  struct variable *var;
-  union value value;
-  int width;
-  gint row;
-
-  row = psppire_data_sheet_get_current_case (data_sheet);
-  var = psppire_data_sheet_get_current_variable (data_sheet);
-  if (row < 0 || !var)
-    return;
-
-  width = var_get_width (var);
-  value_init (&value, width);
-  if (psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
-                                     &value, width))
-    psppire_data_store_set_value (de->data_store, row, var, &value);
-  value_destroy (&value, width);
 }
 
+
+/* Called when the active cell or the selection in the data sheet changes */
 static void
-on_data_sheet_selection_changed (PsppSheetSelection *selection,
-                                 PsppireDataEditor *de)
+on_data_selection_change (PsppireDataEditor *de, SswRange *sel)
 {
-  /* In a split view, ensure that only a single data sheet has a nonempty
-     selection.  */
-  if (de->split
-      && pspp_sheet_selection_count_selected_rows (selection)
-      && pspp_sheet_selection_count_selected_columns (selection))
-    {
-      PsppireDataSheet *ds;
-      int i;
-
-      FOR_EACH_DATA_SHEET (ds, i, de)
-        {
-          PsppSheetSelection *s;
+  gchar *ref_cell_text = NULL;
 
-          s = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
-          if (s != selection)
-            pspp_sheet_selection_unselect_all (s);
-        }
-    }
+  gint n_cases = abs (sel->end_y - sel->start_y) + 1;
+  gint n_vars = abs (sel->end_x - sel->start_x) + 1;
 
-  refresh_entry (de);
-}
+  if (n_cases == 1 && n_vars == 1)
+    {
+      /* A single cell is selected */
+      const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x);
 
-/* Ensures that rows in the right-hand panes in the split view have the same
-   row height as the left-hand panes.  Otherwise, the rows in the right-hand
-   pane tend to be smaller, because the right-hand pane doesn't have buttons
-   for case numbers. */
-static void
-on_data_sheet_fixed_height_notify (PsppireDataSheet *ds,
-                                   GParamSpec *pspec,
-                                   PsppireDataEditor *de)
-{
-  enum
+      if (var)
+       ref_cell_text = g_strdup_printf (_("%d : %s"),
+                                        sel->start_y + 1, var_get_name (var));
+    }
+  else
     {
-      TL = GTK_XPANED_TOP_LEFT,
-      TR = GTK_XPANED_TOP_RIGHT,
-      BL = GTK_XPANED_BOTTOM_LEFT,
-      BR = GTK_XPANED_BOTTOM_RIGHT
-    };
+      struct string s;
+
+      /* The glib string library does not understand the ' printf modifier
+        on all platforms, but the "struct string" library does (because
+        Gnulib fixes that problem), so use the latter.  */
+      ds_init_empty (&s);
+      ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
+                    n_cases);
+      ds_put_byte (&s, ' ');
+      ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
+      ds_put_byte (&s, ' ');
+      ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
+                                  n_vars),
+                    n_vars);
+      ref_cell_text = ds_steal_cstr (&s);
+    }
 
-  int fixed_height = pspp_sheet_view_get_fixed_height (PSPP_SHEET_VIEW (ds));
+  gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
+                      ref_cell_text ? ref_cell_text : "");
 
-  pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[TR]),
-                                    fixed_height);
-  pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[BR]),
-                                    fixed_height);
+  g_free (ref_cell_text);
 }
 
-static void
-disconnect_data_sheets (PsppireDataEditor *de)
-{
-  PsppireDataSheet *ds;
-  int i;
 
-  FOR_EACH_DATA_SHEET (ds, i, de)
-    {
-      PsppSheetSelection *selection;
-
-      if (ds == NULL)
-        {
-          /* This can only happen if 'dispose' runs more than once. */
-          continue;
-        }
+static void set_font_recursively (GtkWidget *w, gpointer data);
 
-      if (i == GTK_XPANED_TOP_LEFT)
-        g_signal_handlers_disconnect_by_func (
-          ds, G_CALLBACK (on_data_sheet_fixed_height_notify), de);
+\f
 
-      g_signal_handlers_disconnect_by_func (
-        ds, G_CALLBACK (refresh_entry), de);
-      g_signal_handlers_disconnect_by_func (
-        ds, G_CALLBACK (on_data_sheet_var_double_clicked), de);
+void
+psppire_data_editor_data_delete_variables (PsppireDataEditor *de)
+{
+  SswRange *range = SSW_SHEET(de->data_sheet)->selection;
 
-      selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
-      g_signal_handlers_disconnect_by_func (
-        selection, G_CALLBACK (on_data_sheet_selection_changed), de);
+  psppire_dict_delete_variables (de->dict, range->start_x,
+                                (range->end_x - range->start_x + 1));
 
-      de->data_sheets[i] = NULL;
-    }
+  gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
 }
 
-static GtkWidget *
-make_data_sheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
-                 gboolean show_value_labels)
+void
+psppire_data_editor_var_delete_variables (PsppireDataEditor *de)
 {
-  PsppSheetSelection *selection;
-  GtkWidget *ds;
-
-  ds = psppire_data_sheet_new ();
-  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (ds), grid_lines);
-  psppire_data_sheet_set_value_labels (PSPPIRE_DATA_SHEET (ds),
-                                       show_value_labels);
-
-  g_signal_connect_swapped (ds, "notify::value-labels",
-                            G_CALLBACK (refresh_entry), de);
-  g_signal_connect (ds, "var-double-clicked",
-                    G_CALLBACK (on_data_sheet_var_double_clicked), de);
+  SswRange *range = SSW_SHEET(de->var_sheet)->selection;
 
-  selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
-  g_signal_connect (selection, "changed",
-                    G_CALLBACK (on_data_sheet_selection_changed), de);
+  psppire_dict_delete_variables (de->dict, range->start_y,
+                                (range->end_y - range->start_y + 1));
 
-  return ds;
+  gtk_widget_queue_draw (GTK_WIDGET (de->var_sheet));
 }
 
-static GtkWidget *
-make_single_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
-                       gboolean show_value_labels)
+void
+psppire_data_editor_insert_new_case_at_posn  (PsppireDataEditor *de, gint posn)
 {
-  GtkWidget *data_sheet_scroller;
-
-  de->data_sheets[0] = make_data_sheet (de, grid_lines, show_value_labels);
-  de->data_sheets[1] = de->data_sheets[2] = de->data_sheets[3] = NULL;
+  psppire_data_store_insert_new_case (de->data_store, posn);
 
-  /* Put data sheet in scroller. */
-  data_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (data_sheet_scroller),
-                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  gtk_container_add (GTK_CONTAINER (data_sheet_scroller), de->data_sheets[0]);
-
-  return data_sheet_scroller;
+  gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
 }
 
-static GtkWidget *
-make_split_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
-                      gboolean show_value_labels)
+void
+psppire_data_editor_insert_new_variable_at_posn (PsppireDataEditor *de, gint posn)
 {
-  /* Panes, in the order in which we want to create them. */
-  enum
-    {
-      TL,                       /* top left */
-      TR,                       /* top right */
-      BL,                       /* bottom left */
-      BR                        /* bottom right */
-    };
-
-  PsppSheetView *ds[4];
-  GtkXPaned *xpaned;
-  int i;
-
-  xpaned = GTK_XPANED (gtk_xpaned_new ());
-
-  for (i = 0; i < 4; i++)
-    {
-      GtkAdjustment *hadjust, *vadjust;
-      GtkPolicyType hpolicy, vpolicy;
-      GtkWidget *scroller;
-
-      de->data_sheets[i] = make_data_sheet (de, grid_lines, show_value_labels);
-      ds[i] = PSPP_SHEET_VIEW (de->data_sheets[i]);
-
-      if (i == BL)
-        hadjust = pspp_sheet_view_get_hadjustment (ds[TL]);
-      else if (i == BR)
-        hadjust = pspp_sheet_view_get_hadjustment (ds[TR]);
-      else
-        hadjust = NULL;
-
-      if (i == TR)
-        vadjust = pspp_sheet_view_get_vadjustment (ds[TL]);
-      else if (i == BR)
-        vadjust = pspp_sheet_view_get_vadjustment (ds[BL]);
-      else
-        vadjust = NULL;
-
-      scroller = gtk_scrolled_window_new (hadjust, vadjust);
-      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
-                                           GTK_SHADOW_ETCHED_IN);
-      hpolicy = i == TL || i == TR ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
-      vpolicy = i == TL || i == BL ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
-      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
-                                      hpolicy, vpolicy);
-      gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ds[i]));
-
-      switch (i)
-        {
-        case TL:
-          gtk_xpaned_pack_top_left (xpaned, scroller, TRUE, TRUE);
-          break;
-
-        case TR:
-          gtk_xpaned_pack_top_right (xpaned, scroller, TRUE, TRUE);
-          break;
-
-        case BL:
-          gtk_xpaned_pack_bottom_left (xpaned, scroller, TRUE, TRUE);
-          break;
-
-        case BR:
-          gtk_xpaned_pack_bottom_right (xpaned, scroller, TRUE, TRUE);
-          break;
-
-        default:
-          g_warn_if_reached ();
-        }
-    }
-
-  /* Bottom sheets don't display variable names. */
-  pspp_sheet_view_set_headers_visible (ds[BL], FALSE);
-  pspp_sheet_view_set_headers_visible (ds[BR], FALSE);
-
-  /* Right sheets don't display case numbers. */
-  psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[TR]), FALSE);
-  psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[BR]), FALSE);
+  const struct variable *v = psppire_dict_insert_variable (de->dict, posn, NULL);
+  psppire_data_store_insert_value (de->data_store, var_get_width(v),
+                                  var_get_case_index (v));
 
-  g_signal_connect (ds[TL], "notify::fixed-height",
-                    G_CALLBACK (on_data_sheet_fixed_height_notify), de);
-
-  return GTK_WIDGET (xpaned);
+  gtk_widget_queue_draw (GTK_WIDGET (de));
 }
 
-static void set_font_recursively (GtkWidget *w, gpointer data);
-
 static void
 psppire_data_editor_init (PsppireDataEditor *de)
 {
-  GtkWidget *var_sheet_scroller;
   GtkWidget *hbox;
   gchar *fontname = NULL;
 
@@ -686,7 +450,6 @@ psppire_data_editor_init (PsppireDataEditor *de)
   gtk_style_context_add_class (context, "psppire-data-editor");
 
   de->font = NULL;
-  de->old_vbox_widget = NULL;
 
   g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
 
@@ -703,33 +466,39 @@ psppire_data_editor_init (PsppireDataEditor *de)
   gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
 
   de->split = FALSE;
-  de->datasheet_vbox_widget
-    = make_single_datasheet (de, GTK_TREE_VIEW_GRID_LINES_BOTH, FALSE);
+  de->data_sheet = psppire_data_sheet_new ();
 
+  GtkWidget *data_button = ssw_sheet_get_button (SSW_SHEET (de->data_sheet));
+  gtk_button_set_label (GTK_BUTTON (data_button), _("Case"));
   de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
   gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
-                      TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0);
+
+
+  g_signal_connect_swapped (de->data_sheet, "selection-changed",
+                   G_CALLBACK (on_data_selection_change), de);
 
   gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
                            gtk_label_new_with_mnemonic (_("Data View")));
 
   gtk_widget_show_all (de->vbox);
 
-  de->var_sheet = GTK_WIDGET (psppire_var_sheet_new ());
-  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet),
-                                  GTK_TREE_VIEW_GRID_LINES_BOTH);
-  var_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (var_sheet_scroller),
-                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  gtk_container_add (GTK_CONTAINER (var_sheet_scroller), de->var_sheet);
-  gtk_widget_show_all (var_sheet_scroller);
-  gtk_notebook_append_page (GTK_NOTEBOOK (de), var_sheet_scroller,
+  de->var_sheet = psppire_variable_sheet_new ();
+
+  GtkWidget *var_button = ssw_sheet_get_button (SSW_SHEET (de->var_sheet));
+  gtk_button_set_label (GTK_BUTTON (var_button), _("Variable"));
+
+  gtk_notebook_append_page (GTK_NOTEBOOK (de), de->var_sheet,
                            gtk_label_new_with_mnemonic (_("Variable View")));
 
-  g_signal_connect (de->var_sheet, "var-double-clicked",
+  gtk_widget_show_all (de->var_sheet);
+
+  g_signal_connect (de->var_sheet, "row-header-double-clicked",
                     G_CALLBACK (on_var_sheet_var_double_clicked), de);
 
+  g_signal_connect (de->data_sheet, "column-header-double-clicked",
+                    G_CALLBACK (on_data_sheet_var_double_clicked), de);
+
   g_object_set (de, "can-focus", FALSE, NULL);
 
   if (psppire_conf_get_string (psppire_conf_new (),
@@ -758,17 +527,8 @@ psppire_data_editor_new (PsppireDict *dict,
 void
 psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
 {
-  GtkTreeViewGridLines grid;
-  PsppireDataSheet *data_sheet;
-  int i;
-
-  grid = (grid_visible
-          ? GTK_TREE_VIEW_GRID_LINES_BOTH
-          : GTK_TREE_VIEW_GRID_LINES_NONE);
-
-  FOR_EACH_DATA_SHEET (data_sheet, i, de)
-    pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (data_sheet), grid);
-  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
+  g_object_set (SSW_SHEET (de->var_sheet), "gridlines", grid_visible, NULL);
+  g_object_set (SSW_SHEET (de->data_sheet), "gridlines", grid_visible, NULL);
 }
 
 
@@ -827,44 +587,7 @@ psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_
 void
 psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
 {
-  GtkTreeViewGridLines grid_lines;
-  gboolean labels;
-
-  if (split == de->split)
-    return;
-
-
-  grid_lines = pspp_sheet_view_get_grid_lines (
-    PSPP_SHEET_VIEW (de->data_sheets[0]));
-  labels = psppire_data_sheet_get_value_labels (PSPPIRE_DATA_SHEET (
-                                                  de->data_sheets[0]));
-
-  disconnect_data_sheets (de);
-  if (de->old_vbox_widget)
-    g_object_unref (de->old_vbox_widget);
-  de->old_vbox_widget = de->datasheet_vbox_widget;
-  g_object_ref (de->old_vbox_widget);
-  /* FIXME:  old_vbox_widget needs to be unreffed in dispose.
-       (currently it seems to provoke an error if I do that.
-       I don't know why. */
-  gtk_container_remove (GTK_CONTAINER (de->vbox), de->datasheet_vbox_widget);
-
-  if (split)
-    de->datasheet_vbox_widget = make_split_datasheet (de, grid_lines, labels);
-  else
-    de->datasheet_vbox_widget = make_single_datasheet (de, grid_lines, labels);
-
-  psppire_data_editor_refresh_model (de);
-
-  gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
-                      TRUE, TRUE, 0);
-  gtk_widget_show_all (de->vbox);
-
-  if (de->font)
-    set_font_recursively (GTK_WIDGET (de), de->font);
-
-  de->split = split;
-  g_object_notify (G_OBJECT (de), "split");
+  g_object_set (de, "split", split, NULL);
 }
 
 /* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
@@ -872,54 +595,43 @@ psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
 void
 psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
 {
-  PsppireDataSheet *data_sheet;
+  gint page = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
 
-  switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
+  switch (page)
     {
-    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      data_sheet = psppire_data_editor_get_active_data_sheet (de);
-      psppire_data_sheet_goto_variable (data_sheet, dict_index);
-      break;
-
-    case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
-                                       dict_index);
-      break;
+      case PSPPIRE_DATA_EDITOR_DATA_VIEW:
+       ssw_sheet_scroll_to (SSW_SHEET (de->data_sheet), dict_index, -1);
+       ssw_sheet_set_active_cell (SSW_SHEET (de->data_sheet), dict_index, -1, NULL);
+       break;
+      case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
+       ssw_sheet_scroll_to (SSW_SHEET (de->var_sheet), -1, dict_index);
+       ssw_sheet_set_active_cell (SSW_SHEET (de->var_sheet), -1, dict_index, NULL);
+       break;
     }
 }
 
-/* Returns the "active" data sheet in DE.  If DE is in single-paned mode, this
-   is the only data sheet.  If DE is in split mode (showing four data sheets),
-   this is the focused data sheet or, if none is focused, the data sheet with
-   selected cells or, if none has selected cells, the upper-left data sheet. */
-PsppireDataSheet *
-psppire_data_editor_get_active_data_sheet (PsppireDataEditor *de)
+/* Set the datum at COL, ROW, to that contained in VALUE.
+ */
+static void
+store_set_datum (GtkTreeModel *model, gint col, gint row,
+                        const GValue *value)
 {
-  if (de->split)
-    {
-      PsppireDataSheet *data_sheet;
-      GtkWidget *scroller;
-      int i;
-
-      /* If one of the datasheet's scrollers is focused, choose that one. */
-      scroller = gtk_container_get_focus_child (
-        GTK_CONTAINER (de->datasheet_vbox_widget));
-      if (scroller != NULL)
-        return PSPPIRE_DATA_SHEET (gtk_bin_get_child (GTK_BIN (scroller)));
-
-      /* Otherwise if there's a nonempty selection in some data sheet, choose
-         that one. */
-      FOR_EACH_DATA_SHEET (data_sheet, i, de)
-        {
-          PsppSheetSelection *selection;
+  PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
+  GVariant *v = g_value_get_variant (value);
+  union value uv;
+  value_variant_get (&uv, v);
+  const struct variable *var = psppire_dict_get_variable (store->dict, col);
+  psppire_data_store_set_value (store, row, var, &uv);
+  value_destroy_from_variant (&uv, v);
+}
 
-          selection = pspp_sheet_view_get_selection (
-            PSPP_SHEET_VIEW (data_sheet));
-          if (pspp_sheet_selection_count_selected_rows (selection)
-              && pspp_sheet_selection_count_selected_columns (selection))
-            return data_sheet;
-        }
-    }
+void
+psppire_data_editor_paste (PsppireDataEditor *de)
+{
+  SswSheet *sheet = SSW_SHEET (de->data_sheet);
+  GtkClipboard *clip =
+    gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (sheet)),
+                                  GDK_SELECTION_CLIPBOARD);
 
-  return PSPPIRE_DATA_SHEET (de->data_sheets[0]);
+  ssw_sheet_paste (sheet, clip, store_set_datum);
 }
index 28ae214a68953bee4ea405cc01057dac79e9b85b..497876a70e0dfa1a2503fdc81fbd29e2a6b93901 100644 (file)
@@ -33,7 +33,6 @@
 #include <gtk/gtk.h>
 
 #include "psppire-data-store.h"
-#include "ui/gui/pspp-sheet-view.h"
 
 G_BEGIN_DECLS
 
@@ -61,17 +60,15 @@ struct _PsppireDataEditor
 
   /* Variable sheet tab. */
   GtkWidget *var_sheet;
+  GtkWidget *data_sheet;
 
   /* Data sheet tab. */
   GtkWidget *vbox;             /* Top-level widget in tab. */
   GtkWidget *cell_ref_label;   /* GtkLabel that shows selected case and var. */
   GtkWidget *datum_entry;      /* PsppireValueEntry for editing current cell. */
-  GtkWidget *datasheet_vbox_widget; /* ->vbox child that holds data sheets. */
-  GtkWidget *data_sheets[4];   /* Normally one data sheet; four, if split. */
-  gboolean split;              /* True if data sheets are split. */
 
-  /* UI manager for whichever var or data sheet is currently in use. */
-  GtkWidget *old_vbox_widget;
+  gboolean split;              /* True if the sheets are in split view. */
+
 };
 
 struct _PsppireDataEditorClass
@@ -86,12 +83,18 @@ void           psppire_data_editor_show_grid       (PsppireDataEditor *, gboolea
 void           psppire_data_editor_set_font        (PsppireDataEditor *, PangoFontDescription *);
 void           psppire_data_editor_split_window    (PsppireDataEditor *, gboolean );
 
-void           psppire_data_editor_goto_variable   (PsppireDataEditor *, gint dict_index);
+void psppire_data_editor_goto_variable               (PsppireDataEditor *, gint dict_index);
+void psppire_data_editor_data_delete_variables       (PsppireDataEditor *de);
+void psppire_data_editor_var_delete_variables        (PsppireDataEditor *de);
+void psppire_data_editor_insert_new_case_at_posn     (PsppireDataEditor *de, gint posn);
+void psppire_data_editor_insert_new_variable_at_posn (PsppireDataEditor *de, gint posn);
 
 struct _PsppireDataSheet *psppire_data_editor_get_active_data_sheet (PsppireDataEditor *);
 
 enum {PSPPIRE_DATA_EDITOR_DATA_VIEW = 0, PSPPIRE_DATA_EDITOR_VARIABLE_VIEW};
 
+void psppire_data_editor_paste (PsppireDataEditor *de);
+
 G_END_DECLS
 
 #endif /* __PSPPIRE_DATA_EDITOR_H__ */
index 962fa1ef2b07f44cee6be9b65c876e63ca7fd1a9..089ab8f4795c5a8cf365fdd4f29c8c138fc88670 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
+   Copyright (C) 2017  John Darrington
 
    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
    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, see <http://www.gnu.org/licenses/>. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include <config.h>
+#include "psppire-data-sheet.h"
 
-#include "ui/gui/psppire-data-sheet.h"
-
-#include "data/case-map.h"
-#include "data/casereader.h"
-#include "data/casewriter.h"
-#include "data/data-out.h"
-#include "data/datasheet.h"
-#include "data/format.h"
-#include "data/value-labels.h"
-#include "libpspp/intern.h"
-#include "libpspp/range-set.h"
-#include "ui/gui/executor.h"
-#include "ui/gui/find-dialog.h"
-#include "ui/gui/goto-case-dialog.h"
-#include "ui/gui/builder-wrapper.h"
-#include "ui/gui/helper.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-cell-renderer-button.h"
-#include "ui/gui/psppire-data-store.h"
-#include "ui/gui/psppire-data-window.h"
-#include "ui/gui/psppire-dialog-action-var-info.h"
-#include "ui/gui/psppire-empty-list-store.h"
-#include "ui/gui/psppire-marshal.h"
-
-#include "gl/intprops.h"
-#include "gl/xalloc.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-static void psppire_data_sheet_dispose (GObject *);
-static void psppire_data_sheet_unset_data_store (PsppireDataSheet *);
-
-static void psppire_data_sheet_update_clip_actions (PsppireDataSheet *);
-static void psppire_data_sheet_update_primary_selection (PsppireDataSheet *,
-                                                         gboolean should_own);
-static void psppire_data_sheet_set_clip (PsppireDataSheet *, gboolean cut);
-
-static void on_selection_changed (PsppSheetSelection *, gpointer);
-static void on_owner_change (GtkClipboard *, GdkEventOwnerChange *, gpointer);
-static void psppire_data_sheet_clip_received_cb (GtkClipboard *,
-                                                 GtkSelectionData *, gpointer);
-
-G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, PSPP_TYPE_SHEET_VIEW);
-
-static gboolean
-get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
-                      gint wx, gint wy,
-                      size_t *row, PsppSheetViewColumn **columnp)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  gint bx, by;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-  PsppSheetViewColumn *tree_column;
-  GtkTreeModel *tree_model;
-  bool ok;
-
-  /* Check that WIDGET is really visible on the screen before we
-     do anything else.  This is a bug fix for a sticky situation:
-     when text_data_import_assistant() returns, it frees the data
-     necessary to compose the tool tip message, but there may be
-     a tool tip under preparation at that point (even if there is
-     no visible tool tip) that will call back into us a little
-     bit later.  Perhaps the correct solution to this problem is
-     to make the data related to the tool tips part of a GObject
-     that only gets destroyed when all references are released,
-     but this solution appears to be effective too. */
-  if (!gtk_widget_get_mapped (widget))
-    return FALSE;
-
-  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
-                                                     wx, wy, &bx, &by);
-  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
-                                      &path, &tree_column, NULL, NULL))
-    return FALSE;
-
-  *columnp = tree_column;
-
-  pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
-                                    NULL);
-
-  tree_model = pspp_sheet_view_get_model (tree_view);
-  ok = gtk_tree_model_get_iter (tree_model, &iter, path);
-  gtk_tree_path_free (path);
-  if (!ok)
-    return FALSE;
-
-  *row = GPOINTER_TO_INT (iter.user_data);
-  return TRUE;
-}
-
-static gboolean
-on_query_tooltip (GtkWidget *widget, gint wx, gint wy,
-                  gboolean keyboard_mode UNUSED,
-                  GtkTooltip *tooltip, gpointer data UNUSED)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  PsppSheetViewColumn *column;
-  struct variable *var;
-  const char *label;
-  union value v;
-  size_t row;
-  int width;
-
-  g_return_val_if_fail (data_store != NULL, FALSE);
-  g_return_val_if_fail (data_store->datasheet != NULL, FALSE);
-
-  if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
-    return FALSE;
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  if (var == NULL)
-    {
-      if (g_object_get_data (G_OBJECT (column), "new-var-column") == NULL)
-        return FALSE;
-
-      gtk_tooltip_set_text (tooltip,
-                            _("Enter a number to add a new variable."));
-      return TRUE;
-    }
-  else if (row >= datasheet_get_n_rows (data_store->datasheet))
-    {
-      gtk_tooltip_set_text (tooltip, _("Enter a number to add a new case."));
-      return TRUE;
-    }
-
-  width = var_get_width (var);
-
-  value_init (&v, width);
-  datasheet_get_value (data_store->datasheet, row, var_get_case_index (var),
-                       &v);
-
-  label = var_lookup_value_label (var, &v);
-  if (label != NULL)
-    {
-      if (data_sheet->show_value_labels)
-        {
-          char *s = value_to_text (v, var);
-          gtk_tooltip_set_text (tooltip, s);
-          free (s);
-        }
-      else
-        gtk_tooltip_set_text (tooltip, label);
-    }
-  value_destroy (&v, width);
-
-  return label != NULL;
-}
-
-static void
-render_row_number_cell (PsppSheetViewColumn *tree_column,
-                        GtkCellRenderer *cell,
-                        GtkTreeModel *model,
-                        GtkTreeIter *iter,
-                        gpointer store_)
-{
-  PsppireDataStore *store = store_;
-  GValue gvalue = { 0, };
-  gint row = GPOINTER_TO_INT (iter->user_data);
-
-  g_return_if_fail (store->datasheet);
-
-  g_value_init (&gvalue, G_TYPE_INT);
-  g_value_set_int (&gvalue, row + 1);
-  g_object_set_property (G_OBJECT (cell), "label", &gvalue);
-  g_value_unset (&gvalue);
-
-  if (row < datasheet_get_n_rows (store->datasheet))
-    g_object_set (cell, "editable", TRUE, NULL);
-  else
-    g_object_set (cell, "editable", FALSE, NULL);
-
-  g_object_set (cell,
-                "slash", psppire_data_store_filtered (store, row),
-                NULL);
-}
-
-static void
-on_row_number_clicked (PsppireCellRendererButton *button,
-                       gchar *path_string,
-                       PsppSheetView *sheet_view)
-{
-  PsppSheetSelection *selection;
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_string (path_string);
-
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  pspp_sheet_selection_unselect_all (selection);
-  pspp_sheet_selection_select_path (selection, path);
-  pspp_sheet_selection_select_all_columns (selection);
-
-  gtk_tree_path_free (path);
-}
-
-static void
-make_row_number_column (PsppireDataSheet *data_sheet,
-                        PsppireDataStore *ds)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *renderer;
-
-  renderer = psppire_cell_renderer_button_new ();
-  g_object_set (renderer, "xalign", 1.0, NULL);
-  g_signal_connect (renderer, "clicked", G_CALLBACK (on_row_number_clicked),
-                    sheet_view);
-
-  column = pspp_sheet_view_column_new_with_attributes (_("Case"),
-                                                       renderer, NULL);
-  pspp_sheet_view_column_set_selectable (column, TRUE);
-  pspp_sheet_view_column_set_row_head (column, TRUE);
-  pspp_sheet_view_column_set_tabbable (column, FALSE);
-  pspp_sheet_view_column_set_clickable (column, TRUE);
-  pspp_sheet_view_column_set_cell_data_func (
-    column, renderer, render_row_number_cell, ds, NULL);
-  pspp_sheet_view_column_set_fixed_width (column, 50);
-  pspp_sheet_view_column_set_visible (column, data_sheet->show_case_numbers);
-  pspp_sheet_view_append_column (sheet_view, column);
-}
-
-static void
-render_data_cell (PsppSheetViewColumn *tree_column,
-                  GtkCellRenderer *cell,
-                  GtkTreeModel *model,
-                  GtkTreeIter *iter,
-                  gpointer data_sheet_)
-{
-  PsppireDataSheet *data_sheet = data_sheet_;
-  PsppireDataStore *store = psppire_data_sheet_get_data_store (data_sheet);
-  struct variable *var;
-  gchar *string;
-  gint row;
-
-  double xalign;
-
-  row = GPOINTER_TO_INT (iter->user_data);
-  var = g_object_get_data (G_OBJECT (tree_column), "variable");
-
-  string = psppire_data_store_get_string (store, row, var,
-                                          data_sheet->show_value_labels);
-  if (string != NULL)
-    {
-      GValue gvalue = { 0 };
-
-      g_value_init (&gvalue, G_TYPE_STRING);
-      g_value_take_string (&gvalue, string);
-      g_object_set_property (G_OBJECT (cell), "text", &gvalue);
-      g_value_unset (&gvalue);
-    }
-  else
-    g_object_set (G_OBJECT (cell), "text", "", NULL);
-
-  switch (var_get_alignment (var))
-    {
-    case ALIGN_LEFT: xalign = 0.0; break;
-    case ALIGN_RIGHT: xalign = 1.0; break;
-    case ALIGN_CENTRE: xalign = 0.5; break;
-    default: xalign = 0.0; break;
-    }
-  g_object_set (cell,
-                "xalign", xalign,
-                "editable", TRUE,
-                NULL);
-}
-
-static gint
-get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
-                  const char *string)
-{
-  gint width;
-  g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
-  gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (treeview),
-                                        NULL, &width);
-
-  return width;
-}
-
-static gint
-get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
-                     size_t char_cnt)
-{
-  struct string s;
-  gint width;
-
-  ds_init_empty (&s);
-  ds_put_byte_multiple (&s, '0', char_cnt);
-  ds_put_byte (&s, ' ');
-  width = get_string_width (treeview, renderer, ds_cstr (&s));
-  ds_destroy (&s);
-
-  return width;
-}
-
-static void
-on_data_column_editing_started (GtkCellRenderer *cell,
-                                GtkCellEditable *editable,
-                                const gchar     *path,
-                                gpointer         user_data)
-{
-  PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
-  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  struct variable *var;
-
-  g_return_if_fail (column);
-  g_return_if_fail (data_sheet);
-  g_return_if_fail (data_store);
-
-
-  g_object_ref (editable);
-  g_object_set_data_full (G_OBJECT (cell), "data-sheet-editable",
-                          editable, g_object_unref);
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  g_return_if_fail (var);
-
-  if (var_has_value_labels (var) && GTK_IS_COMBO_BOX (editable))
-    {
-      const struct val_labs *labels = var_get_value_labels (var);
-      const struct val_lab **vls = val_labs_sorted (labels);
-      size_t n_vls = val_labs_count (labels);
-      GtkListStore *list_store;
-      int i;
-
-      list_store = gtk_list_store_new (1, G_TYPE_STRING);
-      for (i = 0; i < n_vls; ++i)
-        {
-          const struct val_lab *vl = vls[i];
-          GtkTreeIter iter;
-
-          gtk_list_store_append (list_store, &iter);
-          gtk_list_store_set (list_store, &iter,
-                              0, val_lab_get_label (vl),
-                              -1);
-        }
-      free (vls);
-
-      gtk_combo_box_set_model (GTK_COMBO_BOX (editable),
-                               GTK_TREE_MODEL (list_store));
-      g_object_unref (list_store);
-    }
-}
-
-static void
-scroll_to_bottom (GtkWidget      *widget,
-                  GtkRequisition *requisition,
-                  gpointer        unused UNUSED)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-  GtkAdjustment *vadjust;
-
-  vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
-  gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
-
-  if (data_sheet->scroll_to_bottom_signal)
-    {
-      g_signal_handler_disconnect (data_sheet,
-                                   data_sheet->scroll_to_bottom_signal);
-      data_sheet->scroll_to_bottom_signal = 0;
-    }
-}
-
-static void
-on_data_column_edited (GtkCellRendererText *cell,
-                       gchar               *path_string,
-                       gchar               *new_text,
-                       gpointer             user_data)
-{
-  PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
-  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  GtkEditable *editable;
-  struct variable *var;
-  GtkTreePath *path;
-  gboolean is_val_lab;
-  gboolean new_row;
-  gint row;
-
-  path = gtk_tree_path_new_from_string (path_string);
-  row = gtk_tree_path_get_indices (path)[0];
-  gtk_tree_path_free (path);
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-
-  new_row = row == psppire_data_store_get_case_count (data_store);
-  if (new_row && new_text[0] == '\0')
-    return;
-
-  editable = g_object_steal_data (G_OBJECT (cell), "data-sheet-editable");
-  g_return_if_fail (editable != NULL);
-  is_val_lab = (GTK_IS_COMBO_BOX (editable)
-                && gtk_combo_box_get_active (GTK_COMBO_BOX (editable)) >= 0);
-  g_object_unref (editable);
-
-  psppire_data_store_set_string (data_store, new_text, row, var, is_val_lab);
-
-  if (new_row && !data_sheet->scroll_to_bottom_signal)
-    {
-      gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
-      data_sheet->scroll_to_bottom_signal =
-        g_signal_connect (data_sheet, "size-allocate",
-                          G_CALLBACK (scroll_to_bottom), NULL);
-    }
-  else
-    {
-      /* We could be more specific about what to redraw, if it seems
-         important for performance. */
-      gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
-    }
-}
-
-static void
-scroll_to_right (GtkWidget      *widget,
-                 PsppireDataSheet  *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetViewColumn *column, *prev;
-  GList *columns, *iter;
-
-  column = NULL;
-  prev = NULL;
-  columns = pspp_sheet_view_get_columns (sheet_view);
-  for (iter = columns; iter; iter = iter->next)
-    {
-      PsppSheetViewColumn *c = iter->data;
-      if (g_object_get_data (G_OBJECT (c), "new-var-column"))
-        {
-          column = c;
-          break;
-        }
-      prev = c;
-    }
-  g_list_free (columns);
-
-  if (column == NULL)
-    return;
-
-  pspp_sheet_view_scroll_to_cell (sheet_view, NULL, column, FALSE, 0, 0);
-
-  if (prev)
-    {
-      GtkTreePath *path;
-
-      pspp_sheet_view_get_cursor (sheet_view, &path, NULL);
-      if (path)
-        {
-          pspp_sheet_view_set_cursor (sheet_view, path, prev, TRUE);
-          gtk_tree_path_free (path);
-        }
-    }
-
-  if (data_sheet->scroll_to_right_signal)
-    {
-      g_signal_handler_disconnect (widget, data_sheet->scroll_to_right_signal);
-      data_sheet->scroll_to_right_signal = 0;
-    }
-}
-
-static void
-on_new_variable_column_edited (GtkCellRendererText *cell,
-                               gchar               *path_string,
-                               gchar               *new_text,
-                               gpointer             user_data)
-{
-  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  PsppireDict *dict = data_store->dict;
-  struct variable *var;
-  GtkTreePath *path;
-  char name[64];
-  gint row;
-
-  if (new_text[0] == '\0')
-    {
-      /* User didn't enter anything so don't create a variable. */
-      return;
-    }
-
-  path = gtk_tree_path_new_from_string (path_string);
-  row = gtk_tree_path_get_indices (path)[0];
-  gtk_tree_path_free (path);
-
-  if (!psppire_dict_generate_name (dict, name, sizeof name))
-    return;
-
-  var = psppire_dict_insert_variable (dict, psppire_dict_get_var_cnt (dict),
-                                      name);
-  g_return_if_fail (var != NULL);
-
-  psppire_data_store_set_string (data_store, new_text, row, var, FALSE);
-
-  if (!data_sheet->scroll_to_right_signal)
-    {
-      gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
-      data_sheet->scroll_to_right_signal =
-        g_signal_connect_after (gtk_widget_get_toplevel (GTK_WIDGET (data_sheet)), "check-resize",
-                                G_CALLBACK (scroll_to_right), data_sheet);
-    }
-  else
-    {
-      /* We could be more specific about what to redraw, if it seems
-         important for performance. */
-      gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
-    }
-}
-
-static void
-calc_width_conversion (PsppireDataSheet *data_sheet,
-                       gint *base_width, gint *incr_width)
-{
-  GtkCellRenderer *cell;
-  gint w1, w10;
-
-  cell = gtk_cell_renderer_text_new ();
-  w1 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 1);
-  w10 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 10);
-  *incr_width = MAX (1, (w10 - w1) / 9);
-  *base_width = MAX (0, w10 - *incr_width * 10);
-  g_object_ref_sink (cell);
-  g_object_unref (cell);
-}
-
-static gint
-display_width_from_pixel_width (PsppireDataSheet *data_sheet,
-                                gint pixel_width)
-{
-  gint base_width, incr_width;
-
-  calc_width_conversion (data_sheet, &base_width, &incr_width);
-  return MAX ((pixel_width - base_width + incr_width / 2) / incr_width, 1);
-}
-
-static gint
-display_width_to_pixel_width (PsppireDataSheet *data_sheet,
-                              gint display_width,
-                              gint base_width,
-                              gint incr_width)
-{
-  return base_width + incr_width * display_width;
-}
-
-static void
-on_data_column_resized (GObject    *gobject,
-                        GParamSpec *pspec,
-                        gpointer    user_data)
-{
-  PsppireDataSheet *data_sheet = user_data;
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (gobject);
-  struct variable *var;
-  gint pixel_width;
-  int display_width;
-
-  if (data_store == NULL)
-    return;
-
-  pixel_width = pspp_sheet_view_column_get_width (column);
-  if (pixel_width == pspp_sheet_view_column_get_fixed_width (column))
-    {
-      /* Short-circuit the expensive display_width_from_pixel_width()
-         calculation, to make loading .sav files with 2000 columns visibly
-         faster. */
-      return;
-    }
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  display_width = display_width_from_pixel_width (data_sheet, pixel_width);
-  var_set_display_width (var, display_width);
-}
-
-enum sort_order
-  {
-    SORT_ASCEND,
-    SORT_DESCEND
-  };
-
-static void
-do_sort (PsppireDataSheet *data_sheet, enum sort_order order)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDataWindow *pdw;
-  GList *list, *iter;
-  GString *syntax;
-  int n_vars;
-
-  pdw = psppire_data_window_for_data_store (data_sheet->data_store);
-  g_return_if_fail (pdw != NULL);
-
-  list = pspp_sheet_selection_get_selected_columns (selection);
-
-  syntax = g_string_new ("SORT CASES BY");
-  n_vars = 0;
-  for (iter = list; iter; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *var;
-
-      var = g_object_get_data (G_OBJECT (column), "variable");
-      if (var != NULL)
-        {
-          g_string_append_printf (syntax, " %s", var_get_name (var));
-          n_vars++;
-        }
-    }
-  if (n_vars > 0)
-    {
-      if (order == SORT_DESCEND)
-        g_string_append (syntax, " (DOWN)");
-      g_string_append_c (syntax, '.');
-      execute_const_syntax_string (pdw, syntax->str);
-    }
-  g_string_free (syntax, TRUE);
-}
-
-static void
-on_sort_up (PsppireDataSheet *data_sheet)
-{
-  do_sort (data_sheet, SORT_ASCEND);
-}
-
-static void
-on_sort_down (PsppireDataSheet *data_sheet)
-{
-  do_sort (data_sheet, SORT_DESCEND);
-}
-
-static void
-do_data_column_popup_menu (PsppSheetViewColumn *column,
-                           guint button, guint32 time)
-{
-  GtkWidget *sheet_view = pspp_sheet_view_column_get_tree_view (column);
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
-
-  gtk_menu_popup (GTK_MENU (data_sheet->column_popup_menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_data_column_popup_menu (PsppSheetViewColumn *column,
-                           gpointer user_data UNUSED)
-{
-  do_data_column_popup_menu (column, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_column_button_press_event (PsppSheetViewColumn *column,
-                              GdkEventButton *event,
-                              gpointer user_data UNUSED)
-{
-  PsppSheetSelection *selection;
-  PsppSheetView *sheet_view;
-
-  sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
-                                  column));
-  g_return_val_if_fail (sheet_view != NULL, FALSE);
-
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  g_return_val_if_fail (selection != NULL, FALSE);
-
-  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
-    {
-      do_data_column_popup_menu (column, event->button, event->time);
-      return TRUE;
-    }
-  else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
-    {
-      PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
-      struct variable *var;
-
-      var = g_object_get_data (G_OBJECT (column), "variable");
-      if (var != NULL)
-        {
-          gboolean handled;
-
-          g_signal_emit_by_name (data_sheet, "var-double-clicked",
-                                 var_get_dict_index (var), &handled);
-          return handled;
-        }
-    }
-
-  return FALSE;
-}
-
-static gboolean
-on_data_column_query_tooltip (PsppSheetViewColumn *column,
-                              GtkTooltip *tooltip,
-                              gpointer user_data UNUSED)
-{
-  struct variable *var;
-  const char *text;
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  g_return_val_if_fail (var != NULL, FALSE);
-
-  text = var_has_label (var) ? var_get_label (var) : var_get_name (var);
-  gtk_tooltip_set_text (tooltip, text);
-
-  return TRUE;
-}
-
-static void
-add_data_column_cell_renderer (PsppireDataSheet *data_sheet,
-                               PsppSheetViewColumn *column)
-{
-  GtkCellRenderer *cell;
-  struct variable *var;
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  g_return_if_fail (var != NULL);
-
-  if (data_sheet->show_value_labels && var_has_value_labels (var))
-    {
-      cell = gtk_cell_renderer_combo_new ();
-      g_object_set (G_OBJECT (cell),
-                    "has-entry", TRUE,
-                    "text-column", 0,
-                    NULL);
-    }
-  else
-    cell = gtk_cell_renderer_text_new ();
-
-  g_signal_connect (cell, "editing-started",
-                    G_CALLBACK (on_data_column_editing_started), NULL);
-  g_signal_connect (cell, "edited", G_CALLBACK (on_data_column_edited), NULL);
-
-  g_object_set_data (G_OBJECT (cell), "column", column);
-  g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
-
-  pspp_sheet_view_column_clear (column);
-  pspp_sheet_view_column_pack_start (column, cell, TRUE);
-
-  pspp_sheet_view_column_set_cell_data_func (
-    column, cell, render_data_cell, data_sheet, NULL);
-}
-
-static PsppSheetViewColumn *
-make_data_column (PsppireDataSheet *data_sheet, gint dict_idx,
-                  gint base_width, gint incr_width)
-{
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  struct variable *var;
-  PsppSheetViewColumn *column;
-  char *name;
-  int width;
-
-  var = psppire_dict_get_variable (data_store->dict, dict_idx);
-
-  column = pspp_sheet_view_column_new ();
-
-  name = escape_underscores (var_get_name (var));
-  pspp_sheet_view_column_set_title (column, name);
-  free (name);
-
-  g_object_set_data (G_OBJECT (column), "variable", var);
-
-  width = display_width_to_pixel_width (data_sheet,
-                                        var_get_display_width (var),
-                                        base_width, incr_width);
-  pspp_sheet_view_column_set_min_width (column, 10);
-  pspp_sheet_view_column_set_fixed_width (column, width);
-  pspp_sheet_view_column_set_resizable (column, TRUE);
-
-  pspp_sheet_view_column_set_clickable (column, TRUE);
-  g_signal_connect (column, "notify::width",
-                    G_CALLBACK (on_data_column_resized), data_sheet);
-
-  g_signal_connect (column, "button-press-event",
-                    G_CALLBACK (on_column_button_press_event),
-                    data_sheet);
-  g_signal_connect (column, "query-tooltip",
-                    G_CALLBACK (on_data_column_query_tooltip), NULL);
-  g_signal_connect (column, "popup-menu",
-                    G_CALLBACK (on_data_column_popup_menu), data_sheet);
-
-  add_data_column_cell_renderer (data_sheet, column);
-
-  return column;
-}
-
-static void
-make_new_variable_column (PsppireDataSheet *data_sheet,
-                          gint base_width, gint incr_width)
-{
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *cell;
-  int width;
-
-  cell = gtk_cell_renderer_text_new ();
-  g_object_set (cell, "editable", TRUE, NULL);
-
-  g_signal_connect (cell, "edited", G_CALLBACK (on_new_variable_column_edited),
-                    NULL);
-
-  column = pspp_sheet_view_column_new_with_attributes ("", cell, NULL);
-  g_object_set_data (G_OBJECT (column), "new-var-column", column);
-
-  width = display_width_to_pixel_width (data_sheet, 8, base_width, incr_width);
-  pspp_sheet_view_column_set_min_width (column, 10);
-  pspp_sheet_view_column_set_fixed_width (column, width);
-  pspp_sheet_view_column_set_tabbable (column, FALSE);
-
-  g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
-  g_signal_connect (column, "button-press-event",
-                    G_CALLBACK (on_column_button_press_event),
-                    data_sheet);
-  g_signal_connect (column, "popup-menu",
-                    G_CALLBACK (on_data_column_popup_menu), data_sheet);
-
-  pspp_sheet_view_column_set_visible (column, data_sheet->may_create_vars);
-
-  pspp_sheet_view_append_column (PSPP_SHEET_VIEW (data_sheet), column);
-  data_sheet->new_variable_column = column;
-}
-
-static void
-psppire_data_sheet_model_changed (GObject    *gobject,
-                                  GParamSpec *pspec,
-                                  gpointer    user_data)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (gobject);
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *data_store;
-
-  /* Remove old columns. */
-  for (;;)
-    {
-      PsppSheetViewColumn *column = pspp_sheet_view_get_column (sheet_view, 0);
-      if (column == NULL)
-        break;
-
-      pspp_sheet_view_remove_column (sheet_view, column);
-    }
-  data_sheet->new_variable_column = NULL;
-
-  if (pspp_sheet_view_get_model (sheet_view) == NULL)
-    {
-      /* Don't create any columns at all if there's no model.  Otherwise we'll
-         create some columns as part of the "dispose" callback for the sheet
-         view, which sets the model to NULL.  That causes warnings to be
-         logged and is obviously undesirable in any case. */
-      return;
-    }
-
-  /* Add new columns. */
-  data_store = psppire_data_sheet_get_data_store (data_sheet);
-  if (data_store != NULL)
-    {
-      gint base_width, incr_width;
-      int i;
-
-      calc_width_conversion (data_sheet, &base_width, &incr_width);
-
-      make_row_number_column (data_sheet, data_store);
-      for (i = 0; i < psppire_dict_get_var_cnt (data_store->dict); i++)
-        {
-          PsppSheetViewColumn *column;
-
-          column = make_data_column (data_sheet, i, base_width, incr_width);
-          pspp_sheet_view_append_column (sheet_view, column);
-        }
-      make_new_variable_column (data_sheet, base_width, incr_width);
-    }
-}
-
-enum
-  {
-    PROP_0,
-    PROP_DATA_STORE,
-    PROP_VALUE_LABELS,
-    PROP_CASE_NUMBERS,
-    PROP_CURRENT_CASE,
-    PROP_MAY_CREATE_VARS,
-    PROP_MAY_DELETE_VARS
-  };
-
-static void
-psppire_data_sheet_set_property (GObject      *object,
-                                 guint         prop_id,
-                                 const GValue *value,
-                                 GParamSpec   *pspec)
-{
-  PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_DATA_STORE:
-      psppire_data_sheet_set_data_store (
-        obj, PSPPIRE_DATA_STORE (g_value_get_object (value)));
-      break;
-
-    case PROP_VALUE_LABELS:
-      psppire_data_sheet_set_value_labels (obj, g_value_get_boolean (value));
-      break;
-
-    case PROP_CASE_NUMBERS:
-      psppire_data_sheet_set_case_numbers (obj, g_value_get_boolean (value));
-      break;
-
-    case PROP_CURRENT_CASE:
-      psppire_data_sheet_goto_case (obj, g_value_get_long (value));
-      break;
-
-    case PROP_MAY_CREATE_VARS:
-      psppire_data_sheet_set_may_create_vars (obj,
-                                              g_value_get_boolean (value));
-      break;
-
-    case PROP_MAY_DELETE_VARS:
-      psppire_data_sheet_set_may_delete_vars (obj,
-                                              g_value_get_boolean (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_data_sheet_get_property (GObject      *object,
-                                 guint         prop_id,
-                                 GValue       *value,
-                                 GParamSpec   *pspec)
-{
-  PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_DATA_STORE:
-      g_value_set_object (value, psppire_data_sheet_get_data_store (obj));
-      break;
-
-    case PROP_VALUE_LABELS:
-      g_value_set_boolean (value, psppire_data_sheet_get_value_labels (obj));
-      break;
-
-    case PROP_CASE_NUMBERS:
-      g_value_set_boolean (value, psppire_data_sheet_get_case_numbers (obj));
-      break;
-
-    case PROP_CURRENT_CASE:
-      g_value_set_long (value, psppire_data_sheet_get_selected_case (obj));
-      break;
-
-    case PROP_MAY_CREATE_VARS:
-      g_value_set_boolean (value, obj->may_create_vars);
-      break;
-
-    case PROP_MAY_DELETE_VARS:
-      g_value_set_boolean (value, obj->may_delete_vars);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-gboolean
-psppire_data_sheet_get_value_labels (const PsppireDataSheet *ds)
-{
-  return ds->show_value_labels;
-}
-
-void
-psppire_data_sheet_set_value_labels (PsppireDataSheet *ds,
-                                  gboolean show_value_labels)
-{
-  show_value_labels = !!show_value_labels;
-  if (show_value_labels != ds->show_value_labels)
-    {
-      ds->show_value_labels = show_value_labels;
-      g_object_notify (G_OBJECT (ds), "value-labels");
-
-      /* Pretend the model changed, to force the columns to be rebuilt.
-         Otherwise cell renderers won't get changed from combo boxes to text
-         entries or vice versa. */
-      g_object_notify (G_OBJECT (ds), "model");
-    }
-}
-
-gboolean
-psppire_data_sheet_get_case_numbers (const PsppireDataSheet *ds)
-{
-  return ds->show_case_numbers;
-}
-
-void
-psppire_data_sheet_set_case_numbers (PsppireDataSheet *ds,
-                                     gboolean show_case_numbers)
-{
-  show_case_numbers = !!show_case_numbers;
-  if (show_case_numbers != ds->show_case_numbers)
-    {
-      PsppSheetViewColumn *column;
-
-      ds->show_case_numbers = show_case_numbers;
-      column = pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ds), 0);
-      if (column)
-        pspp_sheet_view_column_set_visible (column, show_case_numbers);
-
-      g_object_notify (G_OBJECT (ds), "case-numbers");
-      gtk_widget_queue_draw (GTK_WIDGET (ds));
-    }
-}
-
-gboolean
-psppire_data_sheet_get_may_create_vars (PsppireDataSheet *data_sheet)
-{
-  return data_sheet->may_create_vars;
-}
-
-void
-psppire_data_sheet_set_may_create_vars (PsppireDataSheet *data_sheet,
-                                       gboolean may_create_vars)
-{
-  if (data_sheet->may_create_vars != may_create_vars)
-    {
-      data_sheet->may_create_vars = may_create_vars;
-      if (data_sheet->new_variable_column)
-        pspp_sheet_view_column_set_visible (data_sheet->new_variable_column,
-                                            may_create_vars);
-
-      on_selection_changed (pspp_sheet_view_get_selection (
-                              PSPP_SHEET_VIEW (data_sheet)), NULL);
-    }
-}
-
-gboolean
-psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *data_sheet)
-{
-  return data_sheet->may_delete_vars;
-}
-
-void
-psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *data_sheet,
-                                       gboolean may_delete_vars)
-{
-  if (data_sheet->may_delete_vars != may_delete_vars)
-    {
-      data_sheet->may_delete_vars = may_delete_vars;
-      on_selection_changed (pspp_sheet_view_get_selection (
-                              PSPP_SHEET_VIEW (data_sheet)), NULL);
-    }
-}
-
-static PsppSheetViewColumn *
-psppire_data_sheet_find_column_for_variable (PsppireDataSheet *data_sheet,
-                                             gint dict_index)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *data_store;
-  PsppSheetViewColumn *column;
-  struct variable *var;
-  GList *list, *iter;
-
-  data_store = psppire_data_sheet_get_data_store (data_sheet);
-  g_return_val_if_fail (data_store != NULL, NULL);
-  g_return_val_if_fail (data_store->dict != NULL, NULL);
-
-  var = psppire_dict_get_variable (data_store->dict, dict_index);
-  g_return_val_if_fail (var != NULL, NULL);
-
-  column = NULL;
-  list = pspp_sheet_view_get_columns (sheet_view);
-  for (iter = list; iter != NULL; iter = iter->next)
-    {
-      PsppSheetViewColumn *c = iter->data;
-      struct variable *v;
-
-      v = g_object_get_data (G_OBJECT (c), "variable");
-      if (v == var)
-        {
-          column = c;
-          break;
-        }
-    }
-  g_list_free (list);
-
-  return column;
-}
-
-void
-psppire_data_sheet_goto_variable (PsppireDataSheet *data_sheet,
-                                  gint dict_index)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetViewColumn *column;
-
-  column = psppire_data_sheet_find_column_for_variable (data_sheet,
-                                                        dict_index);
-  if (column != NULL)
-    {
-      GtkTreePath *path;
-
-      gint row = psppire_data_sheet_get_current_case (data_sheet);
-      path = gtk_tree_path_new_from_indices (row >= 0 ? row : 0, -1);
-
-      pspp_sheet_view_scroll_to_cell (sheet_view, path, column,
-                                      FALSE, 0.0, 0.0);
-      pspp_sheet_view_set_cursor (sheet_view, path, column, FALSE);
-      gtk_tree_path_free (path);
-    }
-}
-
-struct variable *
-psppire_data_sheet_get_current_variable (const PsppireDataSheet *data_sheet)
-{
-  PsppSheetSelection *selection;
-  struct variable *var;
-  GList *selected_columns;
-  GList *iter;
-
-  selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (data_sheet));
-  selected_columns = pspp_sheet_selection_get_selected_columns (selection);
-
-  var = NULL;
-  for (iter = selected_columns; iter != NULL; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
-      if (v != NULL)
-        {
-          if (var)
-            {
-              var = NULL;
-              break;
-            }
-          else
-            var = v;
-        }
-    }
-
-  g_list_free (selected_columns);
-
-  return var;
-
-}
-void
-psppire_data_sheet_goto_case (PsppireDataSheet *data_sheet, gint case_index)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *store = data_sheet->data_store;
-  PsppSheetSelection *selection;
-  GtkTreePath *path;
-
-  g_return_if_fail (case_index >= 0);
-  g_return_if_fail (case_index < psppire_data_store_get_case_count (store));
-
-  path = gtk_tree_path_new_from_indices (case_index, -1);
-
-  /* Select the case. */
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  pspp_sheet_selection_unselect_all (selection);
-  pspp_sheet_selection_select_path (selection, path);
-  pspp_sheet_selection_select_all_columns (selection);
-
-  /* Scroll so that the case is visible. */
-  pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
-
-  gtk_tree_path_free (path);
-}
-
-/* Returns the 0-based index of a selected case, if there is at least one, and
-   -1 otherwise.
-
-   If more than one case is selected, returns the one with the smallest index,
-   that is, the index of the case closest to the beginning of the file.  The
-   row that can be used to insert a new case is not considered a case. */
-gint
-psppire_data_sheet_get_selected_case (const PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *store = data_sheet->data_store;
-  const struct range_set_node *node;
-  PsppSheetSelection *selection;
-  struct range_set *rows;
-  gint row;
-
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  rows = pspp_sheet_selection_get_range_set (selection);
-  node = range_set_first (rows);
-  row = (node && node->start < psppire_data_store_get_case_count (store)
-         ? node->start
-         : -1);
-  range_set_destroy (rows);
-
-  return row;
-}
-
-/* Returns the 0-based index of a selected case, if exactly one case is
-   selected, and -1 otherwise.  Returns -1 if the row that can be used to
-   insert a new case is selected. */
-gint
-psppire_data_sheet_get_current_case (const PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *store = data_sheet->data_store;
-  const struct range_set_node *node;
-  PsppSheetSelection *selection;
-  struct range_set *rows;
-  gint row;
-
-  selection = pspp_sheet_view_get_selection (sheet_view);
-  if (pspp_sheet_selection_count_selected_rows (selection) != 1)
-    return -1;
-
-  rows = pspp_sheet_selection_get_range_set (selection);
-  node = range_set_first (rows);
-  row = (node && node->start < psppire_data_store_get_case_count (store)
-         ? node->start
-         : -1);
-  range_set_destroy (rows);
-
-  return row;
-}
-
-
-static void
-psppire_data_sheet_dispose (GObject *object)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (object);
-
-  if (data_sheet->clip != NULL && data_sheet->on_owner_change_signal != 0)
-    {
-      g_signal_handler_disconnect (data_sheet->clip,
-                                   data_sheet->on_owner_change_signal);
-      data_sheet->on_owner_change_signal = 0;
-    }
-
-  if (data_sheet->dispose_has_run)
-    return;
-
-  data_sheet->dispose_has_run = TRUE;
-
-  psppire_data_sheet_unset_data_store (data_sheet);
-
-  G_OBJECT_CLASS (psppire_data_sheet_parent_class)->dispose (object);
-}
-
-static void
-psppire_data_sheet_map (GtkWidget *widget)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-
-  GTK_WIDGET_CLASS (psppire_data_sheet_parent_class)->map (widget);
-
-  data_sheet->clip = gtk_widget_get_clipboard (widget,
-                                               GDK_SELECTION_CLIPBOARD);
-  if (data_sheet->on_owner_change_signal)
-    g_signal_handler_disconnect (data_sheet->clip,
-                                 data_sheet->on_owner_change_signal);
-  data_sheet->on_owner_change_signal
-    = g_signal_connect (data_sheet->clip, "owner-change",
-                        G_CALLBACK (on_owner_change), widget);
-  on_owner_change (data_sheet->clip, NULL, widget);
-}
-
-static void
-psppire_data_sheet_class_init (PsppireDataSheetClass *class)
-{
-  GObjectClass *gobject_class;
-  GtkWidgetClass *widget_class;
-
-  gobject_class = G_OBJECT_CLASS (class);
-  gobject_class->set_property = psppire_data_sheet_set_property;
-  gobject_class->get_property = psppire_data_sheet_get_property;
-  gobject_class->dispose = psppire_data_sheet_dispose;
-
-  widget_class = GTK_WIDGET_CLASS (class);
-  widget_class->map = psppire_data_sheet_map;
-
-  g_signal_new ("var-double-clicked",
-                G_OBJECT_CLASS_TYPE (gobject_class),
-                G_SIGNAL_RUN_LAST,
-                0,
-                g_signal_accumulator_true_handled, NULL,
-                psppire_marshal_BOOLEAN__INT,
-                G_TYPE_BOOLEAN, 1, G_TYPE_INT);
-
-  g_object_class_install_property (
-    gobject_class, PROP_DATA_STORE,
-    g_param_spec_object ("data-store",
-                         "Data Store",
-                         "The data store for the data sheet to display.",
-                         PSPPIRE_TYPE_DATA_STORE,
-                         G_PARAM_WRITABLE | G_PARAM_READABLE));
-
-  g_object_class_install_property (
-    gobject_class, PROP_VALUE_LABELS,
-    g_param_spec_boolean ("value-labels",
-                          "Value Labels",
-                          "Whether or not the data sheet should display labels instead of values",
-                         FALSE,
-                          G_PARAM_WRITABLE | G_PARAM_READABLE));
-
-  g_object_class_install_property (
-    gobject_class, PROP_CASE_NUMBERS,
-    g_param_spec_boolean ("case-numbers",
-                          "Case Numbers",
-                          "Whether or not the data sheet should display case numbers",
-                         FALSE,
-                          G_PARAM_WRITABLE | G_PARAM_READABLE));
-
-  g_object_class_install_property (
-    gobject_class,
-    PROP_CURRENT_CASE,
-    g_param_spec_long ("current-case",
-                      "Current Case",
-                      "Zero based number of the selected case",
-                      0, CASENUMBER_MAX,
-                      0,
-                      G_PARAM_WRITABLE | G_PARAM_READABLE));
-
-  g_object_class_install_property (
-    gobject_class,
-    PROP_MAY_CREATE_VARS,
-    g_param_spec_boolean ("may-create-vars",
-                          "May create variables",
-                          "Whether the user may create more variables",
-                          TRUE,
-                          G_PARAM_READWRITE));
-
-
-  g_object_class_install_property (
-    gobject_class,
-    PROP_MAY_DELETE_VARS,
-    g_param_spec_boolean ("may-delete-vars",
-                          "May delete variables",
-                          "Whether the user may delete variables",
-                          TRUE,
-                          G_PARAM_READWRITE));
-}
-
-static void
-do_row_popup_menu (GtkWidget *widget, guint button, guint32 time)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-
-
-  gtk_menu_popup (GTK_MENU (data_sheet->row_popup_menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
-{
-  do_row_popup_menu (widget, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
-                   gpointer user_data UNUSED)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-
-  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
-    {
-      PsppSheetSelection *selection;
-
-      selection = pspp_sheet_view_get_selection (sheet_view);
-      if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
-        {
-          GtkTreePath *path;
-
-          if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
-                                               &path, NULL, NULL, NULL))
-            {
-              pspp_sheet_selection_unselect_all (selection);
-              pspp_sheet_selection_select_path (selection, path);
-              pspp_sheet_selection_select_all_columns (selection);
-              gtk_tree_path_free (path);
-            }
-        }
-
-      do_row_popup_menu (widget, event->button, event->time);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define P_(X) (X)
 
-void
-psppire_data_sheet_edit_clear_cases (PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  const struct range_set_node *node;
-  struct range_set *selected;
-
-  selected = pspp_sheet_selection_get_range_set (selection);
-  for (node = range_set_last (selected); node != NULL;
-       node = range_set_prev (selected, node))
-    {
-      unsigned long int start = range_set_node_get_start (node);
-      unsigned long int count = range_set_node_get_width (node);
+#include "value-variant.h"
 
-      psppire_data_store_delete_cases (data_sheet->data_store, start, count);
-    }
-  range_set_destroy (selected);
-}
+#include "ui/gui/executor.h"
+#include "psppire-data-window.h"
 
 static void
-on_selection_changed (PsppSheetSelection *selection,
-                      gpointer user_data UNUSED)
+do_sort (PsppireDataSheet *sheet, GtkSortType order)
 {
-  PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
-  gboolean any_variables_selected;
-  gboolean may_delete_cases, may_delete_vars, may_insert_vars;
-  GList *list, *iter;
-  GtkTreePath *path;
-
-  GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
-  if (! PSPPIRE_IS_DATA_WINDOW (top))
-    return;
-
-  PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
-
-  gint n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
+  SswRange *range = SSW_SHEET(sheet)->selection;
 
-  gtk_widget_set_sensitive (dw->mi_insert_case, n_selected_rows > 0);
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-  switch (n_selected_rows)
-    {
-    case 0:
-      may_delete_cases = FALSE;
-      break;
-
-    case 1:
-      /* The row used for inserting new cases cannot be deleted. */
-      path = gtk_tree_path_new_from_indices (
-        psppire_data_store_get_case_count (data_sheet->data_store), -1);
-      may_delete_cases = !pspp_sheet_selection_path_is_selected (selection,
-                                                                 path);
-      gtk_tree_path_free (path);
-      break;
-
-    default:
-      may_delete_cases = TRUE;
-      break;
-    }
+  int n_vars = 0;
+  int i;
 
-  gtk_widget_set_sensitive (dw->mi_clear_cases, may_delete_cases);
+  PsppireDataWindow *pdw =
+     psppire_data_window_for_data_store (data_store);
 
-  any_variables_selected = FALSE;
-  may_delete_vars = may_insert_vars = FALSE;
-  list = pspp_sheet_selection_get_selected_columns (selection);
-
-  for (iter = list; iter != NULL; iter = iter->next)
+  GString *syntax = g_string_new ("SORT CASES BY");
+  for (i = range->start_x ; i <= range->end_x; ++i)
     {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
+      const struct variable *var = psppire_dict_get_variable (data_store->dict, i);
       if (var != NULL)
         {
-          may_delete_vars = may_insert_vars = TRUE;
-          any_variables_selected = TRUE;
-          break;
+          g_string_append_printf (syntax, " %s", var_get_name (var));
+          n_vars++;
         }
-      if (g_object_get_data (G_OBJECT (column), "new-var-column") != NULL)
-        may_insert_vars = TRUE;
-    }
-  g_list_free (list);
-
-  may_insert_vars = may_insert_vars && data_sheet->may_create_vars;
-  may_delete_vars = may_delete_vars && data_sheet->may_delete_vars;
-
-  gtk_widget_set_sensitive (dw->mi_insert_var, may_insert_vars);
-  gtk_widget_set_sensitive (dw->mi_clear_variables, may_delete_vars);
-  gtk_widget_set_sensitive (data_sheet->pu_sort_up, may_delete_vars);
-  gtk_widget_set_sensitive (data_sheet->pu_sort_down, may_delete_vars);
-
-  psppire_data_sheet_update_clip_actions (data_sheet);
-  psppire_data_sheet_update_primary_selection (data_sheet,
-                                               (n_selected_rows > 0
-                                                && any_variables_selected));
-}
-
-static gboolean
-psppire_data_sheet_get_selected_range (PsppireDataSheet *data_sheet,
-                                    struct range_set **rowsp,
-                                    struct range_set **colsp)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppireDataStore *data_store = data_sheet->data_store;
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  unsigned long n_cases;
-  struct range_set *rows, *cols;
-  GList *list, *iter;
-
-  if (data_store == NULL)
-    return FALSE;
-  n_cases = psppire_data_store_get_case_count (data_store);
-
-  rows = pspp_sheet_selection_get_range_set (selection);
-  range_set_set0 (rows, n_cases, ULONG_MAX - n_cases);
-  if (range_set_is_empty (rows))
-    {
-      range_set_destroy (rows);
-      return FALSE;
-    }
-
-  cols = range_set_create ();
-  list = pspp_sheet_selection_get_selected_columns (selection);
-  for (iter = list; iter != NULL; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
-      if (var != NULL)
-        range_set_set1 (cols, var_get_dict_index (var), 1);
     }
-  g_list_free (list);
-  if (range_set_is_empty (cols))
+  if (n_vars > 0)
     {
-      range_set_destroy (rows);
-      range_set_destroy (cols);
-      return FALSE;
+      if (order == GTK_SORT_DESCENDING)
+        g_string_append (syntax, " (DOWN)");
+      g_string_append_c (syntax, '.');
+      execute_const_syntax_string (pdw, syntax->str);
     }
-
-  *rowsp = rows;
-  *colsp = cols;
-  return TRUE;
-}
-
-/* Insert a case at the selected row */
-void
-psppire_data_sheet_insert_case (PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDataStore *data_store = data_sheet->data_store;
-  struct range_set *selected = pspp_sheet_selection_get_range_set (selection);
-  unsigned long row = range_set_scan (selected, 0);
-  range_set_destroy (selected);
-
-  if (row <= psppire_data_store_get_case_count (data_store))
-    psppire_data_store_insert_new_case (data_store, row);
+  g_string_free (syntax, TRUE);
 }
 
-void
-psppire_data_sheet_insert_variable (PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDict *dict = data_sheet->data_store->dict;
-  PsppSheetViewColumn *column;
-  struct variable *var;
-  gchar name[64];
-  GList *list;
-  gint index;
-
-  list = pspp_sheet_selection_get_selected_columns (selection);
-  if (list == NULL)
-    return;
-  column = list->data;
-  g_list_free (list);
-
-  var = g_object_get_data (G_OBJECT (column), "variable");
-  index = var ? var_get_dict_index (var) : psppire_dict_get_var_cnt (dict);
-  if (psppire_dict_generate_name (dict, name, sizeof name))
-    psppire_dict_insert_variable (dict, index, name);
-}
 
-void
-psppire_data_sheet_edit_clear_variables (PsppireDataSheet *data_sheet)
+static void
+sort_ascending (PsppireDataSheet *sheet)
 {
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDict *dict = data_sheet->data_store->dict;
-  GList *iter;
-  GList *list = pspp_sheet_selection_get_selected_columns (selection);
+  do_sort (sheet, GTK_SORT_ASCENDING);
 
-  if (list == NULL)
-    return;
-  list = g_list_reverse (list);
-  for (iter = list; iter; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-      if (var != NULL)
-        psppire_dict_delete_variables (dict, var_get_dict_index (var), 1);
-    }
-  g_list_free (list);
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
 }
 
-void
-psppire_data_sheet_edit_copy (PsppireDataSheet *data_sheet)
+static void
+sort_descending (PsppireDataSheet *sheet)
 {
-  psppire_data_sheet_set_clip (data_sheet, FALSE);
-}
+  do_sort (sheet, GTK_SORT_DESCENDING);
 
-void
-psppire_data_sheet_edit_cut (PsppireDataSheet *data_sheet)
-{
-  psppire_data_sheet_set_clip (data_sheet, TRUE);
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
 }
 
-void
-psppire_data_sheet_edit_paste (PsppireDataSheet *data_sheet)
-{
-  GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
-  GtkClipboard *clipboard =
-    gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
-
-  gtk_clipboard_request_contents (clipboard,
-                                  gdk_atom_intern ("UTF8_STRING", TRUE),
-                                  psppire_data_sheet_clip_received_cb,
-                                  data_sheet);
-}
+\f
 
 static void
-psppire_data_sheet_init (PsppireDataSheet *obj)
+change_data_value (PsppireDataSheet *sheet, gint col, gint row, GValue *value)
 {
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
-
-  obj->show_value_labels = FALSE;
-  obj->show_case_numbers = TRUE;
-  obj->may_create_vars = TRUE;
-  obj->may_delete_vars = TRUE;
-
-  obj->owns_primary_selection = FALSE;
-
-  obj->scroll_to_bottom_signal = 0;
-  obj->scroll_to_right_signal = 0;
-  obj->on_owner_change_signal = 0;
-  obj->new_variable_column = NULL;
-  obj->container = NULL;
-
-  obj->dispose_has_run = FALSE;
-
-  pspp_sheet_view_set_special_cells (sheet_view, PSPP_SHEET_VIEW_SPECIAL_CELLS_YES);
-
-  {
-    obj->row_popup_menu = gtk_menu_new ();
-    int i = 0;
-
-    GtkWidget *insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
-    GtkWidget *clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
-
-    gtk_menu_attach (GTK_MENU (obj->row_popup_menu), insert_case,     0, 1, i, i + 1); ++i;
-    gtk_menu_attach (GTK_MENU (obj->row_popup_menu), clear_cases,     0, 1, i, i + 1); ++i;
-
-    g_signal_connect_swapped (clear_cases, "activate", G_CALLBACK (psppire_data_sheet_edit_clear_cases), obj);
-    g_signal_connect_swapped (insert_case, "activate", G_CALLBACK (psppire_data_sheet_insert_case), obj);
-
-    gtk_widget_show_all (obj->row_popup_menu);
-  }
+  PsppireDataStore *store = NULL;
+  g_object_get (sheet, "data-model", &store, NULL);
 
-  {
-    obj->column_popup_menu = gtk_menu_new ();
-    int i = 0;
-
-    GtkWidget *insert_variable = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
-    GtkWidget *clear_variables = gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
-    obj->pu_sort_up = gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
-    obj->pu_sort_down = gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
-
-    g_signal_connect_swapped (clear_variables, "activate", G_CALLBACK (psppire_data_sheet_edit_clear_variables), obj);
-    g_signal_connect_swapped (insert_variable, "activate", G_CALLBACK (psppire_data_sheet_insert_variable), obj);
-
-    g_signal_connect_swapped (obj->pu_sort_up, "activate", G_CALLBACK (on_sort_up), obj);
-    g_signal_connect_swapped (obj->pu_sort_down, "activate", G_CALLBACK (on_sort_down), obj);
-
-    gtk_menu_attach (GTK_MENU (obj->column_popup_menu), insert_variable,     0, 1, i, i + 1); ++i;
-    gtk_menu_attach (GTK_MENU (obj->column_popup_menu), clear_variables,     0, 1, i, i + 1); ++i;
-
-    gtk_menu_attach (GTK_MENU (obj->column_popup_menu), gtk_separator_menu_item_new (),     0, 1, i, i + 1); ++i;
-
-    gtk_menu_attach (GTK_MENU (obj->column_popup_menu), obj->pu_sort_up,             0, 1, i, i + 1); ++i;
-    gtk_menu_attach (GTK_MENU (obj->column_popup_menu), obj->pu_sort_down,           0, 1, i, i + 1); ++i;
-
-    gtk_widget_show_all (obj->column_popup_menu);
-  }
+  const struct variable *var = psppire_dict_get_variable (store->dict, col);
 
+  if (NULL == var)
+    return;
 
-  g_signal_connect (obj, "notify::model",
-                    G_CALLBACK (psppire_data_sheet_model_changed), NULL);
+  union value v;
 
-  pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
-  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
-                                 PSPP_SHEET_SELECTION_RECTANGLE);
+  GVariant *vrnt = g_value_get_variant (value);
 
-  g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, (void *) NULL);
-  g_signal_connect (obj, "query-tooltip",
-                    G_CALLBACK (on_query_tooltip), NULL);
-  g_signal_connect (obj, "button-press-event",
-                    G_CALLBACK (on_button_pressed), NULL);
+  value_variant_get (&v, vrnt);
 
-  g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
+  psppire_data_store_set_value (store, row, var, &v);
 
-  g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
-                    "changed", G_CALLBACK (on_selection_changed), NULL);
+  value_destroy_from_variant (&v, vrnt);
 }
 
-GtkWidget *
-psppire_data_sheet_new (void)
-{
-  return g_object_new (PSPP_TYPE_DATA_SHEET, NULL);
-}
+gboolean myreversefunc (GtkTreeModel *model, gint col, gint row, const gchar *in,
+                   GValue *out);
 
-PsppireDataStore *
-psppire_data_sheet_get_data_store (PsppireDataSheet *data_sheet)
-{
-  return data_sheet->data_store;
-}
+\f
 
 static void
-refresh_model (PsppireDataSheet *data_sheet)
+show_cases_row_popup (PsppireDataSheet *sheet, int row,
+                     uint button, uint state, gpointer p)
 {
-  pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet), NULL);
+  GListModel *vmodel = NULL;
+  g_object_get (sheet, "vmodel", &vmodel, NULL);
+  if (vmodel == NULL)
+    return;
 
-  if (data_sheet->data_store != NULL)
-    {
-      int n_rows = psppire_data_store_get_case_count (data_sheet->data_store) + 1;
-      PsppireEmptyListStore *model = psppire_empty_list_store_new (n_rows);
-      pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet),
-                                 GTK_TREE_MODEL (model));
-      g_object_unref (model);
-    }
-}
+  guint n_items = g_list_model_get_n_items (vmodel);
 
-static void
-on_case_inserted (PsppireDataStore *data_store, gint row,
-                  PsppireDataSheet *data_sheet)
-{
-  PsppireEmptyListStore *empty_list_store;
-  GtkTreeModel *tree_model;
-  gint n_rows;
+  if (row >= n_items)
+    return;
 
-  g_return_if_fail (data_store == data_sheet->data_store);
+  if (button != 3)
+    return;
 
-  n_rows = psppire_data_store_get_case_count (data_store) + 1;
-  if (row == n_rows - 1)
-    row++;
+  g_object_set_data (G_OBJECT (sheet->data_sheet_cases_row_popup), "item",
+                    GINT_TO_POINTER (row));
 
-  tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
-  empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
-  psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
-  psppire_empty_list_store_row_inserted (empty_list_store, row);
+  gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_row_popup), NULL);
 }
 
-static void
-on_cases_deleted (PsppireDataStore *data_store, gint first, gint n_cases,
-                  PsppireDataSheet *data_sheet)
-{
-
-  g_return_if_fail (data_store == data_sheet->data_store);
-
-  if (n_cases > 1)
-    {
-      /* This is a bit of a cop-out.  We could do better, if it ever turns out
-         that this performs too poorly. */
-      refresh_model (data_sheet);
-    }
-  else
-    {
-      PsppireEmptyListStore *empty_list_store;
-      GtkTreeModel *tree_model;
-      gint n_rows = psppire_data_store_get_case_count (data_store) + 1;
-
-      tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
-      empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
-      psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
-      psppire_empty_list_store_row_deleted (empty_list_store, first);
-    }
-}
 
 static void
-on_case_change (PsppireDataStore *data_store, gint row,
-                PsppireDataSheet *data_sheet)
+insert_new_case (PsppireDataSheet *sheet)
 {
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-  pspp_sheet_view_stop_editing (sheet_view, TRUE);
-  gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
-}
+  gint posn = GPOINTER_TO_INT (g_object_get_data
+                               (G_OBJECT (sheet->data_sheet_cases_row_popup), "item"));
 
-static void
-on_backend_changed (PsppireDataStore *data_store,
-                    PsppireDataSheet *data_sheet)
-{
-  g_return_if_fail (data_store == data_sheet->data_store);
-  refresh_model (data_sheet);
+  psppire_data_store_insert_new_case (data_store, posn);
+
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
 }
 
 static void
-on_variable_display_width_changed (PsppireDict *dict, int dict_index,
-                                   PsppireDataSheet *data_sheet)
+delete_cases (PsppireDataSheet *sheet)
 {
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  PsppSheetViewColumn *column;
-  struct variable *var;
-  int display_width;
-  gint pixel_width;
-
-  g_return_if_fail (data_sheet->data_store != NULL);
-  g_return_if_fail (dict == data_sheet->data_store->dict);
-
-  column = psppire_data_sheet_find_column_for_variable (data_sheet,
-                                                        dict_index);
-  if (column == NULL)
-    return;
+  SswRange *range = SSW_SHEET(sheet)->selection;
 
-  var = psppire_dict_get_variable (data_store->dict, dict_index);
-  g_return_if_fail (var != NULL);
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-  pixel_width = pspp_sheet_view_column_get_fixed_width (column);
-  display_width = display_width_from_pixel_width (data_sheet, pixel_width);
-  if (display_width != var_get_display_width (var))
-    {
-      gint base_width, incr_width;
+  psppire_data_store_delete_cases (data_store, range->start_y,
+                                  range->end_y - range->start_y + 1);
 
-      display_width = var_get_display_width (var);
-      calc_width_conversion (data_sheet, &base_width, &incr_width);
-      pixel_width = display_width_to_pixel_width (data_sheet, display_width,
-                                                  base_width, incr_width);
-      pspp_sheet_view_column_set_fixed_width (column, pixel_width);
-    }
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
 }
 
-static void
-on_variable_changed (PsppireDict *dict, int dict_index,
-                    guint what, const struct variable *oldvar,
-                     PsppireDataSheet *data_sheet)
+static GtkWidget *
+create_data_row_header_popup_menu (PsppireDataSheet *sheet)
 {
-  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *cell;
-  struct variable *var;
-  GList *cells;
-  char *name;
+  GtkWidget *menu = gtk_menu_new ();
 
-  g_return_if_fail (data_sheet->data_store != NULL);
-  g_return_if_fail (dict == data_sheet->data_store->dict);
+  GtkWidget *item =
+    gtk_menu_item_new_with_mnemonic  (_("_Insert Case"));
 
+  g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_case), sheet);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
-  if (what & VAR_TRAIT_DISPLAY_WIDTH)
-    on_variable_display_width_changed (dict, dict_index, data_sheet);
-
-  column = psppire_data_sheet_find_column_for_variable (data_sheet,
-                                                        dict_index);
-  if (column == NULL)
-    return;
-
-
-  var = psppire_dict_get_variable (data_store->dict, dict_index);
-  g_return_if_fail (var != NULL);
-
-  name = escape_underscores (var_get_name (var));
-  if (strcmp (name, pspp_sheet_view_column_get_title (column)))
-    pspp_sheet_view_column_set_title (column, name);
-  free (name);
-
-  cells = pspp_sheet_view_column_get_cell_renderers (column);
-  g_return_if_fail (cells);
-  cell = cells->data;
-  g_list_free (cells);
-
-  if (var_has_value_labels (var) != GTK_IS_CELL_RENDERER_COMBO (cell))
-    {
-      /* Stop editing before we delete and replace the cell renderers.
-         Otherwise if this column is currently being edited, an eventual call
-         to pspp_sheet_view_stop_editing() will obtain a NULL cell and pass
-         that to gtk_cell_renderer_stop_editing(), which causes a critical.
+  item = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
-         It's possible that this is a bug in PsppSheetView, and it's possible
-         that PsppSheetView inherits that from GtkTreeView, but I haven't
-         investigated yet. */
-      pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (data_sheet), TRUE);
+  sheet->data_clear_cases_menu_item = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
+  gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, FALSE);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_cases_menu_item);
+  g_signal_connect_swapped (sheet->data_clear_cases_menu_item, "activate",
+                           G_CALLBACK (delete_cases), sheet);
 
-      add_data_column_cell_renderer (data_sheet, column);
-    }
+  gtk_widget_show_all (menu);
+  return menu;
 }
 
-static void
-on_variable_inserted (PsppireDict *dict, int var_index,
-                      PsppireDataSheet *data_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  gint base_width, incr_width;
-  PsppSheetViewColumn *column;
-
-  calc_width_conversion (data_sheet, &base_width, &incr_width);
-  column = make_data_column (data_sheet, var_index, base_width, incr_width);
-  pspp_sheet_view_insert_column (sheet_view, column, var_index + 1);
-}
 
 static void
-on_variable_deleted (PsppireDict *dict,
-                     const struct variable *var, int case_idx, int width,
-                     PsppireDataSheet *data_sheet)
+show_cases_column_popup (PsppireDataSheet *sheet, int column, uint button, uint state,
+                        gpointer p)
 {
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-  GList *columns, *iter;
-
-  columns = pspp_sheet_view_get_columns (sheet_view);
-  for (iter = columns; iter != NULL; iter = iter->next)
-    {
-      PsppSheetViewColumn *column = iter->data;
-      const struct variable *column_var;
+  GListModel *hmodel = NULL;
+  g_object_get (sheet, "hmodel", &hmodel, NULL);
+  if (hmodel == NULL)
+    return;
 
-      column_var = g_object_get_data (G_OBJECT (column), "variable");
-      if (column_var == var)
-        pspp_sheet_view_remove_column (sheet_view, column);
-    }
-  g_list_free (columns);
-}
+  guint n_items = g_list_model_get_n_items (hmodel);
 
-static void
-psppire_data_sheet_unset_data_store (PsppireDataSheet *data_sheet)
-{
-  PsppireDataStore *store = data_sheet->data_store;
+  if (column >= n_items)
+    return;
 
-  if (store == NULL)
+  if (button != 3)
     return;
 
-  data_sheet->data_store = NULL;
-
-  g_signal_handlers_disconnect_by_func (
-    store, G_CALLBACK (on_backend_changed), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store, G_CALLBACK (on_case_inserted), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store, G_CALLBACK (on_cases_deleted), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store, G_CALLBACK (on_case_change), data_sheet);
-
-  g_signal_handlers_disconnect_by_func (
-    store->dict, G_CALLBACK (on_variable_changed), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store->dict, G_CALLBACK (on_variable_display_width_changed), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store->dict, G_CALLBACK (on_variable_inserted), data_sheet);
-  g_signal_handlers_disconnect_by_func (
-    store->dict, G_CALLBACK (on_variable_deleted), data_sheet);
-
-  g_object_unref (store);
+  g_object_set_data (G_OBJECT (sheet->data_sheet_cases_column_popup), "item",
+                    GINT_TO_POINTER (column));
+
+  gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_column_popup), NULL);
 }
 
-void
-psppire_data_sheet_set_data_store (PsppireDataSheet *data_sheet,
-                                PsppireDataStore *data_store)
+static void
+insert_new_variable (PsppireDataSheet *sheet)
 {
-  psppire_data_sheet_unset_data_store (data_sheet);
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-  data_sheet->data_store = data_store;
-  if (data_store != NULL)
-    {
-      g_object_ref (data_store);
-      g_signal_connect (data_store, "backend-changed",
-                        G_CALLBACK (on_backend_changed), data_sheet);
-      g_signal_connect (data_store, "case-inserted",
-                        G_CALLBACK (on_case_inserted), data_sheet);
-      g_signal_connect (data_store, "cases-deleted",
-                        G_CALLBACK (on_cases_deleted), data_sheet);
-      g_signal_connect (data_store, "case-changed",
-                        G_CALLBACK (on_case_change), data_sheet);
-
-      /* XXX it's unclean to hook into the dict this way--what if the dict
-         changes?  As of this writing, though, nothing ever changes the
-         data_store's dict. */
-      g_signal_connect (data_store->dict, "variable-changed",
-                        G_CALLBACK (on_variable_changed),
-                        data_sheet);
-      g_signal_connect (data_store->dict, "variable-inserted",
-                        G_CALLBACK (on_variable_inserted), data_sheet);
-      g_signal_connect (data_store->dict, "variable-deleted",
-                        G_CALLBACK (on_variable_deleted), data_sheet);
-    }
-  refresh_model (data_sheet);
-}
-\f
-/* Clipboard stuff */
+  gint posn = GPOINTER_TO_INT (g_object_get_data
+                               (G_OBJECT (sheet->data_sheet_cases_column_popup),
+                                "item"));
 
-/* A casereader and dictionary holding the data currently in the clip */
-static struct casereader *clip_datasheet = NULL;
-static struct dictionary *clip_dict = NULL;
+  const struct variable *v = psppire_dict_insert_variable (data_store->dict,
+                                                          posn, NULL);
 
+  psppire_data_store_insert_value (data_store, var_get_width(v),
+                                  var_get_case_index (v));
 
-static void psppire_data_sheet_update_clipboard (PsppireDataSheet *);
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
+}
 
-static gboolean
-psppire_data_sheet_fetch_clip (PsppireDataSheet *data_sheet, gboolean cut,
-                               struct casereader **readerp,
-                               struct dictionary **dictp)
+static void
+set_menu_items_sensitivity (PsppireDataSheet *sheet, gpointer selection, gpointer p)
 {
-  struct casewriter *writer ;
-  PsppireDataStore *ds = psppire_data_sheet_get_data_store (data_sheet);
-  struct case_map *map = NULL;
-  struct range_set *rows, *cols;
-  const struct range_set_node *node;
-  struct dictionary *dict;
-
-  if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
-    {
-      *readerp = NULL;
-      *dictp = NULL;
-      return FALSE;
-    }
-
-  /* Construct clip dictionary. */
-  *dictp = dict = dict_create (dict_get_encoding (ds->dict->dict));
-  RANGE_SET_FOR_EACH (node, cols)
-    {
-      int dict_index;
-
-      for (dict_index = node->start; dict_index < node->end; dict_index++)
-        {
-          struct variable *var = dict_get_var (ds->dict->dict, dict_index);
-          dict_clone_var_assert (dict, var);
-        }
-    }
+  SswRange *range = selection;
 
-  /* Construct clip data. */
-  map = case_map_by_name (ds->dict->dict, dict);
-  writer = autopaging_writer_create (dict_get_proto (dict));
-  RANGE_SET_FOR_EACH (node, rows)
-    {
-      unsigned long int row;
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-      for (row = node->start; row < node->end; row++)
-        {
-          struct ccase *old = psppire_data_store_get_case (ds, row);
-          if (old != NULL)
-            casewriter_write (writer, case_map_execute (map, old));
-          else
-            casewriter_force_error (writer);
-        }
-    }
-  case_map_destroy (map);
 
-  /* Clear data that we copied out, if we're doing a "cut". */
-  if (cut && !casewriter_error (writer))
-    {
-      RANGE_SET_FOR_EACH (node, rows)
-        {
-          unsigned long int row;
-
-          for (row = node->start; row < node->end; row++)
-            {
-              const struct range_set_node *node2;
-
-              RANGE_SET_FOR_EACH (node2, cols)
-                {
-                  int dict_index;
-
-                  for (dict_index = node2->start; dict_index < node2->end;
-                       dict_index++)
-                    {
-                      struct variable *var;
-
-                      var = dict_get_var (ds->dict->dict, dict_index);
-                      psppire_data_store_set_string (ds, "", row,
-                                                     var, false);
-                    }
-                }
-            }
-        }
-    }
+  gint width = gtk_tree_model_get_n_columns (GTK_TREE_MODEL (data_store));
+  gint length = psppire_data_store_get_case_count (data_store);
 
-  range_set_destroy (rows);
-  range_set_destroy (cols);
 
-  *readerp = casewriter_make_reader (writer);
+  gboolean whole_row_selected = (range->start_x == 0 && range->end_x == width - 1);
+  gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, whole_row_selected);
 
-  return TRUE;
+  gboolean whole_column_selected =
+    (range->start_y == 0 && range->end_y == length - 1);
+  gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item,
+                           whole_column_selected);
+  gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item,
+                           whole_column_selected);
+  gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item,
+                           whole_column_selected);
 }
 
-/* Set the clip from the currently selected range in DATA_SHEET.  If CUT is
-   true, clears the original data from DATA_SHEET, otherwise leaves the
-   original data in-place. */
 static void
-psppire_data_sheet_set_clip (PsppireDataSheet *data_sheet,
-                             gboolean cut)
+delete_variables (PsppireDataSheet *sheet)
 {
-  struct casereader *reader;
-  struct dictionary *dict;
+  SswRange *range = SSW_SHEET(sheet)->selection;
 
-  if (psppire_data_sheet_fetch_clip (data_sheet, cut, &reader, &dict))
-    {
-      casereader_destroy (clip_datasheet);
-      dict_destroy (clip_dict);
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-      clip_datasheet = reader;
-      clip_dict = dict;
+  psppire_dict_delete_variables (data_store->dict, range->start_x,
+                                (range->end_x - range->start_x + 1));
 
-      psppire_data_sheet_update_clipboard (data_sheet);
-    }
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
 }
 
-enum {
-  SELECT_FMT_NULL,
-  SELECT_FMT_TEXT,
-  SELECT_FMT_HTML
-};
 
 
-/* Perform data_out for case CC, variable V, appending to STRING */
-static void
-data_out_g_string (GString *string, const struct variable *v,
-                  const struct ccase *cc)
+static GtkWidget *
+create_data_column_header_popup_menu (PsppireDataSheet *sheet)
 {
-  const struct fmt_spec *fs = var_get_print_format (v);
-  const union value *val = case_data (cc, v);
+  GtkWidget *menu = gtk_menu_new ();
 
-  char *s = data_out (val, var_get_encoding (v), fs);
+  GtkWidget *item =
+    gtk_menu_item_new_with_mnemonic  (_("_Insert Variable"));
+  g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_variable),
+                           sheet);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
-  g_string_append (string, s);
+  item = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
-  g_free (s);
-}
+  sheet->data_clear_variables_menu_item =
+    gtk_menu_item_new_with_mnemonic  (_("Cl_ear Variables"));
+  g_signal_connect_swapped (sheet->data_clear_variables_menu_item, "activate",
+                           G_CALLBACK (delete_variables),
+                           sheet);
+  gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item, FALSE);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_variables_menu_item);
 
-static GString *
-clip_to_text (struct casereader *datasheet, struct dictionary *dict)
-{
-  casenumber r;
-  GString *string;
+  item = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
-  const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
-  const casenumber case_cnt = casereader_get_case_cnt (datasheet);
-  const size_t var_cnt = dict_get_var_cnt (dict);
 
-  string = g_string_sized_new (10 * val_cnt * case_cnt);
+  sheet->data_sort_ascending_menu_item =
+    gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
+  g_signal_connect_swapped (sheet->data_sort_ascending_menu_item, "activate",
+                           G_CALLBACK (sort_ascending), sheet);
+  gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item, FALSE);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_ascending_menu_item);
 
-  for (r = 0 ; r < case_cnt ; ++r )
-    {
-      int c;
-      struct ccase *cc;
-
-      cc = casereader_peek (datasheet, r);
-      if (cc == NULL)
-       {
-         g_warning ("Clipboard seems to have inexplicably shrunk");
-         break;
-       }
-
-      for (c = 0 ; c < var_cnt ; ++c)
-       {
-         const struct variable *v = dict_get_var (dict, c);
-         data_out_g_string (string, v, cc);
-         if ( c < val_cnt - 1 )
-           g_string_append (string, "\t");
-       }
-
-      if ( r < case_cnt)
-       g_string_append (string, "\n");
-
-      case_unref (cc);
-    }
+  sheet->data_sort_descending_menu_item =
+    gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
+  g_signal_connect_swapped (sheet->data_sort_descending_menu_item, "activate",
+                           G_CALLBACK (sort_descending), sheet);
+  gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item, FALSE);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_descending_menu_item);
 
-  return string;
+  gtk_widget_show_all (menu);
+  return menu;
 }
 
 
-static GString *
-clip_to_html (struct casereader *datasheet, struct dictionary *dict)
-{
-  casenumber r;
-  GString *string;
-
-  const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
-  const casenumber case_cnt = casereader_get_case_cnt (datasheet);
-  const size_t var_cnt = dict_get_var_cnt (dict);
-
-  /* Guestimate the size needed */
-  string = g_string_sized_new (80 + 20 * val_cnt * case_cnt);
-
-  g_string_append (string,
-                  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
-
-  g_string_append (string, "<table>\n");
-  for (r = 0 ; r < case_cnt ; ++r )
-    {
-      int c;
-      struct ccase *cc = casereader_peek (datasheet, r);
-      if (cc == NULL)
-       {
-         g_warning ("Clipboard seems to have inexplicably shrunk");
-         break;
-       }
-      g_string_append (string, "<tr>\n");
-
-      for (c = 0 ; c < var_cnt ; ++c)
-       {
-         const struct variable *v = dict_get_var (dict, c);
-         g_string_append (string, "<td>");
-         data_out_g_string (string, v, cc);
-         g_string_append (string, "</td>\n");
-       }
-
-      g_string_append (string, "</tr>\n");
-
-      case_unref (cc);
-    }
-  g_string_append (string, "</table>\n");
-
-  return string;
-}
+\f
 
+G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, SSW_TYPE_SHEET)
 
+static GObjectClass * parent_class = NULL;
+static gboolean dispose_has_run = FALSE;
 
 static void
-psppire_data_sheet_clipboard_set (GtkSelectionData *selection_data,
-                                  guint             info,
-                                  struct casereader *reader,
-                                  struct dictionary *dict)
+psppire_data_sheet_dispose (GObject *obj)
 {
-  GString *string = NULL;
-
-  switch (info)
-    {
-    case SELECT_FMT_TEXT:
-      string = clip_to_text (reader, dict);
-      break;
-    case SELECT_FMT_HTML:
-      string = clip_to_html (reader, dict);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
+  //  PsppireDataSheet *sheet = PSPPIRE_DATA_SHEET (obj);
 
-  gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
-                         8,
-                         (const guchar *) string->str, string->len);
+  if (dispose_has_run)
+    return;
 
-  g_string_free (string, TRUE);
-}
+  dispose_has_run = TRUE;
 
-static void
-psppire_data_sheet_clipboard_get_cb (GtkClipboard     *clipboard,
-                                     GtkSelectionData *selection_data,
-                                     guint             info,
-                                     gpointer          data)
-{
-  psppire_data_sheet_clipboard_set (selection_data, info,
-                                    clip_datasheet, clip_dict);
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 
 static void
-psppire_data_sheet_clipboard_clear_cb (GtkClipboard *clipboard,
-                                       gpointer data)
+psppire_data_sheet_class_init (PsppireDataSheetClass *class)
 {
-  dict_destroy (clip_dict);
-  clip_dict = NULL;
-
-  casereader_destroy (clip_datasheet);
-  clip_datasheet = NULL;
-}
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  object_class->dispose = psppire_data_sheet_dispose;
 
-
-static const GtkTargetEntry targets[] = {
-  { "UTF8_STRING",   0, SELECT_FMT_TEXT },
-  { "STRING",        0, SELECT_FMT_TEXT },
-  { "TEXT",          0, SELECT_FMT_TEXT },
-  { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
-  { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
-  { "text/plain",    0, SELECT_FMT_TEXT },
-  { "text/html",     0, SELECT_FMT_HTML }
-};
-
-
-
-static void
-psppire_data_sheet_update_clipboard (PsppireDataSheet *sheet)
-{
-  GtkClipboard *clipboard =
-    gtk_widget_get_clipboard (GTK_WIDGET (sheet),
-                             GDK_SELECTION_CLIPBOARD);
-
-  if (!gtk_clipboard_set_with_owner (clipboard, targets,
-                                    G_N_ELEMENTS (targets),
-                                    psppire_data_sheet_clipboard_get_cb,
-                                     psppire_data_sheet_clipboard_clear_cb,
-                                    G_OBJECT (sheet)))
-    psppire_data_sheet_clipboard_clear_cb (clipboard, sheet);
+  parent_class = g_type_class_peek_parent (class);
 }
 
-static void
-psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
+GtkWidget*
+psppire_data_sheet_new (void)
 {
-  struct range_set *rows, *cols;
-  GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
-  if (! PSPPIRE_IS_DATA_WINDOW (top))
-    return;
-
-  PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
-  gboolean enable =
-    psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols);
-
-  if (enable)
-    {
-      range_set_destroy (rows);
-      range_set_destroy (cols);
-    }
+  GObject *obj =
+    g_object_new (PSPPIRE_TYPE_DATA_SHEET,
+                 "forward-conversion", psppire_data_store_value_to_string,
+                 "reverse-conversion", myreversefunc,
+                 NULL);
 
-  gtk_widget_set_sensitive (dw->mi_copy, enable);
-  gtk_widget_set_sensitive (dw->mi_cut, enable);
+  return GTK_WIDGET (obj);
 }
 
 static void
-psppire_data_sheet_primary_get_cb (GtkClipboard     *clipboard,
-                                   GtkSelectionData *selection_data,
-                                   guint             info,
-                                   gpointer          data)
+set_dictionary (PsppireDataSheet *sheet)
 {
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
-  struct casereader *reader;
-  struct dictionary *dict;
+  GtkTreeModel *data_model = NULL;
+  g_object_get (sheet, "data-model", &data_model, NULL);
 
-  if (psppire_data_sheet_fetch_clip (data_sheet, FALSE, &reader, &dict))
-    {
-      psppire_data_sheet_clipboard_set (selection_data, info,
-                                        reader, dict);
-      casereader_destroy (reader);
-      dict_destroy (dict);
-    }
+  PsppireDataStore *store = PSPPIRE_DATA_STORE (data_model);
+  g_object_set (sheet, "hmodel", store->dict, NULL);
 }
 
 static void
-psppire_data_sheet_update_primary_selection (PsppireDataSheet *data_sheet,
-                                             gboolean should_own)
-{
-  GtkClipboard *clipboard;
-  GdkDisplay *display;
-
-  display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
-  clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_PRIMARY);
-  g_return_if_fail (clipboard != NULL);
-
-  if (data_sheet->owns_primary_selection && !should_own)
-    {
-      data_sheet->owns_primary_selection = FALSE;
-      gtk_clipboard_clear (clipboard);
-    }
-  else if (should_own)
-    data_sheet->owns_primary_selection =
-      gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
-                                    psppire_data_sheet_primary_get_cb,
-                                    NULL, G_OBJECT (data_sheet));
-}
-\f
-/* A callback for when the clipboard contents have been received. */
-static void
-psppire_data_sheet_clip_received_cb (GtkClipboard *clipboard,
-                                     GtkSelectionData *sd,
-                                     gpointer data)
+move_variable (PsppireDataSheet *sheet, gint from, gint to, gpointer ud)
 {
-  PsppireDataSheet *data_sheet = data;
-  PsppireDataStore *store = data_sheet->data_store;
-  struct range_set *rows, *cols;
-  gint count = 0;
-  gint next_row, next_column;
-  gint first_column;
-  char *c;
-
-  if ( gtk_selection_data_get_length (sd) < 0 )
-    return;
+  PsppireDataStore *data_store = NULL;
+  g_object_get (sheet, "data-model", &data_store, NULL);
 
-  if ( gtk_selection_data_get_data_type (sd) != gdk_atom_intern ("UTF8_STRING", FALSE))
+  if (data_store == NULL)
     return;
 
-  c = (char *) gtk_selection_data_get_data (sd);
+  PsppireDict *dict = data_store->dict;
+  struct variable *var = psppire_dict_get_variable (dict, from);
 
-  /* Get the starting selected position in the data sheet.  (Possibly we should
-     only paste into the selected range if it's larger than one cell?) */
-  if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
+  if (var == NULL)
     return;
-  next_row = range_set_first (rows)->start;
-  first_column = next_column = range_set_first (cols)->start;
-  range_set_destroy (rows);
-  range_set_destroy (cols);
-
-  g_return_if_fail (next_row >= 0);
-  g_return_if_fail (next_column >= 0);
-
-  while (count < gtk_selection_data_get_length (sd))
-    {
-      gint row = next_row;
-      gint column = next_column;
-      struct variable *var;
-      char *s = c;
-
-      while (*c != '\t' && *c != '\n' && count < gtk_selection_data_get_length (sd))
-        {
-          c++;
-          count++;
-        }
-      if ( *c == '\t')
-        {
-          next_row = row ;
-          next_column = column + 1;
-        }
-      else if ( *c == '\n')
-        {
-          next_row = row + 1;
-          next_column = first_column;
-        }
-      *c++ = '\0';
-      count++;
-
-      var = psppire_dict_get_variable (store->dict, column);
-      if (var != NULL)
-        psppire_data_store_set_string (store, s, row, var, FALSE);
-    }
+  gint new_pos = to;
+  /* The index refers to the final position, so if the source
+     is less than the destination, then we must subtract 1, to
+     account for the position vacated by the source */
+  if (from < to)
+    new_pos--;
+  dict_reorder_var (dict->dict, var, new_pos);
 }
 
 static void
-psppire_data_sheet_targets_received_cb (GtkClipboard *clipboard,
-                                        GdkAtom *atoms,
-                                        gint n_atoms,
-                                        gpointer data)
+psppire_data_sheet_init (PsppireDataSheet *sheet)
 {
-  GtkWidget *mi = GTK_WIDGET (data);
-  gboolean compatible_target = FALSE;
-  gint i;
-  for (i = 0; i < G_N_ELEMENTS (targets); i++)
-    {
-      GdkAtom target = gdk_atom_intern (targets[i].target, TRUE);
-      gint j;
-
-      for (j = 0; j < n_atoms; j++)
-        if (target == atoms[j])
-          {
-            compatible_target = TRUE;
-            break;
-          }
-    }
+  sheet->data_sheet_cases_column_popup =
+    create_data_column_header_popup_menu (sheet);
 
-  gtk_widget_set_sensitive (mi, compatible_target);
-}
+  sheet->data_sheet_cases_row_popup =
+    create_data_row_header_popup_menu (sheet);
 
-static void
-on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
-{
-  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
+  g_signal_connect (sheet, "selection-changed",
+                   G_CALLBACK (set_menu_items_sensitivity), sheet);
 
-  GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
-  if (! PSPPIRE_IS_DATA_WINDOW (top))
-    return;
+  g_signal_connect (sheet, "column-header-pressed",
+                   G_CALLBACK (show_cases_column_popup), sheet);
+
+  g_signal_connect (sheet, "row-header-pressed",
+                   G_CALLBACK (show_cases_row_popup), sheet);
+
+  g_signal_connect (sheet, "value-changed",
+                   G_CALLBACK (change_data_value), NULL);
 
-  PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
+  g_signal_connect (sheet, "notify::data-model",
+                   G_CALLBACK (set_dictionary), NULL);
 
-  gtk_clipboard_request_targets (clip,
-                                psppire_data_sheet_targets_received_cb,
-                                dw->mi_paste);
+  g_signal_connect (sheet, "column-moved", G_CALLBACK (move_variable), NULL);
 }
index 3870a92099b49b7f71010e6d132a74e487f5c714..49e7a1751c36a6c64b766bc11212c3bb1f4eb757 100644 (file)
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
+    Copyright (C) 2017  John Darrington
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 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.
+    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, see <http://www.gnu.org/licenses/>. */
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
-#ifndef PSPPIRE_DATA_SHEET_H
-#define PSPPIRE_DATA_SHEET_H 1
-
-/* PsppireDataSheet is a PsppSheetView that displays the data in a dataset,
-   with one column per variable and one row per case.
-
-   PsppireDataSheet is usually a child of PsppireDataEditor in the widget
-   hierarchy.  Other widgets can also use it. */
+#ifndef _PSPPIRE_DATA_SHEET_H
+#define _PSPPIRE_DATA_SHEET_H
 
 #include <gtk/gtk.h>
-#include "ui/gui/pspp-sheet-view.h"
-
-G_BEGIN_DECLS
-
-#define PSPP_TYPE_DATA_SHEET              (psppire_data_sheet_get_type())
-#define PSPPIRE_DATA_SHEET(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheet))
-#define PSPPIRE_DATA_SHEET_CLASS(class)   (G_TYPE_CHECK_CLASS_CAST ((class),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
-#define PSPP_IS_DATA_SHEET(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPP_TYPE_DATA_SHEET))
-#define PSPP_IS_DATA_SHEET_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class),PSPP_TYPE_DATA_SHEET))
-#define PSPPIRE_DATA_SHEET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
-
-typedef struct _PsppireDataSheet      PsppireDataSheet;
-typedef struct _PsppireDataSheetClass PsppireDataSheetClass;
+#include <ssw-sheet.h>
 
 struct _PsppireDataSheet
 {
-  PsppSheetView parent;
-
-  struct _PsppireDataStore *data_store;
-  gboolean show_value_labels;
-  gboolean show_case_numbers;
-  gboolean may_create_vars;
-  gboolean may_delete_vars;
+  SswSheet parent_instance;
 
-  gboolean owns_primary_selection;
+  GtkWidget *data_sheet_cases_column_popup;
 
-  guint scroll_to_bottom_signal;
-  guint scroll_to_right_signal;
+  GtkWidget *data_clear_variables_menu_item;
+  GtkWidget *data_clear_cases_menu_item;
+  GtkWidget *data_sheet_cases_row_popup;
 
-  GtkClipboard *clip;
-  guint on_owner_change_signal;
-
-  PsppSheetViewColumn *new_variable_column;
-
-  GtkWidget *container;
-  gboolean dispose_has_run;
-
-  GtkWidget *column_popup_menu;
-  GtkWidget *row_popup_menu;
-
-  GtkWidget *pu_sort_up;
-  GtkWidget *pu_sort_down;
+  /* Data sheet popup menu */
+  GtkWidget *data_sort_ascending_menu_item;
+  GtkWidget *data_sort_descending_menu_item;
 };
 
 struct _PsppireDataSheetClass
 {
-  PsppSheetViewClass parent_class;
+  SswSheetClass parent_class;
 };
 
-GType psppire_data_sheet_get_type (void) G_GNUC_CONST;
-GtkWidget *psppire_data_sheet_new (void);
+#define PSPPIRE_TYPE_DATA_SHEET psppire_data_sheet_get_type ()
 
-struct _PsppireDataStore *psppire_data_sheet_get_data_store (PsppireDataSheet *);
-void psppire_data_sheet_set_data_store (PsppireDataSheet *,
-                                        struct _PsppireDataStore *);
+G_DECLARE_FINAL_TYPE (PsppireDataSheet, psppire_data_sheet, PSPPIRE, DATA_SHEET, SswSheet)
 
-gboolean psppire_data_sheet_get_value_labels (const PsppireDataSheet *);
-void psppire_data_sheet_set_value_labels (PsppireDataSheet *,
-                                          gboolean show_value_labels);
-
-gboolean psppire_data_sheet_get_case_numbers (const PsppireDataSheet *);
-void psppire_data_sheet_set_case_numbers (PsppireDataSheet *,
-                                          gboolean show_case_numbers);
-
-gboolean psppire_data_sheet_get_may_create_vars (PsppireDataSheet *);
-void psppire_data_sheet_set_may_create_vars (PsppireDataSheet *, gboolean);
-
-gboolean psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *);
-void psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *, gboolean);
-
-void psppire_data_sheet_goto_variable (PsppireDataSheet *, gint dict_index);
-struct variable *psppire_data_sheet_get_current_variable (const PsppireDataSheet *);
-
-void psppire_data_sheet_goto_case (PsppireDataSheet *, gint case_index);
-gint psppire_data_sheet_get_selected_case (const PsppireDataSheet *);
-gint psppire_data_sheet_get_current_case (const PsppireDataSheet *);
-
-void psppire_data_sheet_insert_case (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_insert_variable (PsppireDataSheet *data_sheet);
-
-void psppire_data_sheet_edit_cut (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_copy (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_paste (PsppireDataSheet *data_sheet);
-
-void psppire_data_sheet_edit_clear_cases (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_clear_variables (PsppireDataSheet *data_sheet);
-
-G_END_DECLS
+GtkWidget *psppire_data_sheet_new (void);
 
-#endif /* PSPPIRE_DATA_SHEET_H */
+#endif
index 59099a153e9297961a659d3bfc1a59b6d70c0ff9..c0843b1a6729496ee445c954c72b3da3055c4436 100644 (file)
@@ -1,5 +1,6 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012, 2013, 2016  Free Software Foundation
+   Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012,
+   2013, 2016, 2017  Free Software Foundation
 
    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
@@ -19,7 +20,7 @@
 #include <stdlib.h>
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
+#define P_(msgid) msgid
 
 #include <data/datasheet.h>
 #include <data/data-out.h>
@@ -44,7 +45,7 @@
 #include "xalloc.h"
 #include "xmalloca.h"
 
-
+#include "value-variant.h"
 
 static void psppire_data_store_init            (PsppireDataStore      *data_store);
 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
@@ -67,15 +68,192 @@ static GObjectClass *parent_class = NULL;
 
 enum
   {
-    BACKEND_CHANGED,
-    CASES_DELETED,
-    CASE_INSERTED,
+    ITEMS_CHANGED,
     CASE_CHANGED,
     n_SIGNALS
   };
 
 static guint signals [n_SIGNALS];
 
+static gint
+__tree_model_iter_n_children (GtkTreeModel *tree_model,
+                            GtkTreeIter *iter)
+{
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
+
+  if (store->datasheet == NULL)
+    return 0;
+
+  gint n =  datasheet_get_n_rows (store->datasheet);
+
+  return n;
+}
+
+static GtkTreeModelFlags
+__tree_model_get_flags (GtkTreeModel *model)
+{
+  g_return_val_if_fail (PSPPIRE_IS_DATA_STORE (model), (GtkTreeModelFlags) 0);
+
+  return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+__tree_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
+
+  return psppire_dict_get_var_cnt (store->dict);
+}
+
+
+static gboolean
+__iter_nth_child (GtkTreeModel *tree_model,
+                 GtkTreeIter *iter,
+                 GtkTreeIter *parent,
+                 gint n)
+{
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
+
+  g_assert (parent == NULL);
+  g_return_val_if_fail (store, FALSE);
+
+  if (!store->datasheet || n >= datasheet_get_n_rows (store->datasheet))
+    {
+      iter->stamp = -1;
+      iter->user_data = NULL;
+      return FALSE;
+    }
+
+  iter->user_data = GINT_TO_POINTER (n);
+  iter->stamp = store->stamp;
+
+  return TRUE;
+}
+
+gboolean
+myreversefunc (GtkTreeModel *model, gint col, gint row,
+              const gchar *in, GValue *out)
+{
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (model);
+
+  const struct variable *variable = psppire_dict_get_variable (store->dict, col);
+  g_return_val_if_fail (variable, FALSE);
+
+  const struct fmt_spec *fmt = var_get_print_format (variable);
+
+  int width = var_get_width (variable);
+
+  union value val;
+  value_init (&val, width);
+  char *xx =
+    data_in (ss_cstr (in), psppire_dict_encoding (store->dict),
+            fmt->type, &val, width, "UTF-8");
+
+  GVariant *vrnt = value_variant_new (&val, width);
+  value_destroy (&val, width);
+
+  g_value_init (out, G_TYPE_VARIANT);
+  g_value_set_variant (out, vrnt);
+  free (xx);
+  return TRUE;
+}
+
+static char *
+unlabeled_value (PsppireDataStore *store, const struct variable *variable, const union value *val)
+{
+  const struct fmt_spec *fmt = var_get_print_format (variable);
+  return data_out (val, psppire_dict_encoding (store->dict),  fmt);
+}
+
+gchar *
+psppire_data_store_value_to_string (gpointer unused, PsppireDataStore *store, gint col, gint row, const GValue *v)
+{
+  const struct variable *variable = psppire_dict_get_variable (store->dict, col);
+  g_return_val_if_fail (variable, g_strdup ("???"));
+
+  GVariant *vrnt = g_value_get_variant (v);
+  union value val;
+  value_variant_get (&val, vrnt);
+
+  char *out = unlabeled_value (store, variable, &val);
+
+  value_destroy_from_variant (&val, vrnt);
+
+  return out;
+}
+
+gchar *
+psppire_data_store_value_to_string_with_labels (gpointer unused, PsppireDataStore *store, gint col, gint row, const GValue *v)
+{
+  const struct variable *variable = psppire_dict_get_variable (store->dict, col);
+  g_return_val_if_fail (variable, g_strdup ("???"));
+
+  GVariant *vrnt = g_value_get_variant (v);
+  union value val;
+  value_variant_get (&val, vrnt);
+
+  char *out = NULL;
+
+  const struct val_labs *vls = var_get_value_labels (variable);
+  struct val_lab *vl = val_labs_lookup (vls, &val);
+  if (vl != NULL)
+    out = strdup (val_lab_get_label (vl));
+  else
+    out = unlabeled_value (store, variable, &val);
+
+  value_destroy_from_variant (&val, vrnt);
+
+  return out;
+}
+
+static void
+__get_value (GtkTreeModel *tree_model,
+            GtkTreeIter *iter,
+            gint column,
+            GValue *value)
+{
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
+
+  g_return_if_fail (iter->stamp == store->stamp);
+
+  const struct variable *variable = psppire_dict_get_variable (store->dict, column);
+  if (NULL == variable)
+    return;
+
+  g_value_init (value, G_TYPE_VARIANT);
+
+  gint row = GPOINTER_TO_INT (iter->user_data);
+
+  struct ccase *cc = datasheet_get_row (store->datasheet, row);
+
+  const union value *val = case_data_idx (cc, var_get_case_index (variable));
+
+  GVariant *vv = value_variant_new (val, var_get_width (variable));
+
+  g_value_set_variant (value, vv);
+
+  case_unref (cc);
+}
+
+
+static void
+__tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags       = __tree_model_get_flags;
+  iface->get_n_columns   = __tree_model_get_n_columns ;
+  iface->get_column_type = NULL;
+  iface->get_iter        = NULL;
+  iface->iter_next       = NULL;
+  iface->get_path        = NULL;
+  iface->get_value       = __get_value;
+
+  iface->iter_children   = NULL;
+  iface->iter_has_child  = NULL;
+  iface->iter_n_children = __tree_model_iter_n_children;
+  iface->iter_nth_child  = __iter_nth_child;
+  iface->iter_parent     = NULL;
+}
+
 
 GType
 psppire_data_store_get_type (void)
@@ -97,9 +275,18 @@ psppire_data_store_get_type (void)
         (GInstanceInitFunc) psppire_data_store_init,
       };
 
+      static const GInterfaceInfo tree_model_info = {
+       (GInterfaceInitFunc) __tree_model_init,
+       NULL,
+       NULL
+      };
+
       data_store_type = g_type_register_static (G_TYPE_OBJECT,
                                                "PsppireDataStore",
                                                &data_store_info, 0);
+
+      g_type_add_interface_static (data_store_type, GTK_TYPE_TREE_MODEL,
+                                  &tree_model_info);
     }
 
   return data_store_type;
@@ -117,27 +304,18 @@ psppire_data_store_class_init (PsppireDataStoreClass *class)
   object_class->finalize = psppire_data_store_finalize;
   object_class->dispose = psppire_data_store_dispose;
 
-  signals [BACKEND_CHANGED] =
-    g_signal_new ("backend-changed",
-                 G_TYPE_FROM_CLASS (class),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-
-  signals [CASE_INSERTED] =
-    g_signal_new ("case-inserted",
+  signals [ITEMS_CHANGED] =
+    g_signal_new ("items-changed",
                  G_TYPE_FROM_CLASS (class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
+                 psppire_marshal_VOID__UINT_UINT_UINT,
                  G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
+                 3,
+                 G_TYPE_UINT,  /* Index of the start of the change */
+                 G_TYPE_UINT,  /* The number of items deleted */
+                 G_TYPE_UINT); /* The number of items inserted */
 
   signals [CASE_CHANGED] =
     g_signal_new ("case-changed",
@@ -149,26 +327,10 @@ psppire_data_store_class_init (PsppireDataStoreClass *class)
                  G_TYPE_NONE,
                  1,
                  G_TYPE_INT);
-
-  signals [CASES_DELETED] =
-    g_signal_new ("cases-deleted",
-                 G_TYPE_FROM_CLASS (class),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 psppire_marshal_VOID__INT_INT,
-                 G_TYPE_NONE,
-                 2,
-                 G_TYPE_INT,
-                 G_TYPE_INT);
 }
 
 
 
-static gboolean
-psppire_data_store_insert_value (PsppireDataStore *ds,
-                                 gint width, gint where);
-
 casenumber
 psppire_data_store_get_case_count (const PsppireDataStore *store)
 {
@@ -193,8 +355,19 @@ psppire_data_store_init (PsppireDataStore *data_store)
   data_store->dict = NULL;
   data_store->datasheet = NULL;
   data_store->dispose_has_run = FALSE;
+  data_store->stamp = g_random_int ();
+}
+
+
+static void
+psppire_data_store_delete_value (PsppireDataStore *store, gint case_index)
+{
+  g_return_if_fail (store->datasheet);
+  datasheet_delete_columns (store->datasheet, case_index, 1);
+  datasheet_insert_column (store->datasheet, NULL, -1, case_index);
 }
 
+
 /*
    A callback which occurs after a variable has been deleted.
  */
@@ -205,10 +378,7 @@ delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
 {
   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
 
-  g_return_if_fail (store->datasheet);
-
-  datasheet_delete_columns (store->datasheet, case_index, 1);
-  datasheet_insert_column (store->datasheet, NULL, -1, case_index);
+  psppire_data_store_delete_value (store, case_index);
 }
 
 struct resize_datum_aux
@@ -292,12 +462,17 @@ psppire_data_store_set_reader (PsppireDataStore *ds,
                               struct casereader *reader)
 {
   gint i;
-
+  gint old_n = 0;
   if ( ds->datasheet)
-    datasheet_destroy (ds->datasheet);
+    {
+      old_n = datasheet_get_n_rows (ds->datasheet);
+      datasheet_destroy (ds->datasheet);
+    }
 
   ds->datasheet = datasheet_create (reader);
 
+  gint new_n = datasheet_get_n_rows (ds->datasheet);
+
   if ( ds->dict )
     for (i = 0 ; i < n_dict_signals; ++i )
       {
@@ -308,7 +483,7 @@ psppire_data_store_set_reader (PsppireDataStore *ds,
          }
       }
 
-  g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
+  g_signal_emit (ds, signals[ITEMS_CHANGED], 0, 0, old_n, new_n);
 }
 
 
@@ -426,6 +601,27 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
   return result;
 }
 
+gboolean
+psppire_data_store_get_value (PsppireDataStore *store,
+                             glong row, const struct variable *var,
+                             union value *val)
+{
+  g_return_val_if_fail (store != NULL, FALSE);
+  g_return_val_if_fail (store->datasheet != NULL, FALSE);
+  g_return_val_if_fail (var != NULL, FALSE);
+
+  if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
+    return FALSE;
+
+  int width = var_get_width (var);
+  value_init (val, width);
+  datasheet_get_value (store->datasheet, row, var_get_case_index (var), val);
+
+  return TRUE;
+}
+
+
+
 gchar *
 psppire_data_store_get_string (PsppireDataStore *store,
                                glong row, const struct variable *var,
@@ -433,19 +629,10 @@ psppire_data_store_get_string (PsppireDataStore *store,
 {
   gchar *string;
   union value v;
-  int width;
-
-  g_return_val_if_fail (store != NULL, NULL);
-  g_return_val_if_fail (store->datasheet != NULL, NULL);
-  g_return_val_if_fail (var != NULL, NULL);
-
-  if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
+  int width = var_get_width (var);
+  if (! psppire_data_store_get_value (store, row, var, &v))
     return NULL;
 
-  width = var_get_width (var);
-  value_init (&v, width);
-  datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
-
   string = NULL;
   if (use_value_label)
     {
@@ -515,7 +702,7 @@ psppire_data_store_clear (PsppireDataStore *ds)
 
   psppire_dict_clear (ds->dict);
 
-  g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
+  g_signal_emit (ds, signals [ITEMS_CHANGED], 0, 0, -1, 0);
 }
 
 
@@ -568,7 +755,7 @@ psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
 
   datasheet_delete_rows (ds->datasheet, first, n_cases);
 
-  g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
+  g_signal_emit (ds, signals[ITEMS_CHANGED], 0, first, n_cases, 0);
 
   return TRUE;
 }
@@ -590,7 +777,9 @@ psppire_data_store_insert_case (PsppireDataStore *ds,
   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
 
   if ( result )
-    g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
+    {
+      g_signal_emit (ds, signals[ITEMS_CHANGED], 0, posn, 0, 1);
+    }
   else
     g_warning ("Cannot insert case at position %ld\n", posn);
 
@@ -665,7 +854,7 @@ psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
    given WIDTH into every one of them at the position immediately
    preceding WHERE.
 */
-static gboolean
+gboolean
 psppire_data_store_insert_value (PsppireDataStore *ds,
                                  gint width, gint where)
 {
index 47ce5e5e729d22dc5f99325b30ceeb9d9c8dd6d5..65e3d24ad3d495fe4531f63da7d51443ebd4546b 100644 (file)
@@ -72,6 +72,7 @@ struct _PsppireDataStore
   gboolean dispose_has_run ;
   PsppireDict *dict;
   struct datasheet *datasheet;
+  gint stamp;
 
   gint dict_handler_id [n_dict_signals];
 };
@@ -96,6 +97,8 @@ void psppire_data_store_clear (PsppireDataStore *data_store);
 
 gboolean psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn);
 
+gboolean psppire_data_store_insert_value (PsppireDataStore *ds,
+                                         gint width, gint where);
 
 gboolean psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first, casenumber count);
 
@@ -105,10 +108,26 @@ struct casereader * psppire_data_store_get_reader (PsppireDataStore *ds);
 gchar *psppire_data_store_get_string (PsppireDataStore *,
                                       glong row, const struct variable *,
                                       bool use_value_label);
+
+gchar * psppire_data_store_value_to_string (gpointer unused, PsppireDataStore *store,
+                                           gint col, gint row,
+                                           const GValue *v);
+
+gchar * psppire_data_store_value_to_string_with_labels (gpointer unused, PsppireDataStore *store,
+                                           gint col, gint row,
+                                           const GValue *v);
+
+
+gboolean psppire_data_store_get_value (PsppireDataStore *store,
+                                      glong row, const struct variable *var,
+                                      union value *val);
+
 gboolean psppire_data_store_set_value (PsppireDataStore *,
                                        casenumber casenum,
                                        const struct variable *,
                                        const union value *);
+
+
 gboolean psppire_data_store_set_string (PsppireDataStore *ds,
                                        const gchar *text,
                                        glong row, const struct variable *,
index 15fe2e9fe956616965ef5c5f98adeca2b1c37b51..b46cddd1f259b01d9a99d68566fa27a1caae9561 100644 (file)
@@ -1,5 +1,6 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014,
+   2016, 2017  Free Software Foundation
 
    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
 #include "ui/gui/helper.h"
 #include "ui/gui/psppire-import-assistant.h"
 #include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-data-editor.h"
 #include "ui/gui/psppire-dialog-action.h"
 #include "ui/gui/psppire-encoding-selector.h"
 #include "ui/gui/psppire-syntax-window.h"
 #include "ui/gui/psppire-window.h"
-#include "ui/gui/psppire-data-sheet.h"
-#include "ui/gui/psppire-var-sheet.h"
 #include "ui/gui/windows-menu.h"
 #include "ui/gui/goto-case-dialog.h"
 #include "ui/gui/psppire.h"
@@ -47,6 +47,8 @@
 #include "gl/c-strcasestr.h"
 #include "gl/xvasprintf.h"
 
+#include <ssw-sheet.h>
+
 #include "find-dialog.h"
 #include "options-dialog.h"
 #include "psppire-dialog-action-1sks.h"
@@ -969,14 +971,9 @@ file_import (PsppireDataWindow *dw)
   PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
   gtk_widget_show_all (w);
 
-  asst->main_loop = g_main_loop_new (NULL, TRUE);
-  g_main_loop_run (asst->main_loop);
-  g_main_loop_unref (asst->main_loop);
-
-  if (!asst->file_name)
-    goto end;
+  int response = psppire_import_assistant_run (asst);
 
-  switch (asst->response)
+  switch (response)
     {
     case GTK_RESPONSE_APPLY:
       {
@@ -992,7 +989,6 @@ file_import (PsppireDataWindow *dw)
       break;
     }
 
- end:
   gtk_widget_destroy (GTK_WIDGET (asst));
 }
 
@@ -1068,10 +1064,52 @@ static void
 on_cut (PsppireDataWindow *dw)
 {
   int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
-    {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_edit_cut (ds);
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
+  {
+      PsppireDict *dict = NULL;
+      g_object_get (dw->data_editor, "dictionary", &dict, NULL);
+
+      gint x, y;
+      SswSheet *sheet = SSW_SHEET (dw->data_editor->data_sheet);
+      SswRange sel = *sheet->selection;
+
+      GtkClipboard *clip =
+       gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
+                                      GDK_SELECTION_CLIPBOARD);
+
+      /* Save the selected area to a string */
+      GString *str = g_string_new ("");
+      for (y = sel.start_y ; y <= sel.end_y; ++y)
+       {
+         for (x = sel.start_x ; x <= sel.end_x; ++x)
+           {
+             const struct variable * var = psppire_dict_get_variable (dict, x);
+             gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
+                                                         y, var, FALSE);
+             g_string_append (str, s);
+             g_string_append (str, "\t");
+             g_free (s);
+           }
+         g_string_append (str, "\n");
+       }
+
+      gtk_clipboard_set_text (clip, str->str, str->len);
+      g_string_free (str, TRUE);
+
+      /* Now fill the selected area with SYSMIS */
+      union value sm ;
+      sm.f = SYSMIS;
+      for (x = sel.start_x ; x <= sel.end_x; ++x)
+       {
+         const struct variable * var = psppire_dict_get_variable (dict, x);
+         for (y = sel.start_y ; y <= sel.end_y; ++y)
+           {
+             psppire_data_store_set_value (dw->data_editor->data_store,
+                                           y,
+                                           var, &sm);
+           }
+       }
+
     }
 }
 
@@ -1079,10 +1117,13 @@ static void
 on_copy (PsppireDataWindow *dw)
 {
   int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
     {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_edit_copy (ds);
+      GtkClipboard *clip =
+       gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
+                                  GDK_SELECTION_CLIPBOARD);
+
+      ssw_sheet_set_clip (SSW_SHEET (dw->data_editor->data_sheet), clip);
     }
 }
 
@@ -1090,75 +1131,78 @@ static void
 on_paste (PsppireDataWindow *dw)
 {
   int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
     {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_edit_paste (ds);
+      psppire_data_editor_paste (dw->data_editor);
     }
 }
 
-
 static void
 on_clear_cases (PsppireDataWindow *dw)
 {
-  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
+  PsppireDataEditor *de = dw->data_editor;
+  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
     {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_edit_clear_cases (ds);
+      SswRange *range = SSW_SHEET(de->data_sheet)->selection;
+      psppire_data_store_delete_cases (de->data_store, range->start_y,
+                                      range->end_y - range->start_y + 1);
+      gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
     }
 }
 
 static void
 on_clear_variables (PsppireDataWindow *dw)
 {
-  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
+  PsppireDataEditor *de = dw->data_editor;
+  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
     {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_edit_clear_variables (ds);
+      psppire_data_editor_data_delete_variables (de);
     }
   else
     {
-      psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
+      psppire_data_editor_var_delete_variables (de);
     }
 }
 
-
 static void
 insert_variable (PsppireDataWindow *dw)
 {
-  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
-  if (p == 0)
+  PsppireDataEditor *de = dw->data_editor;
+  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
+
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
     {
-      PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-      psppire_data_sheet_insert_variable (ds);
+      SswRange *range = SSW_SHEET(de->data_sheet)->selection;
+      psppire_data_editor_insert_new_variable_at_posn (de, range->start_x);
     }
   else
     {
-      psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
+      SswRange *range = SSW_SHEET(de->var_sheet)->selection;
+      psppire_data_editor_insert_new_variable_at_posn (de, range->start_y);
     }
 }
 
-
 static void
 insert_case_at_row (PsppireDataWindow *dw)
 {
-  PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-
-  psppire_data_sheet_insert_case (ds);
+  PsppireDataEditor *de = dw->data_editor;
+  SswRange *range = SSW_SHEET(de->data_sheet)->selection;
+  psppire_data_editor_insert_new_case_at_posn (de, range->start_y);
 }
 
 static void
 goto_case (PsppireDataWindow *dw)
 {
-  PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-
-  goto_case_dialog (ds);
+  PsppireDataEditor *de = dw->data_editor;
+  int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
+  if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
+    {
+      goto_case_dialog (PSPPIRE_DATA_SHEET (de->data_sheet));
+    }
 }
 
-
-
 static GtkWidget *
 create_file_menu (PsppireDataWindow *dw)
 {
@@ -1291,6 +1335,7 @@ create_file_menu (PsppireDataWindow *dw)
   return menuitem;
 }
 
+
 static GtkWidget *
 create_edit_menu (PsppireDataWindow *dw)
 {
@@ -1376,7 +1421,6 @@ create_edit_menu (PsppireDataWindow *dw)
   return menuitem;
 }
 
-
 static void
 psppire_data_window_finish_init (PsppireDataWindow *de,
                                  struct dataset *ds)
@@ -1414,12 +1458,6 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
   g_signal_connect_swapped (de->data_store, "case-changed",
                            G_CALLBACK (set_unsaved), de);
 
-  g_signal_connect_swapped (de->data_store, "case-inserted",
-                           G_CALLBACK (set_unsaved), de);
-
-  g_signal_connect_swapped (de->data_store, "cases-deleted",
-                           G_CALLBACK (set_unsaved), de);
-
   dataset_set_callbacks (de->dataset, &cbs, de);
 
   connect_help (de->builder);
@@ -1443,7 +1481,7 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
                    G_CALLBACK (on_split_change),
                    de);
 
-  g_signal_connect_swapped (de->dict, "backend-changed",
+  g_signal_connect_swapped (de->dict, "items-changed",
                             G_CALLBACK (enable_save), de);
   g_signal_connect_swapped (de->dict, "variable-inserted",
                             G_CALLBACK (enable_save), de);
@@ -1751,6 +1789,7 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
   ll_push_head (&all_data_windows, &de->ll);
 }
 
+
 static void
 psppire_data_window_dispose (GObject *object)
 {
@@ -1853,6 +1892,7 @@ psppire_data_window_get_property (GObject         *object,
 }
 
 
+
 GtkWidget*
 psppire_data_window_new (struct dataset *ds)
 {
@@ -1886,12 +1926,15 @@ psppire_data_window_new (struct dataset *ds)
   return dw;
 }
 
+
+
 bool
 psppire_data_window_is_empty (PsppireDataWindow *dw)
 {
   return psppire_dict_get_var_cnt (dw->dict) == 0;
 }
 
+
 static void
 psppire_data_window_iface_init (PsppireWindowIface *iface)
 {
@@ -1902,6 +1945,7 @@ psppire_data_window_iface_init (PsppireWindowIface *iface)
 
 \f
 
+
 PsppireDataWindow *
 psppire_default_data_window (void)
 {
@@ -1910,6 +1954,8 @@ psppire_default_data_window (void)
   return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
 }
 
+
+
 void
 psppire_data_window_set_default (PsppireDataWindow *pdw)
 {
@@ -1924,6 +1970,8 @@ psppire_data_window_undefault (PsppireDataWindow *pdw)
   ll_push_tail (&all_data_windows, &pdw->ll);
 }
 
+
+
 PsppireDataWindow *
 psppire_data_window_for_dataset (struct dataset *ds)
 {
diff --git a/src/ui/gui/psppire-delimited-text.c b/src/ui/gui/psppire-delimited-text.c
new file mode 100644 (file)
index 0000000..dd13f1c
--- /dev/null
@@ -0,0 +1,630 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2017 Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define P_(msgid) msgid
+
+#include "psppire-delimited-text.h"
+#include "psppire-text-file.h"
+#include "libpspp/str.h"
+#include "libpspp/i18n.h"
+
+#include <gtk/gtk.h>
+
+/* Properties */
+enum
+  {
+    PROP_0,
+    PROP_CHILD,
+    PROP_DELIMITERS,
+    PROP_FIRST_LINE
+  };
+
+struct enclosure
+{
+  gunichar opening;
+  gunichar closing;
+};
+
+static const struct enclosure enclosures[3] =
+  {
+    {'(',   ')'},
+    {'"',   '"'},
+    {'\'',  '\''}
+  };
+
+static void
+count_delims (PsppireDelimitedText *tf)
+{
+  if (tf->child == NULL)
+    return;
+
+  tf->max_delimiters = 0;
+  GtkTreeIter iter;
+  gboolean valid;
+  for (valid = gtk_tree_model_get_iter_first (tf->child, &iter);
+       valid;
+       valid = gtk_tree_model_iter_next (tf->child, &iter))
+    {
+      gint enc = -1;
+      // FIXME: Box these lines to avoid constant allocation/deallocation
+      gchar *line = NULL;
+      gtk_tree_model_get (tf->child, &iter, 1, &line, -1);
+      {
+       char *p;
+       gint count = 0;
+       for (p = line; ; p = g_utf8_find_next_char (p, NULL))
+         {
+           const gunichar c = g_utf8_get_char (p);
+           if (c == 0)
+             break;
+           if (enc == -1)
+             {
+               gint i;
+               for (i = 0; i < 3; ++i)
+                 {
+                   if (c == enclosures[i].opening)
+                     {
+                       enc = i;
+                       break;
+                     }
+                 }
+             }
+           else if (c == enclosures[enc].closing)
+             {
+               enc = -1;
+             }
+           if (enc == -1)
+             {
+               GSList *del;
+               for (del = tf->delimiters; del; del = g_slist_next (del))
+                 {
+                   if (c == GPOINTER_TO_INT (del->data))
+                     count++;
+                 }
+             }
+         }
+       tf->max_delimiters = MAX (tf->max_delimiters, count);
+      }
+      g_free (line);
+    }
+}
+
+static void
+cache_invalidate (PsppireDelimitedText *tf)
+{
+  memset (tf->cache_starts, 0, 512);
+  if (tf->const_cache.string)
+    {
+      ss_dealloc (&tf->const_cache);
+      tf->const_cache.string = NULL;
+      tf->cache_row = -1;
+    }
+}
+
+static void
+psppire_delimited_text_set_property (GObject         *object,
+                               guint            prop_id,
+                               const GValue    *value,
+                               GParamSpec      *pspec)
+{
+  PsppireDelimitedText *tf = PSPPIRE_DELIMITED_TEXT (object);
+
+  switch (prop_id)
+    {
+    case PROP_FIRST_LINE:
+      tf->first_line = g_value_get_int (value);
+      break;
+    case PROP_CHILD:
+      tf->child = g_value_get_object (value);
+      g_return_if_fail (PSPPIRE_IS_TEXT_FILE (tf->child));
+      break;
+    case PROP_DELIMITERS:
+      g_slist_free (tf->delimiters);
+      tf->delimiters =  g_slist_copy (g_value_get_pointer (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+
+  cache_invalidate (tf);
+  count_delims (tf);
+}
+
+static void
+psppire_delimited_text_get_property (GObject         *object,
+                               guint            prop_id,
+                               GValue          *value,
+                               GParamSpec      *pspec)
+{
+  PsppireDelimitedText *text_file = PSPPIRE_DELIMITED_TEXT (object);
+
+  switch (prop_id)
+    {
+    case PROP_FIRST_LINE:
+      g_value_set_int (value, text_file->first_line);
+      break;
+    case PROP_DELIMITERS:
+      g_value_set_pointer (value, text_file->delimiters);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+
+static void psppire_delimited_text_init            (PsppireDelimitedText      *text_file);
+static void psppire_delimited_text_class_init      (PsppireDelimitedTextClass *class);
+
+static void psppire_delimited_text_finalize        (GObject           *object);
+static void psppire_delimited_text_dispose        (GObject           *object);
+
+static GObjectClass *parent_class = NULL;
+
+static gint
+n_lines (PsppireDelimitedText *file)
+{
+  PsppireTextFile *child = PSPPIRE_TEXT_FILE (file->child);
+
+  return child->maximum_lines;
+}
+
+static gboolean
+__tree_get_iter (GtkTreeModel *tree_model,
+                GtkTreeIter *iter,
+                GtkTreePath *path)
+{
+  PsppireDelimitedText *file = PSPPIRE_DELIMITED_TEXT (tree_model);
+  if (path == NULL)
+    return FALSE;
+
+
+  gint *indices = gtk_tree_path_get_indices (path);
+
+  if (!indices)
+    return FALSE;
+
+  gint n = *indices;
+
+  gint children = n_lines (file);
+
+  if (n >= children - file->first_line)
+    return FALSE;
+
+
+  iter->user_data = GINT_TO_POINTER (n);
+  iter->stamp = file->stamp;
+
+  return TRUE;
+}
+
+
+static gboolean
+__tree_iter_next (GtkTreeModel *tree_model,
+                 GtkTreeIter *iter)
+{
+  PsppireDelimitedText *file  = PSPPIRE_DELIMITED_TEXT (tree_model);
+  g_return_val_if_fail (file->stamp == iter->stamp, FALSE);
+
+  gint n = GPOINTER_TO_INT (iter->user_data);
+
+
+  gint children = n_lines (file);
+
+  if (n + 1 >= children - file->first_line)
+    return FALSE;
+
+  iter->user_data = GINT_TO_POINTER (n + 1);
+
+  return TRUE;
+}
+
+
+static GType
+__tree_get_column_type (GtkTreeModel *tree_model,
+                       gint          index)
+{
+  if (index == 0)
+    return G_TYPE_INT;
+
+  return G_TYPE_STRING;
+}
+
+static gboolean
+__iter_has_child (GtkTreeModel *tree_model,
+                 GtkTreeIter  *iter)
+{
+  return 0;
+}
+
+
+static gboolean
+__iter_parent     (GtkTreeModel *tree_model,
+                  GtkTreeIter  *iter,
+                  GtkTreeIter  *child)
+{
+  return 0;
+}
+
+static GtkTreePath *
+__tree_get_path (GtkTreeModel *tree_model,
+                GtkTreeIter  *iter)
+{
+  PsppireDelimitedText *file  = PSPPIRE_DELIMITED_TEXT (tree_model);
+  g_return_val_if_fail (file->stamp == iter->stamp, FALSE);
+
+  gint n = GPOINTER_TO_INT (iter->user_data);
+
+  gint children = n_lines (file);
+
+  if (n >= children - file->first_line)
+    return NULL;
+
+  return gtk_tree_path_new_from_indices (n, -1);
+}
+
+
+static gboolean
+__iter_children (GtkTreeModel *tree_model,
+                              GtkTreeIter *iter,
+                              GtkTreeIter *parent)
+{
+  return 0;
+}
+
+
+static gint
+__tree_model_iter_n_children (GtkTreeModel *tree_model,
+                             GtkTreeIter *iter)
+{
+  PsppireDelimitedText *file  = PSPPIRE_DELIMITED_TEXT (tree_model);
+  g_assert (iter == NULL);
+
+  gint children = n_lines (file);
+
+  return children - file->first_line;
+}
+
+static GtkTreeModelFlags
+__tree_model_get_flags (GtkTreeModel *model)
+{
+  g_return_val_if_fail (PSPPIRE_IS_DELIMITED_TEXT (model), (GtkTreeModelFlags) 0);
+
+  return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+__tree_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  PsppireDelimitedText *tf  = PSPPIRE_DELIMITED_TEXT (tree_model);
+
+  /* + 1 for the trailing field and +1 for the leading line number column */
+  return tf->max_delimiters + 1 + 1;
+}
+
+
+static gboolean
+__iter_nth_child (GtkTreeModel *tree_model,
+                 GtkTreeIter *iter,
+                 GtkTreeIter *parent,
+                 gint n)
+{
+  PsppireDelimitedText *file  = PSPPIRE_DELIMITED_TEXT (tree_model);
+
+  g_assert (parent == NULL);
+
+  g_return_val_if_fail (file, FALSE);
+
+  gint children = gtk_tree_model_iter_n_children (file->child, NULL);
+
+  if (n >= children - file->first_line)
+    {
+      iter->stamp = -1;
+      iter->user_data = NULL;
+      return FALSE;
+    }
+
+  iter->user_data = GINT_TO_POINTER (n);
+  iter->stamp = file->stamp;
+
+  return TRUE;
+}
+
+
+static void
+nullify_char (struct substring cs)
+{
+  int char_len = ss_first_mblen (cs);
+  while (char_len > 0)
+    {
+      cs.string[char_len - 1] = '\0';
+      char_len--;
+    }
+}
+
+
+/* Split row N into it's delimited fields (if it is not already cached)
+   and set this row as the current cache. */
+static void
+split_row_into_fields (PsppireDelimitedText *file, gint n)
+{
+  if (n == file->cache_row)  /* Cache hit */
+    {
+      return;
+    }
+
+  memset (file->cache_starts, 0, 512);
+  /* Cache miss */
+  if (file->const_cache.string)
+    {
+      ss_dealloc (&file->const_cache);
+    }
+  ss_alloc_substring_pool (&file->const_cache,
+                          PSPPIRE_TEXT_FILE (file->child)->lines[n], NULL);
+  struct substring cs = file->const_cache;
+  int field = 0;
+  file->cache_starts[0] = cs.string;
+  gint enc = -1;
+  for (;
+       UINT32_MAX != ss_first_mb (cs);
+       ss_get_mb (&cs))
+    {
+      ucs4_t character = ss_first_mb (cs);
+      gboolean char_is_quote = FALSE;
+      if (enc == -1)
+       {
+         gint i;
+         for (i = 0; i < 3; ++i)
+           {
+             if (character == enclosures[i].opening)
+               {
+                 enc = i;
+                 char_is_quote = TRUE;
+                 file->cache_starts[field] += ss_first_mblen (cs);
+                 break;
+               }
+           }
+       }
+      else if (character == enclosures[enc].closing)
+       {
+         char_is_quote = TRUE;
+         nullify_char (cs);
+         enc = -1;
+       }
+
+      if (enc == -1 && char_is_quote == FALSE)
+       {
+         GSList *del;
+         for (del = file->delimiters; del; del = g_slist_next (del))
+           {
+             if (character == GPOINTER_TO_INT (del->data))
+               {
+                 field++;
+                 int char_len = ss_first_mblen (cs);
+                 file->cache_starts[field] = cs.string + char_len;
+                 nullify_char (cs);
+                 break;
+               }
+           }
+       }
+    }
+
+  file->cache_row = n;
+}
+
+const gchar *
+psppire_delimited_text_get_header_title (PsppireDelimitedText *file, gint column)
+{
+  if (file->first_line <= 0)
+    return NULL;
+
+  split_row_into_fields (file, file->first_line - 1);
+
+  return file->cache_starts [column];
+}
+
+static void
+__get_value (GtkTreeModel *tree_model,
+            GtkTreeIter *iter,
+            gint column,
+            GValue *value)
+{
+  PsppireDelimitedText *file  = PSPPIRE_DELIMITED_TEXT (tree_model);
+
+  g_return_if_fail (iter->stamp == file->stamp);
+
+  gint n = GPOINTER_TO_INT (iter->user_data) + file->first_line;
+
+
+  if (column == 0)
+    {
+      g_value_init (value, G_TYPE_INT);
+      g_value_set_int (value, n + 1);
+      return;
+    }
+
+  g_value_init (value, G_TYPE_STRING);
+
+  split_row_into_fields (file, n);
+
+  g_value_set_string (value, file->cache_starts [column - 1]);
+}
+
+
+static void
+__tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags       = __tree_model_get_flags;
+  iface->get_n_columns   = __tree_model_get_n_columns ;
+  iface->get_column_type = __tree_get_column_type;
+  iface->get_iter        = __tree_get_iter;
+  iface->iter_next       = __tree_iter_next;
+  iface->get_path        = __tree_get_path;
+  iface->get_value       = __get_value;
+
+  iface->iter_children   = __iter_children;
+  iface->iter_has_child  = __iter_has_child;
+  iface->iter_n_children = __tree_model_iter_n_children;
+  iface->iter_nth_child  = __iter_nth_child;
+  iface->iter_parent     = __iter_parent;
+}
+
+
+GType
+psppire_delimited_text_get_type (void)
+{
+  static GType text_file_type = 0;
+
+  if (!text_file_type)
+    {
+      static const GTypeInfo text_file_info =
+       {
+         sizeof (PsppireDelimitedTextClass),
+         NULL,         /* base_init */
+         NULL,         /* base_finalize */
+         (GClassInitFunc) psppire_delimited_text_class_init,
+         NULL,         /* class_finalize */
+         NULL,         /* class_data */
+         sizeof (PsppireDelimitedText),
+         0,
+         (GInstanceInitFunc) psppire_delimited_text_init,
+       };
+
+      static const GInterfaceInfo tree_model_info = {
+       (GInterfaceInitFunc) __tree_model_init,
+       NULL,
+       NULL
+      };
+
+      text_file_type = g_type_register_static (G_TYPE_OBJECT,
+                                              "PsppireDelimitedText",
+                                              &text_file_info, 0);
+
+      g_type_add_interface_static (text_file_type, GTK_TYPE_TREE_MODEL,
+                                  &tree_model_info);
+    }
+
+  return text_file_type;
+}
+
+
+static void
+psppire_delimited_text_class_init (PsppireDelimitedTextClass *class)
+{
+  GObjectClass *object_class;
+
+  parent_class = g_type_class_peek_parent (class);
+  object_class = (GObjectClass*) class;
+
+  GParamSpec *first_line_spec =
+    g_param_spec_int ("first-line",
+                     "First Line",
+                     P_("The first line to be considered."),
+                     0, 1000, 0,
+                     G_PARAM_READWRITE);
+
+  GParamSpec *delimiters_spec =
+    g_param_spec_pointer ("delimiters",
+                         "Field Delimiters",
+                         P_("A GSList of gunichars which delimit the fields."),
+                         G_PARAM_READWRITE);
+
+  GParamSpec *child_spec =
+    g_param_spec_object ("child",
+                        "Child Model",
+                        P_("The GtkTextModel which this object wraps."),
+                        GTK_TYPE_TREE_MODEL,
+                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
+
+  object_class->set_property = psppire_delimited_text_set_property;
+  object_class->get_property = psppire_delimited_text_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_CHILD,
+                                   child_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_DELIMITERS,
+                                   delimiters_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_FIRST_LINE,
+                                   first_line_spec);
+
+  object_class->finalize = psppire_delimited_text_finalize;
+  object_class->dispose = psppire_delimited_text_dispose;
+}
+
+
+static void
+psppire_delimited_text_init (PsppireDelimitedText *text_file)
+{
+  text_file->child = NULL;
+  text_file->first_line = 0;
+  text_file->delimiters = g_slist_prepend (NULL, GINT_TO_POINTER (':'));
+
+  text_file->const_cache.string = NULL;
+  text_file->const_cache.length = 0;
+  text_file->cache_row = -1;
+  memset (text_file->cache_starts, 0, 512);
+
+  text_file->max_delimiters = 0;
+
+  text_file->dispose_has_run = FALSE;
+  text_file->stamp = g_random_int ();
+}
+
+
+PsppireDelimitedText *
+psppire_delimited_text_new (GtkTreeModel *child)
+{
+  return
+    g_object_new (PSPPIRE_TYPE_DELIMITED_TEXT,
+                 "child", child,
+                 NULL);
+}
+
+static void
+psppire_delimited_text_finalize (GObject *object)
+{
+  PsppireDelimitedText *tf = PSPPIRE_DELIMITED_TEXT (object);
+
+  g_slist_free (tf->delimiters);
+
+  ss_dealloc (&tf->const_cache);
+
+  /* must chain up */
+  (* parent_class->finalize) (object);
+}
+
+
+static void
+psppire_delimited_text_dispose (GObject *object)
+{
+  PsppireDelimitedText *ds = PSPPIRE_DELIMITED_TEXT (object);
+
+  if (ds->dispose_has_run)
+    return;
+
+  /* must chain up */
+  (* parent_class->dispose) (object);
+
+  ds->dispose_has_run = TRUE;
+}
diff --git a/src/ui/gui/psppire-delimited-text.h b/src/ui/gui/psppire-delimited-text.h
new file mode 100644 (file)
index 0000000..d18570a
--- /dev/null
@@ -0,0 +1,91 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2017  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __PSPPIRE_DELIMITED_TEXT_H__
+#define __PSPPIRE_DELIMITED_TEXT_H__
+
+#include "libpspp/str.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+
+#define PSPPIRE_TYPE_DELIMITED_TEXT           (psppire_delimited_text_get_type ())
+
+#define PSPPIRE_DELIMITED_TEXT(obj)    \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               PSPPIRE_TYPE_DELIMITED_TEXT, PsppireDelimitedText))
+
+#define PSPPIRE_DELIMITED_TEXT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                                    \
+                            PSPPIRE_TYPE_DELIMITED_TEXT,                    \
+                            PsppireDelimitedTextClass))
+
+
+#define PSPPIRE_IS_DELIMITED_TEXT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DELIMITED_TEXT))
+
+#define PSPPIRE_IS_DELIMITED_TEXT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DELIMITED_TEXT))
+
+#define PSPPIRE_DELIMITED_TEXT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              PSPPIRE_TYPE_DELIMITED_TEXT,                  \
+                              PsppireDelimitedTextClass))
+
+struct _PsppireDelimitedText
+{
+  GObject parent;
+
+  GtkTreeModel *child;
+  
+  /* The first line of the file to be modelled */
+  gint first_line;
+  
+  GSList *delimiters;
+  gint max_delimiters;
+  
+  /*< private >*/
+  gboolean dispose_has_run ;
+  gint stamp;
+
+  /* caching */
+  const char *cache_starts[512];
+  struct substring const_cache;
+  int cache_row;
+};
+
+struct _PsppireDelimitedTextClass
+{
+  GObjectClass parent_class;
+};
+
+
+typedef struct _PsppireDelimitedText       PsppireDelimitedText;
+typedef struct _PsppireDelimitedTextClass  PsppireDelimitedTextClass;
+
+GType psppire_delimited_text_get_type (void) G_GNUC_CONST;
+PsppireDelimitedText *psppire_delimited_text_new (GtkTreeModel *);
+
+const gchar *psppire_delimited_text_get_header_title (PsppireDelimitedText *file, gint column);
+
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DELIMITED_TEXT_H__ */
index 0ee608cadef083eacb9f770aecfb37ff9d32af72..59b57b490c200df5a535a20c89b9ad85226db3e1 100644 (file)
@@ -1,5 +1,6 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012  Free Software Foundation
+   Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012,
+   2016, 2017  Free Software Foundation
 
    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
 #include "ui/gui/psppire-marshal.h"
 #include "ui/gui/psppire-var-ptr.h"
 
+#include <ssw-datum.h>
+
+#include <gobject/genums.h>
+
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-enum  {
-  BACKEND_CHANGED,
 
+
+GType align_enum_type;
+GType measure_enum_type;
+GType role_enum_type;
+
+
+enum  {
   VARIABLE_CHANGED,
   VARIABLE_INSERTED,
   VARIABLE_DELETED,
@@ -59,6 +69,53 @@ static void psppire_dict_dispose     (GObject                *object);
 static void dictionary_tree_model_init (GtkTreeModelIface *iface);
 
 
+
+static guint
+gni (GListModel *list)
+{
+  PsppireDict *dict = PSPPIRE_DICT (list);
+
+  return psppire_dict_get_var_cnt (dict);
+}
+
+static GType
+git (GListModel *list)
+{
+  return SSW_TYPE_DATUM;
+}
+
+static gpointer
+gi (GListModel *list, guint id)
+{
+  SswDatum *gd = SSW_DATUM (g_object_new (SSW_TYPE_DATUM, NULL));
+
+  PsppireDict *dict = PSPPIRE_DICT (list);
+
+  if (id >= psppire_dict_get_var_cnt (dict))
+    {
+      gd->text = g_strdup (_("Var"));
+    }
+  else
+    {
+      const struct variable *v =  psppire_dict_get_variable (dict, id);
+
+      gd->text = g_strdup (var_get_name (v));
+      gd->label = g_strdup (var_get_label (v));
+    }
+
+  return gd;
+}
+
+
+static void
+ssw_init_iface (GListModelInterface *iface)
+{
+  iface->get_n_items = gni;
+  iface->get_item = gi;
+  iface->get_item_type = git;
+}
+
+
 /* --- variables --- */
 static GObjectClass     *parent_class = NULL;
 
@@ -94,12 +151,21 @@ psppire_dict_get_type (void)
        NULL
       };
 
+      static const GInterfaceInfo list_model_info = {
+       (GInterfaceInitFunc) ssw_init_iface,
+       NULL,
+       NULL
+      };
+
       object_type = g_type_register_static (G_TYPE_OBJECT,
                                            "PsppireDict",
                                            &object_info, 0);
 
       g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
                                   &tree_model_info);
+
+      g_type_add_interface_static (object_type, G_TYPE_LIST_MODEL,
+                                  &list_model_info);
     }
 
   return object_type;
@@ -115,17 +181,6 @@ psppire_dict_class_init (PsppireDictClass *class)
 
   object_class->dispose = psppire_dict_dispose;
 
-  signals [BACKEND_CHANGED] =
-    g_signal_new ("backend-changed",
-                 G_TYPE_FROM_CLASS (class),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-
-
   signals [VARIABLE_CHANGED] =
     g_signal_new ("variable-changed",
                  G_TYPE_FROM_CLASS (class),
@@ -221,7 +276,10 @@ addcb (struct dictionary *d, int idx, void *pd)
   PsppireDict *dict = PSPPIRE_DICT (pd);
 
   if ( ! dict->disable_insert_signal)
-    g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
+    {
+      g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
+      g_signal_emit_by_name (dict, "items-changed", idx, 1, 1);
+    }
 }
 
 static void
@@ -230,12 +288,14 @@ delcb (struct dictionary *d, const struct variable *var,
 {
   g_signal_emit (pd, signals [VARIABLE_DELETED], 0,
                  var, dict_idx, case_idx);
+  g_signal_emit_by_name (pd, "items-changed",  dict_idx, 1, 0);
 }
 
 static void
 mutcb (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd)
 {
   g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx, what, oldvar);
+  g_signal_emit_by_name (pd, "items-changed", idx, 1, 1);
 }
 
 static void
@@ -296,6 +356,9 @@ psppire_dict_replace_dictionary (PsppireDict *dict, struct dictionary *d)
 {
   struct variable *var =  dict_get_weight (d);
 
+  guint old_n = dict_get_var_cnt (dict->dict);
+  guint new_n = dict_get_var_cnt (d);
+
   dict->dict = d;
 
   weight_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
@@ -307,7 +370,7 @@ psppire_dict_replace_dictionary (PsppireDict *dict, struct dictionary *d)
 
   dict_set_callbacks (dict->dict, &gui_callbacks, dict);
 
-  g_signal_emit (dict, signals [BACKEND_CHANGED], 0);
+  g_signal_emit_by_name (dict, "items-changed", 0, old_n, new_n);
 }
 
 
@@ -371,6 +434,7 @@ psppire_dict_insert_variable (PsppireDict *d, gint idx, const gchar *name)
   d->disable_insert_signal = FALSE;
 
   g_signal_emit (d, signals[VARIABLE_INSERTED], 0, idx);
+  g_signal_emit_by_name (d, "items-changed", idx, 0, 1);
 
   return var;
 }
@@ -499,7 +563,7 @@ psppire_dict_clear (PsppireDict *d)
 }
 
 
-/* Return true is NAME would be a valid name of a variable to add to the
+/* Return true if NAME would be a valid name of a variable to add to the
    dictionary.  False otherwise.
    If REPORT is true, then invalid names will be reported as such as errors
 */
@@ -617,24 +681,34 @@ tree_model_column_type (GtkTreeModel *model, gint index)
 {
   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
 
+  GType t = 0;
+
   switch (index)
     {
     case DICT_TVM_COL_NAME:
-      return G_TYPE_STRING;
+    case DICT_TVM_COL_LABEL:
+      t = G_TYPE_STRING;
+      break;
+    case DICT_TVM_COL_DECIMAL:
+    case DICT_TVM_COL_WIDTH:
+    case DICT_TVM_COL_COLUMNS:
+      t = G_TYPE_INT;
       break;
     case DICT_TVM_COL_VAR:
-      return PSPPIRE_VAR_PTR_TYPE;
+      t = PSPPIRE_VAR_PTR_TYPE;
       break;
-    case DICT_TVM_COL_LABEL:
-      return G_TYPE_STRING;
+    case DICT_TVM_COL_ALIGNMENT:
+      t = align_enum_type;
       break;
-    default:
-      g_return_val_if_reached ((GType)0);
+    case DICT_TVM_COL_MEASURE:
+      t = measure_enum_type;
+      break;
+    case DICT_TVM_COL_ROLE:
+      t = role_enum_type;
       break;
     }
 
-  g_assert_not_reached ();
-  return ((GType)0);
+  return t;
 }
 
 static gboolean
@@ -722,6 +796,7 @@ tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
   return path;
 }
 
+const struct fmt_spec *var_get_write_format (const struct variable *);
 
 static void
 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
@@ -732,22 +807,51 @@ tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
 
   g_return_if_fail (iter->stamp == dict->stamp);
 
-  var =  iter->user_data;
+  var = iter->user_data;
+
+  const struct fmt_spec *fs = var_get_write_format (var);
 
   switch (column)
     {
     case DICT_TVM_COL_NAME:
-      {
-       g_value_init (value, G_TYPE_STRING);
-       g_value_set_string (value, var_get_name (var));
-      }
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, var_get_name (var));
+      break;
+    case DICT_TVM_COL_WIDTH:
+      g_value_init (value, G_TYPE_INT);
+      g_value_set_int (value, fs->w);
+      break;
+    case DICT_TVM_COL_DECIMAL:
+      g_value_init (value, G_TYPE_INT);
+      g_value_set_int (value, fs->d);
+      break;
+    case DICT_TVM_COL_LABEL:
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, var_get_label (var));
+      break;
+    case DICT_TVM_COL_COLUMNS:
+      g_value_init (value, G_TYPE_INT);
+      g_value_set_int (value, var_get_display_width (var));
+      break;
+    case DICT_TVM_COL_ALIGNMENT:
+      g_value_init (value, align_enum_type);
+      g_value_set_enum (value, var_get_alignment (var));
+      break;
+    case DICT_TVM_COL_MEASURE:
+      g_value_init (value, measure_enum_type);
+      g_value_set_enum (value, var_get_measure (var));
+      break;
+    case DICT_TVM_COL_ROLE:
+      g_value_init (value, role_enum_type);
+      g_value_set_enum (value, var_get_role (var));
       break;
     case DICT_TVM_COL_VAR:
       g_value_init (value, PSPPIRE_VAR_PTR_TYPE);
       g_value_set_boxed (value, var);
       break;
     default:
-      g_return_if_reached ();
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, "????");
       break;
     }
 }
@@ -766,7 +870,7 @@ tree_model_n_children (GtkTreeModel *model,
 {
   PsppireDict *dict = PSPPIRE_DICT (model);
 
-  if ( iter == NULL )
+  if (iter == NULL)
     return psppire_dict_get_var_cnt (dict);
 
   return 0;
index ecd5de063fbe4d37ec4b4dcc500c2793ce2e99d6..4d78807cba2d97464d9b9a052b8df5904207587d 100644 (file)
@@ -42,7 +42,19 @@ G_BEGIN_DECLS
 typedef struct _PsppireDict       PsppireDict;
 typedef struct _PsppireDictClass PsppireDictClass;
 
-enum {DICT_TVM_COL_NAME=0, DICT_TVM_COL_VAR, DICT_TVM_COL_LABEL, n_DICT_COLS} ;
+enum {DICT_TVM_COL_NAME=0,
+      DICT_TVM_COL_TYPE,
+      DICT_TVM_COL_WIDTH,
+      DICT_TVM_COL_DECIMAL,
+      DICT_TVM_COL_LABEL,
+      DICT_TVM_COL_VALUE_LABELS,
+      DICT_TVM_COL_MISSING_VALUES,
+      DICT_TVM_COL_COLUMNS,
+      DICT_TVM_COL_ALIGNMENT,
+      DICT_TVM_COL_MEASURE,
+      DICT_TVM_COL_ROLE,
+      DICT_TVM_COL_VAR,
+      n_DICT_COLS} ;
 
 struct _PsppireDict
 {
diff --git a/src/ui/gui/psppire-empty-list-store.c b/src/ui/gui/psppire-empty-list-store.c
deleted file mode 100644 (file)
index 1658d1f..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "psppire-empty-list-store.h"
-
-static void psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *);
-static void psppire_empty_list_store_init (PsppireEmptyListStore *);
-
-/* GtkTreeModel interface. */
-static void gtk_tree_model_interface_init (GtkTreeModelIface *iface);
-static GtkTreeModelFlags empty_list_store_get_flags (GtkTreeModel *tree_model);
-static gint empty_list_store_get_n_columns (GtkTreeModel *tree_model);
-static GType empty_list_store_get_column_type (GtkTreeModel *tree_model,
-                                               gint          index_);
-static gboolean empty_list_store_get_iter (GtkTreeModel *tree_model,
-                                           GtkTreeIter  *iter,
-                                           GtkTreePath  *path);
-static GtkTreePath * empty_list_store_get_path (GtkTreeModel *tree_model,
-                                                GtkTreeIter  *iter);
-static void empty_list_store_get_value (GtkTreeModel *tree_model,
-                                        GtkTreeIter  *iter,
-                                        gint          column,
-                                        GValue       *value);
-static gboolean empty_list_store_iter_next (GtkTreeModel *tree_model,
-                                            GtkTreeIter  *iter);
-static gboolean empty_list_store_iter_children (GtkTreeModel *tree_model,
-                                                GtkTreeIter  *iter,
-                                                GtkTreeIter  *parent);
-static gboolean empty_list_store_iter_has_child (GtkTreeModel *tree_model,
-                                                 GtkTreeIter  *iter);
-static gint empty_list_store_iter_n_children (GtkTreeModel *tree_model,
-                                              GtkTreeIter  *iter);
-static gboolean empty_list_store_iter_nth_child (GtkTreeModel *tree_model,
-                                                 GtkTreeIter  *iter,
-                                                 GtkTreeIter  *parent,
-                                                 gint          n);
-static gboolean empty_list_store_iter_parent (GtkTreeModel *tree_model,
-                                              GtkTreeIter  *iter,
-                                              GtkTreeIter  *child);
-
-GType
-psppire_empty_list_store_get_type (void)
-{
-  static GType type = 0;
-  if (!type)
-    {
-      static const GTypeInfo psppire_empty_list_store_info =
-        {
-          sizeof(PsppireEmptyListStoreClass),
-          NULL,    /* base init */
-          NULL,    /* base finalize */
-          (GClassInitFunc) psppire_empty_list_store_class_init,
-          NULL,    /* class finalize */
-          NULL,    /* class data */
-          sizeof(PsppireEmptyListStore),
-          0,    /* n_preallocs, ignored since 2.10 */
-          (GInstanceInitFunc) psppire_empty_list_store_init,
-          NULL
-        };
-      static const GInterfaceInfo gtk_tree_model_info =
-        {
-          (GInterfaceInitFunc) gtk_tree_model_interface_init,
-          (GInterfaceFinalizeFunc) NULL,
-          NULL
-        };
-      type = g_type_register_static (G_TYPE_OBJECT,
-                                 "PsppireEmptyListStore",
-                                 &psppire_empty_list_store_info, 0);
-      g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL,
-                                   &gtk_tree_model_info);
-    }
-  return type;
-}
-
-enum
-  {
-    PROP_0,
-    PROP_N_ROWS
-  };
-
-static void
-psppire_empty_list_store_set_property (GObject      *object,
-                                       guint         prop_id,
-                                       const GValue *value,
-                                       GParamSpec   *pspec)
-{
-  PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object);
-
-  switch (prop_id)
-    {
-    case PROP_N_ROWS:
-      obj->n_rows = g_value_get_int (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_empty_list_store_get_property (GObject      *object,
-                                       guint         prop_id,
-                                       GValue       *value,
-                                       GParamSpec   *pspec)
-{
-  PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object);
-
-  switch (prop_id)
-    {
-    case PROP_N_ROWS:
-      g_value_set_int (value, obj->n_rows);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *class)
-{
-  GObjectClass *gobject_class;
-  gobject_class = G_OBJECT_CLASS (class);
-
-  gobject_class->set_property = psppire_empty_list_store_set_property;
-  gobject_class->get_property = psppire_empty_list_store_get_property;
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_N_ROWS,
-                                   g_param_spec_int ("n-rows",
-                                                    ("Number of rows"),
-                                                    ("Number of rows in GtkTreeModel"),
-                                                    0,
-                                                    G_MAXINT,
-                                                    0,
-                                                    G_PARAM_READWRITE));
-}
-
-static void
-psppire_empty_list_store_init (PsppireEmptyListStore *obj)
-{
-  obj->n_rows = 0;
-}
-
-PsppireEmptyListStore *
-psppire_empty_list_store_new (gint n_rows)
-{
-  return PSPPIRE_EMPTY_LIST_STORE (g_object_new (PSPPIRE_TYPE_EMPTY_LIST_STORE,
-                                                 "n-rows", n_rows,
-                                                 NULL));
-}
-
-gint
-psppire_empty_list_store_get_n_rows (const PsppireEmptyListStore *obj)
-{
-  return obj->n_rows;
-}
-
-void
-psppire_empty_list_store_set_n_rows (PsppireEmptyListStore *obj,
-                                     gint n_rows)
-{
-  obj->n_rows = n_rows;
-}
-
-void
-psppire_empty_list_store_row_changed (PsppireEmptyListStore *obj,
-                                      gint row)
-{
-  GtkTreeModel *tree_model = GTK_TREE_MODEL (obj);
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_indices (row, -1);
-  gtk_tree_model_get_iter (tree_model, &iter, path);
-  gtk_tree_model_row_changed (tree_model, path, &iter);
-  gtk_tree_path_free (path);
-}
-
-void
-psppire_empty_list_store_row_inserted (PsppireEmptyListStore *obj,
-                                       gint row)
-{
-  GtkTreeModel *tree_model = GTK_TREE_MODEL (obj);
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_indices (row, -1);
-  gtk_tree_model_get_iter (tree_model, &iter, path);
-  gtk_tree_model_row_inserted (tree_model, path, &iter);
-  gtk_tree_path_free (path);
-}
-
-void
-psppire_empty_list_store_row_deleted (PsppireEmptyListStore *obj,
-                                      gint row)
-{
-  GtkTreeModel *tree_model = GTK_TREE_MODEL (obj);
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_indices (row, -1);
-  gtk_tree_model_row_deleted (tree_model, path);
-  gtk_tree_path_free (path);
-}
-\f
-/* GtkTreeModel interface. */
-
-/* Random number used in 'stamp' member of GtkTreeIter. */
-#define TREE_MODEL_STAMP 0x10c44c13
-
-static gboolean
-empty_list_store_init_iter (GtkTreeModel *model, gint idx, GtkTreeIter *iter)
-{
-  const PsppireEmptyListStore *store = PSPPIRE_EMPTY_LIST_STORE (model);
-
-  if (idx < 0 || idx >= store->n_rows)
-    {
-      iter->stamp = 0;
-      iter->user_data = GINT_TO_POINTER (-1);
-      return FALSE;
-    }
-  else
-    {
-      iter->stamp = TREE_MODEL_STAMP;
-      iter->user_data = GINT_TO_POINTER (idx);
-      return TRUE;
-    }
-}
-
-static void
-gtk_tree_model_interface_init (GtkTreeModelIface *iface)
-{
-  g_return_if_fail (iface != NULL);
-
-  iface->get_flags = empty_list_store_get_flags;
-  iface->get_n_columns = empty_list_store_get_n_columns;
-  iface->get_column_type = empty_list_store_get_column_type;
-  iface->get_iter = empty_list_store_get_iter;
-  iface->get_path = empty_list_store_get_path;
-  iface->get_value = empty_list_store_get_value;
-  iface->iter_next = empty_list_store_iter_next;
-  iface->iter_children = empty_list_store_iter_children;
-  iface->iter_has_child = empty_list_store_iter_has_child;
-  iface->iter_n_children = empty_list_store_iter_n_children;
-  iface->iter_nth_child = empty_list_store_iter_nth_child;
-  iface->iter_parent = empty_list_store_iter_parent;
-}
-
-static GtkTreeModelFlags
-empty_list_store_get_flags (GtkTreeModel *tree_model G_GNUC_UNUSED)
-{
-  return GTK_TREE_MODEL_LIST_ONLY;
-}
-
-static gint
-empty_list_store_get_n_columns (GtkTreeModel *tree_model G_GNUC_UNUSED)
-{
-  return 0;
-}
-
-static GType
-empty_list_store_get_column_type (GtkTreeModel *tree_model,
-                                  gint          index_)
-{
-  g_return_val_if_reached (G_TYPE_NONE);
-}
-
-static gboolean
-empty_list_store_get_iter (GtkTreeModel *tree_model,
-                           GtkTreeIter  *iter,
-                           GtkTreePath  *path)
-{
-  gint *indices, depth;
-
-  g_return_val_if_fail (path, FALSE);
-
-  indices = gtk_tree_path_get_indices (path);
-  depth = gtk_tree_path_get_depth (path);
-
-  g_return_val_if_fail (depth == 1, FALSE);
-
-  return empty_list_store_init_iter (tree_model, indices[0], iter);
-}
-
-static GtkTreePath *
-empty_list_store_get_path (GtkTreeModel *tree_model,
-                           GtkTreeIter  *iter)
-{
-  GtkTreePath *path;
-
-  g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE);
-
-  path = gtk_tree_path_new ();
-  gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data));
-
-  return path;
-}
-
-static void
-empty_list_store_get_value (GtkTreeModel *tree_model,
-                            GtkTreeIter  *iter,
-                            gint          column,
-                            GValue       *value)
-{
-  g_return_if_reached ();
-}
-
-static gboolean
-empty_list_store_iter_next (GtkTreeModel *tree_model,
-                            GtkTreeIter  *iter)
-{
-  gint idx;
-
-  g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE);
-
-  idx = GPOINTER_TO_INT (iter->user_data);
-  return empty_list_store_init_iter (tree_model, idx + (idx >= 0), iter);
-}
-
-static gboolean
-empty_list_store_iter_children (GtkTreeModel *tree_model,
-                                GtkTreeIter  *iter,
-                                GtkTreeIter  *parent)
-{
-  return FALSE;
-}
-
-static gboolean
-empty_list_store_iter_has_child (GtkTreeModel *tree_model,
-                                 GtkTreeIter  *iter)
-{
-  return FALSE;
-}
-
-static gint
-empty_list_store_iter_n_children (GtkTreeModel *tree_model,
-                                  GtkTreeIter  *iter)
-{
-  return iter == NULL ? PSPPIRE_EMPTY_LIST_STORE (tree_model)->n_rows : 0;
-}
-
-static gboolean
-empty_list_store_iter_nth_child (GtkTreeModel *tree_model,
-                                 GtkTreeIter  *iter,
-                                 GtkTreeIter  *parent,
-                                 gint          n)
-{
-  g_return_val_if_fail (parent == NULL, FALSE);
-
-  return empty_list_store_init_iter (tree_model, n, iter);
-}
-
-static gboolean
-empty_list_store_iter_parent (GtkTreeModel *tree_model,
-                              GtkTreeIter  *iter,
-                              GtkTreeIter  *child)
-{
-  return FALSE;
-}
-
-gint
-empty_list_store_iter_to_row (const GtkTreeIter *iter)
-{
-  g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, 0);
-  return GPOINTER_TO_INT (iter->user_data);
-}
diff --git a/src/ui/gui/psppire-empty-list-store.h b/src/ui/gui/psppire-empty-list-store.h
deleted file mode 100644 (file)
index c207843..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef PSPPIRE_EMPTY_LIST_STORE_H
-#define PSPPIRE_EMPTY_LIST_STORE_H 1
-
-/* PsppireEmptyListStore is an GtkTreeModel implementation that has a
-   client-specified number of rows and zero columns.  It is a useful model for
-   GtkTreeView or PsppSheetView when the client can easily synthesize cell data
-   using a callback set with gtk_tree_view_column_set_cell_data_func().  In
-   that situation, GtkListStore can be wasteful (because it uses a lot of
-   memory to store what does not need to be stored) and situation-specific
-   custom models require additional boilerplate. */
-
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_EMPTY_LIST_STORE             (psppire_empty_list_store_get_type())
-#define PSPPIRE_EMPTY_LIST_STORE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStore))
-#define PSPPIRE_EMPTY_LIST_STORE_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStoreClass))
-#define PSPPIRE_IS_EMPTY_LIST_STORE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE))
-#define PSPPIRE_IS_EMPTY_LIST_STORE_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_EMPTY_LIST_STORE))
-#define PSPPIRE_EMPTY_LIST_STORE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStoreClass))
-
-typedef struct _PsppireEmptyListStore      PsppireEmptyListStore;
-typedef struct _PsppireEmptyListStoreClass PsppireEmptyListStoreClass;
-
-struct _PsppireEmptyListStore {
-  GObject parent;
-  gint n_rows;
-};
-
-struct _PsppireEmptyListStoreClass {
-  GObjectClass parent_class;
-};
-
-GType psppire_empty_list_store_get_type (void) G_GNUC_CONST;
-PsppireEmptyListStore* psppire_empty_list_store_new (gint n_rows);
-
-gint psppire_empty_list_store_get_n_rows (const PsppireEmptyListStore *);
-void psppire_empty_list_store_set_n_rows (PsppireEmptyListStore *,
-                                          gint n_rows);
-
-void psppire_empty_list_store_row_changed (PsppireEmptyListStore *,
-                                           gint row);
-void psppire_empty_list_store_row_inserted (PsppireEmptyListStore *,
-                                            gint row);
-void psppire_empty_list_store_row_deleted (PsppireEmptyListStore *,
-                                           gint row);
-
-gint empty_list_store_iter_to_row (const GtkTreeIter *);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_EMPTY_LIST_STORE_H */
index 5f8793186b3303e8201c724f48c6b5cfe0892239..f38438b37534e2b658951e8948526d9026208af3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2015, 2016  Free Software Foundation
+   Copyright (C) 2015, 2016, 2017  Free Software Foundation
 
    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
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-
 #include <config.h>
 
-#include <errno.h>
-#include <fcntl.h>
 #include <gtk/gtk.h>
-#include <sys/stat.h>
 
 #include "data/casereader.h"
 #include "data/data-in.h"
 #include "data/ods-reader.h"
 #include "data/spreadsheet-reader.h"
 #include "data/value-labels.h"
-
-#include "gl/intprops.h"
+#include "data/casereader-provider.h"
 
 #include "libpspp/i18n.h"
 #include "libpspp/line-reader.h"
 #include "libpspp/message.h"
+#include "libpspp/hmap.h"
+#include "libpspp/hash-functions.h"
 #include "libpspp/str.h"
 
 #include "builder-wrapper.h"
-#include "helper.h"
-#include "pspp-sheet-view.h"
-#include "pspp-sheet-selection.h"
-#include "psppire-import-assistant.h"
-#include "psppire-scanf.h"
+
+#include "psppire-data-sheet.h"
+#include "psppire-data-store.h"
 #include "psppire-dialog.h"
-#include "psppire-empty-list-store.h"
+#include "psppire-delimited-text.h"
+#include "psppire-dict.h"
 #include "psppire-encoding-selector.h"
+#include "psppire-import-assistant.h"
+#include "psppire-scanf.h"
 #include "psppire-spreadsheet-model.h"
-#include "psppire-var-sheet.h"
+#include "psppire-text-file.h"
+#include "psppire-variable-sheet.h"
+
 #include "ui/syntax-gen.h"
 
 #include <gettext.h>
 enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
 
 
-/* Sets IA's separators substructure to match the widgets. */
-static void get_separators (PsppireImportAssistant *ia);
-static void split_fields (PsppireImportAssistant *ia);
-
 /* Chooses a name for each column on the separators page */
 static void choose_column_names (PsppireImportAssistant *ia);
 
-
-/* Frees IA's file substructure. */
-static void destroy_file (PsppireImportAssistant *ia);
-
-static void clear_fields (PsppireImportAssistant *ia);
-
-
 static void intro_page_create (PsppireImportAssistant *ia);
 static void first_line_page_create (PsppireImportAssistant *ia);
 
-static gboolean process_file (PsppireImportAssistant *ia);
-
-
-static GtkWidget * create_data_tree_view (gboolean input, GtkContainer *parent,
-                                         PsppireImportAssistant *ia);
-
 static void separators_page_create (PsppireImportAssistant *ia);
 static void formats_page_create (PsppireImportAssistant *ia);
 
-static void push_watch_cursor (PsppireImportAssistant *ia);
-static void pop_watch_cursor (PsppireImportAssistant *ia);
-
-
-
 static void psppire_import_assistant_init            (PsppireImportAssistant      *act);
 static void psppire_import_assistant_class_init      (PsppireImportAssistantClass *class);
 
@@ -139,29 +117,20 @@ psppire_import_assistant_get_property (GObject    *object,
 static GObjectClass * parent_class = NULL;
 
 
-static void destroy_columns (PsppireImportAssistant *ia);
-
 static void
 psppire_import_assistant_finalize (GObject *object)
 {
   PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (object);
 
-
   if (ia->spreadsheet)
     spreadsheet_unref (ia->spreadsheet);
 
-  //  clear_fields (ia);
-  destroy_columns (ia);
-
-  ds_destroy (&ia->separators);
   ds_destroy (&ia->quotes);
 
   g_object_unref (ia->builder);
 
-  destroy_file (ia);
-
-  g_object_unref (ia->prop_renderer);
-  g_object_unref (ia->fixed_renderer);
+  ia->response = -1;
+  g_main_loop_unref (ia->main_loop);
 
   if (G_OBJECT_CLASS (parent_class)->finalize)
     G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -201,56 +170,44 @@ on_paste (GtkButton *button, PsppireImportAssistant *ia)
   close_assistant (ia, PSPPIRE_RESPONSE_PASTE);
 }
 
+
 /* Revises the contents of the fields tree view based on the
    currently chosen set of separators. */
 static void
 revise_fields_preview (PsppireImportAssistant *ia)
 {
-  push_watch_cursor (ia);
-
-  get_separators (ia);
-  split_fields (ia);
   choose_column_names (ia);
-  ia->fields_tree_view =
-    GTK_WIDGET (create_data_tree_view (TRUE,
-                                      GTK_CONTAINER (get_widget_assert (ia->builder, "fields-scroller")),
-                                      ia));
-
-  pop_watch_cursor (ia);
 }
 
-/* Chooses the most common character among those in TARGETS,
-   based on the frequency data in HISTOGRAM, and stores it in
-   RESULT.  If there is a tie for the most common character among
-   those in TARGETS, the earliest character is chosen.  If none
-   of the TARGETS appear at all, then DEF is used as a
-   fallback. */
-static void
-find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
-                      const char *targets, const char *def,
-                      struct string *result)
+
+struct separator
 {
-  unsigned char max = 0;
-  unsigned long int max_count = 0;
+  const char *name;           /* Name (for use with get_widget_assert). */
+  gunichar c;                 /* Separator character. */
+};
 
-  for (; *targets != '\0'; targets++)
-    {
-      unsigned char c = *targets;
-      unsigned long int count = histogram[c];
-      if (count > max_count)
-        {
-          max = c;
-          max_count = count;
-        }
-    }
-  if (max_count > 0)
-    {
-      ds_clear (result);
-      ds_put_byte (result, max);
-    }
-  else
-    ds_assign_cstr (result, def);
-}
+/* All the separators in the dialog box. */
+static const struct separator separators[] =
+  {
+    {"space",     ' '},
+    {"tab",       '\t'},
+    {"bang",      '!'},
+    {"colon",     ':'},
+    {"comma",     ','},
+    {"hyphen",    '-'},
+    {"pipe",      '|'},
+    {"semicolon", ';'},
+    {"slash",     '/'},
+  };
+
+#define SEPARATOR_CNT (sizeof separators / sizeof *separators)
+
+struct separator_count_node
+{
+  struct hmap_node node;
+  int occurance; /* The number of times the separator occurs in a line */
+  int quantity;  /* The number of lines with this occurance */
+};
 
 
 /* Picks the most likely separator and quote characters based on
@@ -258,115 +215,176 @@ find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
 static void
 choose_likely_separators (PsppireImportAssistant *ia)
 {
-  unsigned long int histogram[UCHAR_MAX + 1] = { 0 };
-  size_t row;
+  gint first_line = 0;
+  g_object_get (ia->delimiters_model, "first-line", &first_line, NULL);
+
+  gboolean valid;
+  GtkTreeIter iter;
+  int j;
+
+  struct hmap count_map[SEPARATOR_CNT];
+  for (j = 0; j < SEPARATOR_CNT; ++j)
+    hmap_init (count_map + j);
 
-  /* Construct a histogram of all the characters used in the
-     file. */
-  for (row = 0; row < ia->line_cnt; row++)
+  GtkTreePath *p = gtk_tree_path_new_from_indices (first_line, -1);
+
+  for (valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (ia->text_file), &iter, p);
+       valid;
+       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->text_file), &iter))
     {
-      struct substring line = ds_ss (&ia->lines[row]);
-      size_t length = ss_length (line);
-      size_t i;
-      for (i = 0; i < length; i++)
-        histogram[(unsigned char) line.string[i]]++;
-    }
+      gchar *line_text = NULL;
+      gtk_tree_model_get (GTK_TREE_MODEL (ia->text_file), &iter, 1, &line_text, -1);
 
-  find_commonest_chars (histogram, "\"'", "", &ia->quotes);
-  find_commonest_chars (histogram, ",;:/|!\t-", ",", &ia->separators);
-}
+      gint *counts = xzalloc (sizeof *counts * SEPARATOR_CNT);
 
+      struct substring cs = ss_cstr (line_text);
+      for (;
+          UINT32_MAX != ss_first_mb (cs);
+          ss_get_mb (&cs))
+       {
+         ucs4_t character = ss_first_mb (cs);
 
-static void set_separators (PsppireImportAssistant *ia);
+         int s;
+         for (s = 0; s < SEPARATOR_CNT; ++s)
+           {
+             if (character == separators[s].c)
+               counts[s]++;
+           }
+       }
+
+      int j;
+      for (j = 0; j < SEPARATOR_CNT; ++j)
+       {
+         if (counts[j] > 0)
+           {
+             struct separator_count_node *cn = NULL;
+             unsigned int hash = hash_int (counts[j], 0);
+             HMAP_FOR_EACH_WITH_HASH (cn, struct separator_count_node, node, hash, &count_map[j])
+               {
+                 if (cn->occurance == counts[j])
+                   break;
+               }
+
+             if (cn == NULL)
+               {
+                 struct separator_count_node *new_cn = xzalloc (sizeof *new_cn);
+                 new_cn->occurance = counts[j];
+                 new_cn->quantity = 1;
+                 hmap_insert (&count_map[j], &new_cn->node, hash);
+               }
+             else
+               cn->quantity++;
+           }
+       }
+
+      free (line_text);
+      free (counts);
+    }
+  gtk_tree_path_free (p);
+
+  int most_frequent = -1;
+  int largest = 0;
+  for (j = 0; j < SEPARATOR_CNT; ++j)
+    {
+      struct separator_count_node *cn;
+      HMAP_FOR_EACH (cn, struct separator_count_node, node, &count_map[j])
+       {
+         if (largest < cn->quantity)
+           {
+             largest = cn->quantity;
+             most_frequent = j;
+           }
+       }
+      hmap_destroy (&count_map[j]);
+    }
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, separators[most_frequent].name)), TRUE);
+}
 
-/* Called just before the separators page becomes visible in the
-   assistant, and when the Reset button is clicked. */
 static void
-prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *page)
+repopulate_delimiter_columns (PsppireImportAssistant *ia)
 {
-  revise_fields_preview (ia);
-  choose_likely_separators (ia);
-  set_separators (ia);
+  /* Remove all the columns */
+  while (gtk_tree_view_get_n_columns (GTK_TREE_VIEW (ia->fields_tree_view)) > 0)
+    {
+      GtkTreeViewColumn *tvc = gtk_tree_view_get_column (GTK_TREE_VIEW (ia->fields_tree_view), 0);
+      gtk_tree_view_remove_column (GTK_TREE_VIEW (ia->fields_tree_view), tvc);
+    }
+
+  gint n_fields =
+    gtk_tree_model_get_n_columns (GTK_TREE_MODEL (ia->delimiters_model));
+
+  /* ... and put them back again. */
+  gint f;
+  for (f = gtk_tree_view_get_n_columns (GTK_TREE_VIEW (ia->fields_tree_view));
+       f < n_fields; f++)
+    {
+      GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+
+      const gchar *title = NULL;
+
+      if (f == 0)
+       title = _("line");
+      else
+       {
+         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb)))
+           {
+             title =
+               psppire_delimited_text_get_header_title
+               (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), f - 1);
+           }
+         if (title == NULL)
+           title = _("var");
+       }
+
+      GtkTreeViewColumn *column =
+       gtk_tree_view_column_new_with_attributes (title,
+                                                 renderer,
+                                                 "text", f,
+                                                 NULL);
+      g_object_set (column,
+                   "resizable", TRUE,
+                   "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
+                   NULL);
+
+      gtk_tree_view_append_column (GTK_TREE_VIEW (ia->fields_tree_view), column);
+    }
 }
 
-struct separator
+static void
+reset_tree_view_model (PsppireImportAssistant *ia)
 {
-  const char *name;           /* Name (for use with get_widget_assert). */
-  int c;                      /* Separator character. */
-};
+  GtkTreeModel *tm = gtk_tree_view_get_model (GTK_TREE_VIEW (ia->fields_tree_view));
+  g_object_ref (tm);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), NULL);
 
-/* All the separators in the dialog box. */
-static const struct separator separators[] =
-  {
-    {"space", ' '},
-    {"tab", '\t'},
-    {"bang", '!'},
-    {"colon", ':'},
-    {"comma", ','},
-    {"hyphen", '-'},
-    {"pipe", '|'},
-    {"semicolon", ';'},
-    {"slash", '/'},
-  };
-#define SEPARATOR_CNT (sizeof separators / sizeof *separators)
 
+  repopulate_delimiter_columns (ia);
 
+  gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), tm);
+  //  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (ia->fields_tree_view));
+
+  g_object_unref (tm);
+}
 
-/* Sets the widgets to match IA's separators substructure. */
+/* Called just before the separators page becomes visible in the
+   assistant, and when the Reset button is clicked. */
 static void
-set_separators (PsppireImportAssistant *ia)
+prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *page)
 {
-  unsigned int seps;
-  struct string custom;
-  bool any_custom;
-  bool any_quotes;
-  size_t i;
+  gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view),
+                          GTK_TREE_MODEL (ia->delimiters_model));
 
-  ds_init_empty (&custom);
-  seps = 0;
-  for (i = 0; i < ds_length (&ia->separators); i++)
-    {
-      unsigned char c = ds_at (&ia->separators, i);
-      int j;
+  g_signal_connect_swapped (GTK_TREE_MODEL (ia->delimiters_model), "notify::delimiters",
+                       G_CALLBACK (reset_tree_view_model), ia);
 
-      for (j = 0; j < SEPARATOR_CNT; j++)
-        {
-          const struct separator *s = &separators[j];
-          if (s->c == c)
-            {
-              seps += 1u << j;
-              goto next;
-            }
-        }
 
-      ds_put_byte (&custom, c);
-    next:;
-    }
+  repopulate_delimiter_columns (ia);
 
-  for (i = 0; i < SEPARATOR_CNT; i++)
-    {
-      const struct separator *s = &separators[i];
-      GtkWidget *button = get_widget_assert (ia->builder, s->name);
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
-                                    (seps & (1u << i)) != 0);
-    }
-  any_custom = !ds_is_empty (&custom);
-  gtk_entry_set_text (GTK_ENTRY (ia->custom_entry), ds_cstr (&custom));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->custom_cb),
-                                any_custom);
-  gtk_widget_set_sensitive (ia->custom_entry, any_custom);
-  ds_destroy (&custom);
-
-  any_quotes = !ds_is_empty (&ia->quotes);
-
-  gtk_entry_set_text (ia->quote_entry,
-                      any_quotes ? ds_cstr (&ia->quotes) : "\"");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->quote_cb),
-                                any_quotes);
-  gtk_widget_set_sensitive (ia->quote_combo, any_quotes);
+  revise_fields_preview (ia);
+  choose_likely_separators (ia);
 }
 
-
 /* Resets IA's intro page to its initial state. */
 static void
 reset_intro_page (PsppireImportAssistant *ia)
@@ -384,13 +402,6 @@ reset_intro_page (PsppireImportAssistant *ia)
 static void
 reset_formats_page (PsppireImportAssistant *ia, GtkWidget *page)
 {
-  size_t i;
-
-  for (i = 0; i < ia->modified_var_cnt; i++)
-    var_destroy (ia->modified_vars[i]);
-  free (ia->modified_vars);
-  ia->modified_vars = NULL;
-  ia->modified_var_cnt = 0;
 }
 
 static void prepare_formats_page (PsppireImportAssistant *ia);
@@ -478,215 +489,6 @@ on_close (GtkAssistant *assistant, PsppireImportAssistant *ia)
 }
 
 
-/* Frees IA's file substructure. */
-static void
-destroy_file (PsppireImportAssistant *ia)
-{
-  size_t i;
-
-  for (i = 0; i < ia->line_cnt; i++)
-    ds_destroy (&ia->lines[i]);
-
-  g_free (ia->file_name);
-  ia->file_name = NULL;
-
-  g_free (ia->encoding);
-  ia->encoding = NULL;
-}
-
-
-/* Increments the "watch cursor" level, setting the cursor for
-   the assistant window to a watch face to indicate to the user
-   that the ongoing operation may take some time. */
-static void
-push_watch_cursor (PsppireImportAssistant *ia)
-{
-  if (++ia->watch_cursor == 1)
-    {
-      GtkWidget *widget = GTK_WIDGET (ia);
-      GdkDisplay *display = gtk_widget_get_display (widget);
-      GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
-      gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
-      g_object_unref (cursor);
-      gdk_display_flush (display);
-    }
-}
-
-/* Decrements the "watch cursor" level.  If the level reaches
-   zero, the cursor is reset to its default shape. */
-static void
-pop_watch_cursor (PsppireImportAssistant *ia)
-{
-  if (--ia->watch_cursor == 0)
-    {
-      GtkWidget *widget = GTK_WIDGET (ia);
-      gdk_window_set_cursor (gtk_widget_get_window (widget), NULL);
-    }
-}
-
-
-static gboolean
-process_file (PsppireImportAssistant *ia)
-{
-  struct string input;
-  struct line_reader *reader = line_reader_for_file (ia->encoding, ia->file_name, O_RDONLY);
-  if (reader == NULL)
-    {
-      msg_error (errno, _("Could not open `%s'"),
-                ia->file_name);
-      return FALSE;
-    }
-
-  ds_init_empty (&input);
-  for (ia->line_cnt = 0; ia->line_cnt < MAX_PREVIEW_LINES; ia->line_cnt++)
-    {
-      ds_clear (&input);
-      if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
-         || ds_length (&input) > MAX_LINE_LEN)
-       {
-         if (line_reader_eof (reader))
-           break;
-         else if (line_reader_error (reader))
-           msg (ME, _("Error reading `%s': %s"),
-                ia->file_name, strerror (line_reader_error (reader)));
-         else
-           msg (ME, _("Failed to read `%s', because it contains a line "
-                      "over %d bytes long and therefore appears not to be "
-                      "a text file."),
-                ia->file_name, MAX_LINE_LEN);
-         line_reader_close (reader);
-         destroy_file (ia);
-         ds_destroy (&input);
-         return FALSE;
-       }
-
-      char *s = recode_string ("UTF-8", line_reader_get_encoding (reader),   ds_cstr (&input), ds_length (&input));
-      ds_init_cstr (&ia->lines[ia->line_cnt], s);
-      free (s);
-    }
-  ds_destroy (&input);
-  if (ia->line_cnt == 0)
-    {
-      msg (ME, _("`%s' is empty."), ia->file_name);
-      line_reader_close (reader);
-      destroy_file (ia);
-      return FALSE;
-    }
-
-  /* Estimate the number of lines in the file. */
-  if (ia->line_cnt < MAX_PREVIEW_LINES)
-    {
-      ia->total_lines = ia->line_cnt;
-      ia->total_is_exact = true;
-    }
-  else
-    {
-      struct stat s;
-      off_t position = line_reader_tell (reader);
-      if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
-       {
-         ia->total_lines = (double) ia->line_cnt / position * s.st_size;
-         ia->total_is_exact = false;
-       }
-      else
-       {
-         ia->total_lines = 0;
-         ia->total_is_exact = true;
-       }
-    }
-  line_reader_close (reader);
-  return TRUE;
-}
-
-
-static void
-render_line_number (PsppSheetViewColumn *tree_column,
-                    GtkCellRenderer *cell,
-                    GtkTreeModel *tree_model,
-                    GtkTreeIter *iter,
-                    gpointer data)
-{
-  gint row = empty_list_store_iter_to_row (iter);
-  char s[INT_BUFSIZE_BOUND (int)];
-  int first_line = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model),
-                                                      "first-line"));
-  sprintf (s, "%d", first_line + row);
-  g_object_set (cell, "text", s, NULL);
-}
-
-
-
-static gint
-get_string_width (GtkWidget *treeview, GtkCellRenderer *renderer,
-                 const char *string)
-{
-  gint width;
-  g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
-  gtk_cell_renderer_get_preferred_width (renderer, treeview,
-                                        NULL, &width);
-  return width;
-}
-
-
-static gint
-get_monospace_width (GtkWidget *treeview, GtkCellRenderer *renderer,
-                     size_t char_cnt)
-{
-  struct string s;
-  gint width;
-
-  ds_init_empty (&s);
-  ds_put_byte_multiple (&s, '0', char_cnt);
-  ds_put_byte (&s, ' ');
-  width = get_string_width (treeview, renderer, ds_cstr (&s));
-  ds_destroy (&s);
-
-  return width;
-}
-
-static void
-add_line_number_column (const PsppireImportAssistant *ia,
-                        GtkWidget *treeview)
-{
-  PsppSheetViewColumn *column =
-    pspp_sheet_view_column_new_with_attributes (_("Line"), ia->prop_renderer, (void *) NULL);
-
-  pspp_sheet_view_column_set_fixed_width (column, get_monospace_width (treeview, ia->prop_renderer, 5));
-
-  pspp_sheet_view_column_set_resizable (column, TRUE);
-
-  pspp_sheet_view_column_set_cell_data_func (column, ia->prop_renderer,
-                                             render_line_number, NULL, NULL);
-
-  pspp_sheet_view_append_column (PSPP_SHEET_VIEW (treeview), column);
-}
-
-
-static void
-set_model_on_treeview (PsppireImportAssistant *ia, GtkWidget *tree_view, size_t first_line)
-{
-  GtkTreeModel *model = GTK_TREE_MODEL (psppire_empty_list_store_new (ia->line_cnt - first_line));
-
-  g_object_set_data (G_OBJECT (model), "lines", &ia->lines + first_line);
-  g_object_set_data (G_OBJECT (model), "first-line", GINT_TO_POINTER (first_line));
-
-  pspp_sheet_view_set_model (PSPP_SHEET_VIEW (tree_view), model);
-
-  g_object_unref (model);
-}
-
-
-static GtkWidget *
-make_tree_view (const PsppireImportAssistant *ia)
-{
-  GtkWidget *tree_view = pspp_sheet_view_new ();
-  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_GRID_LINES_BOTH);
-
-  add_line_number_column (ia, tree_view);
-
-  return tree_view;
-}
-
 static GtkWidget *
 add_page_to_assistant (PsppireImportAssistant *ia,
                       GtkWidget *page, GtkAssistantPageType type, const gchar *);
@@ -724,7 +526,6 @@ prepare_sheet_spec_page (PsppireImportAssistant *ia)
 }
 
 
-
 /* Initializes IA's sheet_spec substructure. */
 static void
 sheet_spec_page_create (PsppireImportAssistant *ia)
@@ -748,7 +549,6 @@ sheet_spec_page_create (PsppireImportAssistant *ia)
   g_object_set_data (G_OBJECT (page), "on-entering", prepare_sheet_spec_page);
 }
 
-
 static void
 on_chosen (PsppireImportAssistant *ia, GtkWidget *page)
 {
@@ -761,7 +561,7 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page)
 
   gtk_assistant_set_page_complete (GTK_ASSISTANT(ia), GTK_WIDGET (fc), FALSE);
 
-  if (f && !g_file_test (f, G_FILE_TEST_IS_DIR))
+  if (f && g_file_test (f, G_FILE_TEST_IS_REGULAR))
     {
       gtk_assistant_set_page_complete (GTK_ASSISTANT(ia), GTK_WIDGET (fc), TRUE);
 
@@ -773,15 +573,15 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page)
       if (!ia->spreadsheet)
        ia->spreadsheet = ods_probe (f, FALSE);
 
-      if (!ia->spreadsheet)
+      if (ia->spreadsheet)
        {
-         intro_page_create (ia);
-         first_line_page_create (ia);
-         separators_page_create (ia);
+         sheet_spec_page_create (ia);
        }
       else
        {
-         sheet_spec_page_create (ia);
+         intro_page_create (ia);
+         first_line_page_create (ia);
+         separators_page_create (ia);
        }
 
       formats_page_create (ia);
@@ -795,14 +595,18 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page)
 static void
 on_map (PsppireImportAssistant *ia, GtkWidget *page)
 {
+#if TEXT_FILE
   GtkFileChooser *fc = GTK_FILE_CHOOSER (page);
 
   if (ia->file_name)
     gtk_file_chooser_set_filename (fc, ia->file_name);
+#endif
 
   on_chosen (ia, page);
 }
 
+
+
 static void
 chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page)
 {
@@ -811,17 +615,19 @@ chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page)
 static void
 chooser_page_leave (PsppireImportAssistant *ia, GtkWidget *page)
 {
-
-  if (ia->file_name)
-    g_free (ia->file_name);
+  g_free (ia->file_name);
   ia->file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (page));
-
-  if (ia->encoding)
-    g_free (ia->encoding);
-  ia->encoding = psppire_encoding_selector_get_encoding (ia->encoding_selector);
+  gchar *encoding = psppire_encoding_selector_get_encoding (ia->encoding_selector);
 
   if (!ia->spreadsheet)
-    process_file (ia);
+    {
+      ia->text_file = psppire_text_file_new (ia->file_name, encoding);
+      gtk_tree_view_set_model (GTK_TREE_VIEW (ia->first_line_tree_view),
+                              GTK_TREE_MODEL (ia->text_file));
+    }
+
+
+  g_free (encoding);
 }
 
 static void
@@ -835,6 +641,8 @@ chooser_page_reset (PsppireImportAssistant *ia, GtkWidget *page)
   on_chosen (ia, page);
 }
 
+
+
 static void
 chooser_page_create (PsppireImportAssistant *ia)
 {
@@ -909,27 +717,18 @@ chooser_page_create (PsppireImportAssistant *ia)
 }
 
 
+
 static void
 psppire_import_assistant_init (PsppireImportAssistant *ia)
 {
   ia->builder = builder_new ("text-data-import.ui");
 
   ia->current_page = -1 ;
-  ia->column_cnt = 0;
-  ia->columns = NULL;
-
   ia->file_name = NULL;
-  ia->encoding = NULL;
+
   ia->spreadsheet = NULL;
-  ia->watch_cursor = 0;
 
-  ia->prop_renderer = gtk_cell_renderer_text_new ();
-  g_object_ref_sink (ia->prop_renderer);
-  ia->fixed_renderer = gtk_cell_renderer_text_new ();
-  g_object_ref_sink (ia->fixed_renderer);
-  g_object_set (G_OBJECT (ia->fixed_renderer),
-                "family", "Monospace",
-                (void *) NULL);
+  ia->main_loop = g_main_loop_new (NULL, TRUE);
 
   g_signal_connect (ia, "prepare", G_CALLBACK (on_prepare), ia);
   g_signal_connect (ia, "cancel", G_CALLBACK (on_cancel), ia);
@@ -981,157 +780,120 @@ static void
 on_intro_amount_changed (PsppireImportAssistant *p)
 {
   gtk_widget_set_sensitive (p->n_cases_spin,
-                            gtk_toggle_button_get_active (
-                                                         GTK_TOGGLE_BUTTON (p->n_cases_button)));
+                           gtk_toggle_button_get_active
+                           (GTK_TOGGLE_BUTTON (p->n_cases_button)));
 
   gtk_widget_set_sensitive (p->percent_spin,
-                            gtk_toggle_button_get_active (
-                                                         GTK_TOGGLE_BUTTON (p->percent_button)));
+                           gtk_toggle_button_get_active
+                           (GTK_TOGGLE_BUTTON (p->percent_button)));
 }
 
-
 static void
-render_line (PsppSheetViewColumn *tree_column,
-             GtkCellRenderer *cell,
-             GtkTreeModel *tree_model,
-             GtkTreeIter *iter,
-             gpointer data)
-{
-  gint row = empty_list_store_iter_to_row (iter);
-  struct string *lines;
-
-  lines = g_object_get_data (G_OBJECT (tree_model), "lines");
-  g_return_if_fail (lines != NULL);
-
-  g_object_set (cell, "text", ds_cstr (&lines[row]), NULL);
-}
-
-/* Sets the widgets to match IA's first_line substructure. */
-static void
-set_first_line (PsppireImportAssistant *ia)
-{
-  GtkTreePath *path = gtk_tree_path_new_from_indices (ia->skip_lines, -1);
-
-
-  set_model_on_treeview (ia, ia->tree_view, 0);
-
-  pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->tree_view),
-                             path, NULL, false);
-  gtk_tree_path_free (path);
-
-  gtk_toggle_button_set_active (
-                               GTK_TOGGLE_BUTTON (ia->variable_names_cb),
-                               ia->variable_names);
-  gtk_widget_set_sensitive (ia->variable_names_cb,
-                            ia->skip_lines > 0);
-}
-
-
-/* Creates and returns a tree view that contains each of the
-   lines in IA's file as a row. */
-static GtkWidget *
-create_lines_tree_view (GtkContainer *parent, PsppireImportAssistant *ia)
-{
-  size_t max_line_length;
-  gint content_width, header_width;
-  size_t i;
-  const gchar *title = _("Text");
-  GtkWidget *tree_view = make_tree_view (ia);
-  PsppSheetViewColumn *column =
-    pspp_sheet_view_column_new_with_attributes (title,
-                                               ia->fixed_renderer, (void *) NULL);
-
-  pspp_sheet_view_column_set_cell_data_func (column, ia->fixed_renderer,
-                                            render_line, NULL, NULL);
-  pspp_sheet_view_column_set_resizable (column, TRUE);
-  pspp_sheet_view_column_set_expand (column, TRUE);
-
-  max_line_length = 0;
-  for (i = 0; i < ia->line_cnt; i++)
-    {
-      size_t w = ds_length (&ia->lines[i]);
-      max_line_length = MAX (max_line_length, w);
-    }
-
-  content_width = get_monospace_width (tree_view, ia->fixed_renderer,
-                                       max_line_length);
-  header_width = get_string_width (tree_view, ia->prop_renderer, title);
-  pspp_sheet_view_column_set_fixed_width (column, MAX (content_width,
-                                                      header_width));
-  pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), column);
-
-  GtkWidget *oldtv = gtk_bin_get_child (GTK_BIN (parent));
-  if (oldtv)
-    gtk_container_remove (parent, oldtv);
-
-  gtk_container_add (parent, tree_view);
-  gtk_widget_show (tree_view);
-
-  return tree_view;
-}
-
-
-/* Sets IA's first_line substructure to match the widgets. */
-static void
-set_first_line_options (PsppireImportAssistant *ia)
+on_treeview_selection_change (PsppireImportAssistant *ia)
 {
+  GtkTreeSelection *selection =
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (ia->first_line_tree_view));
+  GtkTreeModel *model = NULL;
   GtkTreeIter iter;
-  GtkTreeModel *model;
-
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view));
-  if (pspp_sheet_selection_get_selected (selection, &model, &iter))
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
     {
+      gint max_lines;
+      int n;
       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
-      int row = gtk_tree_path_get_indices (path)[0];
+      gint *index = gtk_tree_path_get_indices (path);
+      n = *index;
       gtk_tree_path_free (path);
-
-      ia->skip_lines = row;
-      ia->variable_names =
-        (ia->skip_lines > 0
-         && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb)));
+      g_object_get (model, "maximum-lines", &max_lines, NULL);
+      gtk_widget_set_sensitive (ia->variable_names_cb,
+                               (n > 0 && n < max_lines));
+      ia->delimiters_model =
+       psppire_delimited_text_new (GTK_TREE_MODEL (ia->text_file));
+      g_object_set (ia->delimiters_model, "first-line", n, NULL);
     }
-
-  gtk_widget_set_sensitive (ia->variable_names_cb, ia->skip_lines > 0);
 }
 
 static void
-reset_first_line_page (PsppireImportAssistant *ia)
-{
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb), FALSE);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view));
-  pspp_sheet_selection_unselect_all (selection);
-  gtk_widget_set_sensitive (ia->variable_names_cb, FALSE);
+render_text_preview_line (GtkTreeViewColumn *tree_column,
+               GtkCellRenderer *cell,
+               GtkTreeModel *tree_model,
+               GtkTreeIter *iter,
+               gpointer data)
+{
+  /*
+     Set the text  to a "insensitive" state if the row
+     is greater than what the user declared to be the maximum.
+  */
+  GtkTreePath *path = gtk_tree_model_get_path (tree_model, iter);
+  gint *ii = gtk_tree_path_get_indices (path);
+  gint max_lines;
+  g_object_get (tree_model, "maximum-lines", &max_lines, NULL);
+  g_object_set (cell, "sensitive", (*ii < max_lines), NULL);
+  gtk_tree_path_free (path);
 }
 
-
 /* Initializes IA's first_line substructure. */
 static void
 first_line_page_create (PsppireImportAssistant *ia)
 {
   GtkWidget *w =  get_widget_assert (ia->builder, "FirstLine");
 
-  g_object_set_data (G_OBJECT (w), "on-entering", set_first_line);
+  g_object_set_data (G_OBJECT (w), "on-entering", on_treeview_selection_change);
 
   add_page_to_assistant (ia, w,
                         GTK_ASSISTANT_PAGE_CONTENT, _("Select the First Line"));
 
-  ia->tree_view = GTK_WIDGET (create_lines_tree_view (
-                                                     GTK_CONTAINER (get_widget_assert (ia->builder, "first-line-scroller")), ia));
-  ia->variable_names_cb = get_widget_assert (ia->builder, "variable-names");
-  pspp_sheet_selection_set_mode (
-                                pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)),
-                                PSPP_SHEET_SELECTION_BROWSE);
-  pspp_sheet_view_set_rubber_banding (PSPP_SHEET_VIEW (ia->tree_view), TRUE);
+  GtkWidget *scrolled_window = get_widget_assert (ia->builder, "first-line-scroller");
+
+  if (ia->first_line_tree_view == NULL)
+    {
+      ia->first_line_tree_view = gtk_tree_view_new ();
+      g_object_set (ia->first_line_tree_view, "enable-search", FALSE, NULL);
 
+      gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ia->first_line_tree_view), TRUE);
 
-  g_signal_connect_swapped (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)),
-                           "changed", G_CALLBACK (set_first_line_options), ia);
+      GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (_("Line"), renderer,
+                                                                           "text", 0,
+                                                                           NULL);
 
-  g_signal_connect_swapped (ia->variable_names_cb, "toggled",
-                           G_CALLBACK (set_first_line_options), ia);
+      gtk_tree_view_column_set_cell_data_func (column, renderer, render_text_preview_line, ia, 0);
+      gtk_tree_view_append_column (GTK_TREE_VIEW (ia->first_line_tree_view), column);
 
+      renderer = gtk_cell_renderer_text_new ();
+      column = gtk_tree_view_column_new_with_attributes (_("Text"), renderer, "text", 1, NULL);
+      gtk_tree_view_column_set_cell_data_func (column, renderer, render_text_preview_line, ia, 0);
 
-  g_object_set_data (G_OBJECT (w), "on-reset", reset_first_line_page);
+      gtk_tree_view_append_column (GTK_TREE_VIEW (ia->first_line_tree_view), column);
+
+      g_signal_connect_swapped (ia->first_line_tree_view, "cursor-changed",
+                               G_CALLBACK (on_treeview_selection_change), ia);
+      gtk_container_add (GTK_CONTAINER (scrolled_window), ia->first_line_tree_view);
+    }
+
+  gtk_widget_show_all (scrolled_window);
+
+  ia->variable_names_cb = get_widget_assert (ia->builder, "variable-names");
+}
+
+static void
+intro_on_leave (PsppireImportAssistant *ia)
+{
+  gint lc = 0;
+  g_object_get (ia->text_file, "line-count", &lc, NULL);
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->n_cases_button)))
+    {
+      gint max_lines = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin));
+      g_object_set (ia->text_file, "maximum-lines", max_lines, NULL);
+    }
+  else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->percent_button)))
+    {
+      gdouble percent = gtk_spin_button_get_value (GTK_SPIN_BUTTON (ia->percent_spin));
+      g_object_set (ia->text_file, "maximum-lines", (gint) (lc * percent / 100.0), NULL);
+    }
+  else
+    {
+      g_object_set (ia->text_file, "maximum-lines", lc, NULL);
+    }
 }
 
 
@@ -1143,39 +905,39 @@ intro_on_enter (PsppireImportAssistant *ia)
 
   struct string s;
 
-  if (ia->line_cnt > MAX_PREVIEW_LINES)
-    ia->line_cnt = MAX_PREVIEW_LINES;
-
   ds_init_empty (&s);
   ds_put_cstr (&s, _("This assistant will guide you through the process of "
                      "importing data into PSPP from a text file with one line "
                      "per case,  in which fields are separated by tabs, "
                      "commas, or other delimiters.\n\n"));
 
-  if (ia->total_is_exact)
-    {
-      ds_put_format (
-                    &s, ngettext ("The selected file contains %'lu line of text.  ",
-                                  "The selected file contains %'lu lines of text.  ",
-                                  ia->total_lines),
-                    ia->total_lines);
-    }
-  else if (ia->total_lines > 0)
+  if (ia->text_file)
     {
-      ds_put_format (
-                    &s, ngettext (
-                                  "The selected file contains approximately %'lu line of text.  ",
-                                  "The selected file contains approximately %'lu lines of text.  ",
-                                  ia->total_lines),
-                    ia->total_lines);
-      ds_put_format (
-                    &s, ngettext (
-                                  "Only the first %zu line of the file will be shown for "
-                                  "preview purposes in the following screens.  ",
-                                  "Only the first %zu lines of the file will be shown for "
-                                  "preview purposes in the following screens.  ",
-                                  ia->line_cnt),
-                    ia->line_cnt);
+      if (ia->text_file->total_is_exact)
+       {
+         ds_put_format (
+                        &s, ngettext ("The selected file contains %'lu line of text.  ",
+                                      "The selected file contains %'lu lines of text.  ",
+                                      ia->text_file->total_lines),
+                        ia->text_file->total_lines);
+       }
+      else if (ia->text_file->total_lines > 0)
+       {
+         ds_put_format (
+                        &s, ngettext (
+                                      "The selected file contains approximately %'lu line of text.  ",
+                                      "The selected file contains approximately %'lu lines of text.  ",
+                                      ia->text_file->total_lines),
+                        ia->text_file->total_lines);
+         ds_put_format (
+                        &s, ngettext (
+                                      "Only the first %zu line of the file will be shown for "
+                                      "preview purposes in the following screens.  ",
+                                      "Only the first %zu lines of the file will be shown for "
+                                      "preview purposes in the following screens.  ",
+                                      ia->text_file->line_cnt),
+                        ia->text_file->line_cnt);
+       }
     }
 
   ds_put_cstr (&s, _("You may choose below how much of the file should "
@@ -1185,38 +947,26 @@ intro_on_enter (PsppireImportAssistant *ia)
                       ds_cstr (&s));
   ds_destroy (&s);
 
-  GtkWidget *w  =  gtk_grid_get_child_at (GTK_GRID (table), 1, 1);
-  int old_value = w ? gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)) : 1;
-  if (w)
-    gtk_container_remove (GTK_CONTAINER (table), w);
-
-  w  =  gtk_grid_get_child_at (GTK_GRID (table), 1, 2);
-  if (w)
-    gtk_container_remove (GTK_CONTAINER (table), w);
-
-
-  GtkWidget *hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &ia->n_cases_spin);
+  if (gtk_grid_get_child_at (GTK_GRID (table), 1, 1) == NULL)
+    {
+      GtkWidget *hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &ia->n_cases_spin);
+      gtk_grid_attach (GTK_GRID (table), hbox_n_cases,
+                      1, 1,
+                      1, 1);
+    }
 
   GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ia->n_cases_spin));
   gtk_adjustment_set_lower (adj, 1.0);
-  if (ia->total_is_exact)
-    gtk_adjustment_set_value (adj, old_value);
-  if (ia->total_is_exact)
-    gtk_adjustment_set_upper (adj, ia->total_lines);
-  else
-    gtk_adjustment_set_upper (adj, DBL_MAX);
-
-  gtk_grid_attach (GTK_GRID (table), hbox_n_cases,
-                  1, 1,
-                  1, 1);
 
+  if (gtk_grid_get_child_at (GTK_GRID (table), 1, 2) == NULL)
+    {
+      GtkWidget *hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"),
+                                                  &ia->percent_spin);
 
-  GtkWidget *hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"),
-                                              &ia->percent_spin);
-
-  gtk_grid_attach (GTK_GRID (table), hbox_percent,
-                  1, 2,
-                  1, 1);
+      gtk_grid_attach (GTK_GRID (table), hbox_percent,
+                      1, 2,
+                      1, 1);
+    }
 
   gtk_widget_show_all (table);
 
@@ -1250,6 +1000,7 @@ intro_page_create (PsppireImportAssistant *ia)
                            G_CALLBACK (on_intro_amount_changed), ia);
 
 
+  g_object_set_data (G_OBJECT (w), "on-forward", intro_on_leave);
   g_object_set_data (G_OBJECT (w), "on-entering", intro_on_enter);
   g_object_set_data (G_OBJECT (w), "on-reset", reset_intro_page);
 }
@@ -1259,275 +1010,29 @@ GtkWidget *
 psppire_import_assistant_new (GtkWindow *toplevel)
 {
   return GTK_WIDGET (g_object_new (PSPPIRE_TYPE_IMPORT_ASSISTANT,
-                                  "transient-for", toplevel,
+                                  /* Some window managers (notably ratpoison)
+                                     ignore the maximise command when a window is
+                                     transient.  This causes problems for this
+                                     window. */
+                                  /* "transient-for", toplevel, */
                                   NULL));
 }
 
-\f
-
-struct column
-{
-  /* Variable name for this column.  This is the variable name
-     used on the separators page; it can be overridden by the
-     user on the formats page. */
-  char *name;
-
-  /* Maximum length of any row in this column. */
-  size_t width;
-
-  /* Contents of this column: contents[row] is the contents for
-     the given row.
-
-     A null substring indicates a missing column for that row
-     (because the line contains an insufficient number of
-     separators).
-
-     contents[] elements may be substrings of the lines[]
-     strings that represent the whole lines of the file, to
-     save memory.  Other elements are dynamically allocated
-     with ss_alloc_substring. */
-  struct substring *contents;
-};
-
-
-static void
-destroy_columns (PsppireImportAssistant *ia)
-{
-  struct column *col;
-  for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++)
-    {
-      free (col->name);
-      free (col->contents);
-    }
-
-  free (ia->columns);
-}
-
-/* Called to render one of the cells in the fields preview tree
-   view. */
-static void
-render_input_cell (PsppSheetViewColumn *tree_column, GtkCellRenderer *cell,
-                   GtkTreeModel *model, GtkTreeIter *iter,
-                   gpointer ia_)
-{
-  PsppireImportAssistant *ia = ia_;
-  struct substring field;
-  size_t row;
-  gint column;
-
-  column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
-                                               "column-number"));
-  row = empty_list_store_iter_to_row (iter) + ia->skip_lines;
-  field = ia->columns[column].contents[row];
-  if (field.string != NULL)
-    {
-      GValue text = {0, };
-      g_value_init (&text, G_TYPE_STRING);
-      g_value_take_string (&text, ss_xstrdup (field));
-      g_object_set_property (G_OBJECT (cell), "text", &text);
-      g_value_unset (&text);
-      g_object_set (cell, "background-set", FALSE, (void *) NULL);
-    }
-  else
-    g_object_set (cell,
-                  "text", "",
-                  "background", "red",
-                  "background-set", TRUE,
-                  (void *) NULL);
-}
-
-
-/* Parses the contents of the field at (ROW,COLUMN) according to
-   its variable format.  If OUTPUTP is non-null, then *OUTPUTP
-   receives the formatted output for that field (which must be
-   freed with free).  If TOOLTIPP is non-null, then *TOOLTIPP
-   receives a message suitable for use in a tooltip, if one is
-   needed, or a null pointer otherwise.  Returns TRUE if a
-   tooltip message is needed, otherwise FALSE. */
-static bool
-parse_field (PsppireImportAssistant *ia,
-             size_t row, size_t column,
-             char **outputp, char **tooltipp)
-{
-  const struct fmt_spec *in;
-  struct fmt_spec out;
-  char *tooltip;
-  bool ok;
-
-  struct substring field = ia->columns[column].contents[row];
-  struct variable *var = dict_get_var (ia->dict, column);
-  union value val;
-
-  value_init (&val, var_get_width (var));
-  in = var_get_print_format (var);
-  out = fmt_for_output_from_input (in);
-  tooltip = NULL;
-  if (field.string != NULL)
-    {
-      char *error = data_in (field, "UTF-8", in->type, &val, var_get_width (var),
-                            dict_get_encoding (ia->dict));
-      if (error != NULL)
-        {
-          tooltip = xasprintf (_("Cannot parse field content `%.*s' as "
-                                 "format %s: %s"),
-                               (int) field.length, field.string,
-                               fmt_name (in->type), error);
-          free (error);
-        }
-    }
-  else
-    {
-      tooltip = xstrdup (_("This input line has too few separators "
-                           "to fill in this field."));
-      value_set_missing (&val, var_get_width (var));
-    }
-  if (outputp != NULL)
-    {
-      *outputp = data_out (&val, dict_get_encoding (ia->dict),  &out);
-    }
-  value_destroy (&val, var_get_width (var));
-
-  ok = tooltip == NULL;
-  if (tooltipp != NULL)
-    *tooltipp = tooltip;
-  else
-    free (tooltip);
-  return ok;
-}
-
-
-/* Called to render one of the cells in the data preview tree
-   view. */
-static void
-render_output_cell (PsppSheetViewColumn *tree_column,
-                    GtkCellRenderer *cell,
-                    GtkTreeModel *model,
-                    GtkTreeIter *iter,
-                    gpointer ia_)
-{
-  PsppireImportAssistant *ia = ia_;
-  char *output;
-  GValue gvalue = { 0, };
-  bool ok = parse_field (ia,
-                        (empty_list_store_iter_to_row (iter)
-                         + ia->skip_lines),
-                        GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
-                                                            "column-number")),
-                        &output, NULL);
-
-  g_value_init (&gvalue, G_TYPE_STRING);
-  g_value_take_string (&gvalue, output);
-  g_object_set_property (G_OBJECT (cell), "text", &gvalue);
-  g_value_unset (&gvalue);
-
-  if (ok)
-    g_object_set (cell, "background-set", FALSE, (void *) NULL);
-  else
-    g_object_set (cell,
-                  "background", "red",
-                  "background-set", TRUE,
-                  (void *) NULL);
-}
-
-
-/* Utility functions used by multiple pages of the assistant. */
-
-static gboolean
-get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
-                      const PsppireImportAssistant *ia,
-                      size_t *row, size_t *column)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  gint bx, by;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-  PsppSheetViewColumn *tree_column;
-  GtkTreeModel *tree_model;
-  bool ok;
-
-  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
-                                                       wx, wy, &bx, &by);
-  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
-                                       &path, &tree_column, NULL, NULL))
-    return FALSE;
-
-  *column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
-                                                "column-number"));
-
-  tree_model = pspp_sheet_view_get_model (tree_view);
-  ok = gtk_tree_model_get_iter (tree_model, &iter, path);
-  gtk_tree_path_free (path);
-  if (!ok)
-    return FALSE;
-
-  *row = empty_list_store_iter_to_row (&iter) + ia->skip_lines;
-  return TRUE;
-}
 
 
 \f
 
-
-/* Called to render a tooltip on one of the cells in the fields
-   preview tree view. */
-static gboolean
-on_query_input_tooltip (GtkWidget *widget, gint wx, gint wy,
-                        gboolean keyboard_mode UNUSED,
-                        GtkTooltip *tooltip, PsppireImportAssistant *ia)
-{
-  size_t row, column;
-
-  if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
-    return FALSE;
-
-  if (ia->columns[column].contents[row].string != NULL)
-    return FALSE;
-
-  gtk_tooltip_set_text (tooltip,
-                        _("This input line has too few separators "
-                          "to fill in this field."));
-  return TRUE;
-}
-
-
-/* Called to render a tooltip for one of the cells in the data
-   preview tree view. */
-static gboolean
-on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy,
-                        gboolean keyboard_mode UNUSED,
-                        GtkTooltip *tooltip, PsppireImportAssistant *ia)
-{
-  size_t row, column;
-  char *text;
-
-  if (!gtk_widget_get_mapped (widget))
-    return FALSE;
-
-  if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
-    return FALSE;
-
-  if (parse_field (ia, row, column, NULL, &text))
-    return FALSE;
-
-  gtk_tooltip_set_text (tooltip, text);
-  free (text);
-  return TRUE;
-}
-
-\f
-
-
 static void
 set_quote_list (GtkComboBox *cb)
 {
   GtkListStore *list =  gtk_list_store_new (1, G_TYPE_STRING);
   GtkTreeIter iter;
   gint i;
-  const gchar *seperator[3] = {"'\"", "\'", "\""};
+  const gchar *separator[3] = {"'\"", "\'", "\""};
 
   for (i = 0; i < 3; i++)
     {
-      const gchar *s = seperator[i];
+      const gchar *s = separator[i];
 
       /* Add a new row to the model */
       gtk_list_store_append (list, &iter);
@@ -1543,294 +1048,58 @@ set_quote_list (GtkComboBox *cb)
   gtk_combo_box_set_entry_text_column (cb, 0);
 }
 
-
-
-
-/* Sets IA's separators substructure to match the widgets. */
-static void
-get_separators (PsppireImportAssistant *ia)
-{
-  int i;
-
-  ds_clear (&ia->separators);
-  for (i = 0; i < SEPARATOR_CNT; i++)
-    {
-      const struct separator *sep = &separators[i];
-      GtkWidget *button = get_widget_assert (ia->builder, sep->name);
-      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
-        ds_put_byte (&ia->separators, sep->c);
-    }
-
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->custom_cb)))
-    ds_put_cstr (&ia->separators,
-                 gtk_entry_get_text (GTK_ENTRY (ia->custom_entry)));
-
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->quote_cb)))
-    {
-      const gchar *text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (ia->quote_combo))));
-      ds_assign_cstr (&ia->quotes, text);
-    }
-  else
-    ds_clear (&ia->quotes);
-}
-
-
-
-
-/* Frees and clears the column data in IA's separators
-   substructure. */
-static void
-clear_fields (PsppireImportAssistant *ia)
-{
-  if (ia->column_cnt > 0)
-    {
-      struct column *col;
-      size_t row;
-
-      for (row = 0; row < ia->line_cnt; row++)
-        {
-          const struct string *line = &ia->lines[row];
-          const char *line_start = ds_data (line);
-          const char *line_end = ds_end (line);
-
-          for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++)
-            {
-              char *s = ss_data (col->contents[row]);
-              if (!(s >= line_start && s <= line_end))
-                ss_dealloc (&col->contents[row]);
-            }
-        }
-
-      for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++)
-        {
-          free (col->name);
-          free (col->contents);
-        }
-
-      free (ia->columns);
-      ia->columns = NULL;
-      ia->column_cnt = 0;
-    }
-}
-
-
-/* Breaks the file data in IA into columns based on the
-   separators set in IA's separators substructure. */
-static void
-split_fields (PsppireImportAssistant *ia)
-{
-  size_t columns_allocated;
-  bool space_sep;
-  size_t row;
-
-  clear_fields (ia);
-
-  /* Is space in the set of separators? */
-  space_sep = ss_find_byte (ds_ss (&ia->separators), ' ') != SIZE_MAX;
-
-  /* Split all the lines, not just those from
-     ia->first_line.skip_lines on, so that we split the line that
-     contains variables names if ia->first_line.variable_names is
-     TRUE. */
-  columns_allocated = 0;
-  for (row = 0; row < ia->line_cnt; row++)
-    {
-      struct string *line = &ia->lines[row];
-      struct substring text = ds_ss (line);
-      size_t column_idx;
-
-      for (column_idx = 0; ; column_idx++)
-        {
-          struct substring field = SS_EMPTY_INITIALIZER;
-          struct column *column;
-
-          if (space_sep)
-           {
-             ss_ltrim (&text, ss_cstr (" "));
-           }
-          if (ss_is_empty (text))
-            {
-              if (column_idx != 0)
-                break;
-              field = text;
-            }
-          else if (!ds_is_empty (&ia->quotes)
-                   && ds_find_byte (&ia->quotes, text.string[0]) != SIZE_MAX)
-            {
-              int quote = ss_get_byte (&text);
-              struct string s;
-              int c;
-
-              ds_init_empty (&s);
-              while ((c = ss_get_byte (&text)) != EOF)
-                if (c != quote)
-                  ds_put_byte (&s, c);
-                else if (ss_match_byte (&text, quote))
-                  ds_put_byte (&s, quote);
-                else
-                  break;
-              field = ds_ss (&s);
-            }
-          else
-           {
-             ss_get_bytes (&text, ss_cspan (text, ds_ss (&ia->separators)),
-                           &field);
-           }
-
-          if (column_idx >= ia->column_cnt)
-            {
-              struct column *column;
-
-              if (ia->column_cnt >= columns_allocated)
-               {
-                 ia->columns = x2nrealloc (ia->columns, &columns_allocated,
-                                           sizeof *ia->columns);
-               }
-              column = &ia->columns[ia->column_cnt++];
-              column->name = NULL;
-              column->width = 0;
-              column->contents = xcalloc (ia->line_cnt,
-                                          sizeof *column->contents);
-            }
-          column = &ia->columns[column_idx];
-          column->contents[row] = field;
-          if (ss_length (field) > column->width)
-            column->width = ss_length (field);
-
-          if (space_sep)
-            ss_ltrim (&text, ss_cstr (" "));
-          if (ss_is_empty (text))
-            break;
-          if (ss_find_byte (ds_ss (&ia->separators), ss_first (text))
-              != SIZE_MAX)
-            ss_advance (&text, 1);
-        }
-    }
-}
-
-static PsppSheetViewColumn *
-make_data_column (PsppireImportAssistant *ia, GtkWidget *tree_view,
-                  bool input, gint dict_idx)
-{
-  struct variable *var = NULL;
-  struct column *column = NULL;
-  size_t char_cnt = 0;
-  gint content_width, header_width;
-  PsppSheetViewColumn *tree_column;
-  char *name = NULL;
-
-  if (input)
-    {
-      column = &ia->columns[dict_idx];
-      name = escape_underscores (column->name);
-      char_cnt = column->width;
-    }
-  else
-    {
-      var = dict_get_var (ia->dict, dict_idx);
-      name = escape_underscores (var_get_name (var));
-      char_cnt = var_get_print_format (var)->w;
-    }
-
-  content_width = get_monospace_width (tree_view, ia->fixed_renderer,
-                                       char_cnt);
-  header_width = get_string_width (tree_view, ia->prop_renderer,
-                                   name);
-
-  tree_column = pspp_sheet_view_column_new ();
-  g_object_set_data (G_OBJECT (tree_column), "column-number",
-                     GINT_TO_POINTER (dict_idx));
-  pspp_sheet_view_column_set_title (tree_column, name);
-  pspp_sheet_view_column_pack_start (tree_column, ia->fixed_renderer,
-                                     FALSE);
-  pspp_sheet_view_column_set_cell_data_func (
-                                            tree_column, ia->fixed_renderer,
-                                            input ? render_input_cell : render_output_cell, ia, NULL);
-  pspp_sheet_view_column_set_fixed_width (tree_column, MAX (content_width,
-                                                            header_width));
-
-  free (name);
-
-  return tree_column;
-}
-
-
-static GtkWidget *
-create_data_tree_view (gboolean input, GtkContainer *parent,
-                       PsppireImportAssistant *ia)
-{
-  gint i;
-  GtkWidget *tree_view = make_tree_view (ia);
-
-  set_model_on_treeview (ia, tree_view, ia->skip_lines);
-
-  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (tree_view)),
-                                 PSPP_SHEET_SELECTION_NONE);
-
-  for (i = 0; i < ia->column_cnt; i++)
-    {
-      PsppSheetViewColumn *w = make_data_column (ia, tree_view, input, i);
-
-      pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), w);
-    }
-
-  g_object_set (G_OBJECT (tree_view), "has-tooltip", TRUE, (void *) NULL);
-  g_signal_connect (tree_view, "query-tooltip",
-                    G_CALLBACK (input ? on_query_input_tooltip
-                                : on_query_output_tooltip), ia);
-
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (parent));
-  if (child)
-    {
-      g_object_ref (child);
-      gtk_container_remove (parent, child);
-    }
-  gtk_container_add (parent, tree_view);
-  if (child)
-    g_object_unref (child);
-
-  gtk_widget_show (tree_view);
-
-  return tree_view;
-}
-
-
 /* Chooses a name for each column on the separators page */
 static void
 choose_column_names (PsppireImportAssistant *ia)
 {
-  struct dictionary *dict;
+  int i;
   unsigned long int generated_name_count = 0;
-  struct column *col;
-  size_t name_row;
+  dict_clear (ia->dict);
 
-  dict = dict_create (get_default_encoding ());
-  name_row = ia->variable_names && ia->skip_lines ? ia->skip_lines : 0;
-  for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++)
+  for (i = 0;
+       i < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (ia->delimiters_model)) - 1;
+       ++i)
     {
-      char *hint, *name;
+      const gchar *candidate_name = NULL;
+
+      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb)))
+       {
+         candidate_name = psppire_delimited_text_get_header_title (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), i);
+       }
 
-      hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL;
-      name = dict_make_unique_var_name (dict, hint, &generated_name_count);
-      free (hint);
+      char *name = dict_make_unique_var_name (ia->dict,
+                                             candidate_name,
+                                             &generated_name_count);
 
-      col->name = name;
-      dict_create_var_assert (dict, name, 0);
+      dict_create_var_assert (ia->dict, name, 0);
+      free (name);
     }
-  dict_destroy (dict);
 }
 
-
-
 /* Called when the user toggles one of the separators
    checkboxes. */
 static void
 on_separator_toggle (GtkToggleButton *toggle UNUSED,
                      PsppireImportAssistant *ia)
 {
+  int i;
+  GSList *delimiters = NULL;
+  for (i = 0; i < SEPARATOR_CNT; i++)
+    {
+      const struct separator *s = &separators[i];
+      GtkWidget *button = get_widget_assert (ia->builder, s->name);
+      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+       {
+         delimiters = g_slist_prepend (delimiters,  GINT_TO_POINTER (s->c));
+       }
+    }
+
+  g_object_set (ia->delimiters_model, "delimiters", delimiters, NULL);
+
   revise_fields_preview (ia);
 }
 
+
 /* Called when the user changes the entry field for custom
    separators. */
 static void
@@ -1857,7 +1126,7 @@ on_separators_custom_cb_toggle (GtkToggleButton *custom_cb,
 static void
 on_quote_combo_change (GtkComboBox *combo, PsppireImportAssistant *ia)
 {
-  revise_fields_preview (ia);
+  //  revise_fields_preview (ia);
 }
 
 /* Called when the user toggles the checkbox that enables
@@ -1883,7 +1152,6 @@ separators_page_create (PsppireImportAssistant *ia)
   g_object_set_data (G_OBJECT (w), "on-entering", prepare_separators_page);
   g_object_set_data (G_OBJECT (w), "on-reset", prepare_separators_page);
 
-
   add_page_to_assistant (ia, w,   GTK_ASSISTANT_PAGE_CONTENT, _("Choose Separators"));
 
   ia->custom_cb = get_widget_assert (builder, "custom-cb");
@@ -1893,7 +1161,15 @@ separators_page_create (PsppireImportAssistant *ia)
   ia->quote_cb = get_widget_assert (builder, "quote-cb");
 
   set_quote_list (GTK_COMBO_BOX (ia->quote_combo));
-  ia->fields_tree_view = NULL;
+
+  if (ia->fields_tree_view == NULL)
+    {
+      GtkWidget *scroller = get_widget_assert (ia->builder, "fields-scroller");
+      ia->fields_tree_view = gtk_tree_view_new ();
+      g_object_set (ia->fields_tree_view, "enable-search", FALSE, NULL);
+      gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ia->fields_tree_view));
+      gtk_widget_show_all (scroller);
+    }
 
   g_signal_connect (ia->quote_combo, "changed",
                     G_CALLBACK (on_quote_combo_change), ia);
@@ -1906,251 +1182,181 @@ separators_page_create (PsppireImportAssistant *ia)
   for (i = 0; i < SEPARATOR_CNT; i++)
     g_signal_connect (get_widget_assert (builder, separators[i].name),
                       "toggled", G_CALLBACK (on_separator_toggle), ia);
+
 }
 
 
 
 \f
-/* Called when the user changes one of the variables in the
-   dictionary. */
-static void
-on_variable_change (PsppireDict *dict, int dict_idx,
-                   unsigned int what, const struct variable *oldvar,
-                    PsppireImportAssistant *ia)
+
+
+static struct casereader_random_class my_casereader_class;
+
+static struct ccase *
+my_read (struct casereader *reader, void *aux, casenumber idx)
 {
-  PsppSheetView *tv = PSPP_SHEET_VIEW (ia->data_tree_view);
-  gint column_idx = dict_idx + 1;
+  PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (aux);
+  GtkTreeModel *tm = GTK_TREE_MODEL (ia->delimiters_model);
 
-  push_watch_cursor (ia);
+  GtkTreePath *tp = gtk_tree_path_new_from_indices (idx, -1);
 
-  /* Remove previous column and replace with new column. */
-  pspp_sheet_view_remove_column (tv, pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ia->data_tree_view), column_idx));
-  pspp_sheet_view_insert_column (tv, PSPP_SHEET_VIEW_COLUMN (make_data_column (ia, ia->data_tree_view, FALSE, dict_idx)),
-                                 column_idx);
+  const struct caseproto *proto = casereader_get_proto (reader);
 
-  /* Save a copy of the modified variable in modified_vars, so
-     that its attributes will be preserved if we back up to the
-     previous page with the Prev button and then come back
-     here. */
-  if (dict_idx >= ia->modified_var_cnt)
+  GtkTreeIter iter;
+  struct ccase *c = NULL;
+  if (gtk_tree_model_get_iter (tm, &iter, tp))
     {
-      size_t i;
-      ia->modified_vars = xnrealloc (ia->modified_vars, dict_idx + 1,
-                                    sizeof *ia->modified_vars);
-      for (i = 0; i <= dict_idx; i++)
-        ia->modified_vars[i] = NULL;
-      ia->modified_var_cnt = dict_idx + 1;
+      c = case_create (proto);
+      int i;
+      for (i = 0 ; i < caseproto_get_n_widths (proto); ++i)
+       {
+         GValue value = {0};
+         gtk_tree_model_get_value (tm, &iter, i + 1, &value);
+
+         const struct variable *var = dict_get_var (ia->dict, i);
+
+         const gchar *ss = g_value_get_string (&value);
+         if (ss)
+           {
+             union value *v = case_data_rw (c, var);
+             char *xx = data_in (ss_cstr (ss),
+                                 "UTF-8",
+                                 var_get_write_format (var)->type,
+                                 v, var_get_width (var), "UTF-8");
+
+             /* if (xx) */
+             /*   g_print ("%s:%d Err %s\n", __FILE__, __LINE__, xx); */
+             free (xx);
+           }
+         g_value_unset (&value);
+       }
     }
-  if (ia->modified_vars[dict_idx])
-    var_destroy (ia->modified_vars[dict_idx]);
-  ia->modified_vars[dict_idx]
-    = var_clone (psppire_dict_get_variable (dict, dict_idx));
 
-  pop_watch_cursor (ia);
+  gtk_tree_path_free (tp);
+
+  return c;
+}
+
+static void
+my_destroy (struct casereader *reader, void *aux)
+{
+  g_print ("%s:%d %p\n", __FILE__, __LINE__, reader);
+}
+
+static void
+my_advance (struct casereader *reader, void *aux, casenumber cnt)
+{
+  g_print ("%s:%d\n", __FILE__, __LINE__);
 }
 
+static void
+foo (struct dictionary *dict, void *aux)
+{
+  PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (aux);
+  g_print ("%s:%d\n", __FILE__, __LINE__);
 
+  struct caseproto *proto = caseproto_create ();
 
+  int i;
+  for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
+    {
+      const struct variable *var = dict_get_var (ia->dict, i);
+      proto = caseproto_add_width (proto, var_get_width (var));
+    }
+
+
+  gint n_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ia->delimiters_model), NULL);
+
+  struct casereader *reader =
+    casereader_create_random (proto, n_rows, &my_casereader_class,  ia);
+
+
+  PsppireDataStore *store = NULL;
+
+  g_object_get (ia->data_sheet, "data-model", &store, NULL);
+
+  psppire_data_store_set_reader (store, reader);
+}
 
 /* Called just before the formats page of the assistant is
    displayed. */
 static void
 prepare_formats_page (PsppireImportAssistant *ia)
 {
-  PsppireDict *psppire_dict = NULL;
-  PsppireVarSheet *var_sheet;
-  GtkBin *vars_scroller;
-  GtkWidget *old_var_sheet;
+  PsppireDict *dict = psppire_dict_new_from_dict (ia->dict);
+  g_object_set (ia->var_sheet, "data-model", dict, NULL);
 
+  my_casereader_class.read = my_read;
+  my_casereader_class.destroy = my_destroy;
+  my_casereader_class.advance = my_advance;
 
-  push_watch_cursor (ia);
+  struct caseproto *proto = caseproto_create ();
+  int i;
 
-  if (ia->spreadsheet == NULL)
+  struct fmt_guesser **fg = xcalloc (sizeof *fg, dict_get_var_cnt (ia->dict));
+  for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
     {
-      struct fmt_guesser *fg;
-      unsigned long int number = 0;
-      size_t column_idx;
+      fg[i] = fmt_guesser_create ();
+    }
 
+  gint n_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ia->delimiters_model), NULL);
 
-      ia->dict = dict_create (get_default_encoding ());
-      fg = fmt_guesser_create ();
-      for (column_idx = 0; column_idx < ia->column_cnt; column_idx++)
+  GtkTreeIter iter;
+  gboolean ok;
+  for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ia->delimiters_model), &iter);
+       ok;
+       ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->delimiters_model), &iter))
+    {
+      for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
        {
-         struct variable *modified_var =
-           (column_idx < ia->modified_var_cnt ? ia->modified_vars[column_idx] : NULL);
-
-         if (modified_var == NULL)
-           {
-             struct column *column = &ia->columns[column_idx];
-             struct variable *var;
-             struct fmt_spec format;
-             char *name;
-             size_t row;
-
-             /* Choose variable name. */
-             name = dict_make_unique_var_name (ia->dict, column->name, &number);
-
-             /* Choose variable format. */
-             fmt_guesser_clear (fg);
-             for (row = ia->skip_lines; row < ia->line_cnt; row++)
-               fmt_guesser_add (fg, column->contents[row]);
-             fmt_guesser_guess (fg, &format);
-             fmt_fix_input (&format);
-
-             /* Create variable. */
-             var = dict_create_var_assert (ia->dict, name, fmt_var_width (&format));
-             var_set_both_formats (var, &format);
-
-             free (name);
-           }
-         else
-           {
-             char *name;
-
-             name = dict_make_unique_var_name (ia->dict, var_get_name (modified_var),
-                                               &number);
-             dict_clone_var_as_assert (ia->dict, modified_var, name);
-             free (name);
-           }
+         gchar *s = NULL;
+         gtk_tree_model_get (GTK_TREE_MODEL (ia->delimiters_model), &iter, i+1, &s, -1);
+         if (s)
+           fmt_guesser_add (fg[i], ss_cstr (s));
+         free (s);
        }
-      fmt_guesser_destroy (fg);
     }
-  else
+
+  for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
     {
-      int row_start = -1;
-      int row_stop = -1;
-      int col_start = -1;
-      int col_stop = -1;
+      struct fmt_spec fs;
+      fmt_guesser_guess (fg[i], &fs);
 
-      GtkBuilder *builder = ia->builder;
+      fmt_fix (&fs, FMT_FOR_INPUT);
 
-      struct casereader *reader = NULL;
+      struct variable *var = dict_get_var (ia->dict, i);
 
-      GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox");
-      GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
-      const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry));
-      GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry");
+      int width = fmt_var_width (&fs);
 
-      gint num = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box));
+      var_set_width_and_formats (var, width,
+                                &fs, &fs);
 
-      struct spreadsheet_read_options sro;
+      proto = caseproto_add_width (proto, width);
+      fmt_guesser_destroy (fg[i]);
+    }
 
-      sro.sheet_name = NULL;
-      sro.cell_range = NULL;
-      sro.sheet_index = num + 1;
+  free (fg);
 
-      if ( convert_cell_ref (range, &col_start, &row_start, &col_stop, &row_stop))
-       {
-         sro.cell_range = g_strdup (range);
-       }
+  //  dict_set_change_callback (ia->dict, foo, ia);
 
-      sro.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (readnames_checkbox));
-      sro.asw = -1;
+  struct casereader *reader =
+    casereader_create_random (proto, n_rows, &my_casereader_class,  ia);
 
-      switch (ia->spreadsheet->type)
-       {
-       case SPREADSHEET_ODS:
-       case SPREADSHEET_GNUMERIC:
-         {
-           reader = spreadsheet_make_reader (ia->spreadsheet, &sro);
-           ia->dict = dict_clone (ia->spreadsheet->dict);
-         }
-         break;
-       default:
-         g_assert_not_reached ();
-         break;
-       }
-      g_free (sro.cell_range);
+  PsppireDataStore *store = psppire_data_store_new (dict);
+  psppire_data_store_set_reader (store, reader);
 
-      if (reader && ia->dict)
-       {
-         struct ccase *c;
-         int col;
+  g_object_set (ia->data_sheet, "data-model", store, NULL);
 
-         ia->column_cnt = dict_get_var_cnt (ia->dict);
-         ia->columns = xcalloc (ia->column_cnt, sizeof (*ia->columns));
-         for (col = 0; col < ia->column_cnt ; ++col)
-           {
-             const struct variable *var = dict_get_var (ia->dict, col);
-             ia->columns[col].name = xstrdup (var_get_name (var));
-             ia->columns[col].contents = NULL;
-           }
 
-         casenumber rows = 0;
-         for (; (c = casereader_read (reader)) != NULL; case_unref (c))
-           {
-             rows++;
-             for (col = 0; col < ia->column_cnt ; ++col)
-               {
-                 char *ss;
-                 const struct variable *var = dict_get_var (ia->dict, col);
+  gint pmax;
+  g_object_get (get_widget_assert (ia->builder, "vpaned1"),
+               "max-position", &pmax, NULL);
 
-                 ia->columns[col].contents = xrealloc (ia->columns[col].contents,
-                                                       sizeof (struct substring) * rows);
 
-                 ss = data_out (case_data (c, var), dict_get_encoding (ia->dict),
-                                var_get_print_format (var));
-
-                 ia->columns[col].contents[rows - 1] = ss_cstr (ss);
-               }
-
-             if (rows > MAX_PREVIEW_LINES)
-               {
-                 case_unref (c);
-                 break;
-               }
-           }
-         casereader_destroy (reader);
-         ia->line_cnt = rows;
-       }
-      else
-       {
-         GtkWidget * dialog = gtk_message_dialog_new (NULL,
-                                                      GTK_DIALOG_MODAL,
-                                                      GTK_MESSAGE_ERROR,
-                                                      GTK_BUTTONS_CLOSE,
-                                                      _("An error occurred reading the spreadsheet file."));
-
-         gtk_dialog_run (GTK_DIALOG (dialog));
-         gtk_widget_destroy (dialog);
-       }
-    }
-
-  psppire_dict = psppire_dict_new_from_dict (ia->dict);
-  g_signal_connect (psppire_dict, "variable-changed",
-                   G_CALLBACK (on_variable_change), ia);
-  ia->psppire_dict = psppire_dict;
-
-
-  /* XXX: PsppireVarStore doesn't hold a reference to
-     psppire_dict for now, but it should.  After it does, we
-     should g_object_ref the psppire_dict here, since we also
-     hold a reference via ia->formats->dict. */
-  var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
-  g_object_set (var_sheet,
-               "dictionary", psppire_dict,
-               "may-create-vars", FALSE,
-               "may-delete-vars", FALSE,
-               "format-use", FMT_FOR_INPUT,
-               "enable-grid-lines", PSPP_SHEET_VIEW_GRID_LINES_BOTH,
-               (void *) NULL);
-
-  vars_scroller = GTK_BIN (get_widget_assert (ia->builder, "vars-scroller"));
-  old_var_sheet = gtk_bin_get_child (GTK_BIN (vars_scroller));
-  if (old_var_sheet != NULL)
-    gtk_container_remove (GTK_CONTAINER (vars_scroller),  old_var_sheet);
-  gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet));
-  gtk_widget_show (GTK_WIDGET (var_sheet));
-
-  ia->data_tree_view =
-    GTK_WIDGET (create_data_tree_view (
-                                      FALSE,
-                                      GTK_CONTAINER (get_widget_assert (ia->builder, "data-scroller")),
-                                      ia));
+  g_object_set (get_widget_assert (ia->builder, "vpaned1"),
+               "position", pmax / 2, NULL);
 
   gtk_widget_show (ia->paste_button);
-
-  pop_watch_cursor (ia);
 }
 
 static void
@@ -2158,17 +1364,33 @@ formats_page_create (PsppireImportAssistant *ia)
 {
   GtkBuilder *builder = ia->builder;
 
-
   GtkWidget *w = get_widget_assert (builder, "Formats");
   g_object_set_data (G_OBJECT (w), "on-entering", prepare_formats_page);
   g_object_set_data (G_OBJECT (w), "on-reset", reset_formats_page);
 
+  GtkWidget *vars_scroller = get_widget_assert (builder, "vars-scroller");
+  if (ia->var_sheet == NULL)
+    {
+      ia->var_sheet = psppire_variable_sheet_new ();
+
+      gtk_container_add (GTK_CONTAINER (vars_scroller), ia->var_sheet);
+
+      ia->dict = dict_create (get_default_encoding ());
+
+      gtk_widget_show_all (vars_scroller);
+    }
+  GtkWidget *data_scroller = get_widget_assert (builder, "data-scroller");
+  if (ia->data_sheet == NULL)
+    {
+      ia->data_sheet = psppire_data_sheet_new ();
+
+      gtk_container_add (GTK_CONTAINER (data_scroller), ia->data_sheet);
+
+      gtk_widget_show_all (data_scroller);
+    }
+
   add_page_to_assistant (ia, w,
                         GTK_ASSISTANT_PAGE_CONFIRM, _("Adjust Variable Formats"));
-
-  ia->data_tree_view = NULL;
-  ia->modified_vars = NULL;
-  ia->modified_var_cnt = 0;
 }
 
 
@@ -2178,25 +1400,28 @@ static void
 separators_append_syntax (const PsppireImportAssistant *ia, struct string *s)
 {
   int i;
+
   ds_put_cstr (s, "  /DELIMITERS=\"");
-  if (ds_find_byte (&ia->separators, '\t') != SIZE_MAX)
+
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, "tab"))))
     ds_put_cstr (s, "\\t");
-  if (ds_find_byte (&ia->separators, '\\') != SIZE_MAX)
-    ds_put_cstr (s, "\\\\");
-  for (i = 0; i < ds_length (&ia->separators); i++)
+  for (i = 0; i < SEPARATOR_CNT; i++)
     {
-      char c = ds_at (&ia->separators, i);
-      if (c == '"')
-       ds_put_cstr (s, "\"\"");
-      else if (c != '\t' && c != '\\')
-       ds_put_byte (s, c);
+      const struct separator *seps = &separators[i];
+      GtkWidget *button = get_widget_assert (ia->builder, seps->name);
+      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+       {
+         if (seps->c == '\t')
+           continue;
+
+         ds_put_byte (s, seps->c);
+       }
     }
   ds_put_cstr (s, "\"\n");
   if (!ds_is_empty (&ia->quotes))
     syntax_gen_pspp (s, "  /QUALIFIER=%sq\n", ds_cstr (&ia->quotes));
 }
 
-
 static void
 formats_append_syntax (const PsppireImportAssistant *ia, struct string *s)
 {
@@ -2219,21 +1444,25 @@ formats_append_syntax (const PsppireImportAssistant *ia, struct string *s)
     }
 }
 
-
 static void
 first_line_append_syntax (const PsppireImportAssistant *ia, struct string *s)
 {
-  if (ia->skip_lines > 0)
-    ds_put_format (s, "  /FIRSTCASE=%d\n", ia->skip_lines + 1);
-}
+  gint first_case = 0;
+  g_object_get (ia->delimiters_model, "first-line", &first_case, NULL);
 
+  if (first_case > 0)
+    ds_put_format (s, "  /FIRSTCASE=%d\n", first_case + 1);
+}
 
 static void
 intro_append_syntax (const PsppireImportAssistant *ia, struct string *s)
 {
+  gint first_line = 0;
+  g_object_get (ia->delimiters_model, "first-line", &first_line, NULL);
+
   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->n_cases_button)))
-    ds_put_format (s, "N OF CASES %d.\n",
-                  gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)));
+    ds_put_format (s, "SELECT IF ($CASENUM <= %d).\n",
+                  gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)) - first_line);
   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->percent_button)))
     ds_put_format (s, "SAMPLE %.4g.\n",
                   gtk_spin_button_get_value (GTK_SPIN_BUTTON (ia->percent_spin)) / 100.0);
@@ -2335,6 +1564,8 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia)
 
   struct string s = DS_EMPTY_INITIALIZER;
 
+  char *filename;
+  g_object_get (ia->text_file, "file-name", &filename, NULL);
   syntax_gen_pspp (&s,
                   "GET DATA"
                   "\n  /TYPE=%ss"
@@ -2342,11 +1573,10 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia)
                   "\n  /SHEET=index %d"
                   "\n  /READNAMES=%ss",
                   (ia->spreadsheet->type == SPREADSHEET_GNUMERIC) ? "GNM" : "ODS",
-                  ia->file_name,
+                  filename,
                   sheet_index,
                   read_names ? "ON" : "OFF");
 
-
   if (range && 0 != strcmp ("", range))
     {
       syntax_gen_pspp (&s,
@@ -2365,6 +1595,7 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia)
   return ds_cstr (&s);
 }
 
+
 gchar *
 psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia)
 {
@@ -2372,16 +1603,23 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia)
 
   if (!ia->spreadsheet)
     {
-      if (ia->file_name == NULL)
+      gchar *file_name = NULL;
+      gchar *encoding = NULL;
+      g_object_get (ia->text_file,
+                   "file-name", &file_name,
+                   "encoding", &encoding,
+                   NULL);
+
+      if (file_name == NULL)
        return NULL;
 
       syntax_gen_pspp (&s,
                       "GET DATA"
                       "\n  /TYPE=TXT"
                       "\n  /FILE=%sq\n",
-                      ia->file_name);
-      if (ia->encoding && strcmp (ia->encoding, "Auto"))
-       syntax_gen_pspp (&s, "  /ENCODING=%sq\n", ia->encoding);
+                      file_name);
+      if (encoding && strcmp (encoding, "Auto"))
+       syntax_gen_pspp (&s, "  /ENCODING=%sq\n", encoding);
 
       ds_put_cstr (&s,
                   "  /ARRANGEMENT=DELIMITED\n"
@@ -2401,3 +1639,12 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia)
 
   return ds_cstr (&s);
 }
+
+
+int
+psppire_import_assistant_run (PsppireImportAssistant *asst)
+{
+  g_main_loop_run (asst->main_loop);
+  return asst->response;
+}
+
index fe8040130d103adb1eb0c3ad2b92339b86422dc9..cdcf8fb73ee48f274745eccffd547da248a28a01 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2015  Free Software Foundation
+   Copyright (C) 2015, 2017  Free Software Foundation
 
    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
 
 #include <gtk/gtk.h>
 
-#include "libpspp/str.h"
 #include "psppire-dict.h"
 #include "data/spreadsheet-reader.h"
+#include "psppire-text-file.h"
+#include "psppire-delimited-text.h"
 
 G_BEGIN_DECLS
 
@@ -58,12 +59,8 @@ typedef struct _PsppireImportAssistant       PsppireImportAssistant;
 typedef struct _PsppireImportAssistantClass  PsppireImportAssistantClass;
 
 
-struct first_line_page;
-
 typedef void page_func (PsppireImportAssistant *, GtkWidget *page);
 
-enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
-
 struct _PsppireImportAssistant
 {
   GtkAssistant parent;
@@ -72,6 +69,8 @@ struct _PsppireImportAssistant
 
   gint current_page;
 
+  gchar *file_name;
+
   /* START The chooser page of the assistant. */
   GtkWidget *encoding_selector;
   GtkFileFilter *default_filter;
@@ -90,29 +89,21 @@ struct _PsppireImportAssistant
 /* START Page where the user chooses field separators. */
 
   /* How to break lines into columns. */
-  struct string separators;   /* Field separators. */
   struct string quotes;       /* Quote characters. */
 
   GtkWidget *custom_cb;
   GtkWidget *custom_entry;
   GtkWidget *quote_cb;
   GtkWidget *quote_combo;
+
   GtkEntry *quote_entry;
   GtkWidget *fields_tree_view;
 
 /* END Page where the user chooses field separators. */
 
 
-/* START Page where the user verifies and adjusts input formats. */
-  GtkWidget *data_tree_view;
-  PsppireDict *psppire_dict;
-  struct variable **modified_vars;
-  size_t modified_var_cnt;
-/* END Page where the user verifies and adjusts input formats. */
-
-
   /* START first line page */
-  GtkWidget *tree_view;
+  GtkWidget *first_line_tree_view;
   GtkWidget *variable_names_cb;
   /* END first line page */
 
@@ -120,37 +111,17 @@ struct _PsppireImportAssistant
   GtkWidget *paste_button;
   GtkWidget *reset_button;
   int response;
-  int watch_cursor;
-
-  GtkCellRenderer *prop_renderer;
-  GtkCellRenderer *fixed_renderer;
 
-  // START     struct file file;
-  char *file_name;        /* File name. */
-
-  /* Relevant only for text files */
-
-  gchar *encoding;        /* Encoding. */
-  unsigned long int total_lines; /* Number of lines in file. */
-  gboolean total_is_exact;    /* Is total_lines exact (or an estimate)? */
-
-  /* The first several lines of the file. */
-  struct string lines[MAX_PREVIEW_LINES];
-  size_t line_cnt;
-
-  // END     struct file file;
+  PsppireTextFile *text_file;
+  PsppireDelimitedText *delimiters_model;
 
   struct sheet_spec_page *sheet_spec;
-  struct first_line_page *first_line;
 
-  /* The columns produced. */
-  struct column *columns;     /* Information about each column. */
-  size_t column_cnt;          /* Number of columns. */
-
-  int skip_lines;             /* Number of initial lines to skip? */
-  gboolean variable_names;        /* Variable names above first line of data? */
   struct dictionary *dict;
 
+  GtkWidget *var_sheet;
+  GtkWidget *data_sheet;
+
   struct spreadsheet *spreadsheet;
 };
 
@@ -166,6 +137,8 @@ GtkWidget *psppire_import_assistant_new (GtkWindow *toplevel);
 
 gchar *psppire_import_assistant_generate_syntax (PsppireImportAssistant *);
 
+int psppire_import_assistant_run (PsppireImportAssistant *asst);
+
 G_END_DECLS
 
 #endif /* __PSPPIRE_IMPORT_ASSISTANT_H__ */
diff --git a/src/ui/gui/psppire-text-file.c b/src/ui/gui/psppire-text-file.c
new file mode 100644 (file)
index 0000000..590455d
--- /dev/null
@@ -0,0 +1,549 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2017 Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define P_(msgid) msgid
+
+#include "psppire-text-file.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "libpspp/line-reader.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "libpspp/i18n.h"
+
+#include <gtk/gtk.h>
+
+/* Properties */
+enum
+  {
+    PROP_0,
+    PROP_FILE_NAME,
+    PROP_ENCODING,
+    PROP_MAXIMUM_LINES,
+    PROP_LINE_COUNT
+  };
+
+enum {MAX_LINE_LEN = 16384};  /* Max length of an acceptable line. */
+
+
+static void
+read_lines (PsppireTextFile *tf)
+{
+  if (tf->file_name && 0 != g_strcmp0 ("unset", tf->encoding))
+    {
+      struct line_reader *reader = line_reader_for_file (tf->encoding, tf->file_name, O_RDONLY);
+
+      if (reader == NULL)
+       {
+         msg_error (errno, _("Could not open `%s'"),  tf->file_name);
+         return;
+       }
+
+      struct string input;
+      ds_init_empty (&input);
+      for (tf->line_cnt = 0; tf->line_cnt < MAX_PREVIEW_LINES; tf->line_cnt++)
+       {
+         ds_clear (&input);
+         if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
+             || ds_length (&input) > MAX_LINE_LEN)
+           {
+             int i;
+             if (line_reader_eof (reader))
+               break;
+             else if (line_reader_error (reader))
+               msg (ME, _("Error reading `%s': %s"),
+                    tf->file_name, strerror (line_reader_error (reader)));
+             else
+               msg (ME, _("Failed to read `%s', because it contains a line "
+                          "over %d bytes long and therefore appears not to be "
+                          "a text file."),
+                    tf->file_name, MAX_LINE_LEN);
+             line_reader_close (reader);
+             for (i = 0; i < tf->line_cnt; i++)
+               g_free (&tf->lines[i]);
+             tf->line_cnt = 0;
+             ds_destroy (&input);
+             return;
+           }
+
+         tf->lines[tf->line_cnt]
+           = recode_substring_pool ("UTF-8",
+                                    line_reader_get_encoding (reader),
+                                    input.ss, NULL);
+       }
+      ds_destroy (&input);
+
+      if (tf->line_cnt == 0)
+       {
+         int i;
+         msg (ME, _("`%s' is empty."), tf->file_name);
+         line_reader_close (reader);
+         for (i = 0; i < tf->line_cnt; i++)
+           g_free (&tf->lines[i]);
+         tf->line_cnt = 0;
+         goto done;
+       }
+
+      if (tf->line_cnt < MAX_PREVIEW_LINES)
+       {
+         tf->total_lines = tf->line_cnt;
+         tf->total_is_exact = true;
+       }
+      else
+       {
+         /* Estimate the number of lines in the file. */
+         struct stat s;
+         off_t position = line_reader_tell (reader);
+         if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
+           {
+             tf->total_lines = (double) tf->line_cnt / position * s.st_size;
+             tf->total_is_exact = false;
+           }
+         else
+           {
+             tf->total_lines = 0;
+             tf->total_is_exact = true;
+           }
+       }
+    done:
+      line_reader_close (reader);
+    }
+}
+
+static void
+psppire_text_file_set_property (GObject         *object,
+                               guint            prop_id,
+                               const GValue    *value,
+                               GParamSpec      *pspec)
+{
+  PsppireTextFile *tf = PSPPIRE_TEXT_FILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_MAXIMUM_LINES:
+      tf->maximum_lines = g_value_get_int (value);
+      break;
+    case PROP_FILE_NAME:
+      tf->file_name = g_value_dup_string (value);
+      read_lines (tf);
+      break;
+    case PROP_ENCODING:
+      g_free (tf->encoding);
+      tf->encoding = g_value_dup_string (value);
+      read_lines (tf);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+
+}
+
+static void
+psppire_text_file_get_property (GObject         *object,
+                               guint            prop_id,
+                               GValue          *value,
+                               GParamSpec      *pspec)
+{
+  PsppireTextFile *text_file = PSPPIRE_TEXT_FILE (object);
+
+  switch (prop_id)
+    {
+    case PROP_MAXIMUM_LINES:
+      g_value_set_int (value, text_file->maximum_lines);
+      break;
+    case PROP_LINE_COUNT:
+      g_value_set_int (value, text_file->line_cnt);
+      break;
+    case PROP_FILE_NAME:
+      g_value_set_string (value, text_file->file_name);
+      break;
+    case PROP_ENCODING:
+      g_value_set_string (value, text_file->encoding);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+
+static void psppire_text_file_init            (PsppireTextFile      *text_file);
+static void psppire_text_file_class_init      (PsppireTextFileClass *class);
+
+static void psppire_text_file_finalize        (GObject           *object);
+static void psppire_text_file_dispose        (GObject           *object);
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+__tree_get_iter (GtkTreeModel *tree_model,
+                GtkTreeIter *iter,
+                GtkTreePath *path)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+
+  if (path == NULL)
+    return FALSE;
+
+  gint *indices = gtk_tree_path_get_indices (path);
+
+  gint n = *indices;
+
+  if (n >= file->line_cnt)
+    return FALSE;
+
+  iter->user_data = GINT_TO_POINTER (n);
+  iter->stamp = file->stamp;
+
+  return TRUE;
+}
+
+
+static gboolean
+__tree_iter_next (GtkTreeModel *tree_model,
+                 GtkTreeIter *iter)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+  g_return_val_if_fail (file->stamp == iter->stamp, FALSE);
+
+  gint n = GPOINTER_TO_INT (iter->user_data) + 1;
+
+  if (n >= file->line_cnt)
+    return FALSE;
+
+  iter->user_data = GINT_TO_POINTER (n);
+
+  return TRUE;
+}
+
+
+static GType
+__tree_get_column_type (GtkTreeModel *tree_model,
+                       gint          index)
+{
+  if (index == 0)
+    return G_TYPE_INT;
+
+  return G_TYPE_STRING;
+}
+
+static gboolean
+__iter_has_child (GtkTreeModel *tree_model,
+                 GtkTreeIter  *iter)
+{
+  return 0;
+}
+
+
+static gboolean
+__iter_parent     (GtkTreeModel *tree_model,
+                  GtkTreeIter  *iter,
+                  GtkTreeIter  *child)
+{
+  return 0;
+}
+
+static GtkTreePath *
+__tree_get_path (GtkTreeModel *tree_model,
+                GtkTreeIter  *iter)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+  g_return_val_if_fail (file->stamp == iter->stamp, FALSE);
+
+  gint n = GPOINTER_TO_INT (iter->user_data);
+
+  return gtk_tree_path_new_from_indices (n, -1);
+}
+
+
+static gboolean
+__iter_children (GtkTreeModel *tree_model,
+                              GtkTreeIter *iter,
+                              GtkTreeIter *parent)
+{
+  return 0;
+}
+
+
+static gint
+__tree_model_iter_n_children (GtkTreeModel *tree_model,
+                             GtkTreeIter *iter)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+  g_assert (iter == NULL);
+  return file->line_cnt;
+}
+
+static GtkTreeModelFlags
+__tree_model_get_flags (GtkTreeModel *model)
+{
+  g_return_val_if_fail (PSPPIRE_IS_TEXT_FILE (model), (GtkTreeModelFlags) 0);
+
+  return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+__tree_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  PsppireTextFile *tf  = PSPPIRE_TEXT_FILE (tree_model);
+  return 2;
+}
+
+
+static gboolean
+__iter_nth_child (GtkTreeModel *tree_model,
+                 GtkTreeIter *iter,
+                 GtkTreeIter *parent,
+                 gint n)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+
+  g_assert (parent == NULL);
+
+  g_return_val_if_fail (file, FALSE);
+
+  if (n >= file->line_cnt)
+    {
+      iter->stamp = -1;
+      iter->user_data = NULL;
+      return FALSE;
+    }
+
+  iter->user_data = GINT_TO_POINTER (n);
+  iter->stamp = file->stamp;
+
+  return TRUE;
+}
+
+
+static void
+__get_value (GtkTreeModel *tree_model,
+            GtkTreeIter *iter,
+            gint column,
+            GValue *value)
+{
+  PsppireTextFile *file  = PSPPIRE_TEXT_FILE (tree_model);
+
+  g_return_if_fail (iter->stamp == file->stamp);
+
+  gint n = GPOINTER_TO_INT (iter->user_data);
+
+  g_return_if_fail (n < file->line_cnt);
+
+  if (column == 0)
+    {
+      g_value_init (value, G_TYPE_INT);
+      g_value_set_int (value, n + 1);
+      return;
+    }
+
+  g_value_init (value, G_TYPE_STRING);
+
+  if (column == 1)
+    {
+      char *s = ss_xstrdup (file->lines[n]);
+      g_value_set_string (value, s);
+      free (s);
+      return;
+    }
+
+  g_assert_not_reached ();
+}
+
+
+static void
+__tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags       = __tree_model_get_flags;
+  iface->get_n_columns   = __tree_model_get_n_columns ;
+  iface->get_column_type = __tree_get_column_type;
+  iface->get_iter        = __tree_get_iter;
+  iface->iter_next       = __tree_iter_next;
+  iface->get_path        = __tree_get_path;
+  iface->get_value       = __get_value;
+
+  iface->iter_children   = __iter_children;
+  iface->iter_has_child  = __iter_has_child;
+  iface->iter_n_children = __tree_model_iter_n_children;
+  iface->iter_nth_child  = __iter_nth_child;
+  iface->iter_parent     = __iter_parent;
+}
+
+
+GType
+psppire_text_file_get_type (void)
+{
+  static GType text_file_type = 0;
+
+  if (!text_file_type)
+    {
+      static const GTypeInfo text_file_info =
+       {
+         sizeof (PsppireTextFileClass),
+         NULL,         /* base_init */
+         NULL,         /* base_finalize */
+         (GClassInitFunc) psppire_text_file_class_init,
+         NULL,         /* class_finalize */
+         NULL,         /* class_data */
+         sizeof (PsppireTextFile),
+         0,
+         (GInstanceInitFunc) psppire_text_file_init,
+       };
+
+      static const GInterfaceInfo tree_model_info = {
+       (GInterfaceInitFunc) __tree_model_init,
+       NULL,
+       NULL
+      };
+
+      text_file_type = g_type_register_static (G_TYPE_OBJECT,
+                                              "PsppireTextFile",
+                                              &text_file_info, 0);
+
+      g_type_add_interface_static (text_file_type, GTK_TYPE_TREE_MODEL,
+                                  &tree_model_info);
+    }
+
+  return text_file_type;
+}
+
+
+static void
+psppire_text_file_class_init (PsppireTextFileClass *class)
+{
+  GObjectClass *object_class;
+
+  parent_class = g_type_class_peek_parent (class);
+  object_class = (GObjectClass*) class;
+
+  GParamSpec *maximum_lines_spec =
+    g_param_spec_int ("maximum-lines",
+                     "Maximum Lines",
+                     P_("An upper limit on the number of lines to consider"),
+                     0, G_MAXINT, G_MAXINT,
+                     G_PARAM_READWRITE);
+
+  GParamSpec *line_count_spec =
+    g_param_spec_int ("line-count",
+                     "Line Count",
+                     P_("The number of lines in the file"),
+                     0, G_MAXINT, G_MAXINT,
+                     G_PARAM_READABLE);
+
+  GParamSpec *file_name_spec =
+    g_param_spec_string ("file-name",
+                        "File Name",
+                        P_("The name of the file from which this object was constructed"),
+                        NULL,
+                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
+
+  GParamSpec *encoding_spec =
+    g_param_spec_string ("encoding",
+                        "Character Encoding",
+                        P_("The character encoding of the file from which this object was constructed"),
+                        "unset",
+                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
+
+  object_class->set_property = psppire_text_file_set_property;
+  object_class->get_property = psppire_text_file_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_MAXIMUM_LINES,
+                                   maximum_lines_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_LINE_COUNT,
+                                   line_count_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_FILE_NAME,
+                                   file_name_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_ENCODING,
+                                   encoding_spec);
+
+  object_class->finalize = psppire_text_file_finalize;
+  object_class->dispose = psppire_text_file_dispose;
+}
+
+static void
+psppire_text_file_init (PsppireTextFile *text_file)
+{
+  text_file->encoding = g_strdup ("unset");
+  text_file->file_name = NULL;
+
+  text_file->dispose_has_run = FALSE;
+  text_file->stamp = g_random_int ();
+}
+
+
+PsppireTextFile *
+psppire_text_file_new (const gchar *file_name, const gchar *encoding)
+{
+  PsppireTextFile *retval =
+    g_object_new (PSPPIRE_TYPE_TEXT_FILE,
+                 "file-name", file_name,
+                 "encoding", encoding,
+                 NULL);
+
+  return retval;
+}
+
+static void
+psppire_text_file_finalize (GObject *object)
+{
+  PsppireTextFile *tf = PSPPIRE_TEXT_FILE (object);
+
+  g_free (tf->encoding);
+  g_free (tf->file_name);
+
+  /* must chain up */
+  (* parent_class->finalize) (object);
+}
+
+
+static void
+psppire_text_file_dispose (GObject *object)
+{
+  PsppireTextFile *ds = PSPPIRE_TEXT_FILE (object);
+
+  if (ds->dispose_has_run)
+    return;
+
+  /* must chain up */
+  (* parent_class->dispose) (object);
+
+  ds->dispose_has_run = TRUE;
+}
+
+gboolean
+psppire_text_file_get_total_exact (PsppireTextFile *tf)
+{
+  return tf->total_is_exact;
+}
+
+gulong
+psppire_text_file_get_n_lines (PsppireTextFile *tf)
+{
+  return tf->total_lines;
+}
diff --git a/src/ui/gui/psppire-text-file.h b/src/ui/gui/psppire-text-file.h
new file mode 100644 (file)
index 0000000..486cefb
--- /dev/null
@@ -0,0 +1,92 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2017  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __PSPPIRE_TEXT_FILE_H__
+#define __PSPPIRE_TEXT_FILE_H__
+
+#include "libpspp/str.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+
+#define PSPPIRE_TYPE_TEXT_FILE        (psppire_text_file_get_type ())
+
+#define PSPPIRE_TEXT_FILE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               PSPPIRE_TYPE_TEXT_FILE, PsppireTextFile))
+
+#define PSPPIRE_TEXT_FILE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                                    \
+                            PSPPIRE_TYPE_TEXT_FILE,                    \
+                            PsppireTextFileClass))
+
+
+#define PSPPIRE_IS_TEXT_FILE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_TEXT_FILE))
+
+#define PSPPIRE_IS_TEXT_FILE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_TEXT_FILE))
+
+#define PSPPIRE_TEXT_FILE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              PSPPIRE_TYPE_TEXT_FILE,                  \
+                              PsppireTextFileClass))
+
+enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
+
+struct _PsppireTextFile
+{
+  GObject parent;
+
+  gchar *file_name;
+  gchar *encoding;
+
+  gint maximum_lines;
+
+  /* The first several lines of the file.   These copies which are UTF8 encoded,
+     regardless of the file encoding.  */
+  struct substring lines[MAX_PREVIEW_LINES];
+  size_t line_cnt;
+
+  gulong total_lines; /* Number of lines in file. */
+  gboolean total_is_exact;    /* Is total_lines exact (or an estimate)? */
+
+  /*< private >*/
+  gboolean dispose_has_run ;
+  gint stamp;
+};
+
+struct _PsppireTextFileClass
+{
+  GObjectClass parent_class;
+};
+
+
+typedef struct _PsppireTextFile       PsppireTextFile;
+typedef struct _PsppireTextFileClass  PsppireTextFileClass;
+
+GType psppire_text_file_get_type (void) G_GNUC_CONST;
+PsppireTextFile *psppire_text_file_new (const gchar *file_name, const gchar *encoding);
+
+gboolean psppire_text_file_get_total_exact (PsppireTextFile *tf);
+gulong psppire_text_file_get_n_lines (PsppireTextFile *tf);
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_TEXT_FILE_H__ */
diff --git a/src/ui/gui/psppire-var-sheet-header.c b/src/ui/gui/psppire-var-sheet-header.c
new file mode 100644 (file)
index 0000000..e26fa95
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+    A candidate replacement for Pspp's sheet
+    Copyright (C) 2016  John Darrington
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+#include <gtk/gtk.h>
+
+#include "psppire-var-sheet-header.h"
+
+#include <ssw-axis-model.h>
+#include <ssw-datum.h>
+
+enum  {CHANGED,
+       n_SIGNALS};
+
+static guint signals [n_SIGNALS];
+
+static guint
+gni (GListModel *list)
+{
+  return 11;
+}
+
+static GType
+git (GListModel *list)
+{
+  return SSW_TYPE_DATUM;
+}
+
+static gpointer
+gi (GListModel *list, guint position)
+{
+  SswDatum *gd = SSW_DATUM (g_object_new (SSW_TYPE_DATUM, NULL));
+
+  switch (position)
+    {
+    case 0:
+      gd->text = g_strdup ("Name");
+      break;
+    case 1:
+      gd->text = g_strdup ("Type");
+      break;
+    case 2:
+      gd->text = g_strdup ("Width");
+      break;
+    case 3:
+      gd->text = g_strdup ("Decimal");
+      break;
+    case 4:
+      gd->text = g_strdup ("Label");
+      break;
+    case 5:
+      gd->text = g_strdup ("Value Labels");
+      break;
+    case 6:
+      gd->text = g_strdup ("Missing Values");
+      break;
+    case 7:
+      gd->text = g_strdup ("Columns");
+      break;
+    case 8:
+      gd->text = g_strdup ("Align");
+      break;
+    case 9:
+      gd->text = g_strdup ("Measure");
+      break;
+    case 10:
+      gd->text = g_strdup ("Role");
+      break;
+    default:
+      //      g_assert_not_reached ();
+      g_print ("Bug: Request for item %d\n", position);
+      break;
+    }
+
+  return gd;
+}
+
+
+static void
+psppire_init_iface (GListModelInterface *iface)
+{
+  iface->get_n_items = gni;
+  iface->get_item = gi;
+  iface->get_item_type = git;
+}
+
+
+G_DEFINE_TYPE_WITH_CODE (PsppireVarSheetHeader, psppire_var_sheet_header,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, psppire_init_iface));
+
+static void
+psppire_var_sheet_header_init (PsppireVarSheetHeader *d)
+{
+}
+
+
+
+static void
+psppire_var_sheet_header_class_init (PsppireVarSheetHeaderClass *dc)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (dc);
+
+  /* This signal is never emitted.  It is just to satisfy the interface. */
+  signals [CHANGED] =
+    g_signal_new ("changed",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 0,
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);
+}
+
diff --git a/src/ui/gui/psppire-var-sheet-header.h b/src/ui/gui/psppire-var-sheet-header.h
new file mode 100644 (file)
index 0000000..476faaf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+    A candidate replacement for Pspp's sheet
+    Copyright (C) 2016  John Darrington
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PSPPIRE_VAR_SHEET_HEADER_H
+#define _PSPPIRE_VAR_SHEET_HEADER_H
+
+
+G_DECLARE_FINAL_TYPE (PsppireVarSheetHeader, psppire_var_sheet_header, PSPPIRE, VAR_SHEET_HEADER, GObject)
+
+
+struct _PsppireVarSheetHeader
+{
+  GObject parent_instance;
+};
+
+struct _PsppireVarSheetHeaderClass
+{
+  GObjectClass parent_instance;
+};
+
+
+
+#define PSPPIRE_TYPE_VAR_SHEET_HEADER psppire_var_sheet_header_get_type ()
+
+#endif
diff --git a/src/ui/gui/psppire-var-sheet.c b/src/ui/gui/psppire-var-sheet.c
deleted file mode 100644 (file)
index 7686b40..0000000
+++ /dev/null
@@ -1,1622 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "ui/gui/psppire-var-sheet.h"
-
-#include "data/format.h"
-#include "data/value-labels.h"
-#include "libpspp/range-set.h"
-#include "ui/gui/builder-wrapper.h"
-#include "ui/gui/helper.h"
-#include "ui/gui/missing-val-dialog.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-cell-renderer-button.h"
-#include "ui/gui/psppire-data-editor.h"
-#include "ui/gui/psppire-data-window.h"
-#include "ui/gui/psppire-dialog-action-var-info.h"
-#include "ui/gui/psppire-dictview.h"
-#include "ui/gui/psppire-empty-list-store.h"
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/val-labs-dialog.h"
-#include "ui/gui/var-type-dialog.h"
-#include "ui/gui/var-display.h"
-#include "ui/gui/var-type-dialog.h"
-
-#include "gl/intprops.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-enum vs_column
-  {
-    VS_NAME,
-    VS_TYPE,
-    VS_WIDTH,
-    VS_DECIMALS,
-    VS_LABEL,
-    VS_VALUES,
-    VS_MISSING,
-    VS_COLUMNS,
-    VS_ALIGN,
-    VS_MEASURE,
-    VS_ROLE
-  };
-
-G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
-
-static void
-set_spin_cell (GtkCellRenderer *cell, int value, int min, int max, int step)
-{
-  char text[INT_BUFSIZE_BOUND (int)];
-  GtkAdjustment *adjust;
-
-  if (max > min)
-    adjust = GTK_ADJUSTMENT (gtk_adjustment_new (value, min, max,
-                                                 step, step, 0.0));
-  else
-    adjust = NULL;
-
-  sprintf (text, "%d", value);
-  g_object_set (cell,
-                "text", text,
-                "adjustment", adjust,
-                "editable", TRUE,
-                NULL);
-}
-
-static void
-error_dialog (GtkWindow *w, gchar *primary_text, gchar *secondary_text)
-{
-  GtkWidget *dialog =
-    gtk_message_dialog_new (w,
-                           GTK_DIALOG_DESTROY_WITH_PARENT,
-                           GTK_MESSAGE_ERROR,
-                           GTK_BUTTONS_CLOSE, "%s", primary_text);
-
-  g_object_set (dialog, "icon-name", "psppicon", NULL);
-
-  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-                                           "%s", secondary_text);
-
-  gtk_dialog_run (GTK_DIALOG (dialog));
-
-  gtk_widget_destroy (dialog);
-}
-
-static void
-on_name_column_editing_started (GtkCellRenderer *cell,
-                                GtkCellEditable *editable,
-                                const gchar     *path,
-                                gpointer         user_data)
-{
-  PsppireVarSheet *var_sheet = g_object_get_data (G_OBJECT (cell), "var-sheet");
-  PsppireDict *dict = psppire_var_sheet_get_dictionary (var_sheet);
-
-  g_return_if_fail (var_sheet);
-          g_return_if_fail (dict);
-
-  if (GTK_IS_ENTRY (editable))
-    {
-      GtkEntry *entry = GTK_ENTRY (editable);
-      if (gtk_entry_get_text (entry)[0] == '\0')
-        {
-          gchar name[64];
-          if (psppire_dict_generate_name (dict, name, sizeof name))
-            gtk_entry_set_text (entry, name);
-        }
-    }
-}
-
-static void
-scroll_to_bottom (GtkWidget      *widget,
-                  GtkRequisition *requisition,
-                  gpointer        unused UNUSED)
-{
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-  GtkAdjustment *vadjust;
-
-  vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
-  gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
-
-  if (var_sheet->scroll_to_bottom_signal)
-    {
-      g_signal_handler_disconnect (var_sheet,
-                                   var_sheet->scroll_to_bottom_signal);
-      var_sheet->scroll_to_bottom_signal = 0;
-    }
-}
-
-static struct variable *
-path_string_to_var (PsppireVarSheet *var_sheet, gchar *path_string)
-{
-  GtkTreePath *path;
-  gint row;
-
-  path = gtk_tree_path_new_from_string (path_string);
-  row = gtk_tree_path_get_indices (path)[0];
-  gtk_tree_path_free (path);
-
-  return psppire_dict_get_variable (var_sheet->dict, row);
-}
-
-static void
-on_var_column_edited (GtkCellRendererText *cell,
-                      gchar               *path_string,
-                      gchar               *new_text,
-                      gpointer             user_data)
-{
-  PsppireVarSheet *var_sheet = user_data;
-  GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (var_sheet)));
-  struct dictionary *dict = var_sheet->dict->dict;
-  enum vs_column column_id;
-  struct variable *var;
-  int width, decimals;
-
-  column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell),
-                                                  "column-id"));
-
-  var = path_string_to_var (var_sheet, path_string);
-  if (var == NULL)
-    {
-      g_return_if_fail (column_id == VS_NAME);
-
-      if (!dict_id_is_valid (dict, new_text, false))
-        error_dialog (window,
-                      g_strdup (_("Cannot create variable.")),
-                      g_strdup_printf (_("\"%s\" is not a valid variable "
-                                         "name."), new_text));
-      else if (dict_lookup_var (dict, new_text) != NULL)
-        error_dialog (window,
-                      g_strdup (_("Cannot create variable.")),
-                      g_strdup_printf (_("This dictionary already contains "
-                                         "a variable named \"%s\"."),
-                                         new_text));
-      else
-        {
-          dict_create_var (var_sheet->dict->dict, new_text, 0);
-          if (!var_sheet->scroll_to_bottom_signal)
-            {
-              gtk_widget_queue_resize (GTK_WIDGET (var_sheet));
-              var_sheet->scroll_to_bottom_signal =
-                g_signal_connect (var_sheet, "size-allocate",
-                                  G_CALLBACK (scroll_to_bottom), NULL);
-            }
-        }
-
-      return;
-    }
-
-  switch (column_id)
-    {
-    case VS_NAME:
-      if (!dict_id_is_valid (dict, new_text, false))
-        error_dialog (window,
-                      g_strdup (_("Cannot rename variable.")),
-                      g_strdup_printf (_("\"%s\" is not a valid variable "
-                                         "name."), new_text));
-      else if (dict_lookup_var (dict, new_text) != NULL
-               && dict_lookup_var (dict, new_text) != var)
-        error_dialog (window,
-                      g_strdup (_("Cannot rename variable.")),
-                      g_strdup_printf (_("This dictionary already contains "
-                                         "a variable named \"%s\"."),
-                                         new_text));
-      else
-        dict_rename_var (dict, var, new_text);
-      break;
-
-    case VS_TYPE:
-      /* Not reachable. */
-      break;
-
-    case VS_WIDTH:
-      width = atoi (new_text);
-      if (width > 0)
-        {
-          struct fmt_spec format;
-
-          format = *var_get_print_format (var);
-          fmt_change_width (&format, width, var_sheet->format_use);
-          var_set_width (var, fmt_var_width (&format));
-          var_set_both_formats (var, &format);
-        }
-      break;
-
-    case VS_DECIMALS:
-      decimals = atoi (new_text);
-      if (decimals >= 0)
-        {
-          struct fmt_spec format;
-
-          format = *var_get_print_format (var);
-          fmt_change_decimals (&format, decimals, var_sheet->format_use);
-          var_set_print_format (var, &format);
-        }
-      break;
-
-    case VS_LABEL:
-      var_set_label (var, new_text);
-      break;
-
-    case VS_VALUES:
-    case VS_MISSING:
-      break;
-
-    case VS_COLUMNS:
-      width = atoi (new_text);
-      if (width > 0 && width < 2 * MAX_STRING)
-        var_set_display_width (var, width);
-      break;
-
-    case VS_ALIGN:
-      if (!strcmp (new_text, alignment_to_string (ALIGN_LEFT)))
-        var_set_alignment (var, ALIGN_LEFT);
-      else if (!strcmp (new_text, alignment_to_string (ALIGN_CENTRE)))
-        var_set_alignment (var, ALIGN_CENTRE);
-      else if (!strcmp (new_text, alignment_to_string (ALIGN_RIGHT)))
-        var_set_alignment (var, ALIGN_RIGHT);
-      break;
-
-    case VS_MEASURE:
-      if (!strcmp (new_text, measure_to_string (MEASURE_NOMINAL)))
-        var_set_measure (var, MEASURE_NOMINAL);
-      else if (!strcmp (new_text, measure_to_string (MEASURE_ORDINAL)))
-        var_set_measure (var, MEASURE_ORDINAL);
-      else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
-        var_set_measure (var, MEASURE_SCALE);
-      break;
-
-    case VS_ROLE:
-      if (!strcmp (new_text, var_role_to_string (ROLE_INPUT)))
-        var_set_role (var, ROLE_INPUT);
-      else if (!strcmp (new_text, var_role_to_string (ROLE_TARGET)))
-        var_set_role (var, ROLE_TARGET);
-      else if (!strcmp (new_text, var_role_to_string (ROLE_BOTH)))
-        var_set_role (var, ROLE_BOTH);
-      else if (!strcmp (new_text, var_role_to_string (ROLE_NONE)))
-        var_set_role (var, ROLE_NONE);
-      else if (!strcmp (new_text, var_role_to_string (ROLE_PARTITION)))
-        var_set_role (var, ROLE_PARTITION);
-      else if (!strcmp (new_text, var_role_to_string (ROLE_SPLIT)))
-        var_set_role (var, ROLE_SPLIT);
-      break;
-    }
-}
-
-static void
-render_popup_cell (PsppSheetViewColumn *tree_column,
-                   GtkCellRenderer *cell,
-                   GtkTreeModel *model,
-                   GtkTreeIter *iter,
-                   void *user_data)
-{
-  PsppireVarSheet *var_sheet = user_data;
-  gint row;
-
-  row = GPOINTER_TO_INT (iter->user_data);
-  g_object_set (cell,
-                "editable", row < psppire_dict_get_var_cnt (var_sheet->dict),
-                NULL);
-}
-
-const char *
-get_var_align_stock_id (enum alignment alignment)
-{
-  switch (alignment)
-    {
-    case ALIGN_LEFT: return "align-left";
-    case ALIGN_CENTRE: return "align-center";
-    case ALIGN_RIGHT: return "align-right";
-    default:
-      g_return_val_if_reached ("");
-    }
-}
-
-const char *
-get_var_role_stock_id (enum var_role role)
-{
-  switch (role)
-    {
-    case ROLE_INPUT: return "role-input";
-    case ROLE_TARGET: return "role-target";
-    case ROLE_BOTH: return "role-both";
-    case ROLE_NONE: return "role-none";
-    case ROLE_PARTITION: return "role-partition";
-    case ROLE_SPLIT: return "role-split";
-    default:
-      g_return_val_if_reached ("");
-    }
-}
-
-static void
-render_var_cell (PsppSheetViewColumn *tree_column,
-                 GtkCellRenderer *cell,
-                 GtkTreeModel *model,
-                 GtkTreeIter *iter,
-                 void *user_data)
-{
-  PsppireVarSheet *var_sheet = user_data;
-  const struct fmt_spec *print;
-  enum vs_column column_id;
-  struct variable *var;
-  gint row;
-
-  column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
-                                                  "column-number")) - 1;
-  row = GPOINTER_TO_INT (iter->user_data);
-
-  gtk_cell_renderer_set_visible (cell, true);
-  if (row >= psppire_dict_get_var_cnt (var_sheet->dict))
-    {
-      if (GTK_IS_CELL_RENDERER_TEXT (cell))
-        {
-          g_object_set (cell,
-                        "text", "",
-                        "editable", column_id == VS_NAME,
-                        NULL);
-          if (column_id == VS_WIDTH
-              || column_id == VS_DECIMALS
-              || column_id == VS_COLUMNS)
-            g_object_set (cell, "adjustment", NULL, NULL);
-        }
-      else
-       {
-         gtk_cell_renderer_set_visible (cell, false);
-       }
-      return;
-    }
-
-  var = psppire_dict_get_variable (var_sheet->dict, row);
-
-  print = var_get_print_format (var);
-  switch (column_id)
-    {
-    case VS_NAME:
-      g_object_set (cell,
-                    "text", var_get_name (var),
-                    "editable", TRUE,
-                    NULL);
-      break;
-
-    case VS_TYPE:
-      g_object_set (cell,
-                    "text", fmt_gui_name (print->type),
-                    "editable", FALSE,
-                    NULL);
-      break;
-
-    case VS_WIDTH:
-      set_spin_cell (cell, print->w,
-                     fmt_min_width (print->type, var_sheet->format_use),
-                     fmt_max_width (print->type, var_sheet->format_use),
-                     fmt_step_width (print->type));
-      break;
-
-    case VS_DECIMALS:
-      if (fmt_takes_decimals (print->type))
-        {
-          int max_w = fmt_max_width (print->type, var_sheet->format_use);
-          int max_d = fmt_max_decimals (print->type, max_w,
-                                        var_sheet->format_use);
-          set_spin_cell (cell, print->d, 0, max_d, 1);
-        }
-      else
-        g_object_set (cell,
-                      "text", "",
-                      "editable", FALSE,
-                      "adjustment", NULL,
-                      NULL);
-      break;
-
-    case VS_LABEL:
-      g_object_set (cell,
-                    "text", var_has_label (var) ? var_get_label (var) : "",
-                    "editable", TRUE,
-                    NULL);
-      break;
-
-    case VS_VALUES:
-      g_object_set (cell, "editable", FALSE, NULL);
-      if ( ! var_has_value_labels (var))
-        g_object_set (cell, "text", _("None"), NULL);
-      else
-        {
-          const struct val_labs *vls = var_get_value_labels (var);
-          const struct val_lab **labels = val_labs_sorted (vls);
-          const struct val_lab *vl = labels[0];
-          gchar *vstr = value_to_text (vl->value, var);
-          char *text = xasprintf (_("{%s, %s}..."), vstr,
-                                  val_lab_get_escaped_label (vl));
-          free (vstr);
-
-          g_object_set (cell, "text", text, NULL);
-          free (text);
-          free (labels);
-        }
-      break;
-
-    case VS_MISSING:
-      {
-        char *text = missing_values_to_string (var, NULL);
-        g_object_set (cell,
-                      "text", text,
-                      "editable", FALSE,
-                      NULL);
-        free (text);
-      }
-      break;
-
-    case VS_COLUMNS:
-      set_spin_cell (cell, var_get_display_width (var), 1, 2 * MAX_STRING, 1);
-      break;
-
-    case VS_ALIGN:
-      if (GTK_IS_CELL_RENDERER_TEXT (cell))
-        g_object_set (cell,
-                      "text", alignment_to_string (var_get_alignment (var)),
-                      "editable", TRUE,
-                      NULL);
-      else
-        g_object_set (cell, "icon-name",
-                      get_var_align_stock_id (var_get_alignment (var)), NULL);
-      break;
-
-    case VS_MEASURE:
-      if (GTK_IS_CELL_RENDERER_TEXT (cell))
-        g_object_set (cell,
-                      "text", measure_to_string (var_get_measure (var)),
-                      "editable", TRUE,
-                      NULL);
-      else
-        {
-          enum fmt_type type = var_get_print_format (var)->type;
-          enum measure measure = var_get_measure (var);
-
-          g_object_set (cell, "icon-name",
-                        get_var_measurement_stock_id (type, measure),
-                        NULL);
-        }
-      break;
-
-    case VS_ROLE:
-      if (GTK_IS_CELL_RENDERER_TEXT (cell))
-        g_object_set (cell,
-                      "text", var_role_to_string (var_get_role (var)),
-                      "editable", TRUE,
-                      NULL);
-      else
-        g_object_set (cell, "icon-name",
-                      get_var_role_stock_id (var_get_role (var)), NULL);
-      break;
-    }
-}
-
-static struct variable *
-path_string_to_variable (PsppireVarSheet *var_sheet, gchar *path_string)
-{
-  PsppireDict *dict;
-  GtkTreePath *path;
-  gint row;
-
-  path = gtk_tree_path_new_from_string (path_string);
-  row = gtk_tree_path_get_indices (path)[0];
-  gtk_tree_path_free (path);
-
-  dict = psppire_var_sheet_get_dictionary (var_sheet);
-  g_return_val_if_fail (dict != NULL, NULL);
-
-  return psppire_dict_get_variable (dict, row);
-}
-
-static void
-on_type_click (PsppireCellRendererButton *cell,
-               gchar *path,
-               PsppireVarSheet *var_sheet)
-{
-  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
-  struct fmt_spec format;
-  struct variable *var;
-
-  var = path_string_to_variable (var_sheet, path);
-  g_return_if_fail (var != NULL);
-
-  format = *var_get_print_format (var);
-  psppire_var_type_dialog_run (GTK_WINDOW (toplevel), &format);
-
-  var_set_width_and_formats (var, fmt_var_width (&format), &format, &format);
-}
-
-static void
-on_value_labels_click (PsppireCellRendererButton *cell,
-                       gchar *path,
-                       PsppireVarSheet *var_sheet)
-{
-  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
-  struct val_labs *labels;
-  struct variable *var;
-
-  var = path_string_to_variable (var_sheet, path);
-  g_return_if_fail (var != NULL);
-
-  labels = psppire_val_labs_dialog_run (GTK_WINDOW (toplevel), var);
-  if (labels)
-    {
-      var_set_value_labels (var, labels);
-      val_labs_destroy (labels);
-    }
-}
-
-static void
-on_missing_values_click (PsppireCellRendererButton *cell,
-                         gchar *path,
-                         PsppireVarSheet *var_sheet)
-{
-  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
-  struct missing_values mv;
-  struct variable *var;
-
-  var = path_string_to_variable (var_sheet, path);
-  g_return_if_fail (var != NULL);
-
-  psppire_missing_val_dialog_run (GTK_WINDOW (toplevel), var, &mv);
-  var_set_missing_values (var, &mv);
-  mv_destroy (&mv);
-}
-
-static gint
-get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
-                  const char *string)
-{
-  gint width;
-  g_object_set (G_OBJECT (renderer),
-                PSPPIRE_IS_CELL_RENDERER_BUTTON (renderer) ? "label" : "text",
-                string, (void *) NULL);
-
-  gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (treeview), NULL, &width);
-
-  return width;
-}
-
-static gint
-get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
-                     size_t char_cnt)
-{
-  struct string s;
-  gint width;
-
-  ds_init_empty (&s);
-  ds_put_byte_multiple (&s, '0', char_cnt);
-  ds_put_byte (&s, ' ');
-  width = get_string_width (treeview, renderer, ds_cstr (&s));
-  ds_destroy (&s);
-
-  return width;
-}
-
-static PsppSheetViewColumn *
-add_var_sheet_column (PsppireVarSheet *var_sheet, GtkCellRenderer *renderer,
-                      enum vs_column column_id,
-                      const char *title, int width)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  int title_width, content_width;
-  PsppSheetViewColumn *column;
-
-  column = pspp_sheet_view_column_new_with_attributes (title, renderer, NULL);
-  g_object_set_data (G_OBJECT (column), "column-number",
-                     GINT_TO_POINTER (column_id) + 1);
-
-  pspp_sheet_view_column_set_cell_data_func (
-    column, renderer, render_var_cell, var_sheet, NULL);
-
-  title_width = get_string_width (sheet_view, renderer, title);
-  content_width = get_monospace_width (sheet_view, renderer, width);
-  g_object_set_data (G_OBJECT (column), "content-width",
-                     GINT_TO_POINTER (content_width));
-
-  pspp_sheet_view_column_set_fixed_width (column,
-                                          MAX (title_width, content_width));
-  pspp_sheet_view_column_set_resizable (column, TRUE);
-
-  pspp_sheet_view_append_column (sheet_view, column);
-
-  g_signal_connect (renderer, "edited",
-                    G_CALLBACK (on_var_column_edited),
-                    var_sheet);
-  g_object_set_data (G_OBJECT (renderer), "column-id",
-                     GINT_TO_POINTER (column_id));
-  g_object_set_data (G_OBJECT (renderer), "var-sheet", var_sheet);
-
-  return column;
-}
-
-static PsppSheetViewColumn *
-add_text_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
-                 const char *title, int width)
-{
-  return add_var_sheet_column (var_sheet, gtk_cell_renderer_text_new (),
-                               column_id, title, width);
-}
-
-static PsppSheetViewColumn *
-add_spin_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
-                 const char *title, int width)
-{
-  return add_var_sheet_column (var_sheet, gtk_cell_renderer_spin_new (),
-                               column_id, title, width);
-}
-
-static const char *
-measure_to_stock_id (enum fmt_type type, int measure)
-{
-  return get_var_measurement_stock_id (type, measure);
-}
-
-static const char *
-alignment_to_stock_id (enum fmt_type type, int alignment)
-{
-  return get_var_align_stock_id (alignment);
-}
-
-static const char *
-role_to_stock_id (enum fmt_type type, int role)
-{
-  return get_var_role_stock_id (role);
-}
-
-static void
-render_var_pixbuf (GtkCellLayout *cell_layout,
-                   GtkCellRenderer *cell,
-                   GtkTreeModel *tree_model,
-                   GtkTreeIter *iter,
-                   gpointer data)
-{
-  const char *(*value_to_stock_id) (enum fmt_type, int value);
-  enum fmt_type type = GPOINTER_TO_INT (data);
-  gint value;
-
-  value_to_stock_id = g_object_get_data (G_OBJECT (cell), "value-to-stock-id");
-
-  gtk_tree_model_get (tree_model, iter, 0, &value, -1);
-  g_object_set (cell, "icon-name", value_to_stock_id (type, value), NULL);
-}
-
-static void
-on_combo_editing_started (GtkCellRenderer *renderer,
-                          GtkCellEditable *editable,
-                          gchar           *path_string,
-                          gpointer         user_data)
-{
-  PsppireVarSheet *var_sheet = user_data;
-
-  if (GTK_IS_COMBO_BOX (editable))
-    {
-      struct variable *var = path_string_to_variable (var_sheet, path_string);
-      const struct fmt_spec *format = var_get_print_format (var);
-      const char *(*value_to_stock_id) (enum fmt_type, int value);
-      GtkCellRenderer *cell;
-
-      value_to_stock_id = g_object_get_data (G_OBJECT (renderer),
-                                             "value-to-stock-id");
-
-      cell = gtk_cell_renderer_pixbuf_new ();
-      g_object_set (cell, "width", 16, "height", 16, NULL);
-      g_object_set_data (G_OBJECT (cell),
-                         "value-to-stock-id", value_to_stock_id);
-      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (editable), cell, FALSE);
-      gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (editable), cell,
-                                          render_var_pixbuf,
-                                          GINT_TO_POINTER (format->type),
-                                          NULL);
-    }
-}
-
-static void
-add_combo_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
-                  const char *title, int width,
-                  const char *(*value_to_stock_id) (enum fmt_type, int value),
-                  ...)
-{
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *cell;
-  GtkListStore *store;
-  const char *name;
-  va_list args;
-
-  store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
-  va_start (args, value_to_stock_id);
-  while ((name = va_arg (args, const char *)) != NULL)
-    {
-      int value = va_arg (args, int);
-      gtk_list_store_insert_with_values (store, NULL, G_MAXINT,
-                                         0, value,
-                                         1, name,
-                                         -1);
-    }
-  va_end (args);
-
-  cell = gtk_cell_renderer_combo_new ();
-  g_object_set (cell,
-                "has-entry", FALSE,
-                "model", GTK_TREE_MODEL (store),
-                "text-column", 1,
-                NULL);
-  if (value_to_stock_id != NULL)
-    {
-      g_object_set_data (G_OBJECT (cell),
-                         "value-to-stock-id", value_to_stock_id);
-      g_signal_connect (cell, "editing-started",
-                        G_CALLBACK (on_combo_editing_started),
-                        var_sheet);
-    }
-
-  column = add_var_sheet_column (var_sheet, cell, column_id, title, width);
-
-  cell = gtk_cell_renderer_pixbuf_new ();
-  g_object_set (cell, "width", 16, "height", 16, NULL);
-  pspp_sheet_view_column_pack_end (column, cell, FALSE);
-  pspp_sheet_view_column_set_cell_data_func (
-    column, cell, render_var_cell, var_sheet, NULL);
-}
-
-static void
-add_popup_menu (PsppireVarSheet *var_sheet,
-                PsppSheetViewColumn *column,
-                void (*on_click) (PsppireCellRendererButton *,
-                                  gchar *path,
-                                  PsppireVarSheet *var_sheet))
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  const char *button_label = "...";
-  GtkCellRenderer *button_renderer;
-  gint content_width;
-
-  button_renderer = psppire_cell_renderer_button_new ();
-  g_object_set (button_renderer,
-                "label", button_label,
-                "editable", TRUE,
-                NULL);
-  g_signal_connect (button_renderer, "clicked", G_CALLBACK (on_click),
-                    var_sheet);
-  pspp_sheet_view_column_pack_start (column, button_renderer, FALSE);
-  pspp_sheet_view_column_set_cell_data_func (
-    column, button_renderer, render_popup_cell, var_sheet, NULL);
-
-  content_width = GPOINTER_TO_INT (g_object_get_data (
-                                     G_OBJECT (column), "content-width"));
-  content_width += get_string_width (sheet_view, button_renderer,
-                                     button_label);
-  if (content_width > pspp_sheet_view_column_get_fixed_width (column))
-    pspp_sheet_view_column_set_fixed_width (column, content_width);
-}
-
-static gboolean
-get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
-                      gint wx, gint wy, size_t *row, size_t *column)
-{
-  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-  gint bx, by;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-  PsppSheetViewColumn *tree_column;
-  GtkTreeModel *tree_model;
-  gpointer column_ptr;
-  bool ok;
-
-  /* Check that WIDGET is really visible on the screen before we
-     do anything else.  This is a bug fix for a sticky situation:
-     when text_data_import_assistant() returns, it frees the data
-     necessary to compose the tool tip message, but there may be
-     a tool tip under preparation at that point (even if there is
-     no visible tool tip) that will call back into us a little
-     bit later.  Perhaps the correct solution to this problem is
-     to make the data related to the tool tips part of a GObject
-     that only gets destroyed when all references are released,
-     but this solution appears to be effective too. */
-  if (!gtk_widget_get_mapped (widget))
-    return FALSE;
-
-  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
-                                                     wx, wy, &bx, &by);
-  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
-                                      &path, &tree_column, NULL, NULL))
-    return FALSE;
-
-  column_ptr = g_object_get_data (G_OBJECT (tree_column), "column-number");
-  if (column_ptr == NULL)
-    return FALSE;
-  *column = GPOINTER_TO_INT (column_ptr) - 1;
-
-  pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
-                                    NULL);
-
-  tree_model = pspp_sheet_view_get_model (tree_view);
-  ok = gtk_tree_model_get_iter (tree_model, &iter, path);
-  gtk_tree_path_free (path);
-  if (!ok)
-    return FALSE;
-
-  *row = GPOINTER_TO_INT (iter.user_data);
-  return TRUE;
-}
-
-static gboolean
-on_query_var_tooltip (GtkWidget *widget, gint wx, gint wy,
-                      gboolean keyboard_mode UNUSED,
-                      GtkTooltip *tooltip, gpointer *user_data UNUSED)
-{
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
-  PsppireDict *dict;
-  struct variable *var;
-  size_t row, column;
-
-  if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
-    return FALSE;
-
-  dict = psppire_var_sheet_get_dictionary (var_sheet);
-  g_return_val_if_fail (dict != NULL, FALSE);
-
-  if (row >= psppire_dict_get_var_cnt (dict))
-    {
-      gtk_tooltip_set_text (tooltip, _("Enter a variable name to add a "
-                                       "new variable."));
-      return TRUE;
-    }
-
-  var = psppire_dict_get_variable (dict, row);
-  g_return_val_if_fail (var != NULL, FALSE);
-
-  switch (column)
-    {
-    case VS_TYPE:
-      {
-        char text[FMT_STRING_LEN_MAX + 1];
-
-        fmt_to_string (var_get_print_format (var), text);
-        gtk_tooltip_set_text (tooltip, text);
-        return TRUE;
-      }
-
-    case VS_VALUES:
-      if (var_has_value_labels (var))
-        {
-          const struct val_labs *vls = var_get_value_labels (var);
-          const struct val_lab **labels = val_labs_sorted (vls);
-          struct string s;
-          size_t i;
-
-          ds_init_empty (&s);
-          for (i = 0; i < val_labs_count (vls); i++)
-            {
-              const struct val_lab *vl = labels[i];
-              gchar *vstr;
-
-              if (i >= 10 || ds_length (&s) > 500)
-                {
-                  ds_put_cstr (&s, "...");
-                  break;
-                }
-
-              vstr = value_to_text (vl->value, var);
-              ds_put_format (&s, _("{%s, %s}\n"), vstr,
-                             val_lab_get_escaped_label (vl));
-              free (vstr);
-
-            }
-          ds_chomp_byte (&s, '\n');
-
-          gtk_tooltip_set_text (tooltip, ds_cstr (&s));
-          ds_destroy (&s);
-          free (labels);
-
-          return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-static void
-do_popup_menu (GtkWidget *widget, guint button, guint32 time)
-{
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
-  GtkWidget *menu = gtk_menu_new ();
-
-  int i = 0;
-
-  GtkWidget *insert_variable = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
-  GtkWidget *clear_variables = gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
-
-  g_signal_connect_swapped (insert_variable, "activate", G_CALLBACK (psppire_var_sheet_insert_variable), var_sheet);
-  g_signal_connect_swapped (clear_variables, "activate", G_CALLBACK (psppire_var_sheet_clear_variables), var_sheet);
-
-  gtk_menu_attach (GTK_MENU (menu), insert_variable,  0, 1, i, i + 1);  ++i;
-  gtk_menu_attach (GTK_MENU (menu), clear_variables,  0, 1, i, i + 1);  ++i;
-
-  gtk_widget_show_all (menu);
-
-  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
-{
-  do_popup_menu (widget, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
-                   gpointer user_data UNUSED)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-
-  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
-    {
-      PsppSheetSelection *selection;
-
-      selection = pspp_sheet_view_get_selection (sheet_view);
-      if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
-        {
-          GtkTreePath *path;
-
-          if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
-                                               &path, NULL, NULL, NULL))
-            {
-              pspp_sheet_selection_unselect_all (selection);
-              pspp_sheet_selection_select_path (selection, path);
-              gtk_tree_path_free (path);
-            }
-        }
-
-      do_popup_menu (widget, event->button, event->time);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-\f
-GType
-psppire_fmt_use_get_type (void)
-{
-  static GType etype = 0;
-  if (etype == 0)
-    {
-      static const GEnumValue values[] =
-       {
-         { FMT_FOR_INPUT, "FMT_FOR_INPUT", "input" },
-         { FMT_FOR_OUTPUT, "FMT_FOR_OUTPUT", "output" },
-         { 0, NULL, NULL }
-       };
-
-      etype = g_enum_register_static
-       (g_intern_static_string ("PsppireFmtUse"), values);
-    }
-  return etype;
-}
-
-enum
-  {
-    PROP_0,
-    PROP_DICTIONARY,
-    PROP_MAY_CREATE_VARS,
-    PROP_MAY_DELETE_VARS,
-    PROP_FORMAT_TYPE
-  };
-
-static void
-psppire_var_sheet_set_property (GObject      *object,
-                             guint         prop_id,
-                             const GValue *value,
-                             GParamSpec   *pspec)
-{
-  PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_DICTIONARY:
-      psppire_var_sheet_set_dictionary (obj,
-                                        PSPPIRE_DICT (g_value_get_object (
-                                                        value)));
-      break;
-
-    case PROP_MAY_CREATE_VARS:
-      psppire_var_sheet_set_may_create_vars (obj,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_MAY_DELETE_VARS:
-      psppire_var_sheet_set_may_delete_vars (obj,
-                                             g_value_get_boolean (value));
-      break;
-
-    case PROP_FORMAT_TYPE:
-      obj->format_use = g_value_get_enum (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_var_sheet_get_property (GObject      *object,
-                                guint         prop_id,
-                                GValue       *value,
-                                GParamSpec   *pspec)
-{
-  PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_DICTIONARY:
-      g_value_set_object (value,
-                          G_OBJECT (psppire_var_sheet_get_dictionary (obj)));
-      break;
-
-    case PROP_MAY_CREATE_VARS:
-      g_value_set_boolean (value, obj->may_create_vars);
-      break;
-
-    case PROP_MAY_DELETE_VARS:
-      g_value_set_boolean (value, obj->may_delete_vars);
-      break;
-
-    case PROP_FORMAT_TYPE:
-      g_value_set_enum (value, obj->format_use);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_var_sheet_dispose (GObject *obj)
-{
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (obj);
-  int i;
-
-  if (var_sheet->dispose_has_run)
-    return;
-
-  var_sheet->dispose_has_run = TRUE;
-
-  for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
-    if ( var_sheet->dict_signals[i])
-      g_signal_handler_disconnect (var_sheet->dict,
-                                  var_sheet->dict_signals[i]);
-
-  if (var_sheet->dict)
-    g_object_unref (var_sheet->dict);
-
-  /* These dialogs are not GObjects (although they should be!)
-    But for now, unreffing them only causes a GCritical Error
-    so comment them out for now. (and accept the memory leakage)
-
-  g_object_unref (var_sheet->val_labs_dialog);
-  g_object_unref (var_sheet->missing_val_dialog);
-  g_object_unref (var_sheet->var_type_dialog);
-  */
-
-  G_OBJECT_CLASS (psppire_var_sheet_parent_class)->dispose (obj);
-}
-
-static void
-psppire_var_sheet_class_init (PsppireVarSheetClass *class)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-  GParamSpec *pspec;
-
-  gobject_class->set_property = psppire_var_sheet_set_property;
-  gobject_class->get_property = psppire_var_sheet_get_property;
-  gobject_class->dispose = psppire_var_sheet_dispose;
-
-  g_signal_new ("var-double-clicked",
-                G_OBJECT_CLASS_TYPE (gobject_class),
-                G_SIGNAL_RUN_LAST,
-                0,
-                g_signal_accumulator_true_handled, NULL,
-                psppire_marshal_BOOLEAN__INT,
-                G_TYPE_BOOLEAN, 1, G_TYPE_INT);
-
-  pspec = g_param_spec_object ("dictionary",
-                               "Dictionary displayed by the sheet",
-                               "The PsppireDict that the sheet displays "
-                               "may allow the user to edit",
-                               PSPPIRE_TYPE_DICT,
-                               G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class, PROP_DICTIONARY, pspec);
-
-  pspec = g_param_spec_boolean ("may-create-vars",
-                                "May create variables",
-                                "Whether the user may create more variables",
-                                TRUE,
-                                G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class, PROP_MAY_CREATE_VARS, pspec);
-
-  pspec = g_param_spec_boolean ("may-delete-vars",
-                                "May delete variables",
-                                "Whether the user may delete variables",
-                                TRUE,
-                                G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class, PROP_MAY_DELETE_VARS, pspec);
-
-  pspec = g_param_spec_enum ("format-use",
-                             "Use of variable format",
-                             ("Whether variables have input or output "
-                              "formats"),
-                             PSPPIRE_TYPE_FMT_USE,
-                             FMT_FOR_OUTPUT,
-                             G_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class, PROP_FORMAT_TYPE, pspec);
-}
-
-static void
-render_row_number_cell (PsppSheetViewColumn *tree_column,
-                        GtkCellRenderer *cell,
-                        GtkTreeModel *model,
-                        GtkTreeIter *iter,
-                        gpointer user_data)
-{
-  PsppireVarSheet *var_sheet = user_data;
-  GValue gvalue = { 0, };
-  gint row;
-
-  row = GPOINTER_TO_INT (iter->user_data);
-
-  g_value_init (&gvalue, G_TYPE_INT);
-  g_value_set_int (&gvalue, row + 1);
-  g_object_set_property (G_OBJECT (cell), "label", &gvalue);
-  g_value_unset (&gvalue);
-
-  if (!var_sheet->dict || row < psppire_dict_get_var_cnt (var_sheet->dict))
-    g_object_set (cell, "editable", TRUE, NULL);
-  else
-    g_object_set (cell, "editable", FALSE, NULL);
-}
-
-static void
-psppire_var_sheet_row_number_double_clicked (PsppireCellRendererButton *button,
-                                             gchar *path_string,
-                                             PsppireVarSheet *var_sheet)
-{
-  GtkTreePath *path;
-
-  g_return_if_fail (var_sheet->dict != NULL);
-
-  path = gtk_tree_path_new_from_string (path_string);
-  if (gtk_tree_path_get_depth (path) == 1)
-    {
-      gint *indices = gtk_tree_path_get_indices (path);
-      if (indices[0] < psppire_dict_get_var_cnt (var_sheet->dict))
-        {
-          gboolean handled;
-          g_signal_emit_by_name (var_sheet, "var-double-clicked",
-                                 indices[0], &handled);
-        }
-    }
-  gtk_tree_path_free (path);
-}
-
-static void
-psppire_var_sheet_variables_column_clicked (PsppSheetViewColumn *column,
-                                            PsppireVarSheet *var_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-
-  pspp_sheet_selection_select_all (selection);
-}
-
-static PsppSheetViewColumn *
-make_row_number_column (PsppireVarSheet *var_sheet)
-{
-  PsppSheetViewColumn *column;
-  GtkCellRenderer *renderer;
-
-  renderer = psppire_cell_renderer_button_new ();
-  g_object_set (renderer, "xalign", 1.0, NULL);
-  g_signal_connect (renderer, "double-clicked",
-                    G_CALLBACK (psppire_var_sheet_row_number_double_clicked),
-                    var_sheet);
-
-  column = pspp_sheet_view_column_new_with_attributes (_("Variable"),
-                                                       renderer, NULL);
-  pspp_sheet_view_column_set_clickable (column, TRUE);
-  pspp_sheet_view_column_set_cell_data_func (
-    column, renderer, render_row_number_cell, var_sheet, NULL);
-  pspp_sheet_view_column_set_fixed_width (column, 50);
-  g_signal_connect (column, "clicked",
-                    G_CALLBACK (psppire_var_sheet_variables_column_clicked),
-                    var_sheet);
-
-  return column;
-}
-
-void
-psppire_var_sheet_clear_variables (PsppireVarSheet *var_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDict *dict = var_sheet->dict;
-  const struct range_set_node *node;
-  struct range_set *selected = pspp_sheet_selection_get_range_set (selection);
-
-  for (node = range_set_last (selected); node != NULL;
-       node = range_set_prev (selected, node))
-    {
-      int i;
-
-      for (i = 1; i <= range_set_node_get_width (node); i++)
-        {
-          unsigned long row = range_set_node_get_end (node) - i;
-          if (row < psppire_dict_get_var_cnt (dict))
-            psppire_dict_delete_variables (dict, row, 1);
-        }
-    }
-  range_set_destroy (selected);
-}
-
-static void
-on_selection_changed (PsppSheetSelection *selection,
-                      gpointer user_data UNUSED)
-{
-  PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet_view);
-  gint n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
-  gboolean may_delete;
-  GtkTreePath *path;
-
-  GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
-  if (! PSPPIRE_IS_DATA_WINDOW (top))
-    return;
-
-  PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
-  gtk_widget_set_sensitive (dw->mi_insert_var, n_selected_rows > 0);
-
-  switch (n_selected_rows)
-    {
-    case 0:
-      may_delete = FALSE;
-      break;
-
-    case 1:
-      /* The row used for inserting new variables cannot be deleted. */
-      path = gtk_tree_path_new_from_indices (
-        psppire_dict_get_var_cnt (var_sheet->dict), -1);
-      may_delete = !pspp_sheet_selection_path_is_selected (selection, path);
-      gtk_tree_path_free (path);
-      break;
-
-    default:
-      may_delete = TRUE;
-      break;
-    }
-
-  gtk_widget_set_sensitive (dw->mi_clear_variables, var_sheet->may_delete_vars && may_delete);
-}
-
-void
-psppire_var_sheet_insert_variable (PsppireVarSheet *var_sheet)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-  PsppireDict *dict = var_sheet->dict;
-  struct range_set *selected;
-  unsigned long row;
-
-  selected = pspp_sheet_selection_get_range_set (selection);
-  row = range_set_scan (selected, 0);
-  range_set_destroy (selected);
-
-  if (row <= psppire_dict_get_var_cnt (dict))
-    {
-      gchar name[64];;
-      if (psppire_dict_generate_name (dict, name, sizeof name))
-        psppire_dict_insert_variable (dict, row, name);
-    }
-}
-
-static void
-psppire_var_sheet_init (PsppireVarSheet *obj)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
-  PsppSheetViewColumn *column;
-  GList *list;
-
-  obj->dict = NULL;
-  obj->format_use = FMT_FOR_OUTPUT;
-  obj->may_create_vars = TRUE;
-  obj->may_delete_vars = TRUE;
-
-  obj->scroll_to_bottom_signal = 0;
-
-  obj->container = NULL;
-  obj->dispose_has_run = FALSE;
-
-  pspp_sheet_view_append_column (sheet_view, make_row_number_column (obj));
-
-  column = add_text_column (obj, VS_NAME, _("Name"), 12);
-  list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
-  g_signal_connect (list->data, "editing-started",
-                    G_CALLBACK (on_name_column_editing_started), NULL);
-  g_list_free (list);
-
-  column = add_text_column (obj, VS_TYPE, _("Type"), 8);
-  add_popup_menu (obj, column, on_type_click);
-
-  add_spin_column (obj, VS_WIDTH, _("Width"), 5);
-
-  add_spin_column (obj, VS_DECIMALS, _("Decimals"), 2);
-
-  add_text_column (obj, VS_LABEL, _("Label"), 20);
-
-  column = add_text_column (obj, VS_VALUES, _("Value Labels"), 20);
-  add_popup_menu (obj, column, on_value_labels_click);
-
-  column = add_text_column (obj, VS_MISSING, _("Missing Values"), 20);
-  add_popup_menu (obj, column, on_missing_values_click);
-
-  add_spin_column (obj, VS_COLUMNS, _("Columns"), 3);
-
-  add_combo_column (obj, VS_ALIGN, _("Align"), 8, alignment_to_stock_id,
-                    alignment_to_string (ALIGN_LEFT), ALIGN_LEFT,
-                    alignment_to_string (ALIGN_CENTRE), ALIGN_CENTRE,
-                    alignment_to_string (ALIGN_RIGHT), ALIGN_RIGHT,
-                    NULL);
-
-  add_combo_column (obj, VS_MEASURE, _("Measure"), 11, measure_to_stock_id,
-                    measure_to_string (MEASURE_NOMINAL), MEASURE_NOMINAL,
-                    measure_to_string (MEASURE_ORDINAL), MEASURE_ORDINAL,
-                    measure_to_string (MEASURE_SCALE), MEASURE_SCALE,
-                    NULL);
-
-  add_combo_column (obj, VS_ROLE, _("Role"), 11, role_to_stock_id,
-                    var_role_to_string (ROLE_INPUT), ROLE_INPUT,
-                    var_role_to_string (ROLE_TARGET), ROLE_TARGET,
-                    var_role_to_string (ROLE_BOTH), ROLE_BOTH,
-                    var_role_to_string (ROLE_NONE), ROLE_NONE,
-                    var_role_to_string (ROLE_PARTITION), ROLE_PARTITION,
-                    var_role_to_string (ROLE_SPLIT), ROLE_SPLIT,
-                    NULL);
-
-  pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
-  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
-                                 PSPP_SHEET_SELECTION_MULTIPLE);
-
-  g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, NULL);
-  g_signal_connect (obj, "query-tooltip",
-                    G_CALLBACK (on_query_var_tooltip), NULL);
-  g_signal_connect (obj, "button-press-event",
-                    G_CALLBACK (on_button_pressed), NULL);
-
-  g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
-
-  g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
-                    "changed", G_CALLBACK (on_selection_changed), NULL);
-}
-
-GtkWidget *
-psppire_var_sheet_new (void)
-{
-  return g_object_new (PSPPIRE_VAR_SHEET_TYPE, NULL);
-}
-
-PsppireDict *
-psppire_var_sheet_get_dictionary (PsppireVarSheet *var_sheet)
-{
-  return var_sheet->dict;
-}
-
-static void
-refresh_model (PsppireVarSheet *var_sheet)
-{
-  pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet), NULL);
-
-  if (var_sheet->dict != NULL)
-    {
-      PsppireEmptyListStore *store;
-      int n_rows;
-
-      n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
-                + var_sheet->may_create_vars);
-      store = psppire_empty_list_store_new (n_rows);
-      pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet),
-                                 GTK_TREE_MODEL (store));
-      g_object_unref (store);
-    }
-}
-
-static void
-on_var_changed (PsppireDict *dict, glong row,
-               guint what, const struct variable *oldvar,
-               PsppireVarSheet *var_sheet)
-{
-  PsppireEmptyListStore *store;
-
-  g_return_if_fail (dict == var_sheet->dict);
-
-  store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
-                                      PSPP_SHEET_VIEW (var_sheet)));
-  g_return_if_fail (store != NULL);
-
-  psppire_empty_list_store_row_changed (store, row);
-}
-
-static void
-on_var_inserted (PsppireDict *dict, glong row, PsppireVarSheet *var_sheet)
-{
-  PsppireEmptyListStore *store;
-  int n_rows;
-
-  g_return_if_fail (dict == var_sheet->dict);
-
-  store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
-                                      PSPP_SHEET_VIEW (var_sheet)));
-  g_return_if_fail (store != NULL);
-
-  n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
-            + var_sheet->may_create_vars);
-  psppire_empty_list_store_set_n_rows (store, n_rows);
-  psppire_empty_list_store_row_inserted (store, row);
-}
-
-static void
-on_var_deleted (PsppireDict *dict,
-                const struct variable *var, int dict_idx, int case_idx,
-                PsppireVarSheet *var_sheet)
-{
-  PsppireEmptyListStore *store;
-  int n_rows;
-
-  g_return_if_fail (dict == var_sheet->dict);
-
-  store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
-                                      PSPP_SHEET_VIEW (var_sheet)));
-  g_return_if_fail (store != NULL);
-
-  n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
-            + var_sheet->may_create_vars);
-  psppire_empty_list_store_set_n_rows (store, n_rows);
-  psppire_empty_list_store_row_deleted (store, dict_idx);
-}
-
-static void
-on_backend_changed (PsppireDict *dict, PsppireVarSheet *var_sheet)
-{
-  g_return_if_fail (dict == var_sheet->dict);
-  refresh_model (var_sheet);
-}
-
-void
-psppire_var_sheet_set_dictionary (PsppireVarSheet *var_sheet,
-                                  PsppireDict *dict)
-{
-  if (var_sheet->dict != NULL)
-    {
-      int i;
-
-      for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
-       {
-         if (var_sheet->dict_signals[i])
-           g_signal_handler_disconnect (var_sheet->dict,
-                                        var_sheet->dict_signals[i]);
-
-         var_sheet->dict_signals[i] = 0;
-       }
-
-      g_object_unref (var_sheet->dict);
-    }
-
-  var_sheet->dict = dict;
-
-  if (dict != NULL)
-    {
-      g_object_ref (dict);
-
-      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_BACKEND_CHANGED]
-        = g_signal_connect (dict, "backend-changed",
-                            G_CALLBACK (on_backend_changed), var_sheet);
-
-      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_CHANGED]
-        = g_signal_connect (dict, "variable-changed",
-                            G_CALLBACK (on_var_changed), var_sheet);
-
-      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_DELETED]
-        = g_signal_connect (dict, "variable-inserted",
-                            G_CALLBACK (on_var_inserted), var_sheet);
-
-      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_INSERTED]
-        = g_signal_connect (dict, "variable-deleted",
-                            G_CALLBACK (on_var_deleted), var_sheet);
-    }
-
-  refresh_model (var_sheet);
-}
-
-gboolean
-psppire_var_sheet_get_may_create_vars (PsppireVarSheet *var_sheet)
-{
-  return var_sheet->may_create_vars;
-}
-
-void
-psppire_var_sheet_set_may_create_vars (PsppireVarSheet *var_sheet,
-                                       gboolean may_create_vars)
-{
-  if (var_sheet->may_create_vars != may_create_vars)
-    {
-      PsppireEmptyListStore *store;
-      gint n_rows;
-
-      var_sheet->may_create_vars = may_create_vars;
-
-      store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
-                                          PSPP_SHEET_VIEW (var_sheet)));
-      g_return_if_fail (store != NULL);
-
-      n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
-                + var_sheet->may_create_vars);
-      psppire_empty_list_store_set_n_rows (store, n_rows);
-
-      if (may_create_vars)
-        psppire_empty_list_store_row_inserted (store, n_rows - 1);
-      else
-        psppire_empty_list_store_row_deleted (store, n_rows);
-
-      on_selection_changed (pspp_sheet_view_get_selection (
-                              PSPP_SHEET_VIEW (var_sheet)), NULL);
-    }
-}
-
-gboolean
-psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *var_sheet)
-{
-  return var_sheet->may_delete_vars;
-}
-
-void
-psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *var_sheet,
-                                       gboolean may_delete_vars)
-{
-  if (var_sheet->may_delete_vars != may_delete_vars)
-    {
-      var_sheet->may_delete_vars = may_delete_vars;
-      on_selection_changed (pspp_sheet_view_get_selection (
-                              PSPP_SHEET_VIEW (var_sheet)), NULL);
-    }
-}
-
-void
-psppire_var_sheet_goto_variable (PsppireVarSheet *var_sheet, int dict_index)
-{
-  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_indices (dict_index, -1);
-  pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
-  pspp_sheet_view_set_cursor (sheet_view, path, NULL, FALSE);
-  gtk_tree_path_free (path);
-}
-
-
diff --git a/src/ui/gui/psppire-var-sheet.h b/src/ui/gui/psppire-var-sheet.h
deleted file mode 100644 (file)
index 6a57cc6..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2011, 2012 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef __PSPPIRE_VAR_SHEET_H__
-#define __PSPPIRE_VAR_SHEET_H__
-
-/* PsppireVarSheet is a PsppSheetView that displays the variables in a
-   dictionary, one variable per row.
-
-   PsppireDataSheet is usually a child of PsppireDataEditor in the widget
-   hierarchy.  Other widgets can also use it. */
-
-#include <gtk/gtk.h>
-#include "data/format.h"
-#include "ui/gui/pspp-sheet-view.h"
-
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_FMT_USE (psppire_fmt_use_get_type ())
-
-GType psppire_fmt_use_get_type (void) G_GNUC_CONST;
-\f
-#define PSPPIRE_VAR_SHEET_TYPE            (psppire_var_sheet_get_type ())
-#define PSPPIRE_VAR_SHEET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheet))
-#define PSPPIRE_VAR_SHEET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheetClass))
-#define PSPPIRE_IS_VAR_SHEET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_VAR_SHEET_TYPE))
-#define PSPPIRE_IS_VAR_SHEET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_VAR_SHEET_TYPE))
-
-
-typedef struct _PsppireVarSheet       PsppireVarSheet;
-typedef struct _PsppireVarSheetClass  PsppireVarSheetClass;
-
-enum
-{
-    PSPPIRE_VAR_SHEET_BACKEND_CHANGED,
-    PSPPIRE_VAR_SHEET_VARIABLE_CHANGED,
-    PSPPIRE_VAR_SHEET_VARIABLE_INSERTED,
-    PSPPIRE_VAR_SHEET_VARIABLE_DELETED,
-    PSPPIRE_VAR_SHEET_N_SIGNALS
- };
-
-struct _PsppireVarSheet
-{
-  PsppSheetView parent;
-
-  gboolean may_create_vars;
-  gboolean may_delete_vars;
-  enum fmt_use format_use;
-
-  struct _PsppireDict *dict;
-
-  gulong scroll_to_bottom_signal;
-  gulong dict_signals[PSPPIRE_VAR_SHEET_N_SIGNALS];
-
-  GtkWidget *container;
-  gulong on_switch_page_handler;
-
-  gboolean dispose_has_run;
-};
-
-struct _PsppireVarSheetClass
-{
-  PsppSheetViewClass parent_class;
-};
-
-GType          psppire_var_sheet_get_type        (void);
-GtkWidget*     psppire_var_sheet_new             (void);
-
-struct _PsppireDict *psppire_var_sheet_get_dictionary (PsppireVarSheet *);
-void psppire_var_sheet_set_dictionary (PsppireVarSheet *,
-                                       struct _PsppireDict *);
-
-gboolean psppire_var_sheet_get_may_create_vars (PsppireVarSheet *);
-void psppire_var_sheet_set_may_create_vars (PsppireVarSheet *, gboolean);
-
-gboolean psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *);
-void psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *, gboolean);
-
-void psppire_var_sheet_goto_variable (PsppireVarSheet *, int dict_index);
-void psppire_var_sheet_insert_variable (PsppireVarSheet *var_sheet);
-void psppire_var_sheet_clear_variables (PsppireVarSheet *var_sheet);
-
-
-G_END_DECLS
-
-#endif /* __PSPPIRE_VAR_SHEET_H__ */
diff --git a/src/ui/gui/psppire-variable-sheet.c b/src/ui/gui/psppire-variable-sheet.c
new file mode 100644 (file)
index 0000000..2adef3f
--- /dev/null
@@ -0,0 +1,522 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2017  John Darrington
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+#include "psppire-variable-sheet.h"
+
+#include "ui/gui/psppire-var-sheet-header.h"
+
+#include "psppire-dict.h"
+#include "var-type-dialog.h"
+#include "missing-val-dialog.h"
+#include "val-labs-dialog.h"
+#include "var-display.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "helper.h"
+
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define P_(X) (X)
+
+
+G_DEFINE_TYPE (PsppireVariableSheet, psppire_variable_sheet, SSW_TYPE_SHEET)
+
+static void
+set_var_type (GtkCellRenderer *renderer,
+     GtkCellEditable *editable,
+     gchar           *path,
+     gpointer         user_data)
+{
+  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
+  gint row = -1, col = -1;
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
+
+  PsppireDict *dict = NULL;
+  g_object_get (sheet, "data-model", &dict, NULL);
+
+  struct variable *var =
+    psppire_dict_get_variable (PSPPIRE_DICT (dict), row);
+
+  const struct fmt_spec *format = var_get_write_format (var);
+  struct fmt_spec fmt = *format;
+  GtkWindow *win = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sheet)));
+  if (GTK_RESPONSE_OK == psppire_var_type_dialog_run (win, &fmt))
+    {
+      var_set_width_and_formats (var, fmt_var_width (&fmt), &fmt, &fmt);
+    }
+}
+
+static void
+set_missing_values (GtkCellRenderer *renderer,
+     GtkCellEditable *editable,
+     gchar           *path,
+     gpointer         user_data)
+{
+  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
+  gint row = -1, col = -1;
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
+
+  PsppireDict *dict = NULL;
+  g_object_get (sheet, "data-model", &dict, NULL);
+
+  struct variable *var =
+    psppire_dict_get_variable (PSPPIRE_DICT (dict), row);
+
+  struct missing_values mv;
+  if (GTK_RESPONSE_OK ==
+      psppire_missing_val_dialog_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sheet))),
+                                     var, &mv))
+    {
+      var_set_missing_values (var, &mv);
+    }
+
+  mv_destroy (&mv);
+}
+
+static void
+set_value_labels (GtkCellRenderer *renderer,
+     GtkCellEditable *editable,
+     gchar           *path,
+     gpointer         user_data)
+{
+  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
+  gint row = -1, col = -1;
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
+
+  PsppireDict *dict = NULL;
+  g_object_get (sheet, "data-model", &dict, NULL);
+
+  struct variable *var =
+    psppire_dict_get_variable (PSPPIRE_DICT (dict), row);
+
+  struct val_labs *vls =
+    psppire_val_labs_dialog_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sheet))), var);
+
+  if (vls)
+    {
+      var_set_value_labels (var, vls);
+      val_labs_destroy (vls);
+    }
+}
+
+static GtkCellRenderer *
+create_spin_renderer (GType type)
+{
+  GtkCellRenderer *r = gtk_cell_renderer_spin_new ();
+
+  GtkAdjustment *adj = gtk_adjustment_new (0,
+                                          0, G_MAXDOUBLE,
+                                          1, 1,
+                                          0);
+  g_object_set (r,
+               "adjustment", adj,
+               NULL);
+
+  return r;
+}
+
+static GtkCellRenderer *
+create_combo_renderer (GType type)
+{
+  GtkListStore *list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
+
+  GEnumClass *ec = g_type_class_ref (type);
+
+  const GEnumValue *ev ;
+  for (ev = ec->values; ev->value_name; ++ev)
+    {
+      GtkTreeIter iter;
+
+      gtk_list_store_append (list_store, &iter);
+
+      gtk_list_store_set (list_store, &iter,
+                         0, ev->value,
+                         1, gettext (ev->value_nick),
+                         -1);
+    }
+
+  GtkCellRenderer *r = gtk_cell_renderer_combo_new ();
+
+  g_object_set (r,
+               "model", list_store,
+               "text-column", 1,
+               "has-entry", TRUE,
+               NULL);
+
+  return r;
+}
+
+static GtkCellRenderer *spin_renderer;
+static GtkCellRenderer *column_width_renderer;
+static GtkCellRenderer *measure_renderer;
+static GtkCellRenderer *alignment_renderer;
+
+static GtkCellRenderer *
+select_renderer_func (PsppireVariableSheet *sheet, gint col, gint row, GType type, gpointer ud)
+{
+  if (!spin_renderer)
+    spin_renderer = create_spin_renderer (type);
+
+  if (col == DICT_TVM_COL_ROLE && !column_width_renderer)
+    column_width_renderer = create_combo_renderer (type);
+
+  if (col == DICT_TVM_COL_MEASURE && !measure_renderer)
+    measure_renderer = create_combo_renderer (type);
+
+  if (col == DICT_TVM_COL_ALIGNMENT && !alignment_renderer)
+    alignment_renderer = create_combo_renderer (type);
+
+  switch  (col)
+    {
+    case DICT_TVM_COL_WIDTH:
+    case DICT_TVM_COL_DECIMAL:
+    case DICT_TVM_COL_COLUMNS:
+      return spin_renderer;
+
+    case DICT_TVM_COL_TYPE:
+      return sheet->var_type_renderer;
+
+    case DICT_TVM_COL_VALUE_LABELS:
+      return sheet->value_label_renderer;
+
+    case DICT_TVM_COL_MISSING_VALUES:
+      return sheet->missing_values_renderer;
+
+    case DICT_TVM_COL_ALIGNMENT:
+      return alignment_renderer;
+
+    case DICT_TVM_COL_MEASURE:
+      return measure_renderer;
+
+    case DICT_TVM_COL_ROLE:
+      return column_width_renderer;
+    }
+
+  return NULL;
+}
+
+\f
+
+static void
+show_variables_row_popup (SswSheet *sheet, int row, uint button,
+                         uint state, gpointer p)
+{
+  PsppireVariableSheet *var_sheet = PSPPIRE_VARIABLE_SHEET (sheet);
+  GListModel *vmodel = NULL;
+  g_object_get (sheet, "vmodel", &vmodel, NULL);
+  if (vmodel == NULL)
+    return;
+
+  guint n_items = g_list_model_get_n_items (vmodel);
+
+  if (row >= n_items)
+    return;
+
+  if (button != 3)
+    return;
+
+  g_object_set_data (G_OBJECT (var_sheet->row_popup), "item",
+                    GINT_TO_POINTER (row));
+
+  gtk_menu_popup_at_pointer (GTK_MENU (var_sheet->row_popup), NULL);
+}
+
+static void
+insert_new_variable_var (PsppireVariableSheet *var_sheet)
+{
+  gint item = GPOINTER_TO_INT (g_object_get_data
+                               (G_OBJECT (var_sheet->row_popup),
+                                "item"));
+
+  PsppireDict *dict = NULL;
+  g_object_get (var_sheet, "data-model", &dict, NULL);
+
+  psppire_dict_insert_variable (dict, item, NULL);
+
+  gtk_widget_queue_draw (GTK_WIDGET (var_sheet));
+}
+
+
+static void
+delete_variables (SswSheet *sheet)
+{
+  SswRange *range = sheet->selection;
+
+  PsppireDict *dict = NULL;
+  g_object_get (sheet, "data-model", &dict, NULL);
+
+  psppire_dict_delete_variables (dict, range->start_y,
+                                (range->end_y - range->start_y + 1));
+
+  gtk_widget_queue_draw (GTK_WIDGET (sheet));
+}
+
+static GtkWidget *
+create_var_row_header_popup_menu (PsppireVariableSheet *var_sheet)
+{
+  GtkWidget *menu = gtk_menu_new ();
+
+  GtkWidget *item =
+    gtk_menu_item_new_with_mnemonic  (_("_Insert Variable"));
+  g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_variable_var),
+                           var_sheet);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+  item = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+  var_sheet->clear_variables_menu_item =
+    gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
+
+  g_signal_connect_swapped (var_sheet->clear_variables_menu_item, "activate",
+                           G_CALLBACK (delete_variables), var_sheet);
+
+  gtk_widget_set_sensitive (var_sheet->clear_variables_menu_item, FALSE);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+                        var_sheet->clear_variables_menu_item);
+
+  gtk_widget_show_all (menu);
+  return menu;
+}
+
+
+static void
+set_var_popup_sensitivity (SswSheet *sheet, gpointer selection, gpointer p)
+{
+  PsppireVariableSheet *var_sheet = PSPPIRE_VARIABLE_SHEET (sheet);
+  SswRange *range = selection;
+  gint width = gtk_tree_model_get_n_columns (sheet->data_model);
+
+  gboolean whole_row_selected = (range->start_x == 0 &&
+                                range->end_x == width - 1 - 1);
+  /*  PsppireDict has an "extra" column: TVM_COL_VAR   ^^^ */
+  gtk_widget_set_sensitive (var_sheet->clear_variables_menu_item,
+                           whole_row_selected);
+}
+
+\f
+
+static void
+change_var_property (PsppireVariableSheet *var_sheet, gint col, gint row, const GValue *value)
+{
+  PsppireDict *dict = NULL;
+  g_object_get (var_sheet, "data-model", &dict, NULL);
+
+  /* Return the IDXth variable */
+  struct variable *var =  psppire_dict_get_variable (dict, row);
+
+  if (NULL == var)
+    var = psppire_dict_insert_variable (dict, row, NULL);
+
+  switch (col)
+    {
+    case DICT_TVM_COL_NAME:
+      {
+       const char *name = g_value_get_string (value);
+       if (psppire_dict_check_name (dict, name, FALSE))
+         dict_rename_var (dict->dict, var, g_value_get_string (value));
+      }
+      break;
+    case DICT_TVM_COL_WIDTH:
+      {
+      gint width = g_value_get_int (value);
+      if (var_is_numeric (var))
+        {
+          struct fmt_spec format = *var_get_print_format (var);
+         fmt_change_width (&format, width, FMT_FOR_OUTPUT);
+          var_set_both_formats (var, &format);
+        }
+      else
+       {
+         var_set_width (var, width);
+       }
+      }
+      break;
+    case DICT_TVM_COL_DECIMAL:
+      {
+      gint decimals = g_value_get_int (value);
+      if (decimals >= 0)
+        {
+          struct fmt_spec format = *var_get_print_format (var);
+         fmt_change_decimals (&format, decimals, FMT_FOR_OUTPUT);
+          var_set_both_formats (var, &format);
+        }
+      }
+      break;
+    case DICT_TVM_COL_LABEL:
+      var_set_label (var, g_value_get_string (value));
+      break;
+    case DICT_TVM_COL_COLUMNS:
+      var_set_display_width (var, g_value_get_int (value));
+      break;
+    case DICT_TVM_COL_MEASURE:
+      var_set_measure (var, g_value_get_int (value));
+      break;
+    case DICT_TVM_COL_ALIGNMENT:
+      var_set_alignment (var, g_value_get_int (value));
+      break;
+    case DICT_TVM_COL_ROLE:
+      var_set_role (var, g_value_get_int (value));
+      break;
+    default:
+      g_warning ("Changing unknown column %d of variable sheet column not supported",
+                col);
+      break;
+    }
+}
+
+static gchar *
+var_sheet_data_to_string (SswSheet *sheet, GtkTreeModel *m,
+                         gint col, gint row, const GValue *in)
+{
+  if (col >= n_DICT_COLS - 1) /* -1 because psppire-dict has an extra column */
+    return NULL;
+
+  const struct variable *var = psppire_dict_get_variable (PSPPIRE_DICT (m), row);
+  if (var == NULL)
+    return NULL;
+
+  if (col == DICT_TVM_COL_TYPE)
+    {
+      const struct fmt_spec *print = var_get_print_format (var);
+      return strdup (fmt_gui_name (print->type));
+    }
+  else if (col == DICT_TVM_COL_MISSING_VALUES)
+    return missing_values_to_string (var, NULL);
+  else if (col == DICT_TVM_COL_VALUE_LABELS)
+    {
+      const struct val_labs *vls = var_get_value_labels (var);
+      if (vls == NULL || val_labs_count (vls) == 0)
+       return strdup (_("None"));
+      const struct val_lab **labels = val_labs_sorted (vls);
+      const struct val_lab *vl = labels[0];
+      gchar *vstr = value_to_text (vl->value, var);
+      char *text = xasprintf (_("{%s, %s}..."), vstr,
+                             val_lab_get_escaped_label (vl));
+      free (vstr);
+      free (labels);
+      return text;
+    }
+
+  return ssw_sheet_default_forward_conversion (sheet, m, col, row, in);
+}
+
+\f
+
+static GObjectClass * parent_class = NULL;
+
+static void
+psppire_variable_sheet_dispose (GObject *obj)
+{
+  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (obj);
+
+  if (sheet->dispose_has_run)
+    return;
+
+  sheet->dispose_has_run = TRUE;
+
+  g_object_unref (sheet->value_label_renderer);
+  g_object_unref (sheet->missing_values_renderer);
+  g_object_unref (sheet->var_type_renderer);
+
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+psppire_variable_sheet_class_init (PsppireVariableSheetClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  object_class->dispose = psppire_variable_sheet_dispose;
+
+  parent_class = g_type_class_peek_parent (class);
+}
+
+GtkWidget*
+psppire_variable_sheet_new (void)
+{
+  PsppireVarSheetHeader *vsh =
+    g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL);
+
+  GObject *obj =
+    g_object_new (PSPPIRE_TYPE_VARIABLE_SHEET,
+                 "select-renderer-func", select_renderer_func,
+                 "hmodel", vsh,
+                 "forward-conversion", var_sheet_data_to_string,
+                 NULL);
+
+  return GTK_WIDGET (obj);
+}
+
+static void
+move_variable (PsppireVariableSheet *sheet, gint from, gint to, gpointer ud)
+{
+  PsppireDict *dict = NULL;
+  g_object_get (sheet, "data-model", &dict, NULL);
+
+  if (dict == NULL)
+    return;
+
+  struct variable *var = psppire_dict_get_variable (dict, from);
+
+  if (var == NULL)
+    return;
+  gint new_pos = to;
+  /* The index refers to the final position, so if the source
+     is less than the destination, then we must subtract 1, to
+     account for the position vacated by the source */
+  if (from < to)
+    new_pos--;
+  dict_reorder_var (dict->dict, var, new_pos);
+}
+
+static void
+psppire_variable_sheet_init (PsppireVariableSheet *sheet)
+{
+  sheet->dispose_has_run = FALSE;
+
+  sheet->value_label_renderer = gtk_cell_renderer_text_new ();
+  g_signal_connect (sheet->value_label_renderer,
+                   "editing-started", G_CALLBACK (set_value_labels),
+                   sheet);
+
+  sheet->missing_values_renderer = gtk_cell_renderer_text_new ();
+  g_signal_connect (sheet->missing_values_renderer,
+                   "editing-started", G_CALLBACK (set_missing_values),
+                   sheet);
+
+  sheet->var_type_renderer = gtk_cell_renderer_text_new ();
+  g_signal_connect (sheet->var_type_renderer,
+                   "editing-started", G_CALLBACK (set_var_type),
+                   sheet);
+
+  sheet->row_popup = create_var_row_header_popup_menu (sheet);
+
+
+  g_signal_connect (sheet, "selection-changed",
+                   G_CALLBACK (set_var_popup_sensitivity), sheet);
+
+  g_signal_connect (sheet, "row-header-pressed",
+                    G_CALLBACK (show_variables_row_popup), sheet);
+
+  g_signal_connect_swapped (sheet, "value-changed",
+                           G_CALLBACK (change_var_property), sheet);
+
+  g_signal_connect (sheet, "row-moved",
+                   G_CALLBACK (move_variable), NULL);
+}
diff --git a/src/ui/gui/psppire-variable-sheet.h b/src/ui/gui/psppire-variable-sheet.h
new file mode 100644 (file)
index 0000000..b77da93
--- /dev/null
@@ -0,0 +1,51 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+    Copyright (C) 2017  John Darrington
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PSPPIRE_VARIABLE_SHEET_H
+#define _PSPPIRE_VARIABLE_SHEET_H
+
+#include <gtk/gtk.h>
+#include <ssw-sheet.h>
+
+
+struct _PsppireVariableSheet
+{
+  SswSheet parent_instance;
+
+  GtkCellRenderer *value_label_renderer;
+  GtkCellRenderer *missing_values_renderer;
+  GtkCellRenderer *var_type_renderer;
+
+  /* Row header popup menu */
+  GtkWidget *row_popup;
+  GtkWidget *clear_variables_menu_item;
+
+  gboolean dispose_has_run;
+};
+
+struct _PsppireVariableSheetClass
+{
+  SswSheetClass parent_class;
+};
+
+#define PSPPIRE_TYPE_VARIABLE_SHEET psppire_variable_sheet_get_type ()
+
+G_DECLARE_FINAL_TYPE (PsppireVariableSheet, psppire_variable_sheet, PSPPIRE, VARIABLE_SHEET, SswSheet)
+
+GtkWidget *psppire_variable_sheet_new (void);
+
+#endif
diff --git a/src/ui/gui/psppire.gtkrc b/src/ui/gui/psppire.gtkrc
deleted file mode 100644 (file)
index d6c0478..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Avoid making buttons inside the PSPPIRE data sheet and variable sheet
-# extra-tall.  This allows more rows to fit on the screen, making data
-# easier to review.
-#
-style "thinbuttons" { ythickness = 0 }
-widget_class "*<PsppSheetView>*GtkButton" style : rc "thinbuttons"
index 0b40468ef1e2300df2aa00654fb84caed84e7e90..86e6f39906e27603569e501cb0f33edca4e6ccda 100644 (file)
@@ -93,6 +93,7 @@
         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
         <property name="orientation">vertical</property>
         <property name="position">94</property>
+       <property name="wide-handle">True</property>
         <child>
           <object class="GtkFrame" id="frame4">
             <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <property name="margin_start">12</property>
+               <property name="margin-bottom">12</property>
                 <child>
                   <placeholder/>
                 </child>
             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
             <property name="label_xalign">0</property>
             <property name="shadow_type">none</property>
+            <property name="margin_top">12</property>
             <child>
               <object class="GtkScrolledWindow" id="data-scroller">
                 <property name="visible">True</property>
diff --git a/src/ui/gui/value-variant.c b/src/ui/gui/value-variant.c
new file mode 100644 (file)
index 0000000..0789717
--- /dev/null
@@ -0,0 +1,99 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2016  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include "value-variant.h"
+#include "data/value.h"
+
+
+enum
+  {
+    IDX_WIDTH,
+    IDX_DATA
+  };
+
+/* Returns a GVariant containing the data contained
+   in IN and WIDTH.  The returned GVariant has a floating
+   reference.
+ */
+GVariant *
+value_variant_new (const union value *in, int width)
+{
+  GVariant *vv[2] = {NULL, NULL};
+  vv[IDX_WIDTH] = g_variant_new_int32 (width);
+
+  if (width == 0)
+    vv[IDX_DATA] = g_variant_new_double (in->f);
+  else if (width <= MAX_SHORT_STRING)
+    {
+      char xx[MAX_SHORT_STRING + 1];
+      memset (xx, '\0', MAX_SHORT_STRING + 1);
+      memcpy (xx, in->short_string, width);
+      vv[IDX_DATA] = g_variant_new_bytestring (xx);
+    }
+  else
+    {
+      gchar *q = xmalloc (width + 1);
+      memcpy (q, in->long_string, width);
+      q[width] = '\0';
+      vv[IDX_DATA] = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING, q,
+                                             width + 1, FALSE, NULL, NULL);
+    }
+
+  return g_variant_new_tuple (vv, 2);
+}
+
+/* Destroy the contents of VAL.  Also unref V */
+void
+value_destroy_from_variant (union value *val, GVariant *v)
+{
+  GVariant *vwidth = g_variant_get_child_value (v, IDX_WIDTH);
+  gint32 width = g_variant_get_int32 (vwidth); /* v is unreffed here */
+  g_variant_unref (vwidth);
+  value_destroy (val, width);
+}
+
+
+/* Fills VAL with the value data held in V.
+   When VAL is no longer required it must be destroyed using
+   value_destroy_from_variant. */
+void
+value_variant_get (union value *val, GVariant *v)
+{
+  GVariant *vwidth = g_variant_get_child_value (v, IDX_WIDTH);
+  gint32 width = g_variant_get_int32 (vwidth);
+  g_variant_unref (vwidth);
+
+  GVariant *vdata = g_variant_get_child_value (v, IDX_DATA);
+
+  if (0 == width)
+    val->f = g_variant_get_double (vdata);
+  else
+    {
+      const gchar *data = g_variant_get_bytestring (vdata);
+      if (width <= MAX_SHORT_STRING)
+       memcpy (val->short_string, data, MAX_SHORT_STRING);
+      else
+       {
+         val->long_string = xmemdup (data, width);
+       }
+    }
+
+  g_variant_unref (vdata);
+}
diff --git a/src/ui/gui/value-variant.h b/src/ui/gui/value-variant.h
new file mode 100644 (file)
index 0000000..22cd176
--- /dev/null
@@ -0,0 +1,28 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef VALUE_VARIANT_H
+#define VALUE_VARIANT_H
+
+union value;
+
+GVariant *value_variant_new (const union value *in, int width);
+
+void value_variant_get (union value *val, GVariant *v);
+
+void value_destroy_from_variant (union value *val, GVariant *v);
+
+#endif
index 7f1d4aeccdc6e187332045965438a54f537f2170..a2792ef08993b5ea7d55830f85b899035b079957 100644 (file)
@@ -201,7 +201,7 @@ psppire_var_type_dialog_new (const struct fmt_spec *format)
                   NULL));
 }
 
-void
+gint
 psppire_var_type_dialog_run (GtkWindow *parent_window,
                              struct fmt_spec *format)
 {
@@ -212,10 +212,13 @@ psppire_var_type_dialog_run (GtkWindow *parent_window,
   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
   gtk_widget_show (GTK_WIDGET (dialog));
 
-  if (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK)
+  gint result = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
+  if (result == GTK_RESPONSE_OK)
     *format = *psppire_var_type_dialog_get_format (dialog);
 
   gtk_widget_destroy (GTK_WIDGET (dialog));
+
+  return result;
 }
 
 
index 32c160f05238f533f99a2bfe78ef1bb85d9e3032..ee9b7b2ac567fb005588ad4ec8f7ea3576ef1fa5 100644 (file)
@@ -102,7 +102,7 @@ struct _PsppireVarTypeDialogClass {
 GType psppire_var_type_dialog_get_type (void) G_GNUC_CONST;
 PsppireVarTypeDialog* psppire_var_type_dialog_new (const struct fmt_spec *);
 
-void psppire_var_type_dialog_run (GtkWindow *parent_window,
+gint psppire_var_type_dialog_run (GtkWindow *parent_window,
                                   struct fmt_spec *format);
 
 G_END_DECLS
index ec9be3351611353a66e7280150c960a5d8abdfdd..26a5dac4fd33f79c30545d1d3dae304727c71bdd 100644 (file)
@@ -22,6 +22,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "widgets.h"
 
+#include "gettext.h"
 
 #include "psppire-dialog.h"
 #include "psppire-selector.h"
@@ -140,6 +141,62 @@ preregister_actions (void)
 }
 
 
+static void
+tx_string_to_double (const GValue *src, GValue *dest)
+{
+  const gchar *str = g_value_get_string (src);
+  gdouble dble = g_strtod (str, NULL);
+  g_value_set_double (dest, dble);
+}
+
+
+static void
+tx_string_to_int (const GValue *src, GValue *dest)
+{
+  const gchar *str = g_value_get_string (src);
+  gint x = atoi (str);
+  g_value_set_int (dest, x);
+}
+
+static void
+enum_to_string (const GValue *src, GValue *dest)
+{
+  gint n = g_value_get_enum (src);
+  GType t = G_VALUE_TYPE (src);
+  GEnumClass *ec = g_type_class_ref (t);
+  GEnumValue *ev = g_enum_get_value (ec, n);
+
+  g_value_set_string (dest, gettext (ev->value_nick));
+}
+
+
+
+GType align_enum_type;
+GType measure_enum_type;
+GType role_enum_type;
+
+
+extern const GEnumValue align[];
+extern const GEnumValue measure[];
+extern const GEnumValue role[];
+
+
+
+static void
+preregister_misc (void)
+{
+  align_enum_type = g_enum_register_static ("PsppAlignment", align);
+  measure_enum_type = g_enum_register_static ("PsppMeasure", measure);
+  role_enum_type = g_enum_register_static ("PsppRole", role);
+
+  g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DOUBLE, tx_string_to_double);
+  g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, tx_string_to_int);
+
+  g_value_register_transform_func (measure_enum_type, G_TYPE_STRING, enum_to_string);
+  g_value_register_transform_func (align_enum_type, G_TYPE_STRING, enum_to_string);
+  g_value_register_transform_func (role_enum_type, G_TYPE_STRING, enum_to_string);
+}
+
 
 /* Any custom widgets which are to be used in GtkBuilder ui files
    need to be preregistered, otherwise GtkBuilder refuses to
@@ -160,6 +217,7 @@ preregister_widgets (void)
   psppire_means_layer_get_type ();
 
   preregister_actions ();
+  preregister_misc ();
 
   /* This seems to be necessary on Cygwin.
      It ought not to be necessary.  Having it here can't do any harm. */