thunar 4.20.2 upstream
Tree of tag thunar-4.20.2 (commit 11a519f) from https://gitlab.xfce.org/xfce/thunar. Upstream history is not included here to keep the repository small.
This commit is contained in:
commit
e969f94310
430 changed files with 482388 additions and 0 deletions
29
plugins/Makefile.am
Normal file
29
plugins/Makefile.am
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
if THUNAR_PLUGIN_APR
|
||||
THUNAR_APR_SUBDIRS = thunar-apr
|
||||
endif
|
||||
|
||||
if THUNAR_PLUGIN_SBR
|
||||
THUNAR_SBR_SUBDIRS = thunar-sbr
|
||||
endif
|
||||
|
||||
if THUNAR_PLUGIN_TPA
|
||||
THUNAR_TPA_SUBDIRS = thunar-tpa
|
||||
endif
|
||||
|
||||
if THUNAR_PLUGIN_UCA
|
||||
THUNAR_UCA_SUBDIRS = thunar-uca
|
||||
endif
|
||||
|
||||
if THUNAR_PLUGIN_WALLPAPER
|
||||
THUNAR_WALLPAPER_SUBDIRS = thunar-wallpaper
|
||||
endif
|
||||
|
||||
SUBDIRS = \
|
||||
$(THUNAR_APR_SUBDIRS) \
|
||||
$(THUNAR_SBR_SUBDIRS) \
|
||||
$(THUNAR_TPA_SUBDIRS) \
|
||||
$(THUNAR_UCA_SUBDIRS) \
|
||||
$(THUNAR_WALLPAPER_SUBDIRS) \
|
||||
thunar-sendto-email
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
60
plugins/thunar-apr/Makefile.am
Normal file
60
plugins/thunar-apr/Makefile.am
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/plugins \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/plugins \
|
||||
-DG_LOG_DOMAIN=\"thunar-apr\" \
|
||||
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
extensionsdir = $(libdir)/thunarx-$(THUNARX_VERSION_API)
|
||||
extensions_LTLIBRARIES = \
|
||||
thunar-apr.la
|
||||
|
||||
thunar_apr_la_SOURCES = \
|
||||
thunar-apr-abstract-page.c \
|
||||
thunar-apr-abstract-page.h \
|
||||
thunar-apr-desktop-page.c \
|
||||
thunar-apr-desktop-page.h \
|
||||
thunar-apr-image-page.c \
|
||||
thunar-apr-image-page.h \
|
||||
thunar-apr-plugin.c \
|
||||
thunar-apr-private.c \
|
||||
thunar-apr-private.h \
|
||||
thunar-apr-provider.c \
|
||||
thunar-apr-provider.h
|
||||
|
||||
thunar_apr_la_CFLAGS = \
|
||||
$(EXIF_CFLAGS) \
|
||||
$(EXO_CFLAGS) \
|
||||
$(LIBXFCE4UTIL_CFLAGS) \
|
||||
$(LIBXFCE4UI_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(GTK_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
thunar_apr_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
-no-undefined \
|
||||
-export-symbols-regex "^thunar_extension_(shutdown|initialize|list_types)" \
|
||||
-module \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
thunar_apr_la_LIBADD = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la \
|
||||
$(EXIF_LIBS) \
|
||||
$(EXO_LIBS) \
|
||||
$(LIBXFCE4UTIL_LIBS) \
|
||||
$(LIBXFCE4UI_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(GTK_LIBS)
|
||||
|
||||
thunar_apr_la_DEPENDENCIES = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
README.md
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
13
plugins/thunar-apr/README.md
Normal file
13
plugins/thunar-apr/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Thunar Advanced Properties (thunar-apr)
|
||||
=======================================
|
||||
|
||||
Thunar-apr is an extension to Thunar, which provides additional pages forthe file properties dialog, that are displayed for certain kinds of files:
|
||||
|
||||
* Launcher/Link
|
||||
* Image
|
||||
|
||||
The Launcher/Link page is displayed for .desktop files and allows users to easily edit the most important values (i.e. the command for a launcher and the URL for a link).
|
||||
|
||||
The Image page is displayed for all kinds of image files supported by the GTK+ version used by Thunar. The page displays atleast the exact format of the image and the dimensions in pixels. If the plugin is build with support for libexif (you can explicitly disable this using the `--disable-exif` configure option) and the image file includes Exif tags, the most important Exif tags found in the image file will also be displayed.
|
||||
|
||||
By default the thunar-apr extension will be installed, but as with every extension, it will slightly increase the resource usage of Thunar (this shouldn't be a real problem unless you're targeting an embedded system), and so you can pass `--disable-apr-plugin` to configure and the plugin won't be built and installed. Since it is an extension, you can also easily uninstall it afterwards by removing the thunar-apr.so file from the lib/thunarx-2/ directory of your installation (be sure to quit Thunar before removing files though).
|
||||
254
plugins/thunar-apr/thunar-apr-abstract-page.c
Normal file
254
plugins/thunar-apr/thunar-apr-abstract-page.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-apr/thunar-apr-abstract-page.h>
|
||||
#include <thunar-apr/thunar-apr-private.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FILE,
|
||||
};
|
||||
|
||||
/* Signal identifiers */
|
||||
enum
|
||||
{
|
||||
FILE_CHANGED,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_dispose (GObject *object);
|
||||
static void
|
||||
thunar_apr_abstract_page_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_apr_abstract_page_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_apr_abstract_page_file_changed (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file);
|
||||
|
||||
|
||||
|
||||
static guint abstract_page_signals[LAST_SIGNAL];
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_ABSTRACT_TYPE (ThunarAprAbstractPage,
|
||||
thunar_apr_abstract_page,
|
||||
THUNARX_TYPE_PROPERTY_PAGE);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_class_init (ThunarAprAbstractPageClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->dispose = thunar_apr_abstract_page_dispose;
|
||||
gobject_class->get_property = thunar_apr_abstract_page_get_property;
|
||||
gobject_class->set_property = thunar_apr_abstract_page_set_property;
|
||||
|
||||
/**
|
||||
* ThunarAprAbstractPage:file:
|
||||
*
|
||||
* The #ThunarxFileInfo for the file being displayed by
|
||||
* this property page.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_FILE,
|
||||
g_param_spec_object ("file", "file", "file",
|
||||
THUNARX_TYPE_FILE_INFO,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarAprAbstractPage::file-changed:
|
||||
* @abstract_page : a #ThunarAprAbstractPage.
|
||||
* @file : a #ThunarxFileInfo.
|
||||
*
|
||||
* Emitted by @abstract_page whenever the associated
|
||||
* @file changes.
|
||||
**/
|
||||
abstract_page_signals[FILE_CHANGED] =
|
||||
g_signal_new ("file-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ThunarAprAbstractPageClass, file_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
THUNARX_TYPE_FILE_INFO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_init (ThunarAprAbstractPage *abstract_page)
|
||||
{
|
||||
/* be sure to setup the i18n support for the thunar-apr plugin */
|
||||
thunar_apr_i18n_init ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_dispose (GObject *object)
|
||||
{
|
||||
ThunarAprAbstractPage *abstract_page = THUNAR_APR_ABSTRACT_PAGE (object);
|
||||
|
||||
/* disconnect from the file */
|
||||
thunar_apr_abstract_page_set_file (abstract_page, NULL);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_apr_abstract_page_parent_class)->dispose) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarAprAbstractPage *abstract_page = THUNAR_APR_ABSTRACT_PAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILE:
|
||||
g_value_set_object (value, thunar_apr_abstract_page_get_file (abstract_page));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarAprAbstractPage *abstract_page = THUNAR_APR_ABSTRACT_PAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILE:
|
||||
thunar_apr_abstract_page_set_file (abstract_page, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_abstract_page_file_changed (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file)
|
||||
{
|
||||
/* emit the "file-changed" signal */
|
||||
g_signal_emit (G_OBJECT (abstract_page), abstract_page_signals[FILE_CHANGED], 0, file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_apr_abstract_page_get_file:
|
||||
* @abstract_page : a #ThunarAprAbstractPage.
|
||||
*
|
||||
* Returns the #ThunarxFileInfo for the file being
|
||||
* displayed by the @abstract_page.
|
||||
*
|
||||
* Return value: the file for @abstract_page.
|
||||
**/
|
||||
ThunarxFileInfo *
|
||||
thunar_apr_abstract_page_get_file (ThunarAprAbstractPage *abstract_page)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_APR_IS_ABSTRACT_PAGE (abstract_page), NULL);
|
||||
return abstract_page->file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_apr_abstract_page_set_file:
|
||||
* @abstract_page : a #ThunarAprAbstractPage.
|
||||
* @file : a #ThunarxFileInfo or %NULL.
|
||||
*
|
||||
* Sets the #ThunarxFileInfo being displayed by the
|
||||
* @abstract_page to @file. If @file is %NULL, the
|
||||
* property will be reset.
|
||||
**/
|
||||
void
|
||||
thunar_apr_abstract_page_set_file (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file)
|
||||
{
|
||||
g_return_if_fail (THUNAR_APR_IS_ABSTRACT_PAGE (abstract_page));
|
||||
g_return_if_fail (file == NULL || THUNARX_IS_FILE_INFO (file));
|
||||
|
||||
/* verify that we don't already display that file */
|
||||
if (G_UNLIKELY (abstract_page->file == file))
|
||||
return;
|
||||
|
||||
/* disconnect from the previous file */
|
||||
if (G_UNLIKELY (abstract_page->file != NULL))
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (abstract_page->file), thunar_apr_abstract_page_file_changed, abstract_page);
|
||||
g_object_unref (G_OBJECT (abstract_page->file));
|
||||
}
|
||||
|
||||
/* activate the new file */
|
||||
abstract_page->file = file;
|
||||
|
||||
/* connect to the new file */
|
||||
if (G_LIKELY (file != NULL))
|
||||
{
|
||||
/* connect "changed" signal and take a reference */
|
||||
g_signal_connect_swapped (G_OBJECT (file), "changed", G_CALLBACK (thunar_apr_abstract_page_file_changed), abstract_page);
|
||||
g_object_ref (G_OBJECT (file));
|
||||
|
||||
/* update the initial state */
|
||||
thunar_apr_abstract_page_file_changed (abstract_page, file);
|
||||
}
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (abstract_page), "file");
|
||||
}
|
||||
66
plugins/thunar-apr/thunar-apr-abstract-page.h
Normal file
66
plugins/thunar-apr/thunar-apr-abstract-page.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_APR_ABSTRACT_PAGE_H__
|
||||
#define __THUNAR_APR_ABSTRACT_PAGE_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarAprAbstractPageClass ThunarAprAbstractPageClass;
|
||||
typedef struct _ThunarAprAbstractPage ThunarAprAbstractPage;
|
||||
|
||||
#define THUNAR_APR_TYPE_ABSTRACT_PAGE (thunar_apr_abstract_page_get_type ())
|
||||
#define THUNAR_APR_ABSTRACT_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_APR_TYPE_ABSTRACT_PAGE, ThunarAprAbstractPage))
|
||||
#define THUNAR_APR_ABSTRACT_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_APR_TYPE_ABSTRACT_PAGE, ThunarAprAbstractPageClass))
|
||||
#define THUNAR_APR_IS_ABSTRACT_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_APR_TYPE_ABSTRACT_PAGE))
|
||||
#define THUNAR_APR_IS_ABSTRACT_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_APR_TYPE_ABSTRACT_PAGE))
|
||||
#define THUNAR_APR_ABSTRACT_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_APR_TYPE_ABSTRACT_PAGE, ThunarAprAbstractPageClass))
|
||||
|
||||
struct _ThunarAprAbstractPageClass
|
||||
{
|
||||
ThunarxPropertyPageClass __parent__;
|
||||
|
||||
/* signals */
|
||||
void (*file_changed) (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file);
|
||||
};
|
||||
|
||||
struct _ThunarAprAbstractPage
|
||||
{
|
||||
ThunarxPropertyPage __parent__;
|
||||
ThunarxFileInfo *file;
|
||||
};
|
||||
|
||||
GType
|
||||
thunar_apr_abstract_page_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_apr_abstract_page_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarxFileInfo *
|
||||
thunar_apr_abstract_page_get_file (ThunarAprAbstractPage *abstract_page);
|
||||
void
|
||||
thunar_apr_abstract_page_set_file (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APR_ABSTRACT_PAGE_H__ */
|
||||
1123
plugins/thunar-apr/thunar-apr-desktop-page.c
Normal file
1123
plugins/thunar-apr/thunar-apr-desktop-page.c
Normal file
File diff suppressed because it is too large
Load diff
45
plugins/thunar-apr/thunar-apr-desktop-page.h
Normal file
45
plugins/thunar-apr/thunar-apr-desktop-page.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_APR_DESKTOP_PAGE_H__
|
||||
#define __THUNAR_APR_DESKTOP_PAGE_H__
|
||||
|
||||
#include <thunar-apr/thunar-apr-abstract-page.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarAprDesktopPageClass ThunarAprDesktopPageClass;
|
||||
typedef struct _ThunarAprDesktopPage ThunarAprDesktopPage;
|
||||
|
||||
#define THUNAR_APR_TYPE_DESKTOP_PAGE (thunar_apr_desktop_page_get_type ())
|
||||
#define THUNAR_APR_DESKTOP_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_APR_TYPE_DESKTOP_PAGE, ThunarAprDesktopPage))
|
||||
#define THUNAR_APR_DESKTOP_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_APR_TYPE_DESKTOP_PAGE, ThunarAprDesktopPageClass))
|
||||
#define THUNAR_APR_IS_DESKTOP_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_APR_TYPE_DESKTOP_PAGE))
|
||||
#define THUNAR_APR_IS_DESKTOP_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_APR_TYPE_DESKTOP_PAGE))
|
||||
#define THUNAR_APR_DESKTOP_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_APR_TYPE_DESKTOP_PAGE, ThunarAprDesktopPageClass))
|
||||
|
||||
GType
|
||||
thunar_apr_desktop_page_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_apr_desktop_page_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APR_DESKTOP_PAGE_H__ */
|
||||
319
plugins/thunar-apr/thunar-apr-image-page.c
Normal file
319
plugins/thunar-apr/thunar-apr-image-page.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <thunar-apr/thunar-apr-image-page.h>
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
#include <libexif/exif-data.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_image_page_file_changed (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file);
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
static const struct
|
||||
{
|
||||
const gchar *name;
|
||||
ExifTag tag;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
TAIP_EXIF[] =
|
||||
{
|
||||
{ N_ ("Date Taken:"), EXIF_TAG_DATE_TIME_ORIGINAL, },
|
||||
{ N_ ("Camera Brand:"), EXIF_TAG_MAKE, },
|
||||
{ N_ ("Camera Model:"), EXIF_TAG_MODEL, },
|
||||
{ N_ ("Exposure Time:"), EXIF_TAG_EXPOSURE_TIME, },
|
||||
{ N_ ("Exposure Program:"), EXIF_TAG_EXPOSURE_PROGRAM, },
|
||||
{ N_ ("Aperture Value:"), EXIF_TAG_APERTURE_VALUE, },
|
||||
{ N_ ("Metering Mode:"), EXIF_TAG_METERING_MODE, },
|
||||
{ N_ ("Flash Fired:"), EXIF_TAG_FLASH, },
|
||||
{ N_ ("Focal Length:"), EXIF_TAG_FOCAL_LENGTH, },
|
||||
{ N_ ("Shutter Speed:"), EXIF_TAG_SHUTTER_SPEED_VALUE, },
|
||||
{ N_ ("ISO Speed Ratings:"), EXIF_TAG_ISO_SPEED_RATINGS, },
|
||||
{ N_ ("Software:"), EXIF_TAG_SOFTWARE, },
|
||||
{ N_ ("Description:"), EXIF_TAG_IMAGE_DESCRIPTION, },
|
||||
{ N_ ("Comment:"), EXIF_TAG_USER_COMMENT, },
|
||||
};
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct _ThunarAprImagePageClass
|
||||
{
|
||||
ThunarAprAbstractPageClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarAprImagePage
|
||||
{
|
||||
ThunarAprAbstractPage __parent__;
|
||||
GtkWidget *type_label;
|
||||
GtkWidget *dimensions_label;
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
GtkWidget *exif_labels[G_N_ELEMENTS (TAIP_EXIF)];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarAprImagePage,
|
||||
thunar_apr_image_page,
|
||||
THUNAR_APR_TYPE_ABSTRACT_PAGE);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_image_page_class_init (ThunarAprImagePageClass *klass)
|
||||
{
|
||||
ThunarAprAbstractPageClass *thunarapr_abstract_page_class;
|
||||
|
||||
thunarapr_abstract_page_class = THUNAR_APR_ABSTRACT_PAGE_CLASS (klass);
|
||||
thunarapr_abstract_page_class->file_changed = thunar_apr_image_page_file_changed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_image_page_init (ThunarAprImagePage *image_page)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
PangoAttribute *attribute;
|
||||
PangoAttrList *attr_list;
|
||||
AtkRelation *relation;
|
||||
AtkObject *object;
|
||||
GtkWidget *label;
|
||||
GtkWidget *grid;
|
||||
#ifdef HAVE_EXIF
|
||||
GtkWidget *spacer;
|
||||
guint n;
|
||||
#endif
|
||||
|
||||
gtk_container_set_border_width (GTK_CONTAINER (image_page), 12);
|
||||
thunarx_property_page_set_label (THUNARX_PROPERTY_PAGE (image_page), _("Image"));
|
||||
|
||||
/* allocate shared bold Pango attributes */
|
||||
attr_list = pango_attr_list_new ();
|
||||
attribute = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
|
||||
attribute->start_index = 0;
|
||||
attribute->end_index = -1;
|
||||
pango_attr_list_insert (attr_list, attribute);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_container_add (GTK_CONTAINER (image_page), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
label = gtk_label_new (_("Image Type:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attr_list);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
image_page->type_label = gtk_label_new ("");
|
||||
gtk_label_set_selectable (GTK_LABEL (image_page->type_label), TRUE);
|
||||
gtk_label_set_xalign (GTK_LABEL (image_page->type_label), 0.0f);
|
||||
gtk_label_set_ellipsize (GTK_LABEL (image_page->type_label), PANGO_ELLIPSIZE_END);
|
||||
gtk_widget_set_hexpand (image_page->type_label, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), image_page->type_label, 1, 0, 1, 1);
|
||||
gtk_widget_show (image_page->type_label);
|
||||
|
||||
/* set Atk label relation for the label */
|
||||
object = gtk_widget_get_accessible (image_page->type_label);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
label = gtk_label_new (_("Image Size:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attr_list);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
image_page->dimensions_label = gtk_label_new ("");
|
||||
gtk_label_set_selectable (GTK_LABEL (image_page->dimensions_label), TRUE);
|
||||
gtk_label_set_xalign (GTK_LABEL (image_page->dimensions_label), 0.0f);
|
||||
gtk_label_set_ellipsize (GTK_LABEL (image_page->dimensions_label), PANGO_ELLIPSIZE_END);
|
||||
gtk_widget_set_hexpand (image_page->dimensions_label, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), image_page->dimensions_label, 1, 1, 1, 1);
|
||||
gtk_widget_show (image_page->dimensions_label);
|
||||
|
||||
/* set Atk label relation for the label */
|
||||
object = gtk_widget_get_accessible (image_page->dimensions_label);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
/* some spacing between the General info and the Exif info */
|
||||
spacer = g_object_new (GTK_TYPE_BOX, "orientation", GTK_ORIENTATION_VERTICAL, "height-request", 6, NULL);
|
||||
gtk_grid_attach (GTK_GRID (grid), spacer, 0, 2, 2, 1);
|
||||
gtk_widget_show (spacer);
|
||||
|
||||
/* add labels for the Exif info */
|
||||
for (n = 0; n < G_N_ELEMENTS (TAIP_EXIF); ++n)
|
||||
{
|
||||
label = gtk_label_new (_(TAIP_EXIF[n].name));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attr_list);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, n + 3, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
image_page->exif_labels[n] = gtk_label_new ("");
|
||||
gtk_label_set_selectable (GTK_LABEL (image_page->exif_labels[n]), TRUE);
|
||||
gtk_label_set_xalign (GTK_LABEL (image_page->exif_labels[n]), 0.0f);
|
||||
gtk_label_set_ellipsize (GTK_LABEL (image_page->exif_labels[n]), PANGO_ELLIPSIZE_END);
|
||||
gtk_widget_set_hexpand (image_page->exif_labels[n], TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), image_page->exif_labels[n], 1, n + 3, 1, 1);
|
||||
gtk_widget_show (image_page->exif_labels[n]);
|
||||
|
||||
g_object_bind_property (G_OBJECT (image_page->exif_labels[n]), "visible", G_OBJECT (label), "visible", G_BINDING_SYNC_CREATE);
|
||||
|
||||
/* set Atk label relation for the label */
|
||||
object = gtk_widget_get_accessible (image_page->exif_labels[n]);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* release shared bold Pango attributes */
|
||||
pango_attr_list_unref (attr_list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_image_page_file_changed (ThunarAprAbstractPage *abstract_page,
|
||||
ThunarxFileInfo *file)
|
||||
{
|
||||
ThunarAprImagePage *image_page = THUNAR_APR_IMAGE_PAGE (abstract_page);
|
||||
GdkPixbufFormat *format;
|
||||
gchar *filename;
|
||||
gchar *text;
|
||||
gchar *uri;
|
||||
gint height;
|
||||
gint width;
|
||||
#ifdef HAVE_EXIF
|
||||
ExifEntry *exif_entry;
|
||||
ExifData *exif_data;
|
||||
gchar exif_buffer[1024];
|
||||
guint n;
|
||||
#endif
|
||||
|
||||
/* determine the URI for the file */
|
||||
uri = thunarx_file_info_get_uri (file);
|
||||
if (G_UNLIKELY (uri == NULL))
|
||||
return;
|
||||
|
||||
/* determine the local path of the file */
|
||||
filename = g_filename_from_uri (uri, NULL, NULL);
|
||||
if (G_LIKELY (filename != NULL))
|
||||
{
|
||||
/* determine the pixbuf format */
|
||||
format = gdk_pixbuf_get_file_info (filename, &width, &height);
|
||||
if (G_LIKELY (format != NULL))
|
||||
{
|
||||
/* update the "Image Type" label */
|
||||
gchar *name = gdk_pixbuf_format_get_name (format);
|
||||
gchar *desc = gdk_pixbuf_format_get_description (format);
|
||||
text = g_strdup_printf ("%s (%s)", name, desc);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (image_page->type_label), text);
|
||||
g_free (name);
|
||||
g_free (desc);
|
||||
g_free (text);
|
||||
|
||||
/* update the "Image Size" label */
|
||||
text = g_strdup_printf (ngettext ("%dx%d pixel", "%dx%d pixels", width + height), width, height);
|
||||
gtk_label_set_text (GTK_LABEL (image_page->dimensions_label), text);
|
||||
g_free (text);
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
/* hide all Exif labels (will be shown again if data is available) */
|
||||
for (n = 0; n < G_N_ELEMENTS (TAIP_EXIF); ++n)
|
||||
gtk_widget_hide (image_page->exif_labels[n]);
|
||||
|
||||
/* try to load the Exif data for the file */
|
||||
exif_data = exif_data_new_from_file (filename);
|
||||
if (G_LIKELY (exif_data != NULL))
|
||||
{
|
||||
/* update all Exif labels */
|
||||
for (n = 0; n < G_N_ELEMENTS (TAIP_EXIF); ++n)
|
||||
{
|
||||
/* lookup the entry for the tag */
|
||||
exif_entry = exif_data_get_entry (exif_data, TAIP_EXIF[n].tag);
|
||||
if (G_LIKELY (exif_entry != NULL))
|
||||
{
|
||||
/* determine the value */
|
||||
if (exif_entry_get_value (exif_entry, exif_buffer, sizeof (exif_buffer)) != NULL)
|
||||
{
|
||||
/* setup the label text */
|
||||
text = (g_utf8_validate (exif_buffer, -1, NULL)) ? g_strdup (exif_buffer) : g_filename_display_name (exif_buffer);
|
||||
gtk_label_set_text (GTK_LABEL (image_page->exif_labels[n]), text);
|
||||
g_free (text);
|
||||
|
||||
/* show the label */
|
||||
gtk_widget_show (image_page->exif_labels[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
exif_data_free (exif_data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tell the user that we're unable to determine the file info */
|
||||
gtk_label_set_text (GTK_LABEL (image_page->type_label), _("Unknown"));
|
||||
gtk_label_set_text (GTK_LABEL (image_page->dimensions_label), _("Unknown"));
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
/* hide all Exif labels */
|
||||
for (n = 0; n < G_N_ELEMENTS (TAIP_EXIF); ++n)
|
||||
gtk_widget_hide (image_page->exif_labels[n]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_free (filename);
|
||||
g_free (uri);
|
||||
}
|
||||
45
plugins/thunar-apr/thunar-apr-image-page.h
Normal file
45
plugins/thunar-apr/thunar-apr-image-page.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_APR_IMAGE_PAGE_H__
|
||||
#define __THUNAR_APR_IMAGE_PAGE_H__
|
||||
|
||||
#include <thunar-apr/thunar-apr-abstract-page.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarAprImagePageClass ThunarAprImagePageClass;
|
||||
typedef struct _ThunarAprImagePage ThunarAprImagePage;
|
||||
|
||||
#define THUNAR_APR_TYPE_IMAGE_PAGE (thunar_apr_image_page_get_type ())
|
||||
#define THUNAR_APR_IMAGE_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_APR_TYPE_IMAGE_PAGE, ThunarAprImagePage))
|
||||
#define THUNAR_APR_IMAGE_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_APR_TYPE_IMAGE_PAGE, ThunarAprImagePageClass))
|
||||
#define THUNAR_APR_IS_IMAGE_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_APR_TYPE_IMAGE_PAGE))
|
||||
#define THUNAR_APR_IS_IMAGE_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_APR_TYPE_IMAGE_PAGE))
|
||||
#define THUNAR_APR_IMAGE_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_APR_TYPE_IMAGE_PAGE, ThunarAprImagePageClass))
|
||||
|
||||
GType
|
||||
thunar_apr_image_page_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_apr_image_page_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APR_IMAGE_PAGE_H__ */
|
||||
91
plugins/thunar-apr/thunar-apr-plugin.c
Normal file
91
plugins/thunar-apr/thunar-apr-plugin.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-apr/thunar-apr-abstract-page.h>
|
||||
#include <thunar-apr/thunar-apr-desktop-page.h>
|
||||
#include <thunar-apr/thunar-apr-image-page.h>
|
||||
#include <thunar-apr/thunar-apr-provider.h>
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types);
|
||||
|
||||
|
||||
|
||||
static GType type_list[1];
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin)
|
||||
{
|
||||
const gchar *mismatch;
|
||||
|
||||
/* verify that the thunarx versions are compatible */
|
||||
mismatch = thunarx_check_version (THUNARX_MAJOR_VERSION, THUNARX_MINOR_VERSION, THUNARX_MICRO_VERSION);
|
||||
if (G_UNLIKELY (mismatch != NULL))
|
||||
{
|
||||
g_warning ("Version mismatch: %s", mismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Initializing ThunarApr extension");
|
||||
#endif
|
||||
|
||||
/* register the types provided by this plugin */
|
||||
thunar_apr_abstract_page_register_type (plugin);
|
||||
thunar_apr_desktop_page_register_type (plugin);
|
||||
thunar_apr_image_page_register_type (plugin);
|
||||
thunar_apr_provider_register_type (plugin);
|
||||
|
||||
/* setup the plugin provider type list */
|
||||
type_list[0] = THUNAR_APR_TYPE_PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Shutting down ThunarApr extension");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types)
|
||||
{
|
||||
*types = type_list;
|
||||
*n_types = G_N_ELEMENTS (type_list);
|
||||
}
|
||||
49
plugins/thunar-apr/thunar-apr-private.c
Normal file
49
plugins/thunar-apr/thunar-apr-private.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <thunar-apr/thunar-apr-private.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_apr_i18n_init:
|
||||
*
|
||||
* Sets up i18n support for the thunar-apr plugin.
|
||||
**/
|
||||
void
|
||||
thunar_apr_i18n_init (void)
|
||||
{
|
||||
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
#endif
|
||||
}
|
||||
33
plugins/thunar-apr/thunar-apr-private.h
Normal file
33
plugins/thunar-apr/thunar-apr-private.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_APR_PRIVATE_H__
|
||||
#define __THUNAR_APR_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
void
|
||||
thunar_apr_i18n_init (void);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APR_PRIVATE_H__ */
|
||||
135
plugins/thunar-apr/thunar-apr-provider.c
Normal file
135
plugins/thunar-apr/thunar-apr-provider.c
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-apr/thunar-apr-desktop-page.h>
|
||||
#include <thunar-apr/thunar-apr-image-page.h>
|
||||
#include <thunar-apr/thunar-apr-provider.h>
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_provider_property_page_provider_init (ThunarxPropertyPageProviderIface *iface);
|
||||
static GList *
|
||||
thunar_apr_provider_get_pages (ThunarxPropertyPageProvider *property_page_provider,
|
||||
GList *files);
|
||||
|
||||
|
||||
|
||||
struct _ThunarAprProviderClass
|
||||
{
|
||||
GObjectClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarAprProvider
|
||||
{
|
||||
GObject __parent__;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE_WITH_CODE (ThunarAprProvider,
|
||||
thunar_apr_provider,
|
||||
G_TYPE_OBJECT,
|
||||
THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_PROPERTY_PAGE_PROVIDER,
|
||||
thunar_apr_provider_property_page_provider_init));
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_provider_class_init (ThunarAprProviderClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_provider_property_page_provider_init (ThunarxPropertyPageProviderIface *iface)
|
||||
{
|
||||
iface->get_pages = thunar_apr_provider_get_pages;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_apr_provider_init (ThunarAprProvider *apr_provider)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_apr_provider_get_pages (ThunarxPropertyPageProvider *property_page_provider,
|
||||
GList *files)
|
||||
{
|
||||
GSList *formats;
|
||||
GSList *lp;
|
||||
gchar **mime_types;
|
||||
gchar *scheme;
|
||||
GList *pages = NULL;
|
||||
gint n;
|
||||
|
||||
/* we can handle only property pages for a single file */
|
||||
if (G_UNLIKELY (files == NULL || files->next != NULL))
|
||||
return NULL;
|
||||
|
||||
/* determine the URI scheme of the file (works only for local files) */
|
||||
scheme = thunarx_file_info_get_uri_scheme (files->data);
|
||||
if (G_LIKELY (strcmp (scheme, "file") == 0))
|
||||
{
|
||||
/* ThunarAprDesktopPage case */
|
||||
if (G_LIKELY (pages == NULL))
|
||||
{
|
||||
/* check if we have a .desktop file here */
|
||||
if (thunarx_file_info_has_mime_type (files->data, "application/x-desktop"))
|
||||
pages = g_list_append (pages, g_object_new (THUNAR_APR_TYPE_DESKTOP_PAGE, "file", files->data, NULL));
|
||||
}
|
||||
|
||||
/* ThunarAprImagePage case */
|
||||
if (G_LIKELY (pages == NULL))
|
||||
{
|
||||
/* determine the supported GdkPixbuf formats */
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
for (lp = formats; lp != NULL && pages == NULL; lp = lp->next)
|
||||
{
|
||||
/* check if any of the mime types of this format matches */
|
||||
mime_types = gdk_pixbuf_format_get_mime_types (lp->data);
|
||||
for (n = 0; mime_types[n] != NULL && pages == NULL; ++n)
|
||||
if (thunarx_file_info_has_mime_type (files->data, mime_types[n]))
|
||||
pages = g_list_append (pages, g_object_new (THUNAR_APR_TYPE_IMAGE_PAGE, "file", files->data, NULL));
|
||||
g_strfreev (mime_types);
|
||||
}
|
||||
g_slist_free (formats);
|
||||
}
|
||||
}
|
||||
g_free (scheme);
|
||||
|
||||
return pages;
|
||||
}
|
||||
45
plugins/thunar-apr/thunar-apr-provider.h
Normal file
45
plugins/thunar-apr/thunar-apr-provider.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_APR_PROVIDER_H__
|
||||
#define __THUNAR_APR_PROVIDER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarAprProviderClass ThunarAprProviderClass;
|
||||
typedef struct _ThunarAprProvider ThunarAprProvider;
|
||||
|
||||
#define THUNAR_APR_TYPE_PROVIDER (thunar_apr_provider_get_type ())
|
||||
#define THUNAR_APR_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_APR_TYPE_PROVIDER, ThunarAprProvider))
|
||||
#define THUNAR_APR_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_APR_TYPE_PROVIDER, ThunarAprProviderClass))
|
||||
#define THUNAR_APR_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_APR_TYPE_PROVIDER))
|
||||
#define THUNAR_APR_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_APR_TYPE_PROVIDER))
|
||||
#define THUNAR_APR_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_APR_TYPE_PROVIDER, ThunarAprProviderClass))
|
||||
|
||||
GType
|
||||
thunar_apr_provider_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_apr_provider_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APR_PROVIDER_H__ */
|
||||
60
plugins/thunar-sbr/Makefile.am
Normal file
60
plugins/thunar-sbr/Makefile.am
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/plugins \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/plugins \
|
||||
-DG_LOG_DOMAIN=\"thunar-sbr\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
extensionsdir = $(libdir)/thunarx-$(THUNARX_VERSION_API)
|
||||
extensions_LTLIBRARIES = \
|
||||
thunar-sbr.la
|
||||
|
||||
thunar_sbr_la_SOURCES = \
|
||||
thunar-sbr-case-renamer.c \
|
||||
thunar-sbr-case-renamer.h \
|
||||
thunar-sbr-date-renamer.c \
|
||||
thunar-sbr-date-renamer.h \
|
||||
thunar-sbr-enum-types.c \
|
||||
thunar-sbr-enum-types.h \
|
||||
thunar-sbr-insert-renamer.c \
|
||||
thunar-sbr-insert-renamer.h \
|
||||
thunar-sbr-number-renamer.c \
|
||||
thunar-sbr-number-renamer.h \
|
||||
thunar-sbr-plugin.c \
|
||||
thunar-sbr-provider.c \
|
||||
thunar-sbr-provider.h \
|
||||
thunar-sbr-remove-renamer.c \
|
||||
thunar-sbr-remove-renamer.h \
|
||||
thunar-sbr-replace-renamer.c \
|
||||
thunar-sbr-replace-renamer.h
|
||||
|
||||
thunar_sbr_la_CFLAGS = \
|
||||
$(EXIF_CFLAGS) \
|
||||
$(EXO_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(PCRE2_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
thunar_sbr_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
-no-undefined \
|
||||
-export-symbols-regex "^thunar_extension_(shutdown|initialize|list_types)" \
|
||||
-module \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
thunar_sbr_la_LIBADD = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la \
|
||||
$(EXIF_LIBS) \
|
||||
$(EXO_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(PCRE2_LIBS)
|
||||
|
||||
thunar_sbr_la_DEPENDENCIES = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
|
||||
|
||||
EXTRA_DIST = \
|
||||
README.md
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
24
plugins/thunar-sbr/README.md
Normal file
24
plugins/thunar-sbr/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Thunar Simple Builtin Renamers (thunar-sbr)
|
||||
===========================================
|
||||
|
||||
Thunar-sbr is an extension to Thunar, which includes a bunch of simple renamers for the bulk rename dialog:
|
||||
|
||||
* Insert / Overwrite
|
||||
* Insert Date / Time
|
||||
* Numbering
|
||||
* Remove Characters
|
||||
* Search & Replace
|
||||
* Uppercase / Lowercase
|
||||
|
||||
By default the thunar-sbr extension will be installed, but as with every extension, it will slightly increase the resource usage of Thunar (this shouldn't be a real problem unless you're targeting an embedded system), and so you can pass `--disable-sbr-plugin` to configure and the plugin won't be built and installed. Since it is an extension, you can also easily uninstall it afterwards by removing the thunar-sbr.so file from the lib/thunarx-2/ directory of your installation (be sure to quit Thunar before removing files though).
|
||||
|
||||
|
||||
Regular Expressions
|
||||
-------------------
|
||||
|
||||
The "Search & Replace" renamer can be built with support for regular expressions using the Perl-compatible regular expression (PCRE) library version 6.0 or above. The reasons to use PCRE instead of the POSIX regular expressions, that are part of the system C library, are:
|
||||
|
||||
* PCRE supports UTF-8, which Thunar uses internally for all user visible texts (be sure to enable this when installing PCRE using the `--enable-utf8` configure switch).
|
||||
* PCRE uses a more consistent syntax, which is easier to understand for most people.
|
||||
|
||||
|
||||
319
plugins/thunar-sbr/thunar-sbr-case-renamer.c
Normal file
319
plugins/thunar-sbr/thunar-sbr-case-renamer.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <thunar-sbr/thunar-sbr-case-renamer.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_MODE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_case_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_case_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gchar *
|
||||
thunar_sbr_case_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrCaseRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrCaseRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
ThunarSbrCaseRenamerMode mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrCaseRenamer, thunar_sbr_case_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_case_renamer_class_init (ThunarSbrCaseRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->get_property = thunar_sbr_case_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_case_renamer_set_property;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_case_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrCaseRenamer:mode:
|
||||
*
|
||||
* The #ThunarSbrCaseRenamerMode for this
|
||||
* #ThunarSbrCaseRenamer instance.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MODE,
|
||||
g_param_spec_enum ("mode", "mode", "mode",
|
||||
THUNAR_SBR_TYPE_CASE_RENAMER_MODE,
|
||||
THUNAR_SBR_CASE_RENAMER_MODE_LOWER,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_case_renamer_init (ThunarSbrCaseRenamer *case_renamer)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
AtkRelation *relation;
|
||||
GEnumClass *klass;
|
||||
AtkObject *object;
|
||||
GtkWidget *combo;
|
||||
GtkWidget *label;
|
||||
GtkWidget *hbox;
|
||||
guint n;
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_box_pack_start (GTK_BOX (case_renamer), hbox, FALSE, FALSE, 0);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Con_vert to:"));
|
||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
||||
gtk_widget_show (label);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_CASE_RENAMER_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (case_renamer), "mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
/* set Atk label relation for the combo */
|
||||
object = gtk_widget_get_accessible (combo);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_case_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrCaseRenamer *case_renamer = THUNAR_SBR_CASE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_case_renamer_get_mode (case_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_case_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrCaseRenamer *case_renamer = THUNAR_SBR_CASE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
thunar_sbr_case_renamer_set_mode (case_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
tscr_utf8_strcase (const gchar *text,
|
||||
gboolean title_case)
|
||||
{
|
||||
const gchar *t;
|
||||
gboolean upper = TRUE;
|
||||
gunichar c;
|
||||
GString *result;
|
||||
|
||||
/* allocate a new string for the result */
|
||||
result = g_string_sized_new (32);
|
||||
|
||||
/* convert the input text */
|
||||
for (t = text; *t != '\0'; t = g_utf8_next_char (t))
|
||||
{
|
||||
/* check the next char */
|
||||
c = g_utf8_get_char (t);
|
||||
if (title_case && g_unichar_isspace (c))
|
||||
{
|
||||
upper = TRUE;
|
||||
}
|
||||
else if (upper && g_unichar_isalpha (c))
|
||||
{
|
||||
c = g_unichar_toupper (c);
|
||||
upper = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = g_unichar_tolower (c);
|
||||
}
|
||||
|
||||
/* append the char to the result */
|
||||
g_string_append_unichar (result, c);
|
||||
}
|
||||
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_case_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrCaseRenamer *case_renamer = THUNAR_SBR_CASE_RENAMER (renamer);
|
||||
|
||||
switch (case_renamer->mode)
|
||||
{
|
||||
case THUNAR_SBR_CASE_RENAMER_MODE_LOWER:
|
||||
return g_utf8_strdown (text, -1);
|
||||
|
||||
case THUNAR_SBR_CASE_RENAMER_MODE_UPPER:
|
||||
return g_utf8_strup (text, -1);
|
||||
|
||||
case THUNAR_SBR_CASE_RENAMER_MODE_TITLE:
|
||||
return tscr_utf8_strcase (text, TRUE);
|
||||
|
||||
case THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER:
|
||||
return tscr_utf8_strcase (text, FALSE);
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_case_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrCaseRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrCaseRenamer.
|
||||
**/
|
||||
ThunarSbrCaseRenamer *
|
||||
thunar_sbr_case_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_CASE_RENAMER,
|
||||
"name", _("Uppercase / Lowercase"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_case_renamer_get_mode:
|
||||
* @case_renamer : a #ThunarSbrCaseRenamer.
|
||||
*
|
||||
* Returns the current #ThunarSbrCaseRenamerMode
|
||||
* for the @case_renamer.
|
||||
*
|
||||
* Return value: the current mode of @case_renamer.
|
||||
**/
|
||||
ThunarSbrCaseRenamerMode
|
||||
thunar_sbr_case_renamer_get_mode (ThunarSbrCaseRenamer *case_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_CASE_RENAMER (case_renamer), THUNAR_SBR_CASE_RENAMER_MODE_LOWER);
|
||||
return case_renamer->mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_case_renamer_set_mode:
|
||||
* @case_renamer : a #ThunarSbrCaseRenamer.
|
||||
* @mode : the new #ThunarSbrCaseRenamerMode.
|
||||
*
|
||||
* Sets the #ThunarSbrCaseRenamerMode of the @case_renamer
|
||||
* to the specified @mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_case_renamer_set_mode (ThunarSbrCaseRenamer *case_renamer,
|
||||
ThunarSbrCaseRenamerMode mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_CASE_RENAMER (case_renamer));
|
||||
|
||||
/* check if we already use that mode */
|
||||
if (G_UNLIKELY (case_renamer->mode == mode))
|
||||
return;
|
||||
|
||||
/* apply the new mode */
|
||||
case_renamer->mode = mode;
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (case_renamer), "mode");
|
||||
|
||||
/* emit the "changed" signal */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (case_renamer));
|
||||
}
|
||||
54
plugins/thunar-sbr/thunar-sbr-case-renamer.h
Normal file
54
plugins/thunar-sbr/thunar-sbr-case-renamer.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_CASE_RENAMER_H__
|
||||
#define __THUNAR_SBR_CASE_RENAMER_H__
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrCaseRenamerClass ThunarSbrCaseRenamerClass;
|
||||
typedef struct _ThunarSbrCaseRenamer ThunarSbrCaseRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_CASE_RENAMER (thunar_sbr_case_renamer_get_type ())
|
||||
#define THUNAR_SBR_CASE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_CASE_RENAMER, ThunarSbrCaseRenamer))
|
||||
#define THUNAR_SBR_CASE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_CASE_RENAMER, ThunarSbrCaseRenamerClass))
|
||||
#define THUNAR_SBR_IS_CASE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_CASE_RENAMER))
|
||||
#define THUNAR_SBR_IS_CASE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_CASE_RENAMER))
|
||||
#define THUNAR_SBR_CASE_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_CASE_RENAMER, ThunarSbrCaseRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_case_renamer_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_case_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrCaseRenamer *
|
||||
thunar_sbr_case_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
ThunarSbrCaseRenamerMode
|
||||
thunar_sbr_case_renamer_get_mode (ThunarSbrCaseRenamer *case_renamer);
|
||||
void
|
||||
thunar_sbr_case_renamer_set_mode (ThunarSbrCaseRenamer *case_renamer,
|
||||
ThunarSbrCaseRenamerMode mode);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_CASE_RENAMER_H__ */
|
||||
789
plugins/thunar-sbr/thunar-sbr-date-renamer.c
Normal file
789
plugins/thunar-sbr/thunar-sbr-date-renamer.c
Normal file
|
|
@ -0,0 +1,789 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2007 Nick Schermer <nick@xfce.org>
|
||||
* Copyright (c) 2007 Benedikt Meurer <benny@xfce.org>
|
||||
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-sbr/thunar-sbr-date-renamer.h>
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
#include <libexif/exif-data.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_MODE,
|
||||
PROP_FORMAT,
|
||||
PROP_OFFSET,
|
||||
PROP_OFFSET_MODE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_finalize (GObject *object);
|
||||
static void
|
||||
thunar_sbr_date_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_date_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gchar *
|
||||
thunar_sbr_get_time_string (guint64 file_time,
|
||||
const gchar *custom_format);
|
||||
#ifdef HAVE_EXIF
|
||||
static guint64
|
||||
thunar_sbr_get_time_from_string (const gchar *string);
|
||||
#endif
|
||||
static guint64
|
||||
thunar_sbr_get_time (ThunarxFileInfo *file,
|
||||
ThunarSbrDateMode mode);
|
||||
static gchar *
|
||||
thunar_sbr_date_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrDateRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrDateRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
ThunarSbrDateMode mode;
|
||||
guint offset;
|
||||
ThunarSbrOffsetMode offset_mode;
|
||||
gchar *format;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrDateRenamer, thunar_sbr_date_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_class_init (ThunarSbrDateRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_sbr_date_renamer_finalize;
|
||||
gobject_class->get_property = thunar_sbr_date_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_date_renamer_set_property;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_date_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrDateRenamer:mode:
|
||||
*
|
||||
* The #ThunarSbrDateMode to use.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MODE,
|
||||
g_param_spec_enum ("mode",
|
||||
"mode",
|
||||
"mode",
|
||||
THUNAR_SBR_TYPE_DATE_MODE,
|
||||
THUNAR_SBR_DATE_MODE_NOW,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrDateRenamer:format:
|
||||
*
|
||||
* The date format to insert.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_FORMAT,
|
||||
g_param_spec_string ("format",
|
||||
"format",
|
||||
"format",
|
||||
"%Y%m%d",
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrDateRenamer:offset:
|
||||
*
|
||||
* The starting offset at which to insert/overwrite.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OFFSET,
|
||||
g_param_spec_uint ("offset",
|
||||
"offset",
|
||||
"offset",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrDateRenamer:offset-mode:
|
||||
*
|
||||
* The offset mode for the renamer.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OFFSET_MODE,
|
||||
g_param_spec_enum ("offset-mode",
|
||||
"offset-mode",
|
||||
"offset-mode",
|
||||
THUNAR_SBR_TYPE_OFFSET_MODE,
|
||||
THUNAR_SBR_OFFSET_MODE_LEFT,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_init (ThunarSbrDateRenamer *date_renamer)
|
||||
{
|
||||
GEnumClass *klass;
|
||||
AtkRelationSet *relations;
|
||||
AtkRelation *relation;
|
||||
AtkObject *object;
|
||||
GtkWidget *grid, *hbox;
|
||||
GtkWidget *label, *combo;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *entry;
|
||||
GtkAdjustment *adjustment;
|
||||
guint n;
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_box_pack_start (GTK_BOX (date_renamer), grid, TRUE, TRUE, 0);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Insert _time:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_DATE_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (date_renamer), "mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 1, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
/* set Atk label relation for the combo */
|
||||
object = gtk_widget_get_accessible (combo);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Format:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
g_object_bind_property (G_OBJECT (entry), "text", G_OBJECT (date_renamer), "format", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_hexpand (GTK_WIDGET (entry), TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), entry, 3, 0, 1, 1);
|
||||
gtk_widget_set_tooltip_text (entry,
|
||||
_("The format describes the date and time parts to insert "
|
||||
"into the file name. For example, %Y will be substituted "
|
||||
"with the year, %m with the month and %d with the day. "
|
||||
"See the documentation of the date utility for additional "
|
||||
"information."));
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
|
||||
gtk_widget_show (entry);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_At position:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_grid_attach (GTK_GRID (grid), hbox, 1, 1, 3, 1);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
spinner = gtk_spin_button_new_with_range (0u, G_MAXUINT, 1u);
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (spinner), 4);
|
||||
gtk_entry_set_alignment (GTK_ENTRY (spinner), 1.0f);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (spinner), TRUE);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner), 0);
|
||||
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
|
||||
gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (spinner), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
|
||||
gtk_widget_show (spinner);
|
||||
|
||||
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spinner));
|
||||
g_object_bind_property (G_OBJECT (date_renamer), "offset", G_OBJECT (adjustment), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_OFFSET_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (date_renamer), "offset-mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_finalize (GObject *object)
|
||||
{
|
||||
ThunarSbrDateRenamer *date_renamer = THUNAR_SBR_DATE_RENAMER (object);
|
||||
|
||||
/* release the format */
|
||||
g_free (date_renamer->format);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_sbr_date_renamer_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrDateRenamer *date_renamer = THUNAR_SBR_DATE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_date_renamer_get_mode (date_renamer));
|
||||
break;
|
||||
|
||||
case PROP_FORMAT:
|
||||
g_value_set_string (value, thunar_sbr_date_renamer_get_format (date_renamer));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
g_value_set_uint (value, thunar_sbr_date_renamer_get_offset (date_renamer));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_date_renamer_get_offset_mode (date_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_date_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrDateRenamer *date_renamer = THUNAR_SBR_DATE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
thunar_sbr_date_renamer_set_mode (date_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_FORMAT:
|
||||
thunar_sbr_date_renamer_set_format (date_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
thunar_sbr_date_renamer_set_offset (date_renamer, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_MODE:
|
||||
thunar_sbr_date_renamer_set_offset_mode (date_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_get_time_string (guint64 file_time,
|
||||
const gchar *format)
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t _time;
|
||||
gchar *converted;
|
||||
gchar buffer[1024];
|
||||
gint length;
|
||||
|
||||
_time = (time_t) file_time;
|
||||
|
||||
/* determine the local file time */
|
||||
tm = localtime (&_time);
|
||||
|
||||
/* conver the format to the current locale */
|
||||
converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
|
||||
|
||||
/* parse the format */
|
||||
length = strftime (buffer, sizeof (buffer), converted, tm);
|
||||
|
||||
/* cleanup */
|
||||
g_free (converted);
|
||||
|
||||
/* check if strftime succeeded */
|
||||
if (G_UNLIKELY (length == 0))
|
||||
return NULL;
|
||||
|
||||
/* return the utf-8 string */
|
||||
return g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
static guint64
|
||||
thunar_sbr_get_time_from_string (const gchar *string)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
#ifdef HAVE_STRPTIME
|
||||
/* parse the string with strptime */
|
||||
strptime (string, "%Y:%m:%d %T", &tm);
|
||||
#else
|
||||
gint result;
|
||||
gint year, month, day, hour, min, sec;
|
||||
|
||||
result = sscanf (string, "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
|
||||
|
||||
/* only continue when atleast the date is parsed succesfully */
|
||||
if (G_LIKELY (result >= 3 && g_date_valid_dmy (day, month, year)))
|
||||
{
|
||||
/* be sure to start with a clean tm */
|
||||
memset (&tm, 0, sizeof (tm));
|
||||
|
||||
/* set the date */
|
||||
tm.tm_year = year - 1900;
|
||||
tm.tm_mon = month - 1;
|
||||
tm.tm_mday = day;
|
||||
|
||||
/* set the time */
|
||||
tm.tm_hour = result >= 4 ? hour : 0;
|
||||
tm.tm_min = result >= 5 ? min : 0;
|
||||
tm.tm_sec = result >= 6 ? sec : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* return the local time */
|
||||
return mktime (&tm);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static guint64
|
||||
thunar_sbr_get_time (ThunarxFileInfo *file,
|
||||
ThunarSbrDateMode mode)
|
||||
{
|
||||
GFileInfo *file_info;
|
||||
guint64 file_time = 0;
|
||||
#ifdef HAVE_EXIF
|
||||
gchar *uri, *filename;
|
||||
ExifEntry *exif_entry;
|
||||
ExifData *exif_data;
|
||||
gchar exif_buffer[128];
|
||||
#endif
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case THUNAR_SBR_DATE_MODE_NOW:
|
||||
/* set the time to the current time */
|
||||
file_time = time (NULL);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_DATE_MODE_ATIME:
|
||||
case THUNAR_SBR_DATE_MODE_MTIME:
|
||||
/* get the file info */
|
||||
file_info = thunarx_file_info_get_file_info (file);
|
||||
|
||||
/* get the time from the info */
|
||||
if (mode == THUNAR_SBR_DATE_MODE_ATIME)
|
||||
{
|
||||
file_time = g_file_info_get_attribute_uint64 (file_info,
|
||||
G_FILE_ATTRIBUTE_TIME_ACCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_time = g_file_info_get_attribute_uint64 (file_info,
|
||||
G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||
}
|
||||
|
||||
/* release the file info */
|
||||
g_object_unref (file_info);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
case THUNAR_SBR_DATE_MODE_TAKEN:
|
||||
/* get the uri */
|
||||
uri = thunarx_file_info_get_uri (file);
|
||||
if (G_LIKELY (uri != NULL))
|
||||
{
|
||||
/* determine the local path of the file */
|
||||
filename = g_filename_from_uri (uri, NULL, NULL);
|
||||
if (G_LIKELY (filename != NULL))
|
||||
{
|
||||
/* try to load the exif data for the file */
|
||||
exif_data = exif_data_new_from_file (filename);
|
||||
if (G_LIKELY (exif_data != NULL))
|
||||
{
|
||||
/* lookup the entry for the tag, fallback on less common ones */
|
||||
exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME);
|
||||
|
||||
if (exif_entry == NULL)
|
||||
exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
|
||||
|
||||
if (exif_entry == NULL)
|
||||
exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME_DIGITIZED);
|
||||
|
||||
if (G_LIKELY (exif_entry != NULL))
|
||||
{
|
||||
/* determine the value */
|
||||
if (exif_entry_get_value (exif_entry, exif_buffer, sizeof (exif_buffer)) != NULL)
|
||||
file_time = thunar_sbr_get_time_from_string (exif_buffer);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
exif_data_free (exif_data);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_free (uri);
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return file_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_date_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrDateRenamer *date_renamer = THUNAR_SBR_DATE_RENAMER (renamer);
|
||||
gchar *string;
|
||||
guint64 file_time;
|
||||
const gchar *s;
|
||||
GString *result;
|
||||
guint text_length;
|
||||
guint offset;
|
||||
|
||||
/* return when there is no text in the custom format entry */
|
||||
if (G_UNLIKELY (date_renamer->format == NULL || *date_renamer->format == '\0'))
|
||||
return g_strdup (text);
|
||||
|
||||
/* determine the input text length */
|
||||
text_length = g_utf8_strlen (text, -1);
|
||||
|
||||
/* determine the real offset and check if it's valid */
|
||||
offset = (date_renamer->offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT) ? date_renamer->offset : (text_length - date_renamer->offset);
|
||||
if (G_UNLIKELY (offset > text_length))
|
||||
return g_strdup (text);
|
||||
|
||||
/* get the file time */
|
||||
file_time = thunar_sbr_get_time (file, date_renamer->mode);
|
||||
if (file_time == 0)
|
||||
return g_strdup (text);
|
||||
|
||||
/* allocate space for the result */
|
||||
result = g_string_sized_new (2 * text_length);
|
||||
|
||||
/* determine the text pointer for the offset */
|
||||
s = g_utf8_offset_to_pointer (text, offset);
|
||||
|
||||
/* add the text before the insert/overwrite offset */
|
||||
g_string_append_len (result, text, s - text);
|
||||
|
||||
/* parse the time string */
|
||||
string = thunar_sbr_get_time_string (file_time, date_renamer->format);
|
||||
if (string)
|
||||
{
|
||||
g_string_append (result, string);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
/* append the remaining text */
|
||||
g_string_append (result, s);
|
||||
|
||||
/* return the result */
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrDateRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrDateRenamer.
|
||||
**/
|
||||
ThunarSbrDateRenamer *
|
||||
thunar_sbr_date_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_DATE_RENAMER,
|
||||
"name", _("Insert Date / Time"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_get_mode:
|
||||
* @date_renamer : a #ThunarSbrDateRenamer.
|
||||
*
|
||||
* Returns the mode of the @date_renamer.
|
||||
*
|
||||
* Return value: the mode of @date_renamer.
|
||||
**/
|
||||
ThunarSbrDateMode
|
||||
thunar_sbr_date_renamer_get_mode (ThunarSbrDateRenamer *date_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer), THUNAR_SBR_DATE_MODE_NOW);
|
||||
|
||||
return date_renamer->mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_set_mode:
|
||||
* @date_renamer : a #ThunarSbrDateRenamer.
|
||||
* @mode : the new #ThunarSbrDateMode for @date_renamer.
|
||||
*
|
||||
* Sets the mode of @date_renamer to @mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_date_renamer_set_mode (ThunarSbrDateRenamer *date_renamer,
|
||||
ThunarSbrDateMode mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer));
|
||||
|
||||
/* check if we have a new mode */
|
||||
if (G_LIKELY (date_renamer->mode != mode))
|
||||
{
|
||||
/* apply the new mode */
|
||||
date_renamer->mode = mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (date_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (date_renamer), "mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_get_format:
|
||||
* @date_renamer : a #ThunarSbrDateRenamer.
|
||||
*
|
||||
* Returns the format for the @date_renamer.
|
||||
*
|
||||
* Return value: the format for @date_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_date_renamer_get_format (ThunarSbrDateRenamer *date_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer), NULL);
|
||||
|
||||
return date_renamer->format;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_set_format:
|
||||
* @date_renamer : a #ThunarSbrDateRenamer.
|
||||
* @format : the new format for @date_renamer.
|
||||
*
|
||||
* Sets the format for @date_renamer to @format.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_date_renamer_set_format (ThunarSbrDateRenamer *date_renamer,
|
||||
const gchar *format)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer));
|
||||
|
||||
/* check if we have a new format */
|
||||
if (G_LIKELY (g_strcmp0 (date_renamer->format, format) != 0))
|
||||
{
|
||||
/* apply the new format */
|
||||
g_free (date_renamer->format);
|
||||
date_renamer->format = g_strdup (format);
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (date_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (date_renamer), "format");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_get_offset:
|
||||
* @date_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the offset for the @date_renamer.
|
||||
*
|
||||
* Return value: the offset for @date_renamer.
|
||||
**/
|
||||
guint
|
||||
thunar_sbr_date_renamer_get_offset (ThunarSbrDateRenamer *date_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer), 0);
|
||||
return date_renamer->offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_set_offset:
|
||||
* @date_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @offset : the new offset for @date_renamer.
|
||||
*
|
||||
* Sets the offset for @date_renamer to @offset.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_date_renamer_set_offset (ThunarSbrDateRenamer *date_renamer,
|
||||
guint offset)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer));
|
||||
|
||||
/* check if we have a new offset */
|
||||
if (G_LIKELY (date_renamer->offset != offset))
|
||||
{
|
||||
/* apply the new offset */
|
||||
date_renamer->offset = offset;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (date_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (date_renamer), "offset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_get_offset_mode:
|
||||
* @date_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the offset mode for the @date_renamer.
|
||||
*
|
||||
* Return value: the offset mode for @date_renamer.
|
||||
**/
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_date_renamer_get_offset_mode (ThunarSbrDateRenamer *date_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer), THUNAR_SBR_OFFSET_MODE_LEFT);
|
||||
return date_renamer->offset_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_date_renamer_set_offset_mode:
|
||||
* @date_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @offset_mode : the new offset mode for @date_renamer.
|
||||
*
|
||||
* Sets the offset mode for @date_renamer to @offset_mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_date_renamer_set_offset_mode (ThunarSbrDateRenamer *date_renamer,
|
||||
ThunarSbrOffsetMode offset_mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_DATE_RENAMER (date_renamer));
|
||||
|
||||
/* check if we have a new setting */
|
||||
if (G_LIKELY (date_renamer->offset_mode != offset_mode))
|
||||
{
|
||||
/* apply the new setting */
|
||||
date_renamer->offset_mode = offset_mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (date_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (date_renamer), "offset-mode");
|
||||
}
|
||||
}
|
||||
74
plugins/thunar-sbr/thunar-sbr-date-renamer.h
Normal file
74
plugins/thunar-sbr/thunar-sbr-date-renamer.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2007 Nick Schermer <nick@xfce.org>
|
||||
* Copyright (c) 2007 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_DATE_RENAMER_H__
|
||||
#define __THUNAR_SBR_DATE_RENAMER_H__
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrDateRenamerClass ThunarSbrDateRenamerClass;
|
||||
typedef struct _ThunarSbrDateRenamer ThunarSbrDateRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_DATE_RENAMER (thunar_sbr_date_renamer_get_type ())
|
||||
#define THUNAR_SBR_DATE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_DATE_RENAMER, ThunarSbrDateRenamer))
|
||||
#define THUNAR_SBR_DATE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_DATE_RENAMER, ThunarSbrDateRenamerClass))
|
||||
#define THUNAR_SBR_IS_DATE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_DATE_RENAMER))
|
||||
#define THUNAR_SBR_IS_DATE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_DATE_RENAMER))
|
||||
#define THUNAR_SBR_DATE_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_DATE_RENAMER, ThunarSbrDateRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_date_renamer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void
|
||||
thunar_sbr_date_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrDateRenamer *
|
||||
thunar_sbr_date_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
ThunarSbrDateMode
|
||||
thunar_sbr_date_renamer_get_mode (ThunarSbrDateRenamer *date_renamer);
|
||||
void
|
||||
thunar_sbr_date_renamer_set_mode (ThunarSbrDateRenamer *date_renamer,
|
||||
ThunarSbrDateMode mode);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_date_renamer_get_format (ThunarSbrDateRenamer *date_renamer);
|
||||
void
|
||||
thunar_sbr_date_renamer_set_format (ThunarSbrDateRenamer *date_renamer,
|
||||
const gchar *format);
|
||||
|
||||
guint
|
||||
thunar_sbr_date_renamer_get_offset (ThunarSbrDateRenamer *date_renamer);
|
||||
void
|
||||
thunar_sbr_date_renamer_set_offset (ThunarSbrDateRenamer *date_renamer,
|
||||
guint offset);
|
||||
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_date_renamer_get_offset_mode (ThunarSbrDateRenamer *date_renamer);
|
||||
void
|
||||
thunar_sbr_date_renamer_set_offset_mode (ThunarSbrDateRenamer *date_renamer,
|
||||
ThunarSbrOffsetMode offset_mode);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_DATE_RENAMER_H__ */
|
||||
154
plugins/thunar-sbr/thunar-sbr-enum-types.c
Normal file
154
plugins/thunar-sbr/thunar-sbr-enum-types.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
|
||||
|
||||
static GType case_renamer_mode_type;
|
||||
static GType insert_mode_type;
|
||||
static GType number_mode_type;
|
||||
static GType offset_mode_type;
|
||||
static GType text_mode_type;
|
||||
static GType date_mode_type;
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_case_renamer_mode_get_type (void)
|
||||
{
|
||||
return case_renamer_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_insert_mode_get_type (void)
|
||||
{
|
||||
return insert_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_number_mode_get_type (void)
|
||||
{
|
||||
return number_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_offset_mode_get_type (void)
|
||||
{
|
||||
return offset_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_text_mode_get_type (void)
|
||||
{
|
||||
return text_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_sbr_date_mode_get_type (void)
|
||||
{
|
||||
return date_mode_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
thunar_sbr_register_enum_types (ThunarxProviderPlugin *plugin)
|
||||
{
|
||||
/* clang-format off */
|
||||
|
||||
static const GEnumValue case_renamer_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_CASE_RENAMER_MODE_LOWER, "THUNAR_SBR_CASE_RENAMER_MODE_LOWER", N_ ("lowercase"), },
|
||||
{ THUNAR_SBR_CASE_RENAMER_MODE_UPPER, "THUNAR_SBR_CASE_RENAMER_MODE_UPPER", N_ ("UPPERCASE"), },
|
||||
{ THUNAR_SBR_CASE_RENAMER_MODE_TITLE, "THUNAR_SBR_CASE_RENAMER_MODE_TITLE", N_ ("Title Case"), },
|
||||
{ THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER, "THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER", N_ ("First character uppercase"), },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
static const GEnumValue insert_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_INSERT_MODE_INSERT, "THUNAR_SBR_INSERT_MODE_INSERT", N_ ("Insert"), },
|
||||
{ THUNAR_SBR_INSERT_MODE_OVERWRITE, "THUNAR_SBR_INSERT_MODE_OVERWRITE", N_ ("Overwrite"), },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
static const GEnumValue number_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_NUMBER_MODE_123, "THUNAR_SBR_NUMBER_MODE_123", N_ ("1, 2, 3, ..."), },
|
||||
{ THUNAR_SBR_NUMBER_MODE_010203, "THUNAR_SBR_NUMBER_MODE_010203", N_ ("01, 02, 03, ..."), },
|
||||
{ THUNAR_SBR_NUMBER_MODE_001002003, "THUNAR_SBR_NUMBER_MODE_001002003", N_ ("001, 002, 003, ..."), },
|
||||
{ THUNAR_SBR_NUMBER_MODE_000100020003, "THUNAR_SBR_NUMBER_MODE_000100020003", N_ ("0001, 0002, 0003, ..."), },
|
||||
{ THUNAR_SBR_NUMBER_MODE_000010000200003, "THUNAR_SBR_NUMBER_MODE_000010000200003", N_ ("00001, 00002, 00003, ..."), },
|
||||
{ THUNAR_SBR_NUMBER_MODE_ABC, "THUNAR_SBR_NUMBER_MODE_ABC", N_ ("a, b, c, d, ..."), },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
static const GEnumValue offset_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_OFFSET_MODE_LEFT, "THUNAR_SBR_OFFSET_MODE_LEFT", N_ ("From the front (left)"), },
|
||||
{ THUNAR_SBR_OFFSET_MODE_RIGHT, "THUNAR_SBR_OFFSET_MODE_RIGHT", N_ ("From the back (right)"), },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
static const GEnumValue text_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_TEXT_MODE_OTN, "THUNAR_SBR_TEXT_MODE_OTN", N_ ("Old Name - Text - Number"), },
|
||||
{ THUNAR_SBR_TEXT_MODE_NTO, "THUNAR_SBR_TEXT_MODE_NTO", N_ ("Number - Text - Old Name"), },
|
||||
{ THUNAR_SBR_TEXT_MODE_TN, "THUNAR_SBR_TEXT_MODE_TN", N_ ("Text - Number"), },
|
||||
{ THUNAR_SBR_TEXT_MODE_NT, "THUNAR_SBR_TEXT_MODE_NT", N_ ("Number - Text"), },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
static const GEnumValue date_mode_values[] =
|
||||
{
|
||||
{ THUNAR_SBR_DATE_MODE_NOW, "THUNAR_SBR_DATE_MODE_NOW", N_ ("Current"), },
|
||||
{ THUNAR_SBR_DATE_MODE_ATIME, "THUNAR_SBR_DATE_MODE_ATIME", N_ ("Date Accessed"), },
|
||||
{ THUNAR_SBR_DATE_MODE_MTIME, "THUNAR_SBR_DATE_MODE_MTIME", N_ ("Date Modified"), },
|
||||
#ifdef HAVE_EXIF
|
||||
{ THUNAR_SBR_DATE_MODE_TAKEN, "THUNAR_SBR_DATE_MODE_TAKEN", N_ ("Date Picture Taken"), },
|
||||
#endif
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
case_renamer_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrCaseRenamerMode", case_renamer_mode_values);
|
||||
insert_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrInsertMode", insert_mode_values);
|
||||
number_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrNumberMode", number_mode_values);
|
||||
offset_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrOffsetMode", offset_mode_values);
|
||||
text_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrTextMode", text_mode_values);
|
||||
date_mode_type = thunarx_provider_plugin_register_enum (plugin, "ThunarSbrDateMode", date_mode_values);
|
||||
}
|
||||
170
plugins/thunar-sbr/thunar-sbr-enum-types.h
Normal file
170
plugins/thunar-sbr/thunar-sbr-enum-types.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_ENUM_TYPES_H__
|
||||
#define __THUNAR_SBR_ENUM_TYPES_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
#define THUNAR_SBR_TYPE_CASE_RENAMER_MODE (thunar_sbr_case_renamer_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrCaseRenamerMode:
|
||||
* @THUNAR_SBR_CASE_RENAMER_MODE_LOWER : convert to lower case.
|
||||
* @THUNAR_SBR_CASE_RENAMER_MODE_UPPER : convert to upper case.
|
||||
* @THUNAR_SBR_CASE_RENAMER_MODE_TITLE : convert to title case.
|
||||
* @THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER : convert to First character uppercase.
|
||||
*
|
||||
* The operation mode for the #ThunarSbrCaseRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_CASE_RENAMER_MODE_LOWER,
|
||||
THUNAR_SBR_CASE_RENAMER_MODE_UPPER,
|
||||
THUNAR_SBR_CASE_RENAMER_MODE_TITLE,
|
||||
THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER,
|
||||
} ThunarSbrCaseRenamerMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_case_renamer_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#define THUNAR_SBR_TYPE_INSERT_MODE (thunar_sbr_insert_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrInsertMode:
|
||||
* @THUNAR_SBR_INSERT_MODE_INSERT : insert characters.
|
||||
* @THUNAR_SBR_INSERT_MODE_OVERWRITE : overwrite existing characters.
|
||||
*
|
||||
* The operation mode for the #ThunarSbrInsertRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_INSERT_MODE_INSERT,
|
||||
THUNAR_SBR_INSERT_MODE_OVERWRITE,
|
||||
} ThunarSbrInsertMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_insert_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#define THUNAR_SBR_TYPE_NUMBER_MODE (thunar_sbr_number_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrNumberMode:
|
||||
* @THUNAR_SBR_NUMBER_MODE_123 : 1, 2, 3, ...
|
||||
* @THUNAR_SBR_NUMBER_MODE_010203 : 01, 02, 03, ...
|
||||
* @THUNAR_SBR_NUMBER_MODE_001002003 : 001, 002, 003, ...
|
||||
* @THUNAR_SBR_NUMBER_MODE_000100020003 : 0001, 0002, 0003, ...
|
||||
* @THUNAR_SBR_NUMBER_MODE_000100020003 : 00001, 00002, 00003, ...
|
||||
* @THUNAR_SBR_NUMBER_MODE_ABC : a, b, c, ...
|
||||
*
|
||||
* The numbering mode for the #ThunarSbrNumberRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_NUMBER_MODE_123,
|
||||
THUNAR_SBR_NUMBER_MODE_010203,
|
||||
THUNAR_SBR_NUMBER_MODE_001002003,
|
||||
THUNAR_SBR_NUMBER_MODE_000100020003,
|
||||
THUNAR_SBR_NUMBER_MODE_000010000200003,
|
||||
THUNAR_SBR_NUMBER_MODE_ABC,
|
||||
} ThunarSbrNumberMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_number_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#define THUNAR_SBR_TYPE_OFFSET_MODE (thunar_sbr_offset_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrOffsetMode:
|
||||
* @THUNAR_SBR_OFFSET_MODE_LEFT : offset starting from the left.
|
||||
* @THUNAR_SBR_OFFSET_MODE_RIGHT : offset starting from the right.
|
||||
*
|
||||
* The offset mode for the #ThunarSbrInsertRenamer and the
|
||||
* #ThunarSbrRemoveRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_OFFSET_MODE_LEFT,
|
||||
THUNAR_SBR_OFFSET_MODE_RIGHT,
|
||||
} ThunarSbrOffsetMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_offset_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#define THUNAR_SBR_TYPE_TEXT_MODE (thunar_sbr_text_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrTextMode:
|
||||
* @THUNAR_SBR_TEXT_MODE_OTN : Old Name - Text - Number
|
||||
* @THUNAR_SBR_TEXT_MODE_NTO : Number - Text - Old Name
|
||||
* @THUNAR_SBR_TEXT_MODE_TN : Text - Number
|
||||
* @THUNAR_SBR_TEXT_MODE_NT : Number - Text
|
||||
*
|
||||
* The text mode for the #ThunarSbrNumberRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_TEXT_MODE_OTN,
|
||||
THUNAR_SBR_TEXT_MODE_NTO,
|
||||
THUNAR_SBR_TEXT_MODE_TN,
|
||||
THUNAR_SBR_TEXT_MODE_NT,
|
||||
} ThunarSbrTextMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_text_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#define THUNAR_SBR_TYPE_DATE_MODE (thunar_sbr_date_mode_get_type ())
|
||||
|
||||
/**
|
||||
* ThunarSbrDateMode:
|
||||
* @THUNAR_SBR_DATE_MODE_NOW : Current Time
|
||||
* @THUNAR_SBR_DATE_MODE_ATIME : Access Time
|
||||
* @THUNAR_SBR_DATE_MODE_MTIME : Modification Time
|
||||
* @THUNAR_SBR_DATE_MODE_TAKEN : Picture Taken Time
|
||||
*
|
||||
* The date mode for the #ThunarSbrDateRenamer.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_SBR_DATE_MODE_NOW,
|
||||
THUNAR_SBR_DATE_MODE_ATIME,
|
||||
THUNAR_SBR_DATE_MODE_MTIME,
|
||||
#ifdef HAVE_EXIF
|
||||
THUNAR_SBR_DATE_MODE_TAKEN,
|
||||
#endif
|
||||
} ThunarSbrDateMode;
|
||||
|
||||
GType
|
||||
thunar_sbr_date_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
void
|
||||
thunar_sbr_register_enum_types (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_ENUM_TYPES_H__ */
|
||||
578
plugins/thunar-sbr/thunar-sbr-insert-renamer.c
Normal file
578
plugins/thunar-sbr/thunar-sbr-insert-renamer.c
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-sbr/thunar-sbr-insert-renamer.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_MODE,
|
||||
PROP_OFFSET,
|
||||
PROP_OFFSET_MODE,
|
||||
PROP_TEXT,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_finalize (GObject *object);
|
||||
static void
|
||||
thunar_sbr_insert_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_insert_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gchar *
|
||||
thunar_sbr_insert_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrInsertRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrInsertRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
ThunarSbrInsertMode mode;
|
||||
guint offset;
|
||||
ThunarSbrOffsetMode offset_mode;
|
||||
gchar *text;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrInsertRenamer, thunar_sbr_insert_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_class_init (ThunarSbrInsertRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_sbr_insert_renamer_finalize;
|
||||
gobject_class->get_property = thunar_sbr_insert_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_insert_renamer_set_property;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_insert_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrInsertRenamer:mode:
|
||||
*
|
||||
* The #ThunarSbrInsertMode to use.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MODE,
|
||||
g_param_spec_enum ("mode", "mode", "mode",
|
||||
THUNAR_SBR_TYPE_INSERT_MODE,
|
||||
THUNAR_SBR_INSERT_MODE_INSERT,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrInsertRenamer:offset:
|
||||
*
|
||||
* The starting offset at which to insert/overwrite.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OFFSET,
|
||||
g_param_spec_uint ("offset",
|
||||
"offset",
|
||||
"offset",
|
||||
0, G_MAXUINT, 1,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrInsertRenamer:offset-mode:
|
||||
*
|
||||
* The offset mode for the renamer.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OFFSET_MODE,
|
||||
g_param_spec_enum ("offset-mode",
|
||||
"offset-mode",
|
||||
"offset-mode",
|
||||
THUNAR_SBR_TYPE_OFFSET_MODE,
|
||||
THUNAR_SBR_OFFSET_MODE_LEFT,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrInsertRenamer:text:
|
||||
*
|
||||
* The text to insert/overwrite.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_TEXT,
|
||||
g_param_spec_string ("text",
|
||||
"text",
|
||||
"text",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_init (ThunarSbrInsertRenamer *insert_renamer)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
GtkAdjustment *adjustment;
|
||||
AtkRelation *relation;
|
||||
GEnumClass *klass;
|
||||
AtkObject *object;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *combo;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *label;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *hbox;
|
||||
guint n;
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_box_pack_start (GTK_BOX (insert_renamer), grid, TRUE, TRUE, 0);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_INSERT_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (insert_renamer), "mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 0, 0, 1, 1);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Text:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
||||
g_object_bind_property (G_OBJECT (entry), "text", G_OBJECT (insert_renamer), "text", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_hexpand (entry, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), entry, 2, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
|
||||
gtk_widget_show (entry);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_At position:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 2, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_grid_attach (GTK_GRID (grid), hbox, 2, 1, 1, 1);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
spinner = gtk_spin_button_new_with_range (0u, G_MAXUINT, 1u);
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (spinner), 4);
|
||||
gtk_entry_set_alignment (GTK_ENTRY (spinner), 1.0f);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (spinner), TRUE);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner), 0);
|
||||
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
|
||||
gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (spinner), TRUE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
|
||||
gtk_widget_show (spinner);
|
||||
|
||||
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spinner));
|
||||
g_object_bind_property (G_OBJECT (insert_renamer), "offset", G_OBJECT (adjustment), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (spinner);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_OFFSET_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (insert_renamer), "offset-mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_finalize (GObject *object)
|
||||
{
|
||||
ThunarSbrInsertRenamer *insert_renamer = THUNAR_SBR_INSERT_RENAMER (object);
|
||||
|
||||
/* release the text */
|
||||
g_free (insert_renamer->text);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_sbr_insert_renamer_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrInsertRenamer *insert_renamer = THUNAR_SBR_INSERT_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_insert_renamer_get_mode (insert_renamer));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
g_value_set_uint (value, thunar_sbr_insert_renamer_get_offset (insert_renamer));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_insert_renamer_get_offset_mode (insert_renamer));
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, thunar_sbr_insert_renamer_get_text (insert_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_insert_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrInsertRenamer *insert_renamer = THUNAR_SBR_INSERT_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
thunar_sbr_insert_renamer_set_mode (insert_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
thunar_sbr_insert_renamer_set_offset (insert_renamer, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET_MODE:
|
||||
thunar_sbr_insert_renamer_set_offset_mode (insert_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
thunar_sbr_insert_renamer_set_text (insert_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_insert_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrInsertRenamer *insert_renamer = THUNAR_SBR_INSERT_RENAMER (renamer);
|
||||
const gchar *t;
|
||||
const gchar *s;
|
||||
GString *result;
|
||||
guint text_length;
|
||||
guint offset;
|
||||
|
||||
/* check if we have any text to insert/overwrite */
|
||||
if (G_UNLIKELY (insert_renamer->text == NULL || *insert_renamer->text == '\0'))
|
||||
return g_strdup (text);
|
||||
|
||||
/* determine the input text length */
|
||||
text_length = g_utf8_strlen (text, -1);
|
||||
|
||||
/* determine the real offset and check if it's valid */
|
||||
offset = (insert_renamer->offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT) ? insert_renamer->offset : (text_length - insert_renamer->offset);
|
||||
if (G_UNLIKELY (offset > text_length))
|
||||
return g_strdup (text);
|
||||
|
||||
/* allocate space for the result */
|
||||
result = g_string_sized_new (2 * text_length);
|
||||
|
||||
/* determine the text pointer for the offset */
|
||||
s = g_utf8_offset_to_pointer (text, offset);
|
||||
|
||||
/* add the text before the insert/overwrite offset */
|
||||
g_string_append_len (result, text, s - text);
|
||||
|
||||
/* add the text to insert */
|
||||
g_string_append (result, insert_renamer->text);
|
||||
|
||||
/* skip over the input text if overwriting */
|
||||
if (insert_renamer->mode == THUNAR_SBR_INSERT_MODE_OVERWRITE)
|
||||
{
|
||||
/* skip over the number of characters in the overwrite text */
|
||||
for (t = insert_renamer->text; *s != '\0' && *t != '\0'; s = g_utf8_next_char (s), t = g_utf8_next_char (t))
|
||||
;
|
||||
}
|
||||
|
||||
/* append the remaining text */
|
||||
g_string_append (result, s);
|
||||
|
||||
/* return the result */
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrInsertRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrInsertRenamer.
|
||||
**/
|
||||
ThunarSbrInsertRenamer *
|
||||
thunar_sbr_insert_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_INSERT_RENAMER,
|
||||
"name", _("Insert / Overwrite"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_get_mode:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the mode of the @insert_renamer.
|
||||
*
|
||||
* Return value: the mode of @insert_renamer.
|
||||
**/
|
||||
ThunarSbrInsertMode
|
||||
thunar_sbr_insert_renamer_get_mode (ThunarSbrInsertRenamer *insert_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer), THUNAR_SBR_INSERT_MODE_INSERT);
|
||||
return insert_renamer->mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_set_mode:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @mode : the new #ThunarSbrInsertMode for @insert_renamer.
|
||||
*
|
||||
* Sets the mode of @insert_renamer to @mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_mode (ThunarSbrInsertRenamer *insert_renamer,
|
||||
ThunarSbrInsertMode mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer));
|
||||
|
||||
/* check if we have a new mode */
|
||||
if (G_LIKELY (insert_renamer->mode != mode))
|
||||
{
|
||||
/* apply the new mode */
|
||||
insert_renamer->mode = mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (insert_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (insert_renamer), "mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_get_offset:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the offset for the @insert_renamer.
|
||||
*
|
||||
* Return value: the offset for @insert_renamer.
|
||||
**/
|
||||
guint
|
||||
thunar_sbr_insert_renamer_get_offset (ThunarSbrInsertRenamer *insert_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer), 0);
|
||||
return insert_renamer->offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_set_offset:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @offset : the new offset for @insert_renamer.
|
||||
*
|
||||
* Sets the offset for @insert_renamer to @offset.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_offset (ThunarSbrInsertRenamer *insert_renamer,
|
||||
guint offset)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer));
|
||||
|
||||
/* check if we have a new offset */
|
||||
if (G_LIKELY (insert_renamer->offset != offset))
|
||||
{
|
||||
/* apply the new offset */
|
||||
insert_renamer->offset = offset;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (insert_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (insert_renamer), "offset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_get_offset_mode:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the offset mode for the @insert_renamer.
|
||||
*
|
||||
* Return value: the offset mode for @insert_renamer.
|
||||
**/
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_insert_renamer_get_offset_mode (ThunarSbrInsertRenamer *insert_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer), THUNAR_SBR_OFFSET_MODE_LEFT);
|
||||
return insert_renamer->offset_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_set_offset_mode:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @offset_mode : the new offset mode for @insert_renamer.
|
||||
*
|
||||
* Sets the offset mode for @insert_renamer to @offset_mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_offset_mode (ThunarSbrInsertRenamer *insert_renamer,
|
||||
ThunarSbrOffsetMode offset_mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer));
|
||||
|
||||
/* check if we have a new setting */
|
||||
if (G_LIKELY (insert_renamer->offset_mode != offset_mode))
|
||||
{
|
||||
/* apply the new setting */
|
||||
insert_renamer->offset_mode = offset_mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (insert_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (insert_renamer), "offset-mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_get_text:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
*
|
||||
* Returns the text for the @insert_renamer.
|
||||
*
|
||||
* Return value: the text for @insert_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_insert_renamer_get_text (ThunarSbrInsertRenamer *insert_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer), NULL);
|
||||
return insert_renamer->text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_insert_renamer_set_text:
|
||||
* @insert_renamer : a #ThunarSbrInsertRenamer.
|
||||
* @text : the new text for @insert_renamer.
|
||||
*
|
||||
* Sets the text for @insert_renamer to @text.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_text (ThunarSbrInsertRenamer *insert_renamer,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_INSERT_RENAMER (insert_renamer));
|
||||
|
||||
/* check if we have a new text */
|
||||
if (G_LIKELY (g_strcmp0 (insert_renamer->text, text) != 0))
|
||||
{
|
||||
/* apply the new text */
|
||||
g_free (insert_renamer->text);
|
||||
insert_renamer->text = g_strdup (text);
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (insert_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (insert_renamer), "text");
|
||||
}
|
||||
}
|
||||
72
plugins/thunar-sbr/thunar-sbr-insert-renamer.h
Normal file
72
plugins/thunar-sbr/thunar-sbr-insert-renamer.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_INSERT_RENAMER_H__
|
||||
#define __THUNAR_SBR_INSERT_RENAMER_H__
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrInsertRenamerClass ThunarSbrInsertRenamerClass;
|
||||
typedef struct _ThunarSbrInsertRenamer ThunarSbrInsertRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_INSERT_RENAMER (thunar_sbr_insert_renamer_get_type ())
|
||||
#define THUNAR_SBR_INSERT_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_INSERT_RENAMER, ThunarSbrInsertRenamer))
|
||||
#define THUNAR_SBR_INSERT_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_INSERT_RENAMER, ThunarSbrInsertRenamerClass))
|
||||
#define THUNAR_SBR_IS_INSERT_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_INSERT_RENAMER))
|
||||
#define THUNAR_SBR_IS_INSERT_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_INSERT_RENAMER))
|
||||
#define THUNAR_SBR_INSERT_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_INSERT_RENAMER, ThunarSbrInsertRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_insert_renamer_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_insert_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrInsertRenamer *
|
||||
thunar_sbr_insert_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
ThunarSbrInsertMode
|
||||
thunar_sbr_insert_renamer_get_mode (ThunarSbrInsertRenamer *insert_renamer);
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_mode (ThunarSbrInsertRenamer *insert_renamer,
|
||||
ThunarSbrInsertMode mode);
|
||||
|
||||
guint
|
||||
thunar_sbr_insert_renamer_get_offset (ThunarSbrInsertRenamer *insert_renamer);
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_offset (ThunarSbrInsertRenamer *insert_renamer,
|
||||
guint offset);
|
||||
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_insert_renamer_get_offset_mode (ThunarSbrInsertRenamer *insert_renamer);
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_offset_mode (ThunarSbrInsertRenamer *insert_renamer,
|
||||
ThunarSbrOffsetMode offset_mode);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_insert_renamer_get_text (ThunarSbrInsertRenamer *insert_renamer);
|
||||
void
|
||||
thunar_sbr_insert_renamer_set_text (ThunarSbrInsertRenamer *insert_renamer,
|
||||
const gchar *text);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_INSERT_RENAMER_H__ */
|
||||
715
plugins/thunar-sbr/thunar-sbr-number-renamer.c
Normal file
715
plugins/thunar-sbr/thunar-sbr-number-renamer.c
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-sbr/thunar-sbr-number-renamer.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_MODE,
|
||||
PROP_START,
|
||||
PROP_TEXT,
|
||||
PROP_TEXT_MODE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_finalize (GObject *object);
|
||||
static void
|
||||
thunar_sbr_number_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_number_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_number_renamer_realize (GtkWidget *widget);
|
||||
static gchar *
|
||||
thunar_sbr_number_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
static void
|
||||
thunar_sbr_number_renamer_update (ThunarSbrNumberRenamer *number_renamer);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrNumberRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrNumberRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
|
||||
GtkWidget *start_entry;
|
||||
|
||||
ThunarSbrNumberMode mode;
|
||||
gchar *start;
|
||||
gchar *text;
|
||||
ThunarSbrTextMode text_mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrNumberRenamer, thunar_sbr_number_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_class_init (ThunarSbrNumberRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GtkWidgetClass *gtkwidget_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_sbr_number_renamer_finalize;
|
||||
gobject_class->get_property = thunar_sbr_number_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_number_renamer_set_property;
|
||||
|
||||
gtkwidget_class = GTK_WIDGET_CLASS (klass);
|
||||
gtkwidget_class->realize = thunar_sbr_number_renamer_realize;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_number_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrNumberRenamer:mode:
|
||||
*
|
||||
* The #ThunarSbrNumberMode to use.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MODE,
|
||||
g_param_spec_enum ("mode", "mode", "mode",
|
||||
THUNAR_SBR_TYPE_NUMBER_MODE,
|
||||
THUNAR_SBR_NUMBER_MODE_123,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrNumberRenamer:start:
|
||||
*
|
||||
* The starting value according to the #ThunarSbrNumberMode.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_START,
|
||||
g_param_spec_string ("start",
|
||||
"start",
|
||||
"start",
|
||||
"1",
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrNumberRenamer:text:
|
||||
*
|
||||
* The additional text, depending on the #ThunarSbrTextMode.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_TEXT,
|
||||
g_param_spec_string ("text",
|
||||
"text",
|
||||
"text",
|
||||
". ",
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrNumberRenamer:text-mode:
|
||||
*
|
||||
* The text mode for the renamer.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_TEXT_MODE,
|
||||
g_param_spec_enum ("text-mode",
|
||||
"text-mode",
|
||||
"text-mode",
|
||||
THUNAR_SBR_TYPE_TEXT_MODE,
|
||||
THUNAR_SBR_TEXT_MODE_NTO,
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_init (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
AtkRelation *relation;
|
||||
GEnumClass *klass;
|
||||
AtkObject *object;
|
||||
GtkWidget *combo;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *label;
|
||||
GtkWidget *grid;
|
||||
guint n;
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_box_pack_start (GTK_BOX (number_renamer), grid, FALSE, FALSE, 0);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Number Format:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_NUMBER_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (number_renamer), "mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 1, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
/* set Atk label relation for the combo */
|
||||
object = gtk_widget_get_accessible (combo);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
number_renamer->start_entry = gtk_entry_new ();
|
||||
gtk_entry_set_max_length (GTK_ENTRY (number_renamer->start_entry), 8);
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (number_renamer->start_entry), 3);
|
||||
gtk_entry_set_alignment (GTK_ENTRY (number_renamer->start_entry), 1.0f);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (number_renamer->start_entry), TRUE);
|
||||
gtk_widget_set_hexpand (GTK_WIDGET (number_renamer->start_entry), TRUE);
|
||||
g_object_bind_property (G_OBJECT (number_renamer->start_entry), "text", G_OBJECT (number_renamer), "start", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), number_renamer->start_entry, 3, 0, 1, 1);
|
||||
gtk_widget_show (number_renamer->start_entry);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Start With:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), number_renamer->start_entry);
|
||||
gtk_widget_show (label);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (number_renamer->start_entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Text _Format:"));
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_TEXT_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (number_renamer), "text-mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 1, 1, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
/* set Atk label relation for the combo */
|
||||
object = gtk_widget_get_accessible (combo);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (entry), 12);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
||||
g_object_bind_property (G_OBJECT (entry), "text", G_OBJECT (number_renamer), "text", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), entry, 3, 1, 1, 1);
|
||||
gtk_widget_show (entry);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Text:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 1, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
|
||||
gtk_widget_show (label);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_finalize (GObject *object)
|
||||
{
|
||||
ThunarSbrNumberRenamer *number_renamer = THUNAR_SBR_NUMBER_RENAMER (object);
|
||||
|
||||
/* release renamer resources */
|
||||
g_free (number_renamer->start);
|
||||
g_free (number_renamer->text);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_sbr_number_renamer_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrNumberRenamer *number_renamer = THUNAR_SBR_NUMBER_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_number_renamer_get_mode (number_renamer));
|
||||
break;
|
||||
|
||||
case PROP_START:
|
||||
g_value_set_string (value, thunar_sbr_number_renamer_get_start (number_renamer));
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, thunar_sbr_number_renamer_get_text (number_renamer));
|
||||
break;
|
||||
|
||||
case PROP_TEXT_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_number_renamer_get_text_mode (number_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrNumberRenamer *number_renamer = THUNAR_SBR_NUMBER_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODE:
|
||||
thunar_sbr_number_renamer_set_mode (number_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_START:
|
||||
thunar_sbr_number_renamer_set_start (number_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
thunar_sbr_number_renamer_set_text (number_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_TEXT_MODE:
|
||||
thunar_sbr_number_renamer_set_text_mode (number_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_realize (GtkWidget *widget)
|
||||
{
|
||||
/* realize the widget */
|
||||
(*GTK_WIDGET_CLASS (thunar_sbr_number_renamer_parent_class)->realize) (widget);
|
||||
|
||||
/* update the state */
|
||||
thunar_sbr_number_renamer_update (THUNAR_SBR_NUMBER_RENAMER (widget));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_number_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrNumberRenamer *number_renamer = THUNAR_SBR_NUMBER_RENAMER (renamer);
|
||||
gboolean invalid = TRUE;
|
||||
gchar *endp;
|
||||
gchar *name;
|
||||
gchar *number = NULL;
|
||||
guint start = 0;
|
||||
|
||||
/* check whether "start" is valid for the "mode" */
|
||||
if (number_renamer->mode < THUNAR_SBR_NUMBER_MODE_ABC)
|
||||
{
|
||||
/* "start" must be a positive number */
|
||||
start = strtoul (number_renamer->start, &endp, 10);
|
||||
invalid = (endp <= number_renamer->start || *endp != '\0');
|
||||
}
|
||||
else if (number_renamer->mode == THUNAR_SBR_NUMBER_MODE_ABC)
|
||||
{
|
||||
/* "start" property must be 'a', 'b', 'c', etc. */
|
||||
start = *number_renamer->start;
|
||||
invalid = (strlen (number_renamer->start) != 1
|
||||
|| g_unichar_tolower (start) < 'a'
|
||||
|| g_unichar_tolower (start) > 'z');
|
||||
}
|
||||
|
||||
/* check if we have invalid settings */
|
||||
if (G_UNLIKELY (invalid))
|
||||
return g_strdup (text);
|
||||
|
||||
/* format the number */
|
||||
switch (number_renamer->mode)
|
||||
{
|
||||
case THUNAR_SBR_NUMBER_MODE_123:
|
||||
number = g_strdup_printf ("%u", start + idx);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_NUMBER_MODE_010203:
|
||||
number = g_strdup_printf ("%02u", start + idx);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_NUMBER_MODE_001002003:
|
||||
number = g_strdup_printf ("%03u", start + idx);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_NUMBER_MODE_000100020003:
|
||||
number = g_strdup_printf ("%04u", start + idx);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_NUMBER_MODE_000010000200003:
|
||||
number = g_strdup_printf ("%05u", start + idx);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_NUMBER_MODE_ABC:
|
||||
if (start >= 'a' && start <= 'z')
|
||||
number = g_strdup_printf ("%c", (gchar) (MIN (start + idx, 'z')));
|
||||
else if (start >= 'A' && start <= 'Z')
|
||||
number = g_strdup_printf ("%c", (gchar) (MIN (start + idx, 'Z')));
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* format the text */
|
||||
switch (number_renamer->text_mode)
|
||||
{
|
||||
case THUNAR_SBR_TEXT_MODE_OTN:
|
||||
name = g_strconcat (text, number_renamer->text, number, NULL);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_TEXT_MODE_NTO:
|
||||
name = g_strconcat (number, number_renamer->text, text, NULL);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_TEXT_MODE_TN:
|
||||
name = g_strconcat (number_renamer->text, number, NULL);
|
||||
break;
|
||||
|
||||
case THUNAR_SBR_TEXT_MODE_NT:
|
||||
name = g_strconcat (number, number_renamer->text, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* release the number */
|
||||
g_free (number);
|
||||
|
||||
/* return the new name */
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_number_renamer_update (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
gboolean invalid = TRUE;
|
||||
gchar *endp;
|
||||
|
||||
/* check whether "start" is valid for the "mode" */
|
||||
if (number_renamer->mode < THUNAR_SBR_NUMBER_MODE_ABC)
|
||||
{
|
||||
/* "start" must be a positive number */
|
||||
strtoul (number_renamer->start, &endp, 10);
|
||||
invalid = (endp <= number_renamer->start || *endp != '\0');
|
||||
}
|
||||
else if (number_renamer->mode == THUNAR_SBR_NUMBER_MODE_ABC)
|
||||
{
|
||||
/* "start" property must be 'a', 'b', 'c', etc. */
|
||||
invalid = (strlen (number_renamer->start) != 1
|
||||
|| g_unichar_tolower (*number_renamer->start) < 'a'
|
||||
|| g_unichar_tolower (*number_renamer->start) > 'z');
|
||||
}
|
||||
|
||||
/* check if the start entry is realized */
|
||||
if (gtk_widget_get_realized (number_renamer->start_entry))
|
||||
{
|
||||
/* highlight invalid input by using theme specific colors */
|
||||
if (G_UNLIKELY (invalid))
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (number_renamer->start_entry)), "error");
|
||||
else
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (number_renamer->start_entry)), "error");
|
||||
}
|
||||
|
||||
/* notify everybody that we have a new state */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (number_renamer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrNumberRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrNumberRenamer.
|
||||
**/
|
||||
ThunarSbrNumberRenamer *
|
||||
thunar_sbr_number_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_NUMBER_RENAMER,
|
||||
"name", _("Numbering"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_get_mode:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
*
|
||||
* Returns the mode of the @number_renamer.
|
||||
*
|
||||
* Return value: the mode of @number_renamer.
|
||||
**/
|
||||
ThunarSbrNumberMode
|
||||
thunar_sbr_number_renamer_get_mode (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer), THUNAR_SBR_NUMBER_MODE_123);
|
||||
return number_renamer->mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_set_mode:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
* @mode : the new #ThunarSbrNumberMode for @number_renamer.
|
||||
*
|
||||
* Sets the mode of @number_renamer to @mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_number_renamer_set_mode (ThunarSbrNumberRenamer *number_renamer,
|
||||
ThunarSbrNumberMode mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer));
|
||||
|
||||
/* check if we have a new mode */
|
||||
if (G_LIKELY (number_renamer->mode != mode))
|
||||
{
|
||||
/* apply the new mode */
|
||||
number_renamer->mode = mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_number_renamer_update (number_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (number_renamer), "mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_get_start:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
*
|
||||
* Returns the start for the @number_renamer.
|
||||
*
|
||||
* Return value: the start for @number_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_number_renamer_get_start (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer), NULL);
|
||||
return number_renamer->start;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_set_start:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
* @start : the new start for @number_renamer.
|
||||
*
|
||||
* Sets the start for @number_renamer to @start.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_number_renamer_set_start (ThunarSbrNumberRenamer *number_renamer,
|
||||
const gchar *start)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer));
|
||||
|
||||
/* check if we have a new start */
|
||||
if (g_strcmp0 (number_renamer->start, start) != 0)
|
||||
{
|
||||
/* apply the new start */
|
||||
g_free (number_renamer->start);
|
||||
number_renamer->start = g_strdup (start);
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_number_renamer_update (number_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (number_renamer), "start");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_get_text:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
*
|
||||
* Returns the text for the @number_renamer.
|
||||
*
|
||||
* Return value: the text for @number_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_number_renamer_get_text (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer), NULL);
|
||||
return number_renamer->text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_set_text:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
* @text : the new text for @number_renamer.
|
||||
*
|
||||
* Sets the text for @number_renamer to @text.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_number_renamer_set_text (ThunarSbrNumberRenamer *number_renamer,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer));
|
||||
|
||||
/* check if we have a new text */
|
||||
if (G_LIKELY (g_strcmp0 (number_renamer->text, text) != 0))
|
||||
{
|
||||
/* apply the new text */
|
||||
g_free (number_renamer->text);
|
||||
number_renamer->text = g_strdup (text);
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_number_renamer_update (number_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (number_renamer), "text");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_get_text_mode:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
*
|
||||
* Returns the text mode for the @number_renamer.
|
||||
*
|
||||
* Return value: the text mode for @number_renamer.
|
||||
**/
|
||||
ThunarSbrTextMode
|
||||
thunar_sbr_number_renamer_get_text_mode (ThunarSbrNumberRenamer *number_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer), THUNAR_SBR_TEXT_MODE_NTO);
|
||||
return number_renamer->text_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_number_renamer_set_offset_mode:
|
||||
* @number_renamer : a #ThunarSbrNumberRenamer.
|
||||
* @text_mode : the new text mode for @number_renamer.
|
||||
*
|
||||
* Sets the text mode for @number_renamer to @text_mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_number_renamer_set_text_mode (ThunarSbrNumberRenamer *number_renamer,
|
||||
ThunarSbrTextMode text_mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_NUMBER_RENAMER (number_renamer));
|
||||
|
||||
/* check if we have a new setting */
|
||||
if (G_LIKELY (number_renamer->text_mode != text_mode))
|
||||
{
|
||||
/* apply the new setting */
|
||||
number_renamer->text_mode = text_mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_number_renamer_update (number_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (number_renamer), "text-mode");
|
||||
}
|
||||
}
|
||||
72
plugins/thunar-sbr/thunar-sbr-number-renamer.h
Normal file
72
plugins/thunar-sbr/thunar-sbr-number-renamer.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_NUMBER_RENAMER_H__
|
||||
#define __THUNAR_SBR_NUMBER_RENAMER_H__
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrNumberRenamerClass ThunarSbrNumberRenamerClass;
|
||||
typedef struct _ThunarSbrNumberRenamer ThunarSbrNumberRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_NUMBER_RENAMER (thunar_sbr_number_renamer_get_type ())
|
||||
#define THUNAR_SBR_NUMBER_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_NUMBER_RENAMER, ThunarSbrNumberRenamer))
|
||||
#define THUNAR_SBR_NUMBER_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_NUMBER_RENAMER, ThunarSbrNumberRenamerClass))
|
||||
#define THUNAR_SBR_IS_NUMBER_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_NUMBER_RENAMER))
|
||||
#define THUNAR_SBR_IS_NUMBER_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_NUMBER_RENAMER))
|
||||
#define THUNAR_SBR_NUMBER_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_NUMBER_RENAMER, ThunarSbrNumberRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_number_renamer_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_number_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrNumberRenamer *
|
||||
thunar_sbr_number_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
ThunarSbrNumberMode
|
||||
thunar_sbr_number_renamer_get_mode (ThunarSbrNumberRenamer *number_renamer);
|
||||
void
|
||||
thunar_sbr_number_renamer_set_mode (ThunarSbrNumberRenamer *number_renamer,
|
||||
ThunarSbrNumberMode mode);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_number_renamer_get_start (ThunarSbrNumberRenamer *number_renamer);
|
||||
void
|
||||
thunar_sbr_number_renamer_set_start (ThunarSbrNumberRenamer *number_renamer,
|
||||
const gchar *start);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_number_renamer_get_text (ThunarSbrNumberRenamer *number_renamer);
|
||||
void
|
||||
thunar_sbr_number_renamer_set_text (ThunarSbrNumberRenamer *number_renamer,
|
||||
const gchar *text);
|
||||
|
||||
ThunarSbrTextMode
|
||||
thunar_sbr_number_renamer_get_text_mode (ThunarSbrNumberRenamer *number_renamer);
|
||||
void
|
||||
thunar_sbr_number_renamer_set_text_mode (ThunarSbrNumberRenamer *number_renamer,
|
||||
ThunarSbrTextMode text_mode);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_NUMBER_RENAMER_H__ */
|
||||
100
plugins/thunar-sbr/thunar-sbr-plugin.c
Normal file
100
plugins/thunar-sbr/thunar-sbr-plugin.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-case-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-date-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-insert-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-number-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-provider.h>
|
||||
#include <thunar-sbr/thunar-sbr-remove-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-replace-renamer.h>
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types);
|
||||
|
||||
|
||||
|
||||
static GType type_list[1];
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin)
|
||||
{
|
||||
const gchar *mismatch;
|
||||
|
||||
/* verify that the thunarx versions are compatible */
|
||||
mismatch = thunarx_check_version (THUNARX_MAJOR_VERSION, THUNARX_MINOR_VERSION, THUNARX_MICRO_VERSION);
|
||||
if (G_UNLIKELY (mismatch != NULL))
|
||||
{
|
||||
g_warning ("Version mismatch: %s", mismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Initializing ThunarSbr extension");
|
||||
#endif
|
||||
|
||||
/* register the enum types for this plugin */
|
||||
thunar_sbr_register_enum_types (plugin);
|
||||
|
||||
/* register the classes provided by this plugin */
|
||||
thunar_sbr_case_renamer_register_type (plugin);
|
||||
thunar_sbr_insert_renamer_register_type (plugin);
|
||||
thunar_sbr_number_renamer_register_type (plugin);
|
||||
thunar_sbr_provider_register_type (plugin);
|
||||
thunar_sbr_remove_renamer_register_type (plugin);
|
||||
thunar_sbr_replace_renamer_register_type (plugin);
|
||||
thunar_sbr_date_renamer_register_type (plugin);
|
||||
|
||||
/* setup the plugin provider type list */
|
||||
type_list[0] = THUNAR_SBR_TYPE_PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Shutting down ThunarSbr extension");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types)
|
||||
{
|
||||
*types = type_list;
|
||||
*n_types = G_N_ELEMENTS (type_list);
|
||||
}
|
||||
97
plugins/thunar-sbr/thunar-sbr-provider.c
Normal file
97
plugins/thunar-sbr/thunar-sbr-provider.c
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-case-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-date-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-insert-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-number-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-provider.h>
|
||||
#include <thunar-sbr/thunar-sbr-remove-renamer.h>
|
||||
#include <thunar-sbr/thunar-sbr-replace-renamer.h>
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_provider_renamer_provider_init (ThunarxRenamerProviderIface *iface);
|
||||
static GList *
|
||||
thunar_sbr_provider_get_renamers (ThunarxRenamerProvider *renamer_provider);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrProviderClass
|
||||
{
|
||||
GObjectClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrProvider
|
||||
{
|
||||
GObject __parent__;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE_WITH_CODE (ThunarSbrProvider,
|
||||
thunar_sbr_provider,
|
||||
G_TYPE_OBJECT,
|
||||
THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_RENAMER_PROVIDER,
|
||||
thunar_sbr_provider_renamer_provider_init));
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_provider_class_init (ThunarSbrProviderClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_provider_renamer_provider_init (ThunarxRenamerProviderIface *iface)
|
||||
{
|
||||
iface->get_renamers = thunar_sbr_provider_get_renamers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_provider_init (ThunarSbrProvider *sbr_provider)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_sbr_provider_get_renamers (ThunarxRenamerProvider *renamer_provider)
|
||||
{
|
||||
GList *renamers = NULL;
|
||||
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_replace_renamer_new ());
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_remove_renamer_new ());
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_number_renamer_new ());
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_insert_renamer_new ());
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_case_renamer_new ());
|
||||
renamers = g_list_prepend (renamers, thunar_sbr_date_renamer_new ());
|
||||
|
||||
return renamers;
|
||||
}
|
||||
45
plugins/thunar-sbr/thunar-sbr-provider.h
Normal file
45
plugins/thunar-sbr/thunar-sbr-provider.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_PROVIDER_H__
|
||||
#define __THUNAR_SBR_PROVIDER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrProviderClass ThunarSbrProviderClass;
|
||||
typedef struct _ThunarSbrProvider ThunarSbrProvider;
|
||||
|
||||
#define THUNAR_SBR_TYPE_PROVIDER (thunar_sbr_provider_get_type ())
|
||||
#define THUNAR_SBR_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_PROVIDER, ThunarSbrProvider))
|
||||
#define THUNAR_SBR_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_PROVIDER, ThunarSbrProviderClass))
|
||||
#define THUNAR_SBR_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_PROVIDER))
|
||||
#define THUNAR_SBR_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_PROVIDER))
|
||||
#define THUNAR_SBR_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_PROVIDER, ThunarSbrProviderClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_provider_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_provider_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_PROVIDER_H__ */
|
||||
609
plugins/thunar-sbr/thunar-sbr-remove-renamer.c
Normal file
609
plugins/thunar-sbr/thunar-sbr-remove-renamer.c
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <thunar-sbr/thunar-sbr-remove-renamer.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_END_OFFSET,
|
||||
PROP_END_OFFSET_MODE,
|
||||
PROP_START_OFFSET,
|
||||
PROP_START_OFFSET_MODE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_remove_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_remove_renamer_realize (GtkWidget *widget);
|
||||
static gchar *
|
||||
thunar_sbr_remove_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
static void
|
||||
thunar_sbr_remove_renamer_update (ThunarSbrRemoveRenamer *remove_renamer);
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrRemoveRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrRemoveRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
GtkWidget *end_spinner;
|
||||
GtkWidget *start_spinner;
|
||||
guint end_offset;
|
||||
ThunarSbrOffsetMode end_offset_mode;
|
||||
guint start_offset;
|
||||
ThunarSbrOffsetMode start_offset_mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrRemoveRenamer, thunar_sbr_remove_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_class_init (ThunarSbrRemoveRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GtkWidgetClass *gtkwidget_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->get_property = thunar_sbr_remove_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_remove_renamer_set_property;
|
||||
|
||||
gtkwidget_class = GTK_WIDGET_CLASS (klass);
|
||||
gtkwidget_class->realize = thunar_sbr_remove_renamer_realize;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_remove_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrRemoveRenamer:end-offset:
|
||||
*
|
||||
* The end offset for the character removal.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_END_OFFSET,
|
||||
g_param_spec_uint ("end-offset",
|
||||
"end-offset",
|
||||
"end-offset",
|
||||
0, G_MAXUINT, 1,
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrRemoveRenamer:end-offset-mode:
|
||||
*
|
||||
* The end offset mode for the character removal.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_END_OFFSET_MODE,
|
||||
g_param_spec_enum ("end-offset-mode",
|
||||
"end-offset-mode",
|
||||
"end-offset-mode",
|
||||
THUNAR_SBR_TYPE_OFFSET_MODE,
|
||||
THUNAR_SBR_OFFSET_MODE_LEFT,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrRemoveRenamer:start-offset:
|
||||
*
|
||||
* The start offset for the character removal.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_START_OFFSET,
|
||||
g_param_spec_uint ("start-offset",
|
||||
"start-offset",
|
||||
"start-offset",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrRemoveRenamer:start-offset-mode:
|
||||
*
|
||||
* The start offset mode for the character removal.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_START_OFFSET_MODE,
|
||||
g_param_spec_enum ("start-offset-mode",
|
||||
"start-offset-mode",
|
||||
"start-offset-mode",
|
||||
THUNAR_SBR_TYPE_OFFSET_MODE,
|
||||
THUNAR_SBR_OFFSET_MODE_LEFT,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_init (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
GtkAdjustment *adjustment;
|
||||
AtkRelation *relation;
|
||||
GEnumClass *klass;
|
||||
AtkObject *object;
|
||||
GtkWidget *combo;
|
||||
GtkWidget *label;
|
||||
GtkWidget *grid;
|
||||
guint n;
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_box_pack_start (GTK_BOX (remove_renamer), grid, TRUE, TRUE, 0);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Remove _From Position:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
remove_renamer->start_spinner = gtk_spin_button_new_with_range (0u, G_MAXUINT, 1u);
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (remove_renamer->start_spinner), 4);
|
||||
gtk_entry_set_alignment (GTK_ENTRY (remove_renamer->start_spinner), 1.0f);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (remove_renamer->start_spinner), TRUE);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (remove_renamer->start_spinner), 0);
|
||||
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (remove_renamer->start_spinner), TRUE);
|
||||
gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (remove_renamer->start_spinner), TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), remove_renamer->start_spinner, 1, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), remove_renamer->start_spinner);
|
||||
gtk_widget_show (remove_renamer->start_spinner);
|
||||
|
||||
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (remove_renamer->start_spinner));
|
||||
g_object_bind_property (G_OBJECT (remove_renamer), "start-offset", G_OBJECT (adjustment), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (remove_renamer->start_spinner);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_OFFSET_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (remove_renamer), "start-offset-mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 2, 0, 1, 1);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_To Position:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
remove_renamer->end_spinner = gtk_spin_button_new_with_range (0u, G_MAXUINT, 1u);
|
||||
gtk_entry_set_width_chars (GTK_ENTRY (remove_renamer->end_spinner), 4);
|
||||
gtk_entry_set_alignment (GTK_ENTRY (remove_renamer->end_spinner), 1.0f);
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (remove_renamer->end_spinner), TRUE);
|
||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (remove_renamer->end_spinner), 0);
|
||||
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (remove_renamer->end_spinner), TRUE);
|
||||
gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (remove_renamer->end_spinner), TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), remove_renamer->end_spinner, 1, 1, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), remove_renamer->end_spinner);
|
||||
gtk_widget_show (remove_renamer->end_spinner);
|
||||
|
||||
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (remove_renamer->end_spinner));
|
||||
g_object_bind_property (G_OBJECT (remove_renamer), "end-offset", G_OBJECT (adjustment), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (remove_renamer->end_spinner);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
klass = g_type_class_ref (THUNAR_SBR_TYPE_OFFSET_MODE);
|
||||
for (n = 0; n < klass->n_values; ++n)
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _(klass->values[n].value_nick));
|
||||
g_object_bind_property (G_OBJECT (remove_renamer), "end-offset-mode", G_OBJECT (combo), "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_grid_attach (GTK_GRID (grid), combo, 2, 1, 1, 1);
|
||||
g_type_class_unref (klass);
|
||||
gtk_widget_show (combo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrRemoveRenamer *remove_renamer = THUNAR_SBR_REMOVE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_END_OFFSET:
|
||||
g_value_set_uint (value, thunar_sbr_remove_renamer_get_end_offset (remove_renamer));
|
||||
break;
|
||||
|
||||
case PROP_END_OFFSET_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_remove_renamer_get_end_offset_mode (remove_renamer));
|
||||
break;
|
||||
|
||||
case PROP_START_OFFSET:
|
||||
g_value_set_uint (value, thunar_sbr_remove_renamer_get_start_offset (remove_renamer));
|
||||
break;
|
||||
|
||||
case PROP_START_OFFSET_MODE:
|
||||
g_value_set_enum (value, thunar_sbr_remove_renamer_get_start_offset_mode (remove_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrRemoveRenamer *remove_renamer = THUNAR_SBR_REMOVE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_END_OFFSET:
|
||||
thunar_sbr_remove_renamer_set_end_offset (remove_renamer, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_END_OFFSET_MODE:
|
||||
thunar_sbr_remove_renamer_set_end_offset_mode (remove_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_START_OFFSET:
|
||||
thunar_sbr_remove_renamer_set_start_offset (remove_renamer, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_START_OFFSET_MODE:
|
||||
thunar_sbr_remove_renamer_set_start_offset_mode (remove_renamer, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_realize (GtkWidget *widget)
|
||||
{
|
||||
/* realize the renamer widget */
|
||||
(*GTK_WIDGET_CLASS (thunar_sbr_remove_renamer_parent_class)->realize) (widget);
|
||||
|
||||
/* update the renamer state */
|
||||
thunar_sbr_remove_renamer_update (THUNAR_SBR_REMOVE_RENAMER (widget));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_remove_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrRemoveRenamer *remove_renamer = THUNAR_SBR_REMOVE_RENAMER (renamer);
|
||||
const gchar *start_pointer;
|
||||
const gchar *end_pointer;
|
||||
GString *result;
|
||||
guint start_offset;
|
||||
guint text_length;
|
||||
guint end_offset;
|
||||
|
||||
/* determine the text length */
|
||||
text_length = g_utf8_strlen (text, -1);
|
||||
|
||||
/* determine the offsets for this file name */
|
||||
end_offset = (remove_renamer->end_offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT)
|
||||
? remove_renamer->end_offset
|
||||
: (text_length - remove_renamer->end_offset);
|
||||
start_offset = (remove_renamer->start_offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT)
|
||||
? remove_renamer->start_offset
|
||||
: (text_length - remove_renamer->start_offset);
|
||||
|
||||
/* check if anything should be removed */
|
||||
if (G_UNLIKELY (start_offset >= end_offset || end_offset > text_length))
|
||||
return g_strdup (text);
|
||||
|
||||
/* determine start and end pointers */
|
||||
end_pointer = g_utf8_offset_to_pointer (text, end_offset);
|
||||
start_pointer = g_utf8_offset_to_pointer (text, start_offset);
|
||||
|
||||
/* allocate the resulting string */
|
||||
result = g_string_sized_new (text_length);
|
||||
g_string_append_len (result, text, start_pointer - text);
|
||||
g_string_append (result, end_pointer);
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_remove_renamer_update (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
guint start_offset;
|
||||
guint end_offset;
|
||||
|
||||
/* check if the renamer is realized */
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (remove_renamer)))
|
||||
{
|
||||
/* check if start and end offset make sense */
|
||||
end_offset = (remove_renamer->end_offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT)
|
||||
? remove_renamer->end_offset
|
||||
: (G_MAXUINT - remove_renamer->end_offset);
|
||||
start_offset = (remove_renamer->start_offset_mode == THUNAR_SBR_OFFSET_MODE_LEFT)
|
||||
? remove_renamer->start_offset
|
||||
: (G_MAXUINT - remove_renamer->start_offset);
|
||||
|
||||
/* highlight invalid input by using theme specific colors */
|
||||
if (G_UNLIKELY (start_offset >= end_offset))
|
||||
{
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (remove_renamer->start_spinner)), "error");
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (remove_renamer->end_spinner)), "error");
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (remove_renamer->start_spinner)), "error");
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (remove_renamer->end_spinner)), "error");
|
||||
}
|
||||
}
|
||||
|
||||
/* tell the bulk renamer that we have a new state */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (remove_renamer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrRemoveRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrRemoveRenamer.
|
||||
**/
|
||||
ThunarSbrRemoveRenamer *
|
||||
thunar_sbr_remove_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_REMOVE_RENAMER,
|
||||
"name", _("Remove Characters"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_get_end_offset:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
*
|
||||
* Returns the end offset of the character removal.
|
||||
*
|
||||
* Return value: the end offset for @remove_renamer.
|
||||
**/
|
||||
guint
|
||||
thunar_sbr_remove_renamer_get_end_offset (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer), 0);
|
||||
return remove_renamer->end_offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_set_end_offset:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
* @end_offset : the new end offset.
|
||||
*
|
||||
* Sets the end offset of @remove_renamer to @end_offset.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_end_offset (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
guint end_offset)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer));
|
||||
|
||||
/* check if we have a new value */
|
||||
if (G_LIKELY (remove_renamer->end_offset != end_offset))
|
||||
{
|
||||
/* apply the new setting */
|
||||
remove_renamer->end_offset = end_offset;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_remove_renamer_update (remove_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (remove_renamer), "end-offset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_get_end_offset_mode:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
*
|
||||
* Returns the end offset mode for @remove_renamer.
|
||||
*
|
||||
* Return value: the end offset mode for @remove_renamer.
|
||||
**/
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_remove_renamer_get_end_offset_mode (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer), THUNAR_SBR_OFFSET_MODE_LEFT);
|
||||
return remove_renamer->end_offset_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_set_end_offset_mode:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
* @end_offset_mode : the new end #ThunarSbrOffsetMode.
|
||||
*
|
||||
* Sets the end offset mode for @remove_renamer to @end_offset_mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_end_offset_mode (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
ThunarSbrOffsetMode end_offset_mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer));
|
||||
|
||||
/* check if we have a new value */
|
||||
if (G_LIKELY (remove_renamer->end_offset_mode != end_offset_mode))
|
||||
{
|
||||
/* apply the new setting */
|
||||
remove_renamer->end_offset_mode = end_offset_mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_remove_renamer_update (remove_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (remove_renamer), "end-offset-mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_get_start_offset:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
*
|
||||
* Returns the start offset of the character removal.
|
||||
*
|
||||
* Return value: the start offset for @remove_renamer.
|
||||
**/
|
||||
guint
|
||||
thunar_sbr_remove_renamer_get_start_offset (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer), 0);
|
||||
return remove_renamer->start_offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_set_start_offset:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
* @start_offset : the new start offset.
|
||||
*
|
||||
* Sets the start offset of @remove_renamer to @start_offset.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_start_offset (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
guint start_offset)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer));
|
||||
|
||||
/* check if we have a new value */
|
||||
if (G_LIKELY (remove_renamer->start_offset != start_offset))
|
||||
{
|
||||
/* apply the new setting */
|
||||
remove_renamer->start_offset = start_offset;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_remove_renamer_update (remove_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (remove_renamer), "start-offset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_get_start_offset_mode:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
*
|
||||
* Returns the start offset mode for @remove_renamer.
|
||||
*
|
||||
* Return value: the start offset mode for @remove_renamer.
|
||||
**/
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_remove_renamer_get_start_offset_mode (ThunarSbrRemoveRenamer *remove_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer), THUNAR_SBR_OFFSET_MODE_LEFT);
|
||||
return remove_renamer->start_offset_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_remove_renamer_set_start_offset_mode:
|
||||
* @remove_renamer : a #ThunarSbrRemoveRenamer.
|
||||
* @start_offset_mode : the new start #ThunarSbrOffsetMode.
|
||||
*
|
||||
* Sets the start offset mode for @remove_renamer to @start_offset_mode.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_start_offset_mode (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
ThunarSbrOffsetMode start_offset_mode)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REMOVE_RENAMER (remove_renamer));
|
||||
|
||||
/* check if we have a new value */
|
||||
if (G_LIKELY (remove_renamer->start_offset_mode != start_offset_mode))
|
||||
{
|
||||
/* apply the new setting */
|
||||
remove_renamer->start_offset_mode = start_offset_mode;
|
||||
|
||||
/* update the renamer */
|
||||
thunar_sbr_remove_renamer_update (remove_renamer);
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (remove_renamer), "start-offset-mode");
|
||||
}
|
||||
}
|
||||
72
plugins/thunar-sbr/thunar-sbr-remove-renamer.h
Normal file
72
plugins/thunar-sbr/thunar-sbr-remove-renamer.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_REMOVE_RENAMER_H__
|
||||
#define __THUNAR_SBR_REMOVE_RENAMER_H__
|
||||
|
||||
#include <thunar-sbr/thunar-sbr-enum-types.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrRemoveRenamerClass ThunarSbrRemoveRenamerClass;
|
||||
typedef struct _ThunarSbrRemoveRenamer ThunarSbrRemoveRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_REMOVE_RENAMER (thunar_sbr_remove_renamer_get_type ())
|
||||
#define THUNAR_SBR_REMOVE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_REMOVE_RENAMER, ThunarSbrRemoveRenamer))
|
||||
#define THUNAR_SBR_REMOVE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_REMOVE_RENAMER, ThunarSbrRemoveRenamerClass))
|
||||
#define THUNAR_SBR_IS_REMOVE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_REMOVE_RENAMER))
|
||||
#define THUNAR_SBR_IS_REMOVE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_REMOVE_RENAMER))
|
||||
#define THUNAR_SBR_REMOVE_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_REMOVE_RENAMER, ThunarSbrRemoveRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_remove_renamer_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_remove_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrRemoveRenamer *
|
||||
thunar_sbr_remove_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
guint
|
||||
thunar_sbr_remove_renamer_get_end_offset (ThunarSbrRemoveRenamer *remove_renamer);
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_end_offset (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
guint end_offset);
|
||||
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_remove_renamer_get_end_offset_mode (ThunarSbrRemoveRenamer *remove_renamer);
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_end_offset_mode (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
ThunarSbrOffsetMode end_offset_mode);
|
||||
|
||||
guint
|
||||
thunar_sbr_remove_renamer_get_start_offset (ThunarSbrRemoveRenamer *remove_renamer);
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_start_offset (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
guint start_offset);
|
||||
|
||||
ThunarSbrOffsetMode
|
||||
thunar_sbr_remove_renamer_get_start_offset_mode (ThunarSbrRemoveRenamer *remove_renamer);
|
||||
void
|
||||
thunar_sbr_remove_renamer_set_start_offset_mode (ThunarSbrRemoveRenamer *remove_renamer,
|
||||
ThunarSbrOffsetMode start_offset_mode);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_REMOVE_RENAMER_H__ */
|
||||
814
plugins/thunar-sbr/thunar-sbr-replace-renamer.c
Normal file
814
plugins/thunar-sbr/thunar-sbr-replace-renamer.c
Normal file
|
|
@ -0,0 +1,814 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
#endif
|
||||
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-sbr/thunar-sbr-replace-renamer.h>
|
||||
|
||||
|
||||
|
||||
/* Property identifiers */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CASE_SENSITIVE,
|
||||
PROP_PATTERN,
|
||||
PROP_REPLACEMENT,
|
||||
PROP_REGEXP,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_finalize (GObject *object);
|
||||
static void
|
||||
thunar_sbr_replace_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_replace_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void
|
||||
thunar_sbr_replace_renamer_realize (GtkWidget *widget);
|
||||
static gchar *
|
||||
thunar_sbr_replace_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx);
|
||||
#ifdef HAVE_PCRE2
|
||||
static gchar *
|
||||
thunar_sbr_replace_renamer_pcre_exec (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *text);
|
||||
static void
|
||||
thunar_sbr_replace_renamer_pcre_update (ThunarSbrReplaceRenamer *replace_renamer);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct _ThunarSbrReplaceRenamerClass
|
||||
{
|
||||
ThunarxRenamerClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarSbrReplaceRenamer
|
||||
{
|
||||
ThunarxRenamer __parent__;
|
||||
GtkWidget *pattern_entry;
|
||||
gboolean case_sensitive;
|
||||
gboolean regexp;
|
||||
gchar *pattern;
|
||||
gchar *replacement;
|
||||
|
||||
/* TRUE if PCRE is available and supports UTF-8 */
|
||||
gint utf8_regexp_supported;
|
||||
|
||||
/* PCRE compiled pattern */
|
||||
#ifdef HAVE_PCRE2
|
||||
pcre2_code *pcre_pattern;
|
||||
gint pcre_capture_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarSbrReplaceRenamer, thunar_sbr_replace_renamer, THUNARX_TYPE_RENAMER);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_class_init (ThunarSbrReplaceRenamerClass *klass)
|
||||
{
|
||||
ThunarxRenamerClass *thunarxrenamer_class;
|
||||
GtkWidgetClass *gtkwidget_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_sbr_replace_renamer_finalize;
|
||||
gobject_class->get_property = thunar_sbr_replace_renamer_get_property;
|
||||
gobject_class->set_property = thunar_sbr_replace_renamer_set_property;
|
||||
|
||||
gtkwidget_class = GTK_WIDGET_CLASS (klass);
|
||||
gtkwidget_class->realize = thunar_sbr_replace_renamer_realize;
|
||||
|
||||
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
|
||||
thunarxrenamer_class->process = thunar_sbr_replace_renamer_process;
|
||||
|
||||
/**
|
||||
* ThunarSbrReplaceRenamer:case-sensitive:
|
||||
*
|
||||
* Whether to use case sensitive search and replace.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CASE_SENSITIVE,
|
||||
g_param_spec_boolean ("case-sensitive",
|
||||
"case-sensitive",
|
||||
"case-sensitive",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrReplaceRenamer:pattern:
|
||||
*
|
||||
* The search pattern.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PATTERN,
|
||||
g_param_spec_string ("pattern",
|
||||
"pattern",
|
||||
"pattern",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrReplaceRenamer:replacement:
|
||||
*
|
||||
* The replacement text.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_REPLACEMENT,
|
||||
g_param_spec_string ("replacement",
|
||||
"replacement",
|
||||
"replacement",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ThunarSbrReplaceRenamer:regexp:
|
||||
*
|
||||
* Whether to use regular expressions.
|
||||
**/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_REGEXP,
|
||||
g_param_spec_boolean ("regexp",
|
||||
"regexp",
|
||||
"regexp",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_init (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
AtkRelationSet *relations;
|
||||
AtkRelation *relation;
|
||||
AtkObject *object;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *button;
|
||||
uint32_t pcre2_compiled_widths;
|
||||
|
||||
replace_renamer->utf8_regexp_supported = FALSE;
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
/* check if PCRE supports UTF-8 */
|
||||
if (pcre2_config (PCRE2_CONFIG_COMPILED_WIDTHS, &pcre2_compiled_widths) >= 0)
|
||||
{
|
||||
/* bit0 indicates 8-bit support. bit1 and bit2 indicate 16-bit and 32-bit support respectively. */
|
||||
if ((pcre2_compiled_widths & (1 << 0)) != 0)
|
||||
replace_renamer->utf8_regexp_supported = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_box_pack_start (GTK_BOX (replace_renamer), grid, FALSE, FALSE, 0);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Search For:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
replace_renamer->pattern_entry = gtk_entry_new ();
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (replace_renamer->pattern_entry), TRUE);
|
||||
g_object_bind_property (G_OBJECT (replace_renamer->pattern_entry), "text", G_OBJECT (replace_renamer), "pattern", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_tooltip_text (replace_renamer->pattern_entry, _("Enter the text to search for in the file names."));
|
||||
gtk_widget_set_hexpand (replace_renamer->pattern_entry, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), replace_renamer->pattern_entry, 1, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), replace_renamer->pattern_entry);
|
||||
gtk_widget_show (replace_renamer->pattern_entry);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (replace_renamer->pattern_entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
button = gtk_check_button_new_with_mnemonic (_("Regular _Expression"));
|
||||
g_object_bind_property (G_OBJECT (button), "active", G_OBJECT (replace_renamer), "regexp", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_tooltip_text (button, _("If you enable this option, the pattern will be treated as a regular expression and "
|
||||
"matched using the Perl-compatible regular expressions (PCRE). Check the documentation "
|
||||
"for details about the regular expression syntax."));
|
||||
gtk_grid_attach (GTK_GRID (grid), button, 2, 0, 1, 1);
|
||||
gtk_widget_set_sensitive (button, replace_renamer->utf8_regexp_supported);
|
||||
gtk_widget_show (button);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Replace _With:"));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
gtk_widget_show (label);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
||||
g_object_bind_property (G_OBJECT (entry), "text", G_OBJECT (replace_renamer), "replacement", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_tooltip_text (entry, _("Enter the text that should be used as replacement for the pattern above."));
|
||||
gtk_widget_set_hexpand (entry, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), entry, 1, 1, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
|
||||
gtk_widget_show (entry);
|
||||
|
||||
/* set Atk label relation for the entry */
|
||||
object = gtk_widget_get_accessible (entry);
|
||||
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
|
||||
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
|
||||
atk_relation_set_add (relations, relation);
|
||||
g_object_unref (G_OBJECT (relation));
|
||||
g_object_unref (relations);
|
||||
|
||||
button = gtk_check_button_new_with_mnemonic (_("C_ase Sensitive Search"));
|
||||
g_object_bind_property (G_OBJECT (button), "active", G_OBJECT (replace_renamer), "case-sensitive", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_set_tooltip_text (button, _("If you enable this option, the pattern will be searched in a case-sensitive manner. "
|
||||
"The default is to use a case-insensitive search."));
|
||||
gtk_grid_attach (GTK_GRID (grid), button, 2, 1, 1, 1);
|
||||
gtk_widget_show (button);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_finalize (GObject *object)
|
||||
{
|
||||
ThunarSbrReplaceRenamer *replace_renamer = THUNAR_SBR_REPLACE_RENAMER (object);
|
||||
|
||||
/* release the PCRE pattern (if any) */
|
||||
#ifdef HAVE_PCRE2
|
||||
if (G_UNLIKELY (replace_renamer->pcre_pattern != NULL))
|
||||
pcre2_code_free (replace_renamer->pcre_pattern);
|
||||
#endif
|
||||
|
||||
/* release the strings */
|
||||
g_free (replace_renamer->replacement);
|
||||
g_free (replace_renamer->pattern);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_sbr_replace_renamer_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrReplaceRenamer *replace_renamer = THUNAR_SBR_REPLACE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CASE_SENSITIVE:
|
||||
g_value_set_boolean (value, thunar_sbr_replace_renamer_get_case_sensitive (replace_renamer));
|
||||
break;
|
||||
|
||||
case PROP_PATTERN:
|
||||
g_value_set_string (value, thunar_sbr_replace_renamer_get_pattern (replace_renamer));
|
||||
break;
|
||||
|
||||
case PROP_REPLACEMENT:
|
||||
g_value_set_string (value, thunar_sbr_replace_renamer_get_replacement (replace_renamer));
|
||||
break;
|
||||
|
||||
case PROP_REGEXP:
|
||||
g_value_set_boolean (value, thunar_sbr_replace_renamer_get_regexp (replace_renamer));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarSbrReplaceRenamer *replace_renamer = THUNAR_SBR_REPLACE_RENAMER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CASE_SENSITIVE:
|
||||
thunar_sbr_replace_renamer_set_case_sensitive (replace_renamer, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_PATTERN:
|
||||
thunar_sbr_replace_renamer_set_pattern (replace_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_REPLACEMENT:
|
||||
thunar_sbr_replace_renamer_set_replacement (replace_renamer, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_REGEXP:
|
||||
thunar_sbr_replace_renamer_set_regexp (replace_renamer, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_realize (GtkWidget *widget)
|
||||
{
|
||||
/* realize the widget */
|
||||
(*GTK_WIDGET_CLASS (thunar_sbr_replace_renamer_parent_class)->realize) (widget);
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
/* update the PCRE pattern */
|
||||
thunar_sbr_replace_renamer_pcre_update (THUNAR_SBR_REPLACE_RENAMER (widget));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
tsrr_replace (const gchar *text,
|
||||
const gchar *pattern,
|
||||
const gchar *replacement,
|
||||
gboolean case_sensitive)
|
||||
{
|
||||
const gchar *p;
|
||||
const gchar *t;
|
||||
gunichar pc;
|
||||
gunichar tc;
|
||||
GString *result = g_string_sized_new (32);
|
||||
|
||||
while (*text != '\0')
|
||||
{
|
||||
/* compare the pattern to this part of the text */
|
||||
for (p = pattern, t = text; *p != '\0' && *t != '\0'; p = g_utf8_next_char (p), t = g_utf8_next_char (t))
|
||||
{
|
||||
/* determine the next unichars */
|
||||
pc = g_utf8_get_char (p);
|
||||
tc = g_utf8_get_char (t);
|
||||
|
||||
/* check if the chars don't match */
|
||||
if (pc != tc && (case_sensitive || g_unichar_toupper (pc) != g_unichar_toupper (tc)))
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if the pattern matches */
|
||||
if (G_UNLIKELY (*p == '\0'))
|
||||
{
|
||||
/* append the replacement to the result... */
|
||||
g_string_append (result, replacement);
|
||||
|
||||
/* ...and skip to the text after the pattern */
|
||||
text = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just append the text char */
|
||||
g_string_append_unichar (result, g_utf8_get_char (text));
|
||||
text = g_utf8_next_char (text);
|
||||
}
|
||||
}
|
||||
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gchar *
|
||||
thunar_sbr_replace_renamer_process (ThunarxRenamer *renamer,
|
||||
ThunarxFileInfo *file,
|
||||
const gchar *text,
|
||||
guint idx)
|
||||
{
|
||||
ThunarSbrReplaceRenamer *replace_renamer = THUNAR_SBR_REPLACE_RENAMER (renamer);
|
||||
|
||||
/* nothing to replace if we don't have a pattern */
|
||||
if (G_UNLIKELY (replace_renamer->pattern == NULL || *replace_renamer->pattern == '\0'))
|
||||
return g_strdup (text);
|
||||
|
||||
/* check if we should use regular expression */
|
||||
if (G_UNLIKELY (replace_renamer->regexp))
|
||||
{
|
||||
#ifdef HAVE_PCRE2
|
||||
/* check if the pattern failed to compile */
|
||||
if (G_UNLIKELY (replace_renamer->pcre_pattern == NULL))
|
||||
return g_strdup (text);
|
||||
|
||||
/* just execute the pattern */
|
||||
return thunar_sbr_replace_renamer_pcre_exec (replace_renamer, text);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* perform the replace operation */
|
||||
return tsrr_replace (text, replace_renamer->pattern, replace_renamer->replacement, replace_renamer->case_sensitive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
static gchar *
|
||||
thunar_sbr_replace_renamer_pcre_exec (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *subject)
|
||||
{
|
||||
GString *result;
|
||||
int error;
|
||||
PCRE2_SIZE erroffset;
|
||||
gchar output[1024];
|
||||
pcre2_code *compiled_pattern;
|
||||
PCRE2_SIZE outlen;
|
||||
int n_substitutions; /* number of substitutions that were carried out */
|
||||
|
||||
result = g_string_sized_new (32);
|
||||
|
||||
compiled_pattern = pcre2_compile_8 ((PCRE2_SPTR) replace_renamer->pattern,
|
||||
PCRE2_ZERO_TERMINATED,
|
||||
0,
|
||||
&error,
|
||||
&erroffset,
|
||||
0);
|
||||
if (compiled_pattern == NULL)
|
||||
return g_strdup (subject);
|
||||
|
||||
pcre2_jit_compile (compiled_pattern, PCRE2_JIT_COMPLETE);
|
||||
|
||||
outlen = sizeof (output) / sizeof (PCRE2_UCHAR);
|
||||
|
||||
n_substitutions = pcre2_substitute (compiled_pattern,
|
||||
(PCRE2_SPTR) subject,
|
||||
PCRE2_ZERO_TERMINATED,
|
||||
0,
|
||||
PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED,
|
||||
0,
|
||||
0,
|
||||
(PCRE2_SPTR) replace_renamer->replacement,
|
||||
PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR *) output,
|
||||
&outlen);
|
||||
|
||||
if (n_substitutions < 0)
|
||||
{
|
||||
PCRE2_UCHAR buffer[256];
|
||||
pcre2_get_error_message (error, buffer, sizeof (buffer));
|
||||
g_warning ("PCRE2 substitution failed at offset %d: %s\n", (int) erroffset, buffer);
|
||||
return g_strdup (subject);
|
||||
}
|
||||
|
||||
pcre2_code_free (compiled_pattern);
|
||||
|
||||
for (size_t i = 0; i < outlen; i++)
|
||||
g_string_append_c (result, output[i]);
|
||||
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_sbr_replace_renamer_pcre_update (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
const gchar *error_message = NULL;
|
||||
gchar *tooltip;
|
||||
gchar *message;
|
||||
glong offset;
|
||||
gint error_offset = -1;
|
||||
int error;
|
||||
PCRE2_SIZE erroffset;
|
||||
|
||||
/* pre-compile the pattern if regexp is enabled */
|
||||
if (G_UNLIKELY (replace_renamer->regexp))
|
||||
{
|
||||
/* release the previous pattern (if any) */
|
||||
if (G_LIKELY (replace_renamer->pcre_pattern != NULL))
|
||||
pcre2_code_free (replace_renamer->pcre_pattern);
|
||||
|
||||
/* try to compile the new pattern */
|
||||
replace_renamer->pcre_pattern = pcre2_compile ((PCRE2_SPTR) replace_renamer->pattern, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, 0);
|
||||
|
||||
if (replace_renamer->pcre_pattern == NULL)
|
||||
{
|
||||
PCRE2_UCHAR buffer[256];
|
||||
pcre2_get_error_message (error, buffer, sizeof (buffer));
|
||||
g_warning ("PCRE2 compilation failed at offset %d: %s\n", (int) erroffset, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if there was an error compiling the pattern */
|
||||
if (G_UNLIKELY (error_message != NULL))
|
||||
{
|
||||
/* convert the message to UTF-8 */
|
||||
message = g_locale_to_utf8 (error_message, -1, NULL, NULL, NULL);
|
||||
if (G_LIKELY (message != NULL))
|
||||
{
|
||||
/* determine the UTF-8 char offset */
|
||||
offset = g_utf8_pointer_to_offset (replace_renamer->pattern, replace_renamer->pattern + error_offset);
|
||||
|
||||
/* setup a tooltip with the error message */
|
||||
tooltip = g_strdup_printf (_("Invalid regular expression, at character position %ld: %s"), offset, message);
|
||||
gtk_widget_set_tooltip_text (replace_renamer->pattern_entry, tooltip);
|
||||
g_free (tooltip);
|
||||
}
|
||||
g_free (message);
|
||||
|
||||
/* check if the entry is realized */
|
||||
if (gtk_widget_get_realized (replace_renamer->pattern_entry))
|
||||
{
|
||||
/* highlight invalid input by using theme-specific colors */
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (replace_renamer->pattern_entry)), "error");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check if the entry is realized */
|
||||
if (gtk_widget_get_realized (replace_renamer->pattern_entry))
|
||||
{
|
||||
/* stop highlight of invalid input if any */
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (replace_renamer->pattern_entry)), "error");
|
||||
}
|
||||
|
||||
/* reset to default tooltip */
|
||||
gtk_widget_set_tooltip_text (replace_renamer->pattern_entry, _("Enter the text to search for in the file names."));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_new:
|
||||
*
|
||||
* Allocates a new #ThunarSbrReplaceRenamer instance.
|
||||
*
|
||||
* Return value: the newly allocated #ThunarSbrReplaceRenamer.
|
||||
**/
|
||||
ThunarSbrReplaceRenamer *
|
||||
thunar_sbr_replace_renamer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_SBR_TYPE_REPLACE_RENAMER,
|
||||
"name", _("Search & Replace"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_get_case_sensitive:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
*
|
||||
* Returns %TRUE if @replace_renamer<!---->s search should
|
||||
* be case sensitive.
|
||||
*
|
||||
* Return value: %TRUE if @replace_renamer is case sensitive.
|
||||
**/
|
||||
gboolean
|
||||
thunar_sbr_replace_renamer_get_case_sensitive (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer), FALSE);
|
||||
return replace_renamer->case_sensitive;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_set_case_sensitive:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
* @case_sensitive : %TRUE to use case sensitive search.
|
||||
*
|
||||
* If @case_sensitive is %TRUE the search of @replace_renamer
|
||||
* will be case sensitive.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_case_sensitive (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
gboolean case_sensitive)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer));
|
||||
|
||||
/* normalize the value */
|
||||
case_sensitive = !!case_sensitive;
|
||||
|
||||
/* check if we have a new setting */
|
||||
if (G_LIKELY (replace_renamer->case_sensitive != case_sensitive))
|
||||
{
|
||||
/* apply the new value */
|
||||
replace_renamer->case_sensitive = case_sensitive;
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
/* pre-compile the pattern */
|
||||
thunar_sbr_replace_renamer_pcre_update (replace_renamer);
|
||||
#endif
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (replace_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (replace_renamer), "case-sensitive");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_get_pattern:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
*
|
||||
* Returns the search pattern for @replace_renamer.
|
||||
*
|
||||
* Return value: the search pattern for @replace_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_replace_renamer_get_pattern (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer), NULL);
|
||||
return replace_renamer->pattern;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_set_pattern:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
* @pattern : the new pattern for @replace_renamer.
|
||||
*
|
||||
* Sets the search pattern of @replace_renamer to @pattern.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_pattern (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *pattern)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer));
|
||||
g_return_if_fail (g_utf8_validate (pattern, -1, NULL));
|
||||
|
||||
/* check if we have a new pattern */
|
||||
if (g_strcmp0 (replace_renamer->pattern, pattern) != 0)
|
||||
{
|
||||
/* apply the new value */
|
||||
g_free (replace_renamer->pattern);
|
||||
replace_renamer->pattern = g_strdup (pattern);
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
/* pre-compile the pattern */
|
||||
thunar_sbr_replace_renamer_pcre_update (replace_renamer);
|
||||
#endif
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (replace_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (replace_renamer), "pattern");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_get_regexp:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
*
|
||||
* Returns %TRUE if @replace_renamer should use a regular
|
||||
* expression.
|
||||
*
|
||||
* Return value: %TRUE if @replace_renamer uses a regexp.
|
||||
**/
|
||||
gboolean
|
||||
thunar_sbr_replace_renamer_get_regexp (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer), FALSE);
|
||||
return replace_renamer->regexp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_set_regexp:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
* @regexp : %TRUE to use regular expressions.
|
||||
*
|
||||
* If @regexp is %TRUE a regular expression should be used
|
||||
* for @replace_renamer.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_regexp (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
gboolean regexp)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer));
|
||||
|
||||
/* normalize the value */
|
||||
regexp = (!!regexp && replace_renamer->utf8_regexp_supported);
|
||||
|
||||
/* check if we have a new value */
|
||||
if (G_LIKELY (replace_renamer->regexp != regexp))
|
||||
{
|
||||
/* apply the new value */
|
||||
replace_renamer->regexp = regexp;
|
||||
|
||||
#ifdef HAVE_PCRE2
|
||||
/* pre-compile the pattern */
|
||||
thunar_sbr_replace_renamer_pcre_update (replace_renamer);
|
||||
#endif
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (replace_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (replace_renamer), "regexp");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_get_replacement:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
*
|
||||
* Returns the replacement for the @replace_renamer.
|
||||
*
|
||||
* Return value: the replacement for @replace_renamer.
|
||||
**/
|
||||
const gchar *
|
||||
thunar_sbr_replace_renamer_get_replacement (ThunarSbrReplaceRenamer *replace_renamer)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer), NULL);
|
||||
return replace_renamer->replacement;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_sbr_replace_renamer_set_replacement:
|
||||
* @replace_renamer : a #ThunarSbrReplaceRenamer.
|
||||
* @replacement : the new replacement.
|
||||
*
|
||||
* Sets the replacement of @replace_renamer to @replacement.
|
||||
**/
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_replacement (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *replacement)
|
||||
{
|
||||
g_return_if_fail (THUNAR_SBR_IS_REPLACE_RENAMER (replace_renamer));
|
||||
g_return_if_fail (g_utf8_validate (replacement, -1, NULL));
|
||||
|
||||
/* check if we have a new replacement */
|
||||
if (g_strcmp0 (replace_renamer->replacement, replacement) != 0)
|
||||
{
|
||||
/* apply the setting */
|
||||
g_free (replace_renamer->replacement);
|
||||
replace_renamer->replacement = g_strdup (replacement);
|
||||
|
||||
/* update the renamer */
|
||||
thunarx_renamer_changed (THUNARX_RENAMER (replace_renamer));
|
||||
|
||||
/* notify listeners */
|
||||
g_object_notify (G_OBJECT (replace_renamer), "replacement");
|
||||
}
|
||||
}
|
||||
72
plugins/thunar-sbr/thunar-sbr-replace-renamer.h
Normal file
72
plugins/thunar-sbr/thunar-sbr-replace-renamer.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_SBR_REPLACE_RENAMER_H__
|
||||
#define __THUNAR_SBR_REPLACE_RENAMER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarSbrReplaceRenamerClass ThunarSbrReplaceRenamerClass;
|
||||
typedef struct _ThunarSbrReplaceRenamer ThunarSbrReplaceRenamer;
|
||||
|
||||
#define THUNAR_SBR_TYPE_REPLACE_RENAMER (thunar_sbr_replace_renamer_get_type ())
|
||||
#define THUNAR_SBR_REPLACE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_SBR_TYPE_REPLACE_RENAMER, ThunarSbrReplaceRenamer))
|
||||
#define THUNAR_SBR_REPLACE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_SBR_TYPE_REPLACE_RENAMER, ThunarSbrReplaceRenamerClass))
|
||||
#define THUNAR_SBR_IS_REPLACE_RENAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_SBR_TYPE_REPLACE_RENAMER))
|
||||
#define THUNAR_SBR_IS_REPLACE_RENAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_SBR_TYPE_REPLACE_RENAMER))
|
||||
#define THUNAR_SBR_REPLACE_RENAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_SBR_TYPE_REPLACE_RENAMER, ThunarSbrReplaceRenamerClass))
|
||||
|
||||
GType
|
||||
thunar_sbr_replace_renamer_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_sbr_replace_renamer_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarSbrReplaceRenamer *
|
||||
thunar_sbr_replace_renamer_new (void) G_GNUC_MALLOC;
|
||||
|
||||
gboolean
|
||||
thunar_sbr_replace_renamer_get_case_sensitive (ThunarSbrReplaceRenamer *replace_renamer);
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_case_sensitive (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
gboolean case_sensitive);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_replace_renamer_get_pattern (ThunarSbrReplaceRenamer *replace_renamer);
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_pattern (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *pattern);
|
||||
|
||||
gboolean
|
||||
thunar_sbr_replace_renamer_get_regexp (ThunarSbrReplaceRenamer *replace_renamer);
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_regexp (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
gboolean regexp);
|
||||
|
||||
const gchar *
|
||||
thunar_sbr_replace_renamer_get_replacement (ThunarSbrReplaceRenamer *replace_renamer);
|
||||
void
|
||||
thunar_sbr_replace_renamer_set_replacement (ThunarSbrReplaceRenamer *replace_renamer,
|
||||
const gchar *replacement);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SBR_REPLACE_RENAMER_H__ */
|
||||
46
plugins/thunar-sendto-email/Makefile.am
Normal file
46
plugins/thunar-sendto-email/Makefile.am
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/plugins \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/plugins \
|
||||
-DG_LOG_DOMAIN=\"thunar-sendto-email\" \
|
||||
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
thunar_sendto_emaildir = \
|
||||
$(HELPER_PATH_PREFIX)/Thunar
|
||||
|
||||
thunar_sendto_email_PROGRAMS = \
|
||||
thunar-sendto-email
|
||||
|
||||
thunar_sendto_email_SOURCES = \
|
||||
main.c
|
||||
|
||||
thunar_sendto_email_CFLAGS = \
|
||||
$(EXO_CFLAGS) \
|
||||
$(LIBXFCE4UTIL_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
thunar_sendto_email_LDADD = \
|
||||
$(EXO_LIBS) \
|
||||
$(LIBXFCE4UTIL_LIBS) \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
desktopdir = $(datadir)/Thunar/sendto
|
||||
desktop_in_in_files = thunar-sendto-email.desktop.in.in
|
||||
desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
|
||||
%.desktop.in: %.desktop.in.in
|
||||
sed -e "s,\@HELPERDIR\@,$(HELPER_PATH_PREFIX),g" < $< > $@
|
||||
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
|
||||
%.desktop: %.desktop.in Makefile
|
||||
$(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(desktop_in_in_files) \
|
||||
README.md
|
||||
|
||||
DISTCLEANFILES = \
|
||||
$(desktop_in_files) \
|
||||
$(desktop_DATA)
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
6
plugins/thunar-sendto-email/README.md
Normal file
6
plugins/thunar-sendto-email/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Thunar Sendto Email (thunar-sendto-email)
|
||||
=========================================
|
||||
|
||||
Thunar-sendto-email is an extension to Thunar, which adds an additional entry to the "Send To" sub menu, named "Mail Recipient", that starts the mail composer and attaches the selected files (using the exo-open mechanism).
|
||||
|
||||
The extension uses the zip command to compress folders prior to sending them to the mail client, since most mail clients cannot handle directories as attachments. For regular files, larger than 200KiB, the extension prompts the user whether to compress the files (using the zip command) prior to sending them to the mail client.
|
||||
705
plugins/thunar-sendto-email/main.c
Normal file
705
plugins/thunar-sendto-email/main.c
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
|
||||
|
||||
|
||||
typedef struct _TseData TseData;
|
||||
|
||||
struct _TseData
|
||||
{
|
||||
GFileInfo *info;
|
||||
GFile *file;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* well known archive types */
|
||||
static const char *TSE_MIME_TYPES[] = {
|
||||
"application/x-7z-compressed",
|
||||
"application/x-7z-compressed-tar",
|
||||
"application/x-ar",
|
||||
"application/x-arj",
|
||||
"application/x-brotli",
|
||||
"application/x-brotli-compressed-tar",
|
||||
"application/x-bzip",
|
||||
"application/x-bzip-compressed-tar",
|
||||
"application/x-compress",
|
||||
"application/x-compressed-tar",
|
||||
"application/x-deb",
|
||||
"application/x-gtar",
|
||||
"application/x-gzip",
|
||||
"application/x-lha",
|
||||
"application/x-lhz",
|
||||
"application/x-lzma",
|
||||
"application/x-lzma-compressed-tar",
|
||||
"application/x-rar",
|
||||
"application/x-rar-compressed",
|
||||
"application/x-tar",
|
||||
"application/x-xz",
|
||||
"application/x-xz-compressed-tar",
|
||||
"application/x-zip",
|
||||
"application/x-zip-compressed",
|
||||
"application/zip",
|
||||
"multipart/x-zip",
|
||||
"application/x-rpm",
|
||||
"application/x-jar",
|
||||
"application/x-java-archive",
|
||||
"application/x-lzop",
|
||||
"application/x-zoo",
|
||||
"application/x-cd-image",
|
||||
"application/zstd",
|
||||
"application/x-zstd-compressed-tar",
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* compress response ids */
|
||||
enum
|
||||
{
|
||||
TSE_RESPONSE_COMPRESS,
|
||||
TSE_RESPONSE_PLAIN,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
tse_error (GError *error,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
va_list args;
|
||||
gchar *primary_text;
|
||||
|
||||
/* determine the primary error text */
|
||||
va_start (args, format);
|
||||
primary_text = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
/* allocate the error dialog */
|
||||
dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s.", primary_text);
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
|
||||
|
||||
/* display the dialog */
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
|
||||
/* cleanup */
|
||||
gtk_widget_destroy (dialog);
|
||||
g_free (primary_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the single file is already an archive
|
||||
**/
|
||||
static gboolean
|
||||
tse_file_is_archive (GFileInfo *file_info)
|
||||
{
|
||||
const gchar *content_type;
|
||||
guint n;
|
||||
/* determine the content type */
|
||||
content_type = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
|
||||
if (content_type == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
for (n = 0; n < G_N_ELEMENTS (TSE_MIME_TYPES); ++n)
|
||||
{
|
||||
/* check if this mime type matches */
|
||||
if (g_content_type_is_a (content_type, TSE_MIME_TYPES[n]))
|
||||
{
|
||||
/* yep, that's a match then */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
tse_ask_compress (GList *infos)
|
||||
{
|
||||
TseData *tse_data;
|
||||
GtkWidget *message;
|
||||
guint64 total_size = 0;
|
||||
GList *lp;
|
||||
gint response = TSE_RESPONSE_PLAIN;
|
||||
gint n_archives = 0;
|
||||
gint n_infos = 0;
|
||||
|
||||
/* check the file infos */
|
||||
for (lp = infos; lp != NULL; lp = lp->next, ++n_infos)
|
||||
{
|
||||
/* need to compress if we have any directories */
|
||||
tse_data = (TseData *) lp->data;
|
||||
|
||||
if (g_file_info_get_file_type (tse_data->info) == G_FILE_TYPE_DIRECTORY)
|
||||
return TSE_RESPONSE_COMPRESS;
|
||||
|
||||
if (tse_file_is_archive (tse_data->info))
|
||||
++n_archives;
|
||||
|
||||
/* add file size to total */
|
||||
total_size += g_file_info_get_size (tse_data->info);
|
||||
}
|
||||
|
||||
/* check if the total size is larger than 200KiB, or we have more than
|
||||
* one file, and at least one of the files is not already an archive.
|
||||
*/
|
||||
if ((n_infos > 1 || total_size > 200 * 1024) && n_infos != n_archives)
|
||||
{
|
||||
/* check if we have more than one file */
|
||||
if (G_LIKELY (n_infos == 1))
|
||||
{
|
||||
/* ask the user whether to compress the file */
|
||||
tse_data = (TseData *) infos->data;
|
||||
message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
|
||||
_("Send \"%s\" as compressed archive?"),
|
||||
g_file_info_get_display_name (tse_data->info));
|
||||
gtk_window_set_title (GTK_WINDOW (message), _("Send email"));
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("_Cancel"), GTK_RESPONSE_CANCEL);
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("Send _directly"), TSE_RESPONSE_PLAIN);
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("Send com_pressed"), TSE_RESPONSE_COMPRESS);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (message), TSE_RESPONSE_COMPRESS);
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message), _("When sending a file via email, you can either choose to "
|
||||
"send the file directly, as is, or compress the file before "
|
||||
"attaching it to an email. It is highly recommended to "
|
||||
"compress large files before sending them."));
|
||||
response = gtk_dialog_run (GTK_DIALOG (message));
|
||||
gtk_widget_destroy (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ask the user whether to send files as archive */
|
||||
message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
|
||||
ngettext ("Send %d file as compressed archive?",
|
||||
"Send %d files as compressed archive?",
|
||||
n_infos),
|
||||
n_infos);
|
||||
gtk_window_set_title (GTK_WINDOW (message), _("Send email"));
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("_Cancel"), GTK_RESPONSE_CANCEL);
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("Send _directly"), TSE_RESPONSE_PLAIN);
|
||||
gtk_dialog_add_button (GTK_DIALOG (message), _("Send as _archive"), TSE_RESPONSE_COMPRESS);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (message), TSE_RESPONSE_COMPRESS);
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message), _("When sending multiple files via email, you can either choose "
|
||||
"to send the files directly, attaching multiple files to an "
|
||||
"email, or send all files compressed into a single archive "
|
||||
"file and attach the archive. It is highly recommended to "
|
||||
"send multiple large files as archive."));
|
||||
response = gtk_dialog_run (GTK_DIALOG (message));
|
||||
gtk_widget_destroy (message);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
tse_child_watch (GPid pid,
|
||||
gint status,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (user_data), I_ ("tse-child-status"), GINT_TO_POINTER (status));
|
||||
gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_YES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
tse_progress_cb (gpointer user_data)
|
||||
{
|
||||
GtkWidget *pulse = user_data;
|
||||
|
||||
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pulse));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tse_progress (const gchar *working_directory,
|
||||
gchar **argv,
|
||||
GError **error)
|
||||
{
|
||||
GtkWidget *progress;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *vbox;
|
||||
gboolean succeed = FALSE;
|
||||
GPid pid;
|
||||
guint pulse_timer_id;
|
||||
gint watch_id;
|
||||
gint response;
|
||||
gint status;
|
||||
|
||||
/* try to run the command */
|
||||
if (!g_spawn_async (working_directory, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, error))
|
||||
return FALSE;
|
||||
|
||||
/* allocate the progress dialog */
|
||||
dialog = gtk_dialog_new_with_buttons (_("Compressing files..."),
|
||||
NULL, 0,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
NULL);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
|
||||
gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
|
||||
|
||||
/* setup the hbox */
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
/* setup the image */
|
||||
image = gtk_image_new_from_icon_name ("gnome-package", GTK_ICON_SIZE_DIALOG);
|
||||
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (image, GTK_ALIGN_START);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
gtk_widget_show (image);
|
||||
|
||||
/* setup the vbox */
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
||||
gtk_widget_show (vbox);
|
||||
|
||||
/* setup the label */
|
||||
label = gtk_label_new (_("Compressing files..."));
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||
gtk_widget_show (label);
|
||||
|
||||
/* setup the progress bar */
|
||||
progress = gtk_progress_bar_new ();
|
||||
gtk_box_pack_start (GTK_BOX (vbox), progress, FALSE, FALSE, 0);
|
||||
gtk_widget_show (progress);
|
||||
|
||||
/* start the child watch */
|
||||
watch_id = g_child_watch_add (pid, tse_child_watch, dialog);
|
||||
|
||||
/* start the pulse timer */
|
||||
pulse_timer_id = g_timeout_add (125, tse_progress_cb, progress);
|
||||
|
||||
/* run the dialog */
|
||||
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
if (response == GTK_RESPONSE_YES)
|
||||
{
|
||||
/* check if the command failed */
|
||||
status = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), I_ ("tse-child-status")));
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
|
||||
{
|
||||
/* tell the user that the command failed */
|
||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("ZIP command terminated with error %d"), status);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the command succeed */
|
||||
succeed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* terminate the ZIP command */
|
||||
kill (pid, SIGQUIT);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_source_remove (pulse_timer_id);
|
||||
gtk_widget_destroy (dialog);
|
||||
g_source_remove (watch_id);
|
||||
|
||||
return succeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef HAVE_MKDTEMP
|
||||
static gchar *
|
||||
mkdtemp (gchar *tmpl)
|
||||
{
|
||||
static const gchar LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
static guint64 value;
|
||||
guint64 v;
|
||||
gint len;
|
||||
gint i, j;
|
||||
|
||||
len = strlen (tmpl);
|
||||
if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX") != 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
value += ((guint64) time (NULL)) ^ getpid ();
|
||||
|
||||
for (i = 0; i < TMP_MAX; ++i, value += 7777)
|
||||
{
|
||||
/* fill in the random bits */
|
||||
for (j = 0, v = value; j < 6; ++j)
|
||||
tmpl[(len - 6) + j] = LETTERS[v % 62];
|
||||
v /= 62;
|
||||
|
||||
/* try to create the directory */
|
||||
if (g_mkdir (tmpl, 0700) == 0)
|
||||
return tmpl;
|
||||
else if (errno != EEXIST)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
tse_compress (GList *infos,
|
||||
gchar **zipfile_return)
|
||||
{
|
||||
TseData *tse_data;
|
||||
gboolean succeed = TRUE;
|
||||
GError *error = NULL;
|
||||
GFile *parent;
|
||||
GFile *parent_parent;
|
||||
gchar **argv;
|
||||
gchar *base_name;
|
||||
gchar *zipfile;
|
||||
gchar *tmppath;
|
||||
gchar *tmpdir;
|
||||
gchar *path;
|
||||
gchar *dot;
|
||||
GList *lp;
|
||||
gint n;
|
||||
|
||||
/* create a temporary directory */
|
||||
tmpdir = g_strdup ("/tmp/thunar-sendto-email.XXXXXX");
|
||||
if (G_UNLIKELY (mkdtemp (tmpdir) == NULL))
|
||||
{
|
||||
/* tell the user that we failed to create a temporary directory */
|
||||
error = g_error_new_literal (G_FILE_ERROR, g_file_error_from_errno (errno), g_strerror (errno));
|
||||
tse_error (error, _("Failed to create temporary directory"));
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check if we have only a single file/folder to compress */
|
||||
if (G_LIKELY (infos != NULL && infos->next == NULL))
|
||||
{
|
||||
/* determine the name for the ZIP file */
|
||||
tse_data = (TseData *) infos->data;
|
||||
path = g_strdup (g_file_info_get_display_name (tse_data->info));
|
||||
dot = strrchr (path, '.');
|
||||
if (G_LIKELY (dot != NULL))
|
||||
*dot = '\0';
|
||||
zipfile = g_strconcat (tmpdir, G_DIR_SEPARATOR_S, path, ".zip", NULL);
|
||||
g_free (path);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* determine the name for the ZIP file */
|
||||
tse_data = (TseData *) infos->data;
|
||||
parent = g_file_get_parent (tse_data->file);
|
||||
|
||||
/* we assume the parent exists because we only allow non-root
|
||||
* files as TseData in main () */
|
||||
g_assert (parent != NULL);
|
||||
|
||||
parent_parent = g_file_get_parent (parent);
|
||||
|
||||
if (parent_parent != NULL)
|
||||
{
|
||||
/* use the parent directory's name */
|
||||
base_name = g_file_get_basename (parent);
|
||||
zipfile = g_strconcat (tmpdir, G_DIR_SEPARATOR_S, base_name, ".zip", NULL);
|
||||
g_free (base_name);
|
||||
|
||||
g_object_unref (parent_parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use the first file's name */
|
||||
zipfile = g_strconcat (tmpdir, G_DIR_SEPARATOR_S, g_file_info_get_display_name (tse_data->info), ".zip", NULL);
|
||||
}
|
||||
|
||||
g_object_unref (parent);
|
||||
}
|
||||
|
||||
/* generate the argument list for the ZIP command */
|
||||
argv = g_new0 (gchar *, g_list_length (infos) + 5);
|
||||
argv[0] = g_strdup ("zip");
|
||||
argv[1] = g_strdup ("-q");
|
||||
argv[2] = g_strdup ("-r");
|
||||
argv[3] = g_strdup (zipfile);
|
||||
for (lp = infos, n = 4; lp != NULL && succeed; lp = lp->next, ++n)
|
||||
{
|
||||
/* create a symlink for the file to the tmp dir */
|
||||
tse_data = (TseData *) lp->data;
|
||||
path = g_file_get_path (tse_data->file);
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
error = g_error_new_literal (G_FILE_ERROR, g_file_error_from_errno (ENOTSUP), g_strerror (errno));
|
||||
tse_error (error, _("Failed to create symbolic link for \"%s\""), g_file_info_get_display_name (tse_data->info));
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmppath = g_build_filename (tmpdir, g_file_get_basename (tse_data->file), NULL);
|
||||
succeed = (symlink (path, tmppath) == 0);
|
||||
if (G_UNLIKELY (!succeed))
|
||||
{
|
||||
/* tell the user that we failed to create a symlink for this file */
|
||||
error = g_error_new_literal (G_FILE_ERROR, g_file_error_from_errno (errno), g_strerror (errno));
|
||||
tse_error (error, _("Failed to create symbolic link for \"%s\""), g_file_info_get_display_name (tse_data->info));
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* add the file to the ZIP command line */
|
||||
argv[n] = g_path_get_basename (tmppath);
|
||||
}
|
||||
g_free (tmppath);
|
||||
g_free (path);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we succeed up to this point */
|
||||
if (G_LIKELY (succeed))
|
||||
{
|
||||
/* try to run the ZIP command */
|
||||
succeed = tse_progress (tmpdir, argv, &error);
|
||||
if (G_UNLIKELY (!succeed))
|
||||
{
|
||||
/* check if we failed or the user cancelled */
|
||||
if (G_LIKELY (error != NULL))
|
||||
{
|
||||
/* tell the user that we failed to compress the file(s) */
|
||||
tse_error (error, ngettext ("Failed to compress %d file", "Failed to compress %d files", g_list_length (infos)),
|
||||
g_list_length (infos));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* delete the temporary directory */
|
||||
dot = g_strdup_printf ("rm -rf '%s'", tmpdir);
|
||||
g_spawn_command_line_sync (dot, NULL, NULL, NULL, NULL);
|
||||
g_free (dot);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* return the path to the compressed file */
|
||||
*zipfile_return = zipfile;
|
||||
zipfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_strfreev (argv);
|
||||
g_free (zipfile);
|
||||
g_free (tmpdir);
|
||||
|
||||
return succeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GFileInfo *info;
|
||||
TseData *tse_data;
|
||||
GFile *file;
|
||||
GFile *parent;
|
||||
GString *mailto;
|
||||
GError *error = NULL;
|
||||
GList *infos = NULL;
|
||||
gchar **attachments = NULL;
|
||||
gchar *zipfile = NULL;
|
||||
GList *lp;
|
||||
gint response;
|
||||
gint n;
|
||||
|
||||
/* setup translation domain */
|
||||
xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
/* Do NOT remove this line for now, If something doesn't work,
|
||||
* fix your code instead!
|
||||
*/
|
||||
g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
|
||||
#endif
|
||||
|
||||
/* initialize Gtk+ */
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
/* set default icon for dialogs */
|
||||
gtk_window_set_default_icon_name ("internet-mail");
|
||||
|
||||
/* verify that atleast one file was supplied */
|
||||
if (G_UNLIKELY (argc == 1))
|
||||
{
|
||||
g_fprintf (stderr, "Usage: thunar-sendto-email [FILES...]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* determine the GFiles and GFileInfos (bundled as TseData) for the files */
|
||||
for (n = 1; n < argc; ++n)
|
||||
{
|
||||
/* try to transform to a GFile */
|
||||
file = g_file_new_for_commandline_arg (argv[n]);
|
||||
|
||||
/* verify that we're not trying to send root */
|
||||
parent = g_file_get_parent (file);
|
||||
if (parent == NULL)
|
||||
{
|
||||
error = g_error_new_literal (G_FILE_ERROR, g_file_error_from_errno (EFBIG), g_strerror (EFBIG));
|
||||
g_fprintf (stderr, "thunar-sendto-email: Invalid argument \"%s\": %s\n", argv[n], error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_object_unref (parent);
|
||||
}
|
||||
|
||||
/* try to determine the info */
|
||||
info = g_file_query_info (file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
|
||||
G_FILE_QUERY_INFO_NONE, NULL, &error);
|
||||
|
||||
/* check if we failed */
|
||||
if (G_UNLIKELY (info == NULL))
|
||||
{
|
||||
g_fprintf (stderr, "thunar-sendto-email: Invalid argument \"%s\": %s\n", argv[n], error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tse_data = g_slice_new0 (TseData);
|
||||
tse_data->info = info;
|
||||
tse_data->file = file;
|
||||
|
||||
/* add to our list of infos */
|
||||
infos = g_list_append (infos, tse_data);
|
||||
}
|
||||
|
||||
/* check whether to compress the files */
|
||||
response = tse_ask_compress (infos);
|
||||
if (response == TSE_RESPONSE_COMPRESS)
|
||||
{
|
||||
/* try to compress the files */
|
||||
if (tse_compress (infos, &zipfile))
|
||||
{
|
||||
/* we have only a single attachment now */
|
||||
attachments = g_new0 (gchar *, 2);
|
||||
attachments[0] = g_filename_to_uri (zipfile, NULL, NULL);
|
||||
g_free (zipfile);
|
||||
}
|
||||
}
|
||||
else if (response == TSE_RESPONSE_PLAIN)
|
||||
{
|
||||
/* attach the files one by one */
|
||||
attachments = g_new0 (gchar *, g_list_length (infos) + 1);
|
||||
for (lp = infos, n = 0; lp != NULL; lp = lp->next, ++n)
|
||||
{
|
||||
tse_data = (TseData *) lp->data;
|
||||
attachments[n] = g_file_get_uri (tse_data->file);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we have anything to attach */
|
||||
if (G_LIKELY (attachments != NULL))
|
||||
{
|
||||
/* no specific email address */
|
||||
mailto = g_string_new ("?");
|
||||
for (n = 0; attachments[n] != NULL; ++n)
|
||||
g_string_append_printf (mailto, "attach=%s&", attachments[n]);
|
||||
g_strfreev (attachments);
|
||||
|
||||
/* open the mail composer */
|
||||
if (!exo_execute_preferred_application ("MailReader", mailto->str, NULL, NULL, &error))
|
||||
{
|
||||
/* tell the user that we failed */
|
||||
tse_error (error, _("Failed to compose new email"));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_string_free (mailto, TRUE);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
for (lp = infos; lp != NULL; lp = lp->next)
|
||||
{
|
||||
tse_data = (TseData *) lp->data;
|
||||
g_object_unref (tse_data->file);
|
||||
g_object_unref (tse_data->info);
|
||||
g_slice_free (TseData, tse_data);
|
||||
}
|
||||
g_list_free (infos);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Version=1.0
|
||||
Name=Mail Recipient
|
||||
Icon=mail-send
|
||||
Exec=@HELPERDIR@/Thunar/thunar-sendto-email %F
|
||||
63
plugins/thunar-tpa/Makefile.am
Normal file
63
plugins/thunar-tpa/Makefile.am
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/plugins \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/plugins \
|
||||
-DG_LOG_DOMAIN=\"libthunar-tpa\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
plugindir = $(libdir)/xfce4/panel/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libthunar-tpa.la
|
||||
|
||||
libthunar_tpa_la_SOURCES = \
|
||||
thunar-tpa.c \
|
||||
thunar-tpa-bindings.c \
|
||||
thunar-tpa-bindings.h
|
||||
|
||||
libthunar_tpa_la_CFLAGS = \
|
||||
$(LIBXFCE4UI_CFLAGS) \
|
||||
$(LIBXFCE4UTIL_CFLAGS) \
|
||||
$(LIBXFCE4PANEL_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
libthunar_tpa_la_LIBADD = \
|
||||
$(LIBXFCE4UTIL_LIBS) \
|
||||
$(LIBXFCE4UI_LIBS) \
|
||||
$(LIBXFCE4PANEL_LIBS)
|
||||
|
||||
libthunar_tpa_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-module \
|
||||
-no-undefined \
|
||||
-export-symbols-regex '^xfce_panel_module_(preinit|init|construct)' \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
desktopdir = $(datadir)/xfce4/panel/plugins
|
||||
desktop_in_files = thunar-tpa.desktop.in
|
||||
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
|
||||
%.desktop: %.desktop.in Makefile
|
||||
$(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
if MAINTAINER_MODE
|
||||
BUILT_SOURCES = \
|
||||
thunar-tpa-bindings.c \
|
||||
thunar-tpa-bindings.h
|
||||
|
||||
DISTCLEANFILES = \
|
||||
thunar-tpa-bindings.c \
|
||||
thunar-tpa-bindings.h
|
||||
|
||||
thunar-tpa-bindings.c thunar-tpa-bindings.h: $(srcdir)/thunar-tpa-bindings.xml Makefile
|
||||
$(AM_V_GEN) gdbus-codegen --generate-c-code thunar-tpa-bindings --c-namespace thunarTPA --interface-prefix org.xfce. $(srcdir)/thunar-tpa-bindings.xml
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(desktop_in_files) \
|
||||
thunar-tpa-bindings.xml \
|
||||
README.md
|
||||
|
||||
CLEANFILES = \
|
||||
$(desktop_DATA)
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
20
plugins/thunar-tpa/README.md
Normal file
20
plugins/thunar-tpa/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Thunar Trash Panel Applet (thunar-tpa)
|
||||
======================================
|
||||
|
||||
Thunar-tpa is an extension for the Xfce Panel, which enables users to add a trash can to their panel, that
|
||||
|
||||
* displays the current state of the trash can
|
||||
* can move files to the trash by dropping them on the trash icon
|
||||
* can empty the trash can
|
||||
* can open the trash can
|
||||
|
||||
In order to build and install this plugin, you will need to have the xfce4-panel development headers and libraries installed (the appropriate package is usually called xfce4-panel-dev or xfce4-panel-devel). In addition, you'll need to have D-BUS 0.34 or above installed and Thunar must be built with D-BUS support.
|
||||
|
||||
|
||||
How does it work?
|
||||
=================
|
||||
|
||||
To avoid running several desktop processes that all monitor and manage the trash can by itself, and thereby create an unnecessary maintaince and resource overhead, the trash applet simply connects to Thunar via D-BUS to query the state of the trash and send commands to the Trash.
|
||||
|
||||
The trash applet is not limited to Thunar, but can work with any file manager that implements the org.xfce.Trash interface and owns the org.xfce.FileManager service. See the thunar-tpa bindings.xml file for a details about the inter- face.
|
||||
|
||||
104
plugins/thunar-tpa/thunar-tpa-bindings.xml
Normal file
104
plugins/thunar-tpa/thunar-tpa-bindings.xml
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
-->
|
||||
|
||||
<node name="/org/xfce/FileManager">
|
||||
<!--
|
||||
org.xfce.Trash
|
||||
|
||||
The generic Xfce Trash Bin interface, implemented by all Xfce File
|
||||
Managers that support a trash bin.
|
||||
-->
|
||||
<interface name="org.xfce.Trash">
|
||||
<!--
|
||||
DisplayTrash (display : STRING) : VOID
|
||||
|
||||
display : the screen on which to display the trash folder
|
||||
contents or "" to use the default screen of the
|
||||
file manager.
|
||||
startup_id : the DESKTOP_STARTUP_ID environment variable for properly
|
||||
handling startup notification and focus stealing.
|
||||
|
||||
Opens a new file manager window showing the trash folder
|
||||
contents.
|
||||
-->
|
||||
<method name="DisplayTrash">
|
||||
<arg direction="in" name="display" type="s" />
|
||||
<arg direction="in" name="startup_id" type="s" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
EmptyTrash (display : STRING) : VOID
|
||||
|
||||
display : the screen on which to display the confirmation of
|
||||
the operation and the progress status or "" to use
|
||||
the default screen of the file manager.
|
||||
startup_id : the DESKTOP_STARTUP_ID environment variable for properly
|
||||
handling startup notification and focus stealing.
|
||||
|
||||
Tells the file manager to empty the trash bin.
|
||||
-->
|
||||
<method name="EmptyTrash">
|
||||
<arg direction="in" name="display" type="s" />
|
||||
<arg direction="in" name="startup_id" type="s" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
MoveToTrash (uris : ARRAY OF STRING, display : STRING) : VOID
|
||||
|
||||
filenames : an array of file:-URIs or absolute paths for the files
|
||||
that should be moved to the trash can.
|
||||
display : the screen on which to display the progress dialog
|
||||
and possible error messages and confirmation dialogs
|
||||
or "" to use the default screen of the file manager.
|
||||
startup_id : the DESKTOP_STARTUP_ID environment variable for properly
|
||||
handling startup notification and focus stealing.
|
||||
|
||||
Tells the file manager to move all files specified by the filenames
|
||||
to the trash bin.
|
||||
-->
|
||||
<method name="MoveToTrash">
|
||||
<arg direction="in" name="filenames" type="as" />
|
||||
<arg direction="in" name="display" type="s" />
|
||||
<arg direction="in" name="startup_id" type="s" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
QueryTrash () : BOOLEAN
|
||||
|
||||
Determines whether the trash bin contains atleast one
|
||||
item.
|
||||
|
||||
Returns: TRUE if the trash bin is not empty, FALSE otherwise.
|
||||
-->
|
||||
<method name="QueryTrash">
|
||||
<arg direction="out" name="full" type="b" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
TrashChanged ()
|
||||
|
||||
This signal is emitted by the file manager whenever the state
|
||||
of the trash bin changes.
|
||||
-->
|
||||
<signal name="TrashChanged"/>
|
||||
</interface>
|
||||
</node>
|
||||
|
||||
<!-- vi:set ts=2 sw=2 et ai: -->
|
||||
610
plugins/thunar-tpa/thunar-tpa.c
Normal file
610
plugins/thunar-tpa/thunar-tpa.c
Normal file
|
|
@ -0,0 +1,610 @@
|
|||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
* Copyright (c) 2010 Nick Schermer <nick@xfce.org>
|
||||
* Copyright (c) 2010 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libxfce4panel/libxfce4panel.h>
|
||||
#include <libxfce4panel/xfce-panel-macros.h>
|
||||
#include <libxfce4ui/libxfce4ui.h>
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-tpa/thunar-tpa-bindings.h>
|
||||
|
||||
typedef struct _ThunarTpaClass ThunarTpaClass;
|
||||
typedef struct _ThunarTpa ThunarTpa;
|
||||
|
||||
|
||||
|
||||
#define THUNAR_TYPE_TPA (thunar_tpa_get_type ())
|
||||
#define THUNAR_TPA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_TPA, ThunarTpa))
|
||||
#define THUNAR_TPA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_TPA, ThunarTpaClass))
|
||||
#define THUNAR_IS_TPA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_TPA))
|
||||
#define THUNAR_IS_TPA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_TPA))
|
||||
#define THUNAR_TPA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_TPA, ThunarTpaClass))
|
||||
|
||||
|
||||
|
||||
GType
|
||||
thunar_tpa_get_type (void);
|
||||
void
|
||||
thunar_tpa_register_type (XfcePanelTypeModule *type_module);
|
||||
static void
|
||||
thunar_tpa_finalize (GObject *object);
|
||||
static void
|
||||
thunar_tpa_construct (XfcePanelPlugin *panel_plugin);
|
||||
static gboolean
|
||||
thunar_tpa_size_changed (XfcePanelPlugin *panel_plugin,
|
||||
gint size);
|
||||
static void
|
||||
thunar_tpa_error (ThunarTpa *plugin,
|
||||
GError *error);
|
||||
static void
|
||||
thunar_tpa_state (ThunarTpa *plugin,
|
||||
gboolean full);
|
||||
static void
|
||||
thunar_tpa_display_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
static void
|
||||
thunar_tpa_empty_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
static void
|
||||
thunar_tpa_move_to_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
static void
|
||||
thunar_tpa_query_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
static void
|
||||
thunar_tpa_drag_data_received (GtkWidget *button,
|
||||
GdkDragContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time,
|
||||
ThunarTpa *plugin);
|
||||
static gboolean
|
||||
thunar_tpa_enter_notify_event (GtkWidget *button,
|
||||
GdkEventCrossing *event,
|
||||
ThunarTpa *plugin);
|
||||
static gboolean
|
||||
thunar_tpa_leave_notify_event (GtkWidget *button,
|
||||
GdkEventCrossing *event,
|
||||
ThunarTpa *plugin);
|
||||
static void
|
||||
thunar_tpa_on_trash_changed (thunarTPATrash *proxy,
|
||||
gpointer user_data);
|
||||
static void
|
||||
thunar_tpa_display_trash (ThunarTpa *plugin);
|
||||
static void
|
||||
thunar_tpa_empty_trash (ThunarTpa *plugin);
|
||||
static gboolean
|
||||
thunar_tpa_move_to_trash (ThunarTpa *plugin,
|
||||
const gchar **uri_list);
|
||||
static void
|
||||
thunar_tpa_query_trash (ThunarTpa *plugin);
|
||||
|
||||
|
||||
|
||||
struct _ThunarTpaClass
|
||||
{
|
||||
XfcePanelPluginClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarTpa
|
||||
{
|
||||
XfcePanelPlugin __parent__;
|
||||
|
||||
/* widgets */
|
||||
GtkWidget *button;
|
||||
GtkWidget *image;
|
||||
GtkWidget *mi;
|
||||
|
||||
thunarTPATrash *proxy;
|
||||
GCancellable *cancellable_display_trash;
|
||||
GCancellable *cancellable_empty_trash;
|
||||
GCancellable *cancellable_move_to_trash;
|
||||
GCancellable *cancellable_query_trash;
|
||||
};
|
||||
|
||||
/* Target types for dropping to the trash can */
|
||||
enum
|
||||
{
|
||||
TARGET_TEXT_URI_LIST,
|
||||
};
|
||||
|
||||
static const GtkTargetEntry drop_targets[] = {
|
||||
{
|
||||
"text/uri-list",
|
||||
0,
|
||||
TARGET_TEXT_URI_LIST,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* define the plugin */
|
||||
XFCE_PANEL_DEFINE_PLUGIN (ThunarTpa, thunar_tpa)
|
||||
|
||||
/* Hint: For debugging the plugin run the panel with "PANEL_DEBUG=1 xfce4-panel" */
|
||||
|
||||
static void
|
||||
thunar_tpa_class_init (ThunarTpaClass *klass)
|
||||
{
|
||||
XfcePanelPluginClass *plugin_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_tpa_finalize;
|
||||
|
||||
plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
|
||||
plugin_class->construct = thunar_tpa_construct;
|
||||
plugin_class->size_changed = thunar_tpa_size_changed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_init (ThunarTpa *plugin)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
/* setup the button for the trash plugin */
|
||||
plugin->button = xfce_panel_create_button ();
|
||||
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
|
||||
gtk_drag_dest_set (plugin->button, GTK_DEST_DEFAULT_ALL, drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_MOVE);
|
||||
g_signal_connect_swapped (G_OBJECT (plugin->button), "clicked", G_CALLBACK (thunar_tpa_display_trash), plugin);
|
||||
g_signal_connect (G_OBJECT (plugin->button), "drag-data-received", G_CALLBACK (thunar_tpa_drag_data_received), plugin);
|
||||
g_signal_connect (G_OBJECT (plugin->button), "enter-notify-event", G_CALLBACK (thunar_tpa_enter_notify_event), plugin);
|
||||
g_signal_connect (G_OBJECT (plugin->button), "leave-notify-event", G_CALLBACK (thunar_tpa_leave_notify_event), plugin);
|
||||
gtk_container_add (GTK_CONTAINER (plugin), plugin->button);
|
||||
gtk_widget_show (plugin->button);
|
||||
|
||||
/* setup the image for the trash plugin */
|
||||
plugin->image = gtk_image_new_from_icon_name ("user-trash", GTK_ICON_SIZE_BUTTON);
|
||||
gtk_container_add (GTK_CONTAINER (plugin->button), plugin->image);
|
||||
gtk_widget_show (plugin->image);
|
||||
|
||||
/* prepare the menu item */
|
||||
plugin->mi = gtk_menu_item_new_with_mnemonic (_("_Empty Trash"));
|
||||
g_signal_connect_swapped (G_OBJECT (plugin->mi), "activate", G_CALLBACK (thunar_tpa_empty_trash), plugin);
|
||||
gtk_widget_show (plugin->mi);
|
||||
|
||||
plugin->cancellable_display_trash = g_cancellable_new ();
|
||||
plugin->cancellable_empty_trash = g_cancellable_new ();
|
||||
plugin->cancellable_move_to_trash = g_cancellable_new ();
|
||||
plugin->cancellable_query_trash = g_cancellable_new ();
|
||||
|
||||
plugin->proxy = thunar_tpa_trash_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, "org.xfce.FileManager", "/org/xfce/FileManager", NULL, &error);
|
||||
|
||||
if (error != NULL)
|
||||
thunar_tpa_error (plugin, error);
|
||||
|
||||
g_signal_connect (plugin->proxy, "trash_changed", G_CALLBACK (thunar_tpa_on_trash_changed), plugin);
|
||||
}
|
||||
|
||||
static void
|
||||
thunar_tpa_finalize (GObject *object)
|
||||
{
|
||||
ThunarTpa *plugin = THUNAR_TPA (object);
|
||||
|
||||
/* cancel any pending calls */
|
||||
if (G_LIKELY (plugin->cancellable_display_trash != NULL))
|
||||
{
|
||||
g_cancellable_cancel (plugin->cancellable_display_trash);
|
||||
g_object_unref (plugin->cancellable_display_trash);
|
||||
}
|
||||
if (G_LIKELY (plugin->cancellable_empty_trash != NULL))
|
||||
{
|
||||
g_cancellable_cancel (plugin->cancellable_empty_trash);
|
||||
g_object_unref (plugin->cancellable_empty_trash);
|
||||
}
|
||||
if (G_LIKELY (plugin->cancellable_move_to_trash != NULL))
|
||||
{
|
||||
g_cancellable_cancel (plugin->cancellable_move_to_trash);
|
||||
g_object_unref (plugin->cancellable_move_to_trash);
|
||||
}
|
||||
if (G_LIKELY (plugin->cancellable_query_trash != NULL))
|
||||
{
|
||||
g_cancellable_cancel (plugin->cancellable_query_trash);
|
||||
g_object_unref (plugin->cancellable_query_trash);
|
||||
}
|
||||
|
||||
/* release the proxy object */
|
||||
if (G_LIKELY (plugin->proxy != NULL))
|
||||
g_object_unref (G_OBJECT (plugin->proxy));
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_tpa_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_construct (XfcePanelPlugin *panel_plugin)
|
||||
{
|
||||
ThunarTpa *plugin = THUNAR_TPA (panel_plugin);
|
||||
|
||||
/* make the plugin fit a single row */
|
||||
xfce_panel_plugin_set_small (panel_plugin, TRUE);
|
||||
|
||||
/* add the "Empty Trash" menu item */
|
||||
xfce_panel_plugin_menu_insert_item (panel_plugin, GTK_MENU_ITEM (plugin->mi));
|
||||
|
||||
/* update the state of the trash plugin */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_tpa_size_changed (XfcePanelPlugin *panel_plugin,
|
||||
gint size)
|
||||
{
|
||||
ThunarTpa *plugin = THUNAR_TPA (panel_plugin);
|
||||
gint image_size;
|
||||
|
||||
/* make the plugin fit a single row */
|
||||
size /= xfce_panel_plugin_get_nrows (panel_plugin);
|
||||
gtk_widget_set_size_request (GTK_WIDGET (panel_plugin), size, size);
|
||||
|
||||
#if LIBXFCE4PANEL_CHECK_VERSION(4, 13, 0)
|
||||
image_size = xfce_panel_plugin_get_icon_size (panel_plugin);
|
||||
#else
|
||||
image_size = size - 2; // fall-back for older panel versions
|
||||
#endif
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (plugin->image), image_size);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_error (ThunarTpa *plugin,
|
||||
GError *error)
|
||||
{
|
||||
gchar *tooltip;
|
||||
|
||||
/* reset to empty first */
|
||||
thunar_tpa_state (plugin, FALSE);
|
||||
|
||||
/* strip off additional whitespace */
|
||||
g_strstrip (error->message);
|
||||
|
||||
/* tell the user that we failed to connect to the trash */
|
||||
tooltip = g_strdup_printf ("%s: %s.", _("Failed to connect to the Trash"), error->message);
|
||||
gtk_widget_set_tooltip_text (plugin->button, tooltip);
|
||||
g_free (tooltip);
|
||||
|
||||
/* setup an error plugin */
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (plugin->image), "stock_dialog-error", GTK_ICON_SIZE_BUTTON);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_state (ThunarTpa *plugin,
|
||||
gboolean full)
|
||||
{
|
||||
/* tell the user whether the trash is full or empty */
|
||||
gtk_widget_set_tooltip_text (plugin->button, full ? _("Trash contains files") : _("Trash is empty"));
|
||||
|
||||
/* setup the appropriate plugin */
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (plugin->image), full ? "user-trash-full" : "user-trash", GTK_ICON_SIZE_BUTTON);
|
||||
|
||||
/* sensitivity of the menu item */
|
||||
gtk_widget_set_sensitive (plugin->mi, full);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_display_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
thunarTPATrash *proxy = THUNAR_TPA_TRASH (source_object);
|
||||
gboolean success = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
success = thunar_tpa_trash_call_display_trash_finish (proxy, result, &error);
|
||||
if (G_UNLIKELY (success != TRUE))
|
||||
{
|
||||
/* display an error message to the user */
|
||||
g_strstrip (error->message);
|
||||
xfce_dialog_show_error (NULL, error, "%s.", _("Failed to connect to the Trash"));
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_empty_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
thunarTPATrash *proxy = THUNAR_TPA_TRASH (source_object);
|
||||
ThunarTpa *plugin = THUNAR_TPA (user_data);
|
||||
gboolean success = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
success = thunar_tpa_trash_call_empty_trash_finish (proxy, result, &error);
|
||||
if (G_LIKELY (success))
|
||||
{
|
||||
/* query the new state of the trash */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* display an error message to the user */
|
||||
g_strstrip (error->message);
|
||||
xfce_dialog_show_error (NULL, error, "%s.", _("Failed to connect to the Trash"));
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_move_to_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
thunarTPATrash *proxy = THUNAR_TPA_TRASH (source_object);
|
||||
ThunarTpa *plugin = THUNAR_TPA (user_data);
|
||||
gboolean success = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
success = thunar_tpa_trash_call_move_to_trash_finish (proxy, result, &error);
|
||||
if (G_LIKELY (success))
|
||||
{
|
||||
/* query the new state of the trash */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* display an error message to the user */
|
||||
g_strstrip (error->message);
|
||||
xfce_dialog_show_error (NULL, error, "%s.", _("Failed to connect to the Trash"));
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_query_trash_reply (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
thunarTPATrash *proxy = THUNAR_TPA_TRASH (source_object);
|
||||
ThunarTpa *plugin = THUNAR_TPA (user_data);
|
||||
gboolean success = FALSE;
|
||||
GError *error = NULL;
|
||||
gboolean full;
|
||||
|
||||
success = thunar_tpa_trash_call_query_trash_finish (proxy, &full, result, &error);
|
||||
if (G_LIKELY (success))
|
||||
{
|
||||
/* update the tooltip/plugin accordingly */
|
||||
thunar_tpa_state (plugin, full);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* setup an error tooltip/plugin */
|
||||
thunar_tpa_error (plugin, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_drag_data_received (GtkWidget *button,
|
||||
GdkDragContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint timestamp,
|
||||
ThunarTpa *plugin)
|
||||
{
|
||||
gboolean succeed = FALSE;
|
||||
gchar **uri_list;
|
||||
|
||||
g_return_if_fail (THUNAR_IS_TPA (plugin));
|
||||
g_return_if_fail (plugin->button == button);
|
||||
|
||||
/* determine the type of drop we received */
|
||||
if (G_LIKELY (info == TARGET_TEXT_URI_LIST))
|
||||
{
|
||||
/* check if the data is valid for text/uri-list */
|
||||
uri_list = gtk_selection_data_get_uris (selection_data);
|
||||
if (G_LIKELY (uri_list != NULL))
|
||||
{
|
||||
succeed = thunar_tpa_move_to_trash (plugin, (const gchar **) uri_list);
|
||||
g_strfreev (uri_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* finish the drag */
|
||||
gtk_drag_finish (context, succeed, TRUE, timestamp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_tpa_enter_notify_event (GtkWidget *button,
|
||||
GdkEventCrossing *event,
|
||||
ThunarTpa *plugin)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_IS_TPA (plugin), FALSE);
|
||||
g_return_val_if_fail (plugin->button == button, FALSE);
|
||||
|
||||
/* query the new state of the trash */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_tpa_leave_notify_event (GtkWidget *button,
|
||||
GdkEventCrossing *event,
|
||||
ThunarTpa *plugin)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_IS_TPA (plugin), FALSE);
|
||||
g_return_val_if_fail (plugin->button == button, FALSE);
|
||||
|
||||
/* query the new state of the trash */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_on_trash_changed (thunarTPATrash *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
ThunarTpa *plugin = THUNAR_TPA (user_data);
|
||||
|
||||
g_return_if_fail (THUNAR_IS_TPA (plugin));
|
||||
g_return_if_fail (plugin->proxy == proxy);
|
||||
|
||||
/* update the state of the trash plugin */
|
||||
thunar_tpa_query_trash (plugin);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_display_trash (ThunarTpa *plugin)
|
||||
{
|
||||
gchar *display_name;
|
||||
gchar *startup_id;
|
||||
GdkScreen *screen;
|
||||
|
||||
g_return_if_fail (THUNAR_IS_TPA (plugin));
|
||||
|
||||
/* check if we are connected to the bus */
|
||||
if (G_LIKELY (plugin->proxy != NULL))
|
||||
{
|
||||
/* cancel any pending call and reset the cancellable */
|
||||
g_cancellable_cancel (plugin->cancellable_display_trash);
|
||||
g_cancellable_reset (plugin->cancellable_display_trash);
|
||||
|
||||
/* schedule a new call */
|
||||
screen = gtk_widget_get_screen (GTK_WIDGET (plugin));
|
||||
display_name = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen)));
|
||||
startup_id = g_strdup_printf ("_TIME%d", gtk_get_current_event_time ());
|
||||
thunar_tpa_trash_call_display_trash (plugin->proxy, display_name, startup_id, plugin->cancellable_display_trash, thunar_tpa_display_trash_reply, plugin);
|
||||
g_free (startup_id);
|
||||
g_free (display_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_empty_trash (ThunarTpa *plugin)
|
||||
{
|
||||
gchar *display_name;
|
||||
gchar *startup_id;
|
||||
GdkScreen *screen;
|
||||
|
||||
g_return_if_fail (THUNAR_IS_TPA (plugin));
|
||||
|
||||
/* check if we are connected to the bus */
|
||||
if (G_LIKELY (plugin->proxy != NULL))
|
||||
{
|
||||
/* cancel any pending call and reset the cancellable */
|
||||
g_cancellable_cancel (plugin->cancellable_empty_trash);
|
||||
g_cancellable_reset (plugin->cancellable_empty_trash);
|
||||
|
||||
/* schedule a new call */
|
||||
screen = gtk_widget_get_screen (GTK_WIDGET (plugin));
|
||||
display_name = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen)));
|
||||
startup_id = g_strdup_printf ("_TIME%d", gtk_get_current_event_time ());
|
||||
thunar_tpa_trash_call_empty_trash (plugin->proxy, display_name, startup_id, plugin->cancellable_empty_trash, thunar_tpa_empty_trash_reply, plugin);
|
||||
g_free (startup_id);
|
||||
g_free (display_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_tpa_move_to_trash (ThunarTpa *plugin,
|
||||
const gchar **uri_list)
|
||||
{
|
||||
gchar *display_name;
|
||||
gchar *startup_id;
|
||||
GdkScreen *screen;
|
||||
|
||||
g_return_val_if_fail (THUNAR_IS_TPA (plugin), FALSE);
|
||||
g_return_val_if_fail (uri_list != NULL, FALSE);
|
||||
|
||||
/* check if we are connected to the bus */
|
||||
if (G_UNLIKELY (plugin->proxy == NULL))
|
||||
return FALSE;
|
||||
|
||||
/* cancel any pending call and reset the cancellable */
|
||||
g_cancellable_cancel (plugin->cancellable_move_to_trash);
|
||||
g_cancellable_reset (plugin->cancellable_move_to_trash);
|
||||
|
||||
/* schedule a new call */
|
||||
screen = gtk_widget_get_screen (GTK_WIDGET (plugin));
|
||||
display_name = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen)));
|
||||
startup_id = g_strdup_printf ("_TIME%d", gtk_get_current_event_time ());
|
||||
thunar_tpa_trash_call_move_to_trash (plugin->proxy, uri_list, display_name, startup_id, plugin->cancellable_move_to_trash, thunar_tpa_move_to_trash_reply, plugin);
|
||||
g_free (startup_id);
|
||||
g_free (display_name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_tpa_query_trash (ThunarTpa *plugin)
|
||||
{
|
||||
g_return_if_fail (THUNAR_IS_TPA (plugin));
|
||||
|
||||
/* check if we are connected to the bus */
|
||||
if (G_LIKELY (plugin->proxy != NULL))
|
||||
{
|
||||
/* cancel any pending call and reset the cancellable */
|
||||
g_cancellable_cancel (plugin->cancellable_query_trash);
|
||||
g_cancellable_reset (plugin->cancellable_query_trash);
|
||||
|
||||
/* schedule a new call */
|
||||
thunar_tpa_trash_call_query_trash (plugin->proxy, plugin->cancellable_query_trash, thunar_tpa_query_trash_reply, plugin);
|
||||
}
|
||||
}
|
||||
9
plugins/thunar-tpa/thunar-tpa.desktop.in
Normal file
9
plugins/thunar-tpa/thunar-tpa.desktop.in
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[Xfce Panel]
|
||||
Type=X-XFCE-PanelPlugin
|
||||
Name=Trash Applet
|
||||
Comment=Display the trash can
|
||||
Icon=user-trash
|
||||
X-XFCE-Module=thunar-tpa
|
||||
X-XFCE-Internal=FALSE
|
||||
X-XFCE-API=2.0
|
||||
X-XFCE-Unique=true
|
||||
84
plugins/thunar-uca/Makefile.am
Normal file
84
plugins/thunar-uca/Makefile.am
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/plugins \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/plugins \
|
||||
-DBINDIR=\"$(bindir)\" \
|
||||
-DDATADIR=\"$(datadir)\" \
|
||||
-DG_LOG_DOMAIN=\"thunar-uca\" \
|
||||
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
extensionsdir = $(libdir)/thunarx-$(THUNARX_VERSION_API)
|
||||
extensions_LTLIBRARIES = \
|
||||
thunar-uca.la
|
||||
|
||||
thunar_uca_la_SOURCES = \
|
||||
thunar-uca-chooser.c \
|
||||
thunar-uca-chooser.h \
|
||||
thunar-uca-context.c \
|
||||
thunar-uca-context.h \
|
||||
thunar-uca-editor.c \
|
||||
thunar-uca-editor.h \
|
||||
thunar-uca-model.c \
|
||||
thunar-uca-model.h \
|
||||
thunar-uca-plugin.c \
|
||||
thunar-uca-private.c \
|
||||
thunar-uca-private.h \
|
||||
thunar-uca-provider.c \
|
||||
thunar-uca-provider.h \
|
||||
thunar-uca.gresource.c
|
||||
|
||||
thunar_uca_la_CFLAGS = \
|
||||
$(EXO_CFLAGS) \
|
||||
$(LIBXFCE4UTIL_CFLAGS) \
|
||||
$(LIBXFCE4UI_CFLAGS) \
|
||||
$(LIBXFCE4KBD_PRIVATE_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
thunar_uca_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
-no-undefined \
|
||||
-export-symbols-regex "^thunar_extension_(shutdown|initialize|list_types)" \
|
||||
-module \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
thunar_uca_la_LIBADD = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la \
|
||||
$(EXO_LIBS) \
|
||||
$(LIBXFCE4UTIL_LIBS) \
|
||||
$(LIBXFCE4UI_LIBS) \
|
||||
$(LIBXFCE4KBD_PRIVATE_LIBS)
|
||||
|
||||
thunar_uca_la_DEPENDENCIES = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
|
||||
|
||||
thunar_uca_templates = \
|
||||
thunar-uca-ui.xml
|
||||
|
||||
GLIB_COMPILE_RESOURCES = $(shell $(PKG_CONFIG) --variable=glib_compile_resources gio-2.0)
|
||||
|
||||
resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/thunar-uca.gresource.xml)
|
||||
|
||||
thunar-uca.gresource.c: thunar-uca.gresource.xml $(resource_files)
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
|
||||
--target=$@ --sourcedir=$(srcdir) --generate-source
|
||||
|
||||
defaultsdir = $(sysconfdir)/xdg/Thunar
|
||||
defaults_in_files = uca.xml.in
|
||||
defaults_DATA = $(defaults_in_files:.xml.in=.xml)
|
||||
$(defaults_DATA): $(defaults_in_files) Makefile
|
||||
$(AM_V_GEN)GETTEXTDATADIRS=$(top_srcdir) $(MSGFMT) --xml --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = \
|
||||
README.md \
|
||||
thunar-uca.gresource.xml \
|
||||
thunar-uca-editor.ui \
|
||||
thunar-uca-chooser.ui \
|
||||
$(defaults_in_files)
|
||||
|
||||
CLEANFILES = \
|
||||
$(defaults_DATA)
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
23
plugins/thunar-uca/README.md
Normal file
23
plugins/thunar-uca/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Thunar User Customizable Actions (thunar-uca)
|
||||
=============================================
|
||||
|
||||
Thunar-uca is an extension to Thunar, which enables sophisticated users to add additional actions to the file managers context menus, without having to write their own extensions for each and every action they want to use.
|
||||
|
||||
By default the thunar-uca extension will be installed, but as with every extension, it will slightly increase the resource usage of Thunar (this shouldn't be a real problem unless you're targeting an embedded system), and so can you pass `--disable-uca-plugin` to configure and the plugin won't be built and installed. Since it is an extension, you can also easily uninstall it
|
||||
afterwards by removing the thunar-uca.so file from the lib/thunarx-2/ directory of your installation (be sure to quit Thunar before removing files though).
|
||||
|
||||
To actually manage the actions open the "Edit" menu in the menu bar of a Thunar window and select "Configure Custom Actions...". A dialog will appear which lists the currently configured actions.
|
||||
|
||||
List of valid command parameter variables
|
||||
=========================================
|
||||
|
||||
| Variable | Usage |
|
||||
| :------------ | :------------ |
|
||||
| %f | The path of the first selected file. |
|
||||
| %F | The paths to all selected files. |
|
||||
|%u |The URI of the first selected file (using the file:-URI scheme). |
|
||||
|%U |The URIs of all selected files (using the file:-URI scheme). |
|
||||
| %d |The directory of the first selected file. |
|
||||
| %D |The directories to all selected files. |
|
||||
| %n |The name of the first selected file (without the path). |
|
||||
|%N |The names of all selected files (without the paths). |
|
||||
454
plugins/thunar-uca/thunar-uca-chooser.c
Normal file
454
plugins/thunar-uca/thunar-uca-chooser.c
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <thunar-uca/thunar-uca-chooser.h>
|
||||
#include <thunar-uca/thunar-uca-editor.h>
|
||||
#include <thunar-uca/thunar-uca-model.h>
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_uca_chooser_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *event);
|
||||
static void
|
||||
thunar_uca_chooser_response (GtkDialog *dialog,
|
||||
gint response);
|
||||
static void
|
||||
thunar_uca_chooser_exchange (ThunarUcaChooser *uca_chooser,
|
||||
GtkTreeSelection *selection,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter_a,
|
||||
GtkTreeIter *iter_b);
|
||||
static void
|
||||
thunar_uca_chooser_open_editor (ThunarUcaChooser *uca_chooser,
|
||||
gboolean edit);
|
||||
static void
|
||||
thunar_uca_chooser_save (ThunarUcaChooser *uca_chooser,
|
||||
ThunarUcaModel *uca_model);
|
||||
static void
|
||||
thunar_uca_chooser_selection_changed (ThunarUcaChooser *uca_chooser,
|
||||
GtkTreeSelection *selection);
|
||||
static void
|
||||
thunar_uca_chooser_add_clicked (ThunarUcaChooser *uca_chooser);
|
||||
static void
|
||||
thunar_uca_chooser_edit_clicked (ThunarUcaChooser *uca_chooser);
|
||||
static void
|
||||
thunar_uca_chooser_delete_clicked (ThunarUcaChooser *uca_chooser);
|
||||
static void
|
||||
thunar_uca_chooser_up_clicked (ThunarUcaChooser *uca_chooser);
|
||||
static void
|
||||
thunar_uca_chooser_down_clicked (ThunarUcaChooser *uca_chooser);
|
||||
|
||||
|
||||
|
||||
struct _ThunarUcaChooserClass
|
||||
{
|
||||
GtkDialogClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarUcaChooser
|
||||
{
|
||||
GtkDialog __parent__;
|
||||
|
||||
GtkWidget *treeview;
|
||||
GtkWidget *add_button;
|
||||
GtkWidget *edit_button;
|
||||
GtkWidget *delete_button;
|
||||
GtkWidget *up_button;
|
||||
GtkWidget *down_button;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarUcaChooser, thunar_uca_chooser, GTK_TYPE_DIALOG);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_class_init (ThunarUcaChooserClass *klass)
|
||||
{
|
||||
GtkDialogClass *dialog_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS (klass);
|
||||
widget_class->key_press_event = thunar_uca_chooser_key_press_event;
|
||||
|
||||
dialog_class = GTK_DIALOG_CLASS (klass);
|
||||
dialog_class->response = thunar_uca_chooser_response;
|
||||
|
||||
/* Setup the template xml */
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/xfce/thunar/uca/chooser.ui");
|
||||
|
||||
/* bind stuff */
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, treeview);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, add_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, edit_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, delete_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, up_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaChooser, down_button);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_add_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_edit_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_delete_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_up_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_down_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_chooser_selection_changed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_init (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *renderer;
|
||||
ThunarUcaModel *uca_model;
|
||||
gboolean use_header_bar = FALSE;
|
||||
|
||||
/* Initialize the template for this instance */
|
||||
gtk_widget_init_template (GTK_WIDGET (uca_chooser));
|
||||
|
||||
/* configure the dialog window */
|
||||
g_object_get (gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (uca_chooser))),
|
||||
"gtk-dialogs-use-header", &use_header_bar, NULL);
|
||||
|
||||
if (!use_header_bar)
|
||||
{
|
||||
/* add a regular close button, the header bar already provides one */
|
||||
gtk_dialog_add_button (GTK_DIALOG (uca_chooser), _("_Close"), GTK_RESPONSE_CLOSE);
|
||||
}
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (uca_chooser), GTK_RESPONSE_CLOSE);
|
||||
|
||||
/* configure the tree view */
|
||||
uca_model = thunar_uca_model_get_default ();
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (uca_chooser->treeview), GTK_TREE_MODEL (uca_model));
|
||||
g_object_unref (G_OBJECT (uca_model));
|
||||
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_column_set_expand (column, TRUE);
|
||||
gtk_tree_view_column_set_resizable (column, FALSE);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (uca_chooser->treeview), column);
|
||||
|
||||
renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF, "stock-size", GTK_ICON_SIZE_DND, "xpad", 2, "ypad", 2, NULL);
|
||||
gtk_tree_view_column_pack_start (column, renderer, FALSE);
|
||||
gtk_tree_view_column_set_attributes (column, renderer, "gicon", THUNAR_UCA_MODEL_COLUMN_GICON, NULL);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
gtk_tree_view_column_pack_start (column, renderer, TRUE);
|
||||
gtk_tree_view_column_set_attributes (column, renderer, "markup", THUNAR_UCA_MODEL_COLUMN_STOCK_LABEL, NULL);
|
||||
|
||||
/* configure the tree view selection */
|
||||
thunar_uca_chooser_selection_changed (uca_chooser, gtk_tree_view_get_selection (GTK_TREE_VIEW (uca_chooser->treeview)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_uca_chooser_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *event)
|
||||
{
|
||||
/* close chooser window on Esc key press */
|
||||
if (G_UNLIKELY (event->keyval == GDK_KEY_Escape))
|
||||
{
|
||||
gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_CLOSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return (*GTK_WIDGET_CLASS (thunar_uca_chooser_parent_class)->key_press_event) (widget, event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_response (GtkDialog *dialog,
|
||||
gint response)
|
||||
{
|
||||
if (response == GTK_RESPONSE_CLOSE)
|
||||
{
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
}
|
||||
else if (GTK_DIALOG_CLASS (thunar_uca_chooser_parent_class)->response != NULL)
|
||||
{
|
||||
(*GTK_DIALOG_CLASS (thunar_uca_chooser_parent_class)->response) (dialog, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_selection_changed (ThunarUcaChooser *uca_chooser,
|
||||
GtkTreeSelection *selection)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreePath *path = NULL;
|
||||
GtkTreeIter iter;
|
||||
gboolean selected;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
|
||||
|
||||
/* check if we have currently selected an item */
|
||||
selected = gtk_tree_selection_get_selected (selection, &model, &iter);
|
||||
if (G_LIKELY (selected))
|
||||
{
|
||||
/* determine the path for the selected iter */
|
||||
path = gtk_tree_model_get_path (model, &iter);
|
||||
}
|
||||
|
||||
/* change sensitivity of "Edit" and "Delete" appropritately */
|
||||
gtk_widget_set_sensitive (uca_chooser->edit_button, selected);
|
||||
gtk_widget_set_sensitive (uca_chooser->delete_button, selected);
|
||||
|
||||
/* change sensitivity of "Move Up" and "Move Down" appropritately */
|
||||
gtk_widget_set_sensitive (uca_chooser->up_button, selected && gtk_tree_path_get_indices (path)[0] > 0);
|
||||
gtk_widget_set_sensitive (uca_chooser->down_button, selected && gtk_tree_path_get_indices (path)[0] < gtk_tree_model_iter_n_children (model, NULL) - 1);
|
||||
|
||||
/* release path (if any) */
|
||||
if (G_LIKELY (path != NULL))
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_exchange (ThunarUcaChooser *uca_chooser,
|
||||
GtkTreeSelection *selection,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter_a,
|
||||
GtkTreeIter *iter_b)
|
||||
{
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
|
||||
g_return_if_fail (GTK_IS_TREE_MODEL (model));
|
||||
g_return_if_fail (iter_a != NULL);
|
||||
g_return_if_fail (iter_b != NULL);
|
||||
|
||||
/* perform the move */
|
||||
thunar_uca_model_exchange (THUNAR_UCA_MODEL (model), iter_a, iter_b);
|
||||
|
||||
/* tell the chooser that the selection may have changed */
|
||||
thunar_uca_chooser_selection_changed (uca_chooser, selection);
|
||||
|
||||
/* sync the model to persistent storage */
|
||||
thunar_uca_chooser_save (uca_chooser, THUNAR_UCA_MODEL (model));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_open_editor (ThunarUcaChooser *uca_chooser,
|
||||
gboolean edit)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkWidget *editor;
|
||||
gboolean use_header_bar = FALSE;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
|
||||
/* allocate the new editor */
|
||||
g_object_get (gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (uca_chooser))),
|
||||
"gtk-dialogs-use-header", &use_header_bar, NULL);
|
||||
|
||||
editor = g_object_new (THUNAR_UCA_TYPE_EDITOR, "use-header-bar", use_header_bar, NULL);
|
||||
gtk_window_set_title (GTK_WINDOW (editor), edit ? _("Edit Action") : _("Create Action"));
|
||||
gtk_window_set_transient_for (GTK_WINDOW (editor), GTK_WINDOW (uca_chooser));
|
||||
|
||||
/* load the editor with the currently selected item (when editing) */
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (uca_chooser->treeview));
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter) && edit)
|
||||
thunar_uca_editor_load (THUNAR_UCA_EDITOR (editor), THUNAR_UCA_MODEL (model), &iter);
|
||||
|
||||
/* run the editor */
|
||||
if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
|
||||
{
|
||||
/* append a new iter (when not editing) */
|
||||
if (G_UNLIKELY (!edit))
|
||||
thunar_uca_model_append (THUNAR_UCA_MODEL (model), &iter);
|
||||
|
||||
/* save the editor values to the model */
|
||||
thunar_uca_editor_save (THUNAR_UCA_EDITOR (editor), THUNAR_UCA_MODEL (model), &iter);
|
||||
|
||||
/* hide the editor window */
|
||||
gtk_widget_hide (editor);
|
||||
|
||||
/* sync the model to persistent storage */
|
||||
thunar_uca_chooser_save (uca_chooser, THUNAR_UCA_MODEL (model));
|
||||
}
|
||||
|
||||
/* destroy the editor */
|
||||
gtk_widget_destroy (editor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_save (ThunarUcaChooser *uca_chooser,
|
||||
ThunarUcaModel *uca_model)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
|
||||
|
||||
/* sync the model to persistent storage */
|
||||
if (!thunar_uca_model_save (uca_model, &error))
|
||||
{
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (uca_chooser),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT
|
||||
| GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
_("Failed to save actions to disk."));
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_add_clicked (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
thunar_uca_chooser_open_editor (uca_chooser, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_edit_clicked (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
thunar_uca_chooser_open_editor (uca_chooser, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_delete_clicked (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
gchar *name;
|
||||
GtkWidget *dialog;
|
||||
gint response;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
|
||||
/* verify that we have an item selected and determine the iter for that item */
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (uca_chooser->treeview));
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
/* create the question dialog */
|
||||
gtk_tree_model_get (model, &iter, THUNAR_UCA_MODEL_COLUMN_NAME, &name, -1);
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (uca_chooser),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT
|
||||
| GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_QUESTION,
|
||||
GTK_BUTTONS_NONE,
|
||||
_("Are you sure that you want to delete\naction \"%s\"?"), name);
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), _("Delete action"));
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("If you delete a custom action, it is permanently lost."));
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Delete"), GTK_RESPONSE_YES, NULL);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
|
||||
g_free (name);
|
||||
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
|
||||
if (response == GTK_RESPONSE_YES)
|
||||
{
|
||||
/* remove the row from the model */
|
||||
thunar_uca_model_remove (THUNAR_UCA_MODEL (model), &iter);
|
||||
|
||||
/* sync the model to persistent storage */
|
||||
thunar_uca_chooser_save (uca_chooser, THUNAR_UCA_MODEL (model));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_up_clicked (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreePath *path;
|
||||
GtkTreeIter iter_a;
|
||||
GtkTreeIter iter_b;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
|
||||
/* determine the currently selected item */
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (uca_chooser->treeview));
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter_a))
|
||||
{
|
||||
/* determine the tree path to the iter */
|
||||
path = gtk_tree_model_get_path (model, &iter_a);
|
||||
if (gtk_tree_path_prev (path))
|
||||
{
|
||||
/* determine the iter for the previous item */
|
||||
gtk_tree_model_get_iter (model, &iter_b, path);
|
||||
|
||||
/* perform the exchange operation */
|
||||
thunar_uca_chooser_exchange (uca_chooser, selection, model, &iter_a, &iter_b);
|
||||
}
|
||||
|
||||
/* release the path */
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_chooser_down_clicked (ThunarUcaChooser *uca_chooser)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter_a;
|
||||
GtkTreeIter iter_b;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_CHOOSER (uca_chooser));
|
||||
|
||||
/* determine the currently selected item */
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (uca_chooser->treeview));
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter_a))
|
||||
{
|
||||
/* determine the iter to the next item */
|
||||
iter_b = iter_a;
|
||||
if (gtk_tree_model_iter_next (model, &iter_b))
|
||||
thunar_uca_chooser_exchange (uca_chooser, selection, model, &iter_a, &iter_b);
|
||||
}
|
||||
}
|
||||
45
plugins/thunar-uca/thunar-uca-chooser.h
Normal file
45
plugins/thunar-uca/thunar-uca-chooser.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_CHOOSER_H__
|
||||
#define __THUNAR_UCA_CHOOSER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarUcaChooserClass ThunarUcaChooserClass;
|
||||
typedef struct _ThunarUcaChooser ThunarUcaChooser;
|
||||
|
||||
#define THUNAR_UCA_TYPE_CHOOSER (thunar_uca_chooser_get_type ())
|
||||
#define THUNAR_UCA_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_UCA_TYPE_CHOOSER, ThunarUcaChooser))
|
||||
#define THUNAR_UCA_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_UCA_TYPE_CHOOSER, ThunarUcaChooserClass))
|
||||
#define THUNAR_UCA_IS_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_UCA_TYPE_CHOOSER))
|
||||
#define THUNAR_UCA_IS_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_UCA_TYPE_CHOOSER))
|
||||
#define THUNAR_UCA_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_UCA_TYPE_CHOOSER, ThunarUcaChooserClass))
|
||||
|
||||
GType
|
||||
thunar_uca_chooser_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_uca_chooser_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_CHOOSER_H__ */
|
||||
139
plugins/thunar-uca/thunar-uca-chooser.ui
Normal file
139
plugins/thunar-uca/thunar-uca-chooser.ui
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
For now, better don't edit this with glade, since glade insists upon inserting
|
||||
deprecated properties and otherwise messing with the file.
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<template class="ThunarUcaChooser" parent="GtkDialog">
|
||||
<property name="default-width">500</property>
|
||||
<property name="default-height">350</property>
|
||||
<property name="type-hint">dialog</property>
|
||||
<property name="title" translatable="yes">Custom Actions</property>
|
||||
<property name="destroy-with-parent">True</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="vbox">
|
||||
<!-- label at the top -->
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="border-width">6</property>
|
||||
<property name="spacing">3</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">dialog-information</property>
|
||||
<property name="icon-size">5</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="yalign">0.0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Configure custom actions that will appear in the file manager's context menus and/or toolbar.
|
||||
These actions are applicable to folders or certain kinds of files.
|
||||
|
||||
Check the <a href="https://docs.xfce.org/xfce/thunar/custom-actions">documentation</a> for a collection of custom action examples.</property>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="wrap">TRUE</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<!-- main part -->
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="border-width">6</property>
|
||||
<property name="visible">true</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">0</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
<!-- tree view containing the list of items -->
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="expand">TRUE</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview">
|
||||
<property name="headers-visible">FALSE</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<signal name="row-activated" handler="thunar_uca_chooser_edit_clicked" swapped="true" />
|
||||
<!-- TODO: setup columns here -->
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<property name="mode">GTK_SELECTION_SINGLE</property>
|
||||
<signal name="changed" handler="thunar_uca_chooser_selection_changed" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<!-- buttons -->
|
||||
<child>
|
||||
<object class="GtkToolbar">
|
||||
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="toolbar-style">GTK_TOOLBAR_ICONS</property>
|
||||
<property name="icon-size">GTK_ICON_SIZE_BUTTON</property>
|
||||
<property name="show-arrow">false</property>
|
||||
<!-- add button -->
|
||||
<child>
|
||||
<object class="GtkToolButton" id="add_button">
|
||||
<property name="tooltip-text" translatable="yes">Add a new custom action.</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<signal name="clicked" handler="thunar_uca_chooser_add_clicked" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
<!-- edit button -->
|
||||
<child>
|
||||
<object class="GtkToolButton" id="edit_button">
|
||||
<property name="tooltip-text" translatable="yes">Edit the currently selected action.</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
<signal name="clicked" handler="thunar_uca_chooser_edit_clicked" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
<!-- remove button -->
|
||||
<child>
|
||||
<object class="GtkToolButton" id="delete_button">
|
||||
<property name="tooltip-text" translatable="yes">Delete the currently selected action.</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<signal name="clicked" handler="thunar_uca_chooser_delete_clicked" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
<!-- move up button -->
|
||||
<child>
|
||||
<object class="GtkToolButton" id="up_button">
|
||||
<property name="tooltip-text" translatable="yes">Move the currently selected action up by one row.</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="icon-name">go-up-symbolic</property>
|
||||
<signal name="clicked" handler="thunar_uca_chooser_up_clicked" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
<!-- move down button -->
|
||||
<child>
|
||||
<object class="GtkToolButton" id="down_button">
|
||||
<property name="tooltip-text" translatable="yes">Move the currently selected action down by one row.</property>
|
||||
<property name="visible">TRUE</property>
|
||||
<property name="icon-name">go-down-symbolic</property>
|
||||
<signal name="clicked" handler="thunar_uca_chooser_down_clicked" swapped="true" />
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child> <!-- end: buttons toolbar -->
|
||||
</object>
|
||||
</child> <!-- end of main part hbox -->
|
||||
</object>
|
||||
</child> <!-- end of main part frame -->
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
143
plugins/thunar-uca/thunar-uca-context.c
Normal file
143
plugins/thunar-uca/thunar-uca-context.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-uca/thunar-uca-context.h>
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
|
||||
|
||||
struct _ThunarUcaContext
|
||||
{
|
||||
gint ref_count;
|
||||
GList *files;
|
||||
GtkWidget *window;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_context_new:
|
||||
* @window : a #GtkWindow.
|
||||
* @files : a #GList of #ThunarxFileInfo<!---->s.
|
||||
*
|
||||
* Allocates a new #ThunarUcaContext with the given @window and
|
||||
* @files.
|
||||
*
|
||||
* The caller is responsible to free the returned context
|
||||
* using thunar_uca_context_unref().
|
||||
*
|
||||
* Return value: the newly allocated #ThunarUcaContext.
|
||||
**/
|
||||
ThunarUcaContext *
|
||||
thunar_uca_context_new (GtkWidget *window,
|
||||
GList *files)
|
||||
{
|
||||
ThunarUcaContext *context;
|
||||
|
||||
context = g_new (ThunarUcaContext, 1);
|
||||
context->ref_count = 1;
|
||||
context->window = window;
|
||||
context->files = thunarx_file_info_list_copy (files);
|
||||
|
||||
/* add a weak reference on the window */
|
||||
if (G_LIKELY (context->window != NULL))
|
||||
g_object_add_weak_pointer (G_OBJECT (context->window), (gpointer) &context->window);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_context_ref:
|
||||
* @context : a #ThunarUcaContext.
|
||||
*
|
||||
* Increases the reference count on @context.
|
||||
*
|
||||
* Return value: reference to @context.
|
||||
**/
|
||||
ThunarUcaContext *
|
||||
thunar_uca_context_ref (ThunarUcaContext *context)
|
||||
{
|
||||
context->ref_count += 1;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_context_unref:
|
||||
* @context : a #ThunarUcaContext.
|
||||
*
|
||||
* Decreases the reference count on @context
|
||||
* and frees @context once the reference count
|
||||
* drops to zero.
|
||||
**/
|
||||
void
|
||||
thunar_uca_context_unref (ThunarUcaContext *context)
|
||||
{
|
||||
if (--context->ref_count == 0)
|
||||
{
|
||||
/* drop the weak ref on the window */
|
||||
if (G_LIKELY (context->window != NULL))
|
||||
g_object_remove_weak_pointer (G_OBJECT (context->window), (gpointer) &context->window);
|
||||
|
||||
/* release the file infos */
|
||||
thunarx_file_info_list_free (context->files);
|
||||
|
||||
/* remove the context data */
|
||||
g_free (context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_context_get_files:
|
||||
* @context : a #ThunarUcaContext.
|
||||
*
|
||||
* Return value: the #ThunarxFileInfo<!---->s for @context.
|
||||
**/
|
||||
GList *
|
||||
thunar_uca_context_get_files (const ThunarUcaContext *context)
|
||||
{
|
||||
return context->files;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_context_get_window:
|
||||
* @context : a #ThunarUcaContext.
|
||||
*
|
||||
* Returns the #GtkWindow for @context or %NULL if the
|
||||
* window was destroyed in the meantime.
|
||||
*
|
||||
* Return value: the #GtkWindow for @context.
|
||||
**/
|
||||
GtkWidget *
|
||||
thunar_uca_context_get_window (const ThunarUcaContext *context)
|
||||
{
|
||||
return context->window;
|
||||
}
|
||||
46
plugins/thunar-uca/thunar-uca-context.h
Normal file
46
plugins/thunar-uca/thunar-uca-context.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_CONTEXT_H__
|
||||
#define __THUNAR_UCA_CONTEXT_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarUcaContext ThunarUcaContext;
|
||||
|
||||
ThunarUcaContext *
|
||||
thunar_uca_context_new (GtkWidget *window,
|
||||
GList *files);
|
||||
|
||||
ThunarUcaContext *
|
||||
thunar_uca_context_ref (ThunarUcaContext *context);
|
||||
void
|
||||
thunar_uca_context_unref (ThunarUcaContext *context);
|
||||
|
||||
GList *
|
||||
thunar_uca_context_get_files (const ThunarUcaContext *context);
|
||||
GtkWidget *
|
||||
thunar_uca_context_get_window (const ThunarUcaContext *context);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_CONTEXT_H__ */
|
||||
705
plugins/thunar-uca/thunar-uca-editor.c
Normal file
705
plugins/thunar-uca/thunar-uca-editor.c
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org>
|
||||
* Copyright (c) 2011 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <libxfce4kbd-private/xfce-shortcut-dialog.h>
|
||||
#include <libxfce4ui/libxfce4ui.h>
|
||||
#include <thunar-uca/thunar-uca-editor.h>
|
||||
|
||||
|
||||
|
||||
static const gchar *
|
||||
thunar_uca_editor_get_icon_name (const ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_set_icon_name (ThunarUcaEditor *uca_editor,
|
||||
const gchar *icon_name);
|
||||
static ThunarUcaTypes
|
||||
thunar_uca_editor_get_types (const ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_set_types (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaTypes types);
|
||||
static void
|
||||
thunar_uca_editor_command_clicked (ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_shortcut_clicked (ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_shortcut_clear_clicked (ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_icon_clicked (ThunarUcaEditor *uca_editor);
|
||||
static void
|
||||
thunar_uca_editor_constructed (GObject *object);
|
||||
static void
|
||||
thunar_uca_editor_finalize (GObject *object);
|
||||
|
||||
|
||||
|
||||
struct _ThunarUcaEditorClass
|
||||
{
|
||||
GtkDialogClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarUcaEditor
|
||||
{
|
||||
GtkDialog __parent__;
|
||||
|
||||
GtkWidget *notebook;
|
||||
GtkWidget *name_entry;
|
||||
GtkWidget *sub_menu_entry;
|
||||
GtkWidget *description_entry;
|
||||
GtkWidget *icon_button;
|
||||
GtkWidget *command_entry;
|
||||
GtkWidget *shortcut_button;
|
||||
GtkWidget *sn_button;
|
||||
GtkWidget *patterns_entry;
|
||||
GtkWidget *range_entry;
|
||||
GtkWidget *directories_button;
|
||||
GtkWidget *audio_files_button;
|
||||
GtkWidget *image_files_button;
|
||||
GtkWidget *text_files_button;
|
||||
GtkWidget *video_files_button;
|
||||
GtkWidget *other_files_button;
|
||||
|
||||
gchar *accel_path;
|
||||
GdkModifierType accel_mods;
|
||||
guint accel_key;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gboolean in_use;
|
||||
GdkModifierType mods;
|
||||
guint key;
|
||||
gchar *current_path;
|
||||
gchar *other_path;
|
||||
} ShortcutInfo;
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE (ThunarUcaEditor, thunar_uca_editor, GTK_TYPE_DIALOG);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_class_init (ThunarUcaEditorClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
/* vfuncs */
|
||||
object_class->constructed = thunar_uca_editor_constructed;
|
||||
object_class->finalize = thunar_uca_editor_finalize;
|
||||
|
||||
/* Setup the template xml */
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/xfce/thunar/uca/editor.ui");
|
||||
|
||||
/* bind stuff */
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, notebook);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, name_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, sub_menu_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, description_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, icon_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, command_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, shortcut_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, sn_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, patterns_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, range_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, directories_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, audio_files_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, image_files_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, text_files_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, video_files_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, other_files_button);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_editor_icon_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_editor_command_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_editor_shortcut_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, thunar_uca_editor_shortcut_clear_clicked);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_init (ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
/* Initialize the template for this instance */
|
||||
gtk_widget_init_template (GTK_WIDGET (uca_editor));
|
||||
|
||||
/* configure the dialog properties */
|
||||
gtk_dialog_add_button (GTK_DIALOG (uca_editor), _("_Cancel"), GTK_RESPONSE_CANCEL);
|
||||
gtk_dialog_add_button (GTK_DIALOG (uca_editor), _("_OK"), GTK_RESPONSE_OK);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (uca_editor), GTK_RESPONSE_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_constructed (GObject *object)
|
||||
{
|
||||
ThunarUcaEditor *editor = THUNAR_UCA_EDITOR (object);
|
||||
|
||||
G_OBJECT_CLASS (thunar_uca_editor_parent_class)->constructed (object);
|
||||
|
||||
/* Visual tweaks for header-bar mode only */
|
||||
g_object_set (gtk_dialog_get_content_area (GTK_DIALOG (editor)), "border-width", 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_finalize (GObject *object)
|
||||
{
|
||||
ThunarUcaEditor *editor = THUNAR_UCA_EDITOR (object);
|
||||
|
||||
g_free (editor->accel_path);
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_uca_editor_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_command_clicked (ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
GtkFileFilter *filter;
|
||||
GtkWidget *chooser;
|
||||
gchar *filename;
|
||||
gchar **argv = NULL;
|
||||
gchar *s;
|
||||
gint argc;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
|
||||
chooser = gtk_file_chooser_dialog_new (_("Select an Application"),
|
||||
GTK_WINDOW (uca_editor),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_Open"), GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
|
||||
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
|
||||
|
||||
/* add file chooser filters */
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("All Files"));
|
||||
gtk_file_filter_add_pattern (filter, "*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Executable Files"));
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-csh");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-executable");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-perl");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-python");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-ruby");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-shellscript");
|
||||
gtk_file_filter_add_pattern (filter, "*.pl");
|
||||
gtk_file_filter_add_pattern (filter, "*.py");
|
||||
gtk_file_filter_add_pattern (filter, "*.rb");
|
||||
gtk_file_filter_add_pattern (filter, "*.sh");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Perl Scripts"));
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-perl");
|
||||
gtk_file_filter_add_pattern (filter, "*.pl");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Python Scripts"));
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-python");
|
||||
gtk_file_filter_add_pattern (filter, "*.py");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Ruby Scripts"));
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-ruby");
|
||||
gtk_file_filter_add_pattern (filter, "*.rb");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, _("Shell Scripts"));
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-csh");
|
||||
gtk_file_filter_add_mime_type (filter, "application/x-shellscript");
|
||||
gtk_file_filter_add_pattern (filter, "*.sh");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
|
||||
|
||||
/* use the bindir as default folder */
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), BINDIR);
|
||||
|
||||
/* setup the currently selected file */
|
||||
filename = gtk_editable_get_chars (GTK_EDITABLE (uca_editor->command_entry), 0, -1);
|
||||
if (G_LIKELY (filename != NULL))
|
||||
{
|
||||
/* use only the first argument */
|
||||
s = strchr (filename, ' ');
|
||||
if (G_UNLIKELY (s != NULL))
|
||||
*s = '\0';
|
||||
|
||||
/* check if we have a file name */
|
||||
if (G_LIKELY (*filename != '\0'))
|
||||
{
|
||||
/* check if the filename is not an absolute path */
|
||||
if (G_LIKELY (!g_path_is_absolute (filename)))
|
||||
{
|
||||
/* try to lookup the filename in $PATH */
|
||||
s = g_find_program_in_path (filename);
|
||||
if (G_LIKELY (s != NULL))
|
||||
{
|
||||
/* use the absolute path instead */
|
||||
g_free (filename);
|
||||
filename = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we have an absolute path now */
|
||||
if (G_LIKELY (g_path_is_absolute (filename)))
|
||||
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename);
|
||||
}
|
||||
|
||||
/* release the filename */
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
/* run the chooser dialog */
|
||||
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
/* determine the path to the selected file */
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
|
||||
|
||||
/* check if we need to quote the filename */
|
||||
if (!g_shell_parse_argv (filename, &argc, &argv, NULL) || argc > 1)
|
||||
{
|
||||
/* shell is unable to interpret properly without quoting */
|
||||
s = g_shell_quote (filename);
|
||||
g_free (filename);
|
||||
filename = s;
|
||||
}
|
||||
g_strfreev (argv);
|
||||
|
||||
/* append %f to filename, user may change that afterwards */
|
||||
s = g_strconcat (filename, " %f", NULL);
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->command_entry), s);
|
||||
g_free (filename);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (chooser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_shortcut_check (gpointer data,
|
||||
const gchar *path,
|
||||
guint key,
|
||||
GdkModifierType mods,
|
||||
gboolean changed)
|
||||
{
|
||||
ShortcutInfo *info = (ShortcutInfo *) data;
|
||||
if (info->in_use)
|
||||
return;
|
||||
|
||||
info->in_use = info->mods == mods && info->key == key && g_strcmp0 (info->current_path, path) != 0;
|
||||
|
||||
if (info->in_use)
|
||||
info->other_path = g_strdup (path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_uca_editor_validate_shortcut (XfceShortcutDialog *dialog,
|
||||
const gchar *shortcut,
|
||||
ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
GdkModifierType accel_mods;
|
||||
guint accel_key;
|
||||
ShortcutInfo info;
|
||||
gchar *command, *message;
|
||||
|
||||
g_return_val_if_fail (XFCE_IS_SHORTCUT_DIALOG (dialog), FALSE);
|
||||
g_return_val_if_fail (shortcut != NULL, FALSE);
|
||||
|
||||
/* Ignore empty shortcuts */
|
||||
if (G_UNLIKELY (g_utf8_strlen (shortcut, -1) == 0))
|
||||
return FALSE;
|
||||
|
||||
/* Ignore raw 'Return' and 'space' since that may have been used to activate the shortcut row */
|
||||
if (G_UNLIKELY (g_utf8_collate (shortcut, "Return") == 0 || g_utf8_collate (shortcut, "space") == 0))
|
||||
return FALSE;
|
||||
|
||||
gtk_accelerator_parse (shortcut, &accel_key, &accel_mods);
|
||||
|
||||
info.in_use = FALSE;
|
||||
info.mods = accel_mods;
|
||||
info.key = accel_key;
|
||||
info.current_path = uca_editor->accel_path;
|
||||
info.other_path = NULL;
|
||||
|
||||
gtk_accel_map_foreach_unfiltered (&info, thunar_uca_editor_shortcut_check);
|
||||
|
||||
if (info.in_use)
|
||||
{
|
||||
command = g_strrstr (info.other_path, "/");
|
||||
command = command == NULL ? info.other_path : command + 1; /* skip leading slash */
|
||||
|
||||
message = g_strdup_printf (_("This keyboard shortcut is currently used by: '%s'"),
|
||||
command);
|
||||
xfce_dialog_show_warning (GTK_WINDOW (dialog), message,
|
||||
_("Keyboard shortcut already in use"));
|
||||
g_free (message);
|
||||
}
|
||||
|
||||
g_free (info.other_path);
|
||||
|
||||
return !info.in_use;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_shortcut_clicked (ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
gint response;
|
||||
const gchar *shortcut;
|
||||
GdkModifierType accel_mods;
|
||||
guint accel_key;
|
||||
gchar *label;
|
||||
|
||||
dialog = xfce_shortcut_dialog_new ("thunar",
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)), "");
|
||||
|
||||
g_signal_connect (dialog, "validate-shortcut",
|
||||
G_CALLBACK (thunar_uca_editor_validate_shortcut),
|
||||
uca_editor);
|
||||
|
||||
response = xfce_shortcut_dialog_run (XFCE_SHORTCUT_DIALOG (dialog),
|
||||
gtk_widget_get_toplevel (uca_editor->shortcut_button));
|
||||
|
||||
if (G_LIKELY (response == GTK_RESPONSE_OK))
|
||||
{
|
||||
shortcut = xfce_shortcut_dialog_get_shortcut (XFCE_SHORTCUT_DIALOG (dialog));
|
||||
gtk_accelerator_parse (shortcut, &accel_key, &accel_mods);
|
||||
|
||||
label = gtk_accelerator_get_label (accel_key, accel_mods);
|
||||
gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), label);
|
||||
|
||||
uca_editor->accel_key = accel_key;
|
||||
uca_editor->accel_mods = accel_mods;
|
||||
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_shortcut_clear_clicked (ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
uca_editor->accel_key = 0;
|
||||
uca_editor->accel_mods = 0;
|
||||
gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), _("None"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_icon_clicked (ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
const gchar *name;
|
||||
GtkWidget *chooser;
|
||||
gchar *title;
|
||||
gchar *icon;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
|
||||
/* determine the name of the action being edited */
|
||||
name = gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry));
|
||||
if (G_UNLIKELY (name == NULL || *name == '\0'))
|
||||
name = _("Unknown");
|
||||
|
||||
/* allocate the chooser dialog */
|
||||
title = g_strdup_printf (_("Select an Icon for \"%s\""), name);
|
||||
chooser = exo_icon_chooser_dialog_new (title, GTK_WINDOW (uca_editor),
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_OK"), GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
|
||||
g_free (title);
|
||||
|
||||
/* setup the currently selected icon */
|
||||
icon = g_object_get_data (G_OBJECT (uca_editor->icon_button), "thunar-uca-icon-name");
|
||||
if (G_LIKELY (icon != NULL && *icon != '\0'))
|
||||
exo_icon_chooser_dialog_set_icon (EXO_ICON_CHOOSER_DIALOG (chooser), icon);
|
||||
|
||||
/* run the icon chooser dialog */
|
||||
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
/* remember the selected icon from the chooser */
|
||||
icon = exo_icon_chooser_dialog_get_icon (EXO_ICON_CHOOSER_DIALOG (chooser));
|
||||
thunar_uca_editor_set_icon_name (uca_editor, icon);
|
||||
g_free (icon);
|
||||
}
|
||||
|
||||
/* destroy the chooser */
|
||||
gtk_widget_destroy (chooser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const gchar *
|
||||
thunar_uca_editor_get_icon_name (const ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
g_return_val_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor), NULL);
|
||||
return g_object_get_data (G_OBJECT (uca_editor->icon_button), "thunar-uca-icon-name");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_set_icon_name (ThunarUcaEditor *uca_editor,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
GIcon *icon = NULL;
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
|
||||
/* drop the previous button child */
|
||||
if (gtk_bin_get_child (GTK_BIN (uca_editor->icon_button)) != NULL)
|
||||
gtk_widget_destroy (gtk_bin_get_child (GTK_BIN (uca_editor->icon_button)));
|
||||
|
||||
/* setup the icon button */
|
||||
if (icon_name != NULL)
|
||||
icon = g_icon_new_for_string (icon_name, NULL);
|
||||
|
||||
if (G_LIKELY (icon != NULL))
|
||||
{
|
||||
/* setup an image for the icon */
|
||||
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
|
||||
g_object_set (image, "icon-size", GTK_ICON_SIZE_DND, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (uca_editor->icon_button), image);
|
||||
gtk_widget_show (image);
|
||||
|
||||
/* remember the name for the icon */
|
||||
g_object_set_data_full (G_OBJECT (uca_editor->icon_button), "thunar-uca-icon-name", g_strdup (icon_name), g_free);
|
||||
|
||||
/* release the icon */
|
||||
g_object_unref (G_OBJECT (icon));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset the remembered icon name */
|
||||
g_object_set_data (G_OBJECT (uca_editor->icon_button), "thunar-uca-icon-name", NULL);
|
||||
|
||||
/* setup a label to tell that no icon was selected */
|
||||
label = gtk_label_new (_("No icon"));
|
||||
gtk_container_add (GTK_CONTAINER (uca_editor->icon_button), label);
|
||||
gtk_widget_show (label);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ThunarUcaTypes
|
||||
thunar_uca_editor_get_types (const ThunarUcaEditor *uca_editor)
|
||||
{
|
||||
ThunarUcaTypes types = 0;
|
||||
|
||||
g_return_val_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor), 0);
|
||||
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->directories_button)))
|
||||
types |= THUNAR_UCA_TYPE_DIRECTORIES;
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->audio_files_button)))
|
||||
types |= THUNAR_UCA_TYPE_AUDIO_FILES;
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->image_files_button)))
|
||||
types |= THUNAR_UCA_TYPE_IMAGE_FILES;
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->text_files_button)))
|
||||
types |= THUNAR_UCA_TYPE_TEXT_FILES;
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->video_files_button)))
|
||||
types |= THUNAR_UCA_TYPE_VIDEO_FILES;
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->other_files_button)))
|
||||
types |= THUNAR_UCA_TYPE_OTHER_FILES;
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_editor_set_types (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaTypes types)
|
||||
{
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->directories_button), (types & THUNAR_UCA_TYPE_DIRECTORIES));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->audio_files_button), (types & THUNAR_UCA_TYPE_AUDIO_FILES));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->image_files_button), (types & THUNAR_UCA_TYPE_IMAGE_FILES));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->text_files_button), (types & THUNAR_UCA_TYPE_TEXT_FILES));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->video_files_button), (types & THUNAR_UCA_TYPE_VIDEO_FILES));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->other_files_button), (types & THUNAR_UCA_TYPE_OTHER_FILES));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_editor_load:
|
||||
* @uca_editor : a #ThunarUcaEditor.
|
||||
* @uca_model : a #ThunarUcaModel.
|
||||
* @iter : a #GtkTreeIter.
|
||||
*
|
||||
* Loads @uca_editor with the data from @uca_model
|
||||
* at the specified @iter.
|
||||
**/
|
||||
void
|
||||
thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
ThunarUcaTypes types;
|
||||
gchar *description;
|
||||
gchar *patterns;
|
||||
gchar *range;
|
||||
gchar *command;
|
||||
gchar *icon_name;
|
||||
gchar *name;
|
||||
gchar *submenu;
|
||||
gchar *unique_id;
|
||||
gchar *accel_label = NULL;
|
||||
gboolean startup_notify;
|
||||
GtkAccelKey key;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
|
||||
g_return_if_fail (iter != NULL);
|
||||
|
||||
/* determine the current values from the model */
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (uca_model), iter,
|
||||
THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, &description,
|
||||
THUNAR_UCA_MODEL_COLUMN_PATTERNS, &patterns,
|
||||
THUNAR_UCA_MODEL_COLUMN_RANGE, &range,
|
||||
THUNAR_UCA_MODEL_COLUMN_COMMAND, &command,
|
||||
THUNAR_UCA_MODEL_COLUMN_TYPES, &types,
|
||||
THUNAR_UCA_MODEL_COLUMN_ICON_NAME, &icon_name,
|
||||
THUNAR_UCA_MODEL_COLUMN_NAME, &name,
|
||||
THUNAR_UCA_MODEL_COLUMN_SUB_MENU, &submenu,
|
||||
THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, &startup_notify,
|
||||
THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
|
||||
-1);
|
||||
|
||||
/* setup the new selection */
|
||||
thunar_uca_editor_set_types (uca_editor, types);
|
||||
|
||||
/* setup the new icon */
|
||||
thunar_uca_editor_set_icon_name (uca_editor, icon_name);
|
||||
|
||||
/* Resolve shortcut from accelerator */
|
||||
uca_editor->accel_path = g_strdup_printf ("<Actions>/ThunarActions/uca-action-%s", unique_id);
|
||||
if (gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
|
||||
{
|
||||
accel_label = gtk_accelerator_get_label (key.accel_key, key.accel_mods);
|
||||
uca_editor->accel_key = key.accel_key;
|
||||
uca_editor->accel_mods = key.accel_mods;
|
||||
}
|
||||
|
||||
/* apply the new values */
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->description_entry), (description != NULL) ? description : "");
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->patterns_entry), (patterns != NULL) ? patterns : "");
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->command_entry), (command != NULL) ? command : "");
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->name_entry), (name != NULL) ? name : "");
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->range_entry), (range != NULL) ? range : "");
|
||||
gtk_entry_set_text (GTK_ENTRY (uca_editor->sub_menu_entry), (submenu != NULL) ? submenu : "");
|
||||
gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), (accel_label != NULL) ? accel_label : _("None"));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->sn_button), startup_notify);
|
||||
|
||||
/* cleanup */
|
||||
g_free (description);
|
||||
g_free (range);
|
||||
g_free (patterns);
|
||||
g_free (command);
|
||||
g_free (icon_name);
|
||||
g_free (name);
|
||||
g_free (submenu);
|
||||
g_free (unique_id);
|
||||
g_free (accel_label);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_editor_save:
|
||||
* @uca_editor : a #ThunarUcaEditor.
|
||||
* @uca_model : a #ThunarUcaModel.
|
||||
* @iter : a #GtkTreeIter.
|
||||
*
|
||||
* Stores the current values from the @uca_editor in
|
||||
* the @uca_model at the item specified by @iter.
|
||||
**/
|
||||
void
|
||||
thunar_uca_editor_save (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gchar *unique_id;
|
||||
GtkAccelKey key;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
|
||||
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
|
||||
g_return_if_fail (iter != NULL);
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (uca_model), iter,
|
||||
THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
|
||||
-1);
|
||||
|
||||
/* always clear the accelerator, it'll be updated in thunar_uca_model_update */
|
||||
if (uca_editor->accel_path != NULL && gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
|
||||
gtk_accel_map_change_entry (uca_editor->accel_path, 0, 0, TRUE);
|
||||
|
||||
thunar_uca_model_update (uca_model, iter,
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)),
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->sub_menu_entry)),
|
||||
unique_id,
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->description_entry)),
|
||||
thunar_uca_editor_get_icon_name (uca_editor),
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->command_entry)),
|
||||
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->sn_button)),
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->patterns_entry)),
|
||||
gtk_entry_get_text (GTK_ENTRY (uca_editor->range_entry)),
|
||||
thunar_uca_editor_get_types (uca_editor),
|
||||
uca_editor->accel_key,
|
||||
uca_editor->accel_mods);
|
||||
|
||||
g_free (unique_id);
|
||||
}
|
||||
54
plugins/thunar-uca/thunar-uca-editor.h
Normal file
54
plugins/thunar-uca/thunar-uca-editor.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_EDITOR_H__
|
||||
#define __THUNAR_UCA_EDITOR_H__
|
||||
|
||||
#include <thunar-uca/thunar-uca-model.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarUcaEditorClass ThunarUcaEditorClass;
|
||||
typedef struct _ThunarUcaEditor ThunarUcaEditor;
|
||||
|
||||
#define THUNAR_UCA_TYPE_EDITOR (thunar_uca_editor_get_type ())
|
||||
#define THUNAR_UCA_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_UCA_TYPE_EDITOR, ThunarUcaEditor))
|
||||
#define THUNAR_UCA_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_UCA_TYPE_EDITOR, ThunarUcaEditorwClass))
|
||||
#define THUNAR_UCA_IS_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_UCA_TYPE_EDITOR))
|
||||
#define THUNAR_UCA_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_UCA_TYPE_EDITOR))
|
||||
#define THUNAR_UCA_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_UCA_TYPE_EDITOR, ThunarUcaEditorwClass))
|
||||
|
||||
GType
|
||||
thunar_uca_editor_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_uca_editor_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
void
|
||||
thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter);
|
||||
void
|
||||
thunar_uca_editor_save (ThunarUcaEditor *uca_editor,
|
||||
ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_EDITOR_H__ */
|
||||
916
plugins/thunar-uca/thunar-uca-editor.ui
Normal file
916
plugins/thunar-uca/thunar-uca-editor.ui
Normal file
|
|
@ -0,0 +1,916 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2 -->
|
||||
<!--
|
||||
For now, better don't edit this with glade, since glade insists upon inserting
|
||||
deprecated properties and otherwise messing with the file.
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<template class="ThunarUcaEditor" parent="GtkDialog">
|
||||
<property name="can-focus">False</property>
|
||||
<property name="title" translatable="yes">Edit Action</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default-width">400</property>
|
||||
<property name="destroy-with-parent">True</property>
|
||||
<property name="type-hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="vbox">
|
||||
<property name="can-focus">False</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox">
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="notebook">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="border-width">6</property>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=8 -->
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="border-width">12</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="name_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Name:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">name_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="name_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="name_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">The name of the action that will be displayed in the context menu.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="description_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Description:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">description_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="description_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="description_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">The description of the action that will be displayed as tooltip in the statusbar when selecting the item from the context menu.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="sub_menu_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Submenu:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">sub_menu_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="sub_menu_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="sub_menu_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">The submenu in which the action will be displayed. Leave empty for no menu. Use '/' for nested menus.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="command_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Command:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">command_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="command_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="command_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">The command (including the necessary parameters) to perform the action. See the command parameter legend below for a list of supported parameter variables, which will be substituted when launching the command. When upper-case letters (e.g. %F, %D, %N) are used, the action will be applicable even if more than one item is selected. Else the action will only be applicable if exactly one item is selected.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="command_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Browse the file system to select an application to use for this action.</property>
|
||||
<signal name="clicked" handler="thunar_uca_editor_command_clicked" swapped="yes"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-open</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="shortcut_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Keyboard _Shortcut:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="shortcut_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="tooltip-text" translatable="yes">The keyboard shortcut for the action.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<signal name="clicked" handler="thunar_uca_editor_shortcut_clicked" swapped="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="shortcut_clear_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Clear the keyboard shortcut for this action.</property>
|
||||
<signal name="clicked" handler="thunar_uca_editor_shortcut_clear_clicked" swapped="yes"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">edit-clear</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="icon_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Icon:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">icon_button</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="icon_button"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="icon_button">
|
||||
<property name="label" translatable="yes">No icon</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Click this button to select an icon file that will be displayed in the context menu in addition to the action name chosen above.</property>
|
||||
<property name="halign">start</property>
|
||||
<signal name="clicked" handler="thunar_uca_editor_icon_clicked" swapped="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="sn_button">
|
||||
<property name="label" translatable="yes">Use Startup Notification</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Enable this option if you want a waiting cursor to be shown while the action is launched. This is also highly recommended if you have focus stealing prevention enabled in your window manager.</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">6</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">7</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=7 -->
|
||||
<object class="GtkGrid" id="grid2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="row-spacing">3</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<property name="margin-top">12</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="pixel-size">32</property>
|
||||
<property name="icon-name">dialog-information</property>
|
||||
<property name="icon_size">5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">The following command parameters will be substituted when launching the action:</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%n</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%N</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%d</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label8">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%D</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%f</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">%F</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label11">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">file name of the selected file</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="hexpand">True</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label12">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">file names of all selected files</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label13">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">path of the selected file's directory</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label14">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">paths of all selected files' directories</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label15">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">path of the selected file including the file name</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label16">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">paths of all selected files including the file names</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="0.80000000000000004"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">7</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Basic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=6 -->
|
||||
<object class="GtkGrid" id="grid3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="border-width">12</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_File Pattern:</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">patterns_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="patterns_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="patterns_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Enter a list of patterns that will be used to determine whether this action should be displayed for a selected file. If you specify more than one pattern here, the list items must be separated with semicolons (e.g. *.txt;*.doc).</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
<property name="text" translatable="yes">*</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label17">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">_Range (min-max):</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">range_entry</property>
|
||||
<property name="xalign">0</property>
|
||||
<accessibility>
|
||||
<relation type="label-for" target="range_entry"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="range_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="tooltip-text" translatable="yes">If the command should operate on say two or three files, enter the numerical range 2-3. If there are no limits, this string should be empty.</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="activates-default">True</property>
|
||||
<property name="text" translatable="yes">*</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label18">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Appears if selection contains:</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=3 -->
|
||||
<object class="GtkGrid" id="grid4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">12</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">48</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="directories_button">
|
||||
<property name="label" translatable="yes">_Directories **</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="hexpand">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="audio_files_button">
|
||||
<property name="label" translatable="yes">_Audio Files</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="image_files_button">
|
||||
<property name="label" translatable="yes">_Image Files</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="image-position">top</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="text_files_button">
|
||||
<property name="label" translatable="yes">_Text Files</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="video_files_button">
|
||||
<property name="label" translatable="yes">_Video Files</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="other_files_button">
|
||||
<property name="label" translatable="yes">_Other Files</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin-right">6</property>
|
||||
<property name="pixel-size">32</property>
|
||||
<property name="icon-name">dialog-information</property>
|
||||
<property name="icon_size">5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label19">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">This page lists the conditions under which the action will appear in the file managers context menus. The file patterns are specified as a list of simple file patterns separated by semicolons (e.g. *.txt;*.doc). For an action to appear in the context menu of a file or folder, at least one of these patterns must match the name of the file or folder. Additionally, you can specify that the action should only appear for certain kinds of files.
|
||||
|
||||
** The custom action will be eligible to appear in the toolbar.</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">5</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">4</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Appearance Conditions</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
1749
plugins/thunar-uca/thunar-uca-model.c
Normal file
1749
plugins/thunar-uca/thunar-uca-model.c
Normal file
File diff suppressed because it is too large
Load diff
129
plugins/thunar-uca/thunar-uca-model.h
Normal file
129
plugins/thunar-uca/thunar-uca-model.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_MODEL_H__
|
||||
#define __THUNAR_UCA_MODEL_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarUcaModelClass ThunarUcaModelClass;
|
||||
typedef struct _ThunarUcaModel ThunarUcaModel;
|
||||
|
||||
#define THUNAR_UCA_TYPE_MODEL (thunar_uca_model_get_type ())
|
||||
#define THUNAR_UCA_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_UCA_TYPE_MODEL, ThunarUcaModel))
|
||||
#define THUNAR_UCA_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_UCA_TYPE_MODEL, ThunarUcaModelClass))
|
||||
#define THUNAR_UCA_IS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_UCA_TYPE_MODEL))
|
||||
#define THUNAR_UCA_IS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_UCA_TYPE_MODEL))
|
||||
#define THUNAR_UCA_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_UCA_TYPE_MODEL, ThunarUcaModelClass))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
THUNAR_UCA_MODEL_COLUMN_NAME,
|
||||
THUNAR_UCA_MODEL_COLUMN_SUB_MENU,
|
||||
THUNAR_UCA_MODEL_COLUMN_DESCRIPTION,
|
||||
THUNAR_UCA_MODEL_COLUMN_GICON,
|
||||
THUNAR_UCA_MODEL_COLUMN_ICON_NAME,
|
||||
THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID,
|
||||
THUNAR_UCA_MODEL_COLUMN_COMMAND,
|
||||
THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY,
|
||||
THUNAR_UCA_MODEL_COLUMN_PATTERNS,
|
||||
THUNAR_UCA_MODEL_COLUMN_RANGE,
|
||||
THUNAR_UCA_MODEL_COLUMN_TYPES,
|
||||
THUNAR_UCA_MODEL_COLUMN_STOCK_LABEL,
|
||||
THUNAR_UCA_MODEL_N_COLUMNS,
|
||||
} ThunarUcaModelColumn;
|
||||
|
||||
/**
|
||||
* ThunarUcaTypes:
|
||||
* @THUNAR_UCA_TYPE_DIRECTORIES : directories.
|
||||
* @THUNAR_UCA_TYPE_AUDIO_FILES : audio files.
|
||||
* @THUNAR_UCA_TYPE_IMAGE_FILES : image files.
|
||||
* @THUNAR_UCA_TYPE_OTHER_FILES : other files.
|
||||
* @THUNAR_UCA_TYPE_TEXT_FILES : text files.
|
||||
* @THUNAR_UCA_TYPE_VIDEO_FILES : video files.
|
||||
**/
|
||||
typedef enum /*< flags >*/
|
||||
{
|
||||
THUNAR_UCA_TYPE_DIRECTORIES = 1 << 0,
|
||||
THUNAR_UCA_TYPE_AUDIO_FILES = 1 << 1,
|
||||
THUNAR_UCA_TYPE_IMAGE_FILES = 1 << 2,
|
||||
THUNAR_UCA_TYPE_OTHER_FILES = 1 << 3,
|
||||
THUNAR_UCA_TYPE_TEXT_FILES = 1 << 4,
|
||||
THUNAR_UCA_TYPE_VIDEO_FILES = 1 << 5,
|
||||
} ThunarUcaTypes;
|
||||
|
||||
GType
|
||||
thunar_uca_model_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_uca_model_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
ThunarUcaModel *
|
||||
thunar_uca_model_get_default (void);
|
||||
|
||||
GList *
|
||||
thunar_uca_model_match (ThunarUcaModel *uca_model,
|
||||
GList *file_infos);
|
||||
|
||||
void
|
||||
thunar_uca_model_append (ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter);
|
||||
|
||||
void
|
||||
thunar_uca_model_exchange (ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter_a,
|
||||
GtkTreeIter *iter_b);
|
||||
|
||||
void
|
||||
thunar_uca_model_remove (ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter);
|
||||
|
||||
void
|
||||
thunar_uca_model_update (ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter,
|
||||
const gchar *name,
|
||||
const gchar *submenu,
|
||||
const gchar *unique_id,
|
||||
const gchar *description,
|
||||
const gchar *icon,
|
||||
const gchar *command,
|
||||
gboolean startup_notify,
|
||||
const gchar *patterns,
|
||||
const gchar *range,
|
||||
ThunarUcaTypes types,
|
||||
guint accel_key,
|
||||
GdkModifierType accel_mods);
|
||||
|
||||
gboolean
|
||||
thunar_uca_model_save (ThunarUcaModel *uca_model,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
thunar_uca_model_parse_argv (ThunarUcaModel *uca_model,
|
||||
GtkTreeIter *iter,
|
||||
GList *file_infos,
|
||||
gint *argcp,
|
||||
gchar ***argvp,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_MODEL_H__ */
|
||||
91
plugins/thunar-uca/thunar-uca-plugin.c
Normal file
91
plugins/thunar-uca/thunar-uca-plugin.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thunar-uca/thunar-uca-chooser.h>
|
||||
#include <thunar-uca/thunar-uca-editor.h>
|
||||
#include <thunar-uca/thunar-uca-model.h>
|
||||
#include <thunar-uca/thunar-uca-provider.h>
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types);
|
||||
|
||||
|
||||
|
||||
static GType type_list[1];
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin)
|
||||
{
|
||||
const gchar *mismatch;
|
||||
|
||||
/* verify that the thunarx versions are compatible */
|
||||
mismatch = thunarx_check_version (THUNARX_MAJOR_VERSION, THUNARX_MINOR_VERSION, THUNARX_MICRO_VERSION);
|
||||
if (G_UNLIKELY (mismatch != NULL))
|
||||
{
|
||||
g_warning ("Version mismatch: %s", mismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Initializing ThunarUca extension");
|
||||
#endif
|
||||
|
||||
/* register the types provided by this plugin */
|
||||
thunar_uca_chooser_register_type (plugin);
|
||||
thunar_uca_editor_register_type (plugin);
|
||||
thunar_uca_model_register_type (plugin);
|
||||
thunar_uca_provider_register_type (plugin);
|
||||
|
||||
/* setup the plugin provider type list */
|
||||
type_list[0] = THUNAR_UCA_TYPE_PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_message ("Shutting down ThunarUca extension");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types)
|
||||
{
|
||||
*types = type_list;
|
||||
*n_types = G_N_ELEMENTS (type_list);
|
||||
}
|
||||
49
plugins/thunar-uca/thunar-uca-private.c
Normal file
49
plugins/thunar-uca/thunar-uca-private.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <exo/exo.h>
|
||||
#include <thunar-uca/thunar-uca-private.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_uca_i18n_init:
|
||||
*
|
||||
* Sets up i18n support for the thunar-uca plugin.
|
||||
**/
|
||||
void
|
||||
thunar_uca_i18n_init (void)
|
||||
{
|
||||
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
#endif
|
||||
}
|
||||
33
plugins/thunar-uca/thunar-uca-private.h
Normal file
33
plugins/thunar-uca/thunar-uca-private.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_PRIVATE_H__
|
||||
#define __THUNAR_UCA_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
void
|
||||
thunar_uca_i18n_init (void);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_PRIVATE_H__ */
|
||||
604
plugins/thunar-uca/thunar-uca-provider.c
Normal file
604
plugins/thunar-uca/thunar-uca-provider.c
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <libxfce4ui/libxfce4ui.h>
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-uca/thunar-uca-chooser.h>
|
||||
#include <thunar-uca/thunar-uca-context.h>
|
||||
#include <thunar-uca/thunar-uca-model.h>
|
||||
#include <thunar-uca/thunar-uca-private.h>
|
||||
#include <thunar-uca/thunar-uca-provider.h>
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_menu_provider_init (ThunarxMenuProviderIface *iface);
|
||||
static void
|
||||
thunar_uca_provider_preferences_provider_init (ThunarxPreferencesProviderIface *iface);
|
||||
static void
|
||||
thunar_uca_provider_finalize (GObject *object);
|
||||
static GList *
|
||||
thunar_uca_provider_get_menu_items (ThunarxPreferencesProvider *preferences_provider,
|
||||
GtkWidget *window);
|
||||
static GList *
|
||||
thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
GList *files);
|
||||
static GList *
|
||||
thunar_uca_provider_get_folder_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
ThunarxFileInfo *folder);
|
||||
static void
|
||||
thunar_uca_provider_activated (ThunarUcaProvider *uca_provider,
|
||||
ThunarxMenuItem *item);
|
||||
static void
|
||||
thunar_uca_provider_child_watch (ThunarUcaProvider *uca_provider,
|
||||
gint exit_status);
|
||||
static void
|
||||
thunar_uca_provider_child_watch_destroy (gpointer user_data,
|
||||
GClosure *closure);
|
||||
|
||||
|
||||
|
||||
struct _ThunarUcaProviderClass
|
||||
{
|
||||
GObjectClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarUcaProvider
|
||||
{
|
||||
GObject __parent__;
|
||||
|
||||
ThunarUcaModel *model;
|
||||
gint last_action_id; /* used to generate unique action names */
|
||||
|
||||
/* child watch support for the last spawned child process
|
||||
* to be able to refresh the folder contents after the
|
||||
* child process has terminated.
|
||||
*/
|
||||
gchar *child_watch_path;
|
||||
GClosure *child_watch;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static GQuark thunar_uca_context_quark;
|
||||
static GQuark thunar_uca_folder_quark;
|
||||
static GQuark thunar_uca_row_quark;
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE_WITH_CODE (ThunarUcaProvider,
|
||||
thunar_uca_provider,
|
||||
G_TYPE_OBJECT,
|
||||
THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_MENU_PROVIDER,
|
||||
thunar_uca_provider_menu_provider_init)
|
||||
THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_PREFERENCES_PROVIDER,
|
||||
thunar_uca_provider_preferences_provider_init));
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_class_init (ThunarUcaProviderClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
/* setup the "thunar-uca-context", "thunar-uca-folder" and "thunar-uca-row" quarks */
|
||||
thunar_uca_context_quark = g_quark_from_string ("thunar-uca-context");
|
||||
thunar_uca_folder_quark = g_quark_from_string ("thunar-uca-folder");
|
||||
thunar_uca_row_quark = g_quark_from_string ("thunar-uca-row");
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = thunar_uca_provider_finalize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_menu_provider_init (ThunarxMenuProviderIface *iface)
|
||||
{
|
||||
iface->get_file_menu_items = thunar_uca_provider_get_file_menu_items;
|
||||
iface->get_folder_menu_items = thunar_uca_provider_get_folder_menu_items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_preferences_provider_init (ThunarxPreferencesProviderIface *iface)
|
||||
{
|
||||
iface->get_menu_items = thunar_uca_provider_get_menu_items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_init (ThunarUcaProvider *uca_provider)
|
||||
{
|
||||
/* setup the i18n support first */
|
||||
thunar_uca_i18n_init ();
|
||||
|
||||
/* grab a reference on the default model */
|
||||
uca_provider->model = thunar_uca_model_get_default ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_finalize (GObject *object)
|
||||
{
|
||||
ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (object);
|
||||
|
||||
/* give up maintaince of any pending child watch */
|
||||
thunar_uca_provider_child_watch_destroy (uca_provider, NULL);
|
||||
|
||||
/* drop our reference on the model */
|
||||
g_object_unref (G_OBJECT (uca_provider->model));
|
||||
|
||||
(*G_OBJECT_CLASS (thunar_uca_provider_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
manage_menu_items (GtkWindow *window)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
gboolean use_header_bar = FALSE;
|
||||
|
||||
g_object_get (gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window))),
|
||||
"gtk-dialogs-use-header", &use_header_bar, NULL);
|
||||
|
||||
dialog = g_object_new (THUNAR_UCA_TYPE_CHOOSER, "use-header-bar", use_header_bar, NULL);
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_uca_provider_get_menu_items (ThunarxPreferencesProvider *preferences_provider,
|
||||
GtkWidget *window)
|
||||
{
|
||||
ThunarxMenuItem *item;
|
||||
GClosure *closure;
|
||||
|
||||
item = thunarx_menu_item_new ("ThunarUca::manage-actions", _("Confi_gure custom actions..."), _("Setup custom actions that will appear in the file managers context menus"), NULL);
|
||||
closure = g_cclosure_new_object_swap (G_CALLBACK (manage_menu_items), G_OBJECT (window));
|
||||
g_signal_connect_closure (G_OBJECT (item), "activate", closure, TRUE);
|
||||
|
||||
return g_list_prepend (NULL, item);
|
||||
}
|
||||
|
||||
|
||||
/* returned menu must be freed with g_object_unref() */
|
||||
static ThunarxMenu *
|
||||
find_submenu_by_name (gchar *name, GList *items)
|
||||
{
|
||||
GList *lp;
|
||||
GList *thunarx_menu_items;
|
||||
|
||||
for (lp = g_list_first (items); lp != NULL; lp = lp->next)
|
||||
{
|
||||
gchar *item_name = NULL;
|
||||
ThunarxMenu *item_menu = NULL;
|
||||
g_object_get (G_OBJECT (lp->data), "name", &item_name, "menu", &item_menu, NULL);
|
||||
|
||||
if (item_menu != NULL)
|
||||
{
|
||||
/* This menu is the correct menu */
|
||||
if (g_strcmp0 (item_name, name) == 0)
|
||||
{
|
||||
g_free (item_name);
|
||||
return item_menu;
|
||||
}
|
||||
|
||||
/* Some other menu found .. lets check recursively if the menu we search for is inside */
|
||||
thunarx_menu_items = thunarx_menu_get_items (item_menu);
|
||||
g_object_unref (item_menu);
|
||||
|
||||
if (thunarx_menu_items != NULL)
|
||||
{
|
||||
ThunarxMenu *submenu = find_submenu_by_name (name, thunarx_menu_items);
|
||||
if (submenu != NULL)
|
||||
{
|
||||
g_free (item_name);
|
||||
return submenu;
|
||||
}
|
||||
thunarx_menu_item_list_free (thunarx_menu_items);
|
||||
}
|
||||
}
|
||||
g_free (item_name);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
GList *files)
|
||||
{
|
||||
GtkTreeRowReference *row;
|
||||
ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (menu_provider);
|
||||
ThunarUcaContext *uca_context = NULL;
|
||||
GtkTreeIter iter;
|
||||
ThunarxMenuItem *menu_item;
|
||||
ThunarxMenuItem *item;
|
||||
GList *items = NULL;
|
||||
GList *paths;
|
||||
GList *lp;
|
||||
ThunarxMenu *submenu;
|
||||
ThunarxMenu *parent_menu = NULL;
|
||||
|
||||
paths = thunar_uca_model_match (uca_provider->model, files);
|
||||
|
||||
for (lp = g_list_last (paths); lp != NULL; lp = lp->prev)
|
||||
{
|
||||
gchar *unique_id = NULL;
|
||||
gchar *name = NULL;
|
||||
gchar *sub_menu_string = NULL;
|
||||
gchar **sub_menus_as_array = NULL;
|
||||
gchar *label = NULL;
|
||||
gchar *tooltip = NULL;
|
||||
gchar *icon_name = NULL;
|
||||
GIcon *gicon = NULL;
|
||||
|
||||
/* try to lookup the tree iter for the specified tree path */
|
||||
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, lp->data))
|
||||
{
|
||||
/* determine the label, tooltip and stock-id for the item */
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (uca_provider->model), &iter,
|
||||
THUNAR_UCA_MODEL_COLUMN_NAME, &label,
|
||||
THUNAR_UCA_MODEL_COLUMN_SUB_MENU, &sub_menu_string,
|
||||
THUNAR_UCA_MODEL_COLUMN_GICON, &gicon,
|
||||
THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, &tooltip,
|
||||
THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
|
||||
-1);
|
||||
|
||||
/* generate a unique action name */
|
||||
name = g_strdup_printf ("uca-action-%s", unique_id);
|
||||
|
||||
if (gicon != NULL)
|
||||
icon_name = g_icon_to_string (gicon);
|
||||
|
||||
/* Search or build the parent submenus, if required */
|
||||
parent_menu = NULL;
|
||||
sub_menus_as_array = g_strsplit (sub_menu_string, "/", -1);
|
||||
|
||||
for (int i = 0; sub_menus_as_array[i] != NULL; i++)
|
||||
{
|
||||
/* get the submenu path up to the iterator */
|
||||
gchar *sub_menu_path = g_strdup (sub_menus_as_array[0]);
|
||||
|
||||
for (int j = 1; j <= i; j++)
|
||||
sub_menu_path = g_strconcat (sub_menu_path, "/", sub_menus_as_array[j], NULL);
|
||||
|
||||
/* Check if the full path already exists */
|
||||
submenu = find_submenu_by_name (sub_menu_path, items);
|
||||
|
||||
if (submenu != NULL)
|
||||
{
|
||||
/* This submenu already exists, we can just use it as new parent */
|
||||
parent_menu = submenu;
|
||||
/* no need to keep the extra reference on it */
|
||||
g_object_unref (submenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not found, we create a new submenu */
|
||||
menu_item = thunarx_menu_item_new (sub_menu_path, sub_menus_as_array[i], "", "folder");
|
||||
|
||||
/* Only add base-submenus to the returned list */
|
||||
if (parent_menu == NULL)
|
||||
items = g_list_prepend (items, menu_item);
|
||||
else
|
||||
thunarx_menu_prepend_item (parent_menu, menu_item);
|
||||
|
||||
/* This sublevel becomes the new parent */
|
||||
parent_menu = thunarx_menu_new ();
|
||||
thunarx_menu_item_set_menu (menu_item, parent_menu);
|
||||
}
|
||||
g_free (sub_menu_path);
|
||||
}
|
||||
g_strfreev (sub_menus_as_array);
|
||||
|
||||
/* create the new menu item with the given parameters */
|
||||
item = thunarx_menu_item_new (name, label, tooltip, icon_name);
|
||||
|
||||
/* grab a tree row reference on the given path */
|
||||
row = gtk_tree_row_reference_new (GTK_TREE_MODEL (uca_provider->model), lp->data);
|
||||
g_object_set_qdata_full (G_OBJECT (item), thunar_uca_row_quark, row,
|
||||
(GDestroyNotify) gtk_tree_row_reference_free);
|
||||
|
||||
/* allocate a new context on-demand */
|
||||
if (G_LIKELY (uca_context == NULL))
|
||||
uca_context = thunar_uca_context_new (window, files);
|
||||
else
|
||||
uca_context = thunar_uca_context_ref (uca_context);
|
||||
g_object_set_qdata_full (G_OBJECT (item), thunar_uca_context_quark, uca_context, (GDestroyNotify) thunar_uca_context_unref);
|
||||
|
||||
/* connect the "activate" signal */
|
||||
g_signal_connect_data (G_OBJECT (item), "activate", G_CALLBACK (thunar_uca_provider_activated),
|
||||
g_object_ref (G_OBJECT (uca_provider)),
|
||||
(GClosureNotify) (void (*) (void)) g_object_unref,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
/* set the action path */
|
||||
g_object_set_data_full (G_OBJECT (item), "action_path",
|
||||
g_strconcat ("<Actions>/ThunarActions/", name, NULL), g_free);
|
||||
|
||||
/* add only base menu items to the return list */
|
||||
if (parent_menu == NULL)
|
||||
items = g_list_prepend (items, item);
|
||||
else
|
||||
thunarx_menu_prepend_item (parent_menu, item);
|
||||
|
||||
/* cleanup */
|
||||
g_free (tooltip);
|
||||
g_free (label);
|
||||
g_free (name);
|
||||
g_free (sub_menu_string);
|
||||
g_free (icon_name);
|
||||
g_free (unique_id);
|
||||
|
||||
if (gicon != NULL)
|
||||
g_object_unref (G_OBJECT (gicon));
|
||||
}
|
||||
|
||||
/* release the tree path */
|
||||
gtk_tree_path_free (lp->data);
|
||||
}
|
||||
g_list_free (paths);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_uca_provider_get_folder_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
ThunarxFileInfo *folder)
|
||||
{
|
||||
GList *items;
|
||||
GList files;
|
||||
GList *lp;
|
||||
|
||||
/* fake a file list... */
|
||||
files.data = folder;
|
||||
files.next = NULL;
|
||||
files.prev = NULL;
|
||||
|
||||
/* ...and use the get_file_menu_items() method */
|
||||
items = thunarx_menu_provider_get_file_menu_items (menu_provider, window, &files);
|
||||
|
||||
/* mark the menu items, so we can properly detect the working directory */
|
||||
for (lp = items; lp != NULL; lp = lp->next)
|
||||
g_object_set_qdata (G_OBJECT (lp->data), thunar_uca_folder_quark, GUINT_TO_POINTER (TRUE));
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_activated (ThunarUcaProvider *uca_provider,
|
||||
ThunarxMenuItem *item)
|
||||
{
|
||||
GtkTreeRowReference *row;
|
||||
ThunarUcaContext *uca_context;
|
||||
GtkTreePath *path;
|
||||
GtkTreeIter iter;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *window;
|
||||
gboolean succeed;
|
||||
GError *error = NULL;
|
||||
GList *files;
|
||||
gchar **argv;
|
||||
gchar *working_directory = NULL;
|
||||
gchar *filename;
|
||||
gchar *label;
|
||||
GFile *location;
|
||||
gint argc;
|
||||
gchar *icon_name = NULL;
|
||||
gboolean startup_notify;
|
||||
GClosure *child_watch;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider));
|
||||
g_return_if_fail (THUNARX_IS_MENU_ITEM (item));
|
||||
|
||||
/* check if the row reference is still valid */
|
||||
row = g_object_get_qdata (G_OBJECT (item), thunar_uca_row_quark);
|
||||
if (G_UNLIKELY (!gtk_tree_row_reference_valid (row)))
|
||||
return;
|
||||
|
||||
/* determine the iterator for the item */
|
||||
path = gtk_tree_row_reference_get_path (row);
|
||||
gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, path);
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
/* determine the files and the window for the menu item */
|
||||
uca_context = g_object_get_qdata (G_OBJECT (item), thunar_uca_context_quark);
|
||||
window = thunar_uca_context_get_window (uca_context);
|
||||
files = thunar_uca_context_get_files (uca_context);
|
||||
|
||||
/* determine the argc/argv for the item */
|
||||
succeed = thunar_uca_model_parse_argv (uca_provider->model, &iter, files, &argc, &argv, &error);
|
||||
if (G_LIKELY (succeed))
|
||||
{
|
||||
/* get the icon name and whether startup notification is active */
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (uca_provider->model), &iter,
|
||||
THUNAR_UCA_MODEL_COLUMN_ICON_NAME, &icon_name,
|
||||
THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, &startup_notify,
|
||||
-1);
|
||||
|
||||
/* determine the working from the first file */
|
||||
if (G_LIKELY (files != NULL))
|
||||
{
|
||||
/* determine the filename of the first selected file */
|
||||
location = thunarx_file_info_get_location (files->data);
|
||||
filename = g_file_get_path (location);
|
||||
if (G_LIKELY (filename != NULL))
|
||||
{
|
||||
/* if this is a folder menu item, we just use the filename as working directory */
|
||||
if (g_object_get_qdata (G_OBJECT (item), thunar_uca_folder_quark) != NULL)
|
||||
{
|
||||
working_directory = filename;
|
||||
filename = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
working_directory = g_path_get_dirname (filename);
|
||||
}
|
||||
}
|
||||
g_free (filename);
|
||||
g_object_unref (location);
|
||||
}
|
||||
|
||||
/* build closre for child watch */
|
||||
child_watch = g_cclosure_new_swap (G_CALLBACK (thunar_uca_provider_child_watch),
|
||||
uca_provider, thunar_uca_provider_child_watch_destroy);
|
||||
g_closure_ref (child_watch);
|
||||
g_closure_sink (child_watch);
|
||||
|
||||
/* spawn the command on the window's screen */
|
||||
succeed = xfce_spawn_on_screen_with_child_watch (gtk_widget_get_screen (GTK_WIDGET (window)),
|
||||
working_directory, argv, NULL,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
startup_notify,
|
||||
gtk_get_current_event_time (),
|
||||
icon_name,
|
||||
child_watch,
|
||||
&error);
|
||||
|
||||
/* check if we succeed */
|
||||
if (G_LIKELY (succeed))
|
||||
{
|
||||
/* release existing child watch */
|
||||
thunar_uca_provider_child_watch_destroy (uca_provider, NULL);
|
||||
|
||||
/* set new closure */
|
||||
uca_provider->child_watch = child_watch;
|
||||
|
||||
/* take over ownership of the working directory as child watch path */
|
||||
uca_provider->child_watch_path = working_directory;
|
||||
working_directory = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* spawn failed, release watch */
|
||||
g_closure_unref (child_watch);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
g_free (working_directory);
|
||||
g_strfreev (argv);
|
||||
g_free (icon_name);
|
||||
}
|
||||
|
||||
/* present error message to the user */
|
||||
if (G_UNLIKELY (!succeed))
|
||||
{
|
||||
g_object_get (G_OBJECT (item), "label", &label, NULL);
|
||||
dialog = gtk_message_dialog_new ((GtkWindow *) window,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT
|
||||
| GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
_("Failed to launch action \"%s\"."), label);
|
||||
gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
g_error_free (error);
|
||||
g_free (label);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_child_watch (ThunarUcaProvider *uca_provider,
|
||||
gint exit_status)
|
||||
|
||||
{
|
||||
GFileMonitor *monitor;
|
||||
GFile *file;
|
||||
|
||||
g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider));
|
||||
|
||||
/* verify that we still have a valid child_watch_path */
|
||||
if (G_LIKELY (uca_provider->child_watch_path != NULL))
|
||||
{
|
||||
/* determine the corresponding file */
|
||||
file = g_file_new_for_path (uca_provider->child_watch_path);
|
||||
|
||||
/* schedule a changed notification on the path */
|
||||
monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
|
||||
if (monitor != NULL)
|
||||
{
|
||||
g_file_monitor_emit_event (monitor, file, file, G_FILE_MONITOR_EVENT_CHANGED);
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
/* release the file */
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
thunar_uca_provider_child_watch_destroy (uca_provider, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_uca_provider_child_watch_destroy (gpointer user_data,
|
||||
GClosure *closure)
|
||||
{
|
||||
ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (user_data);
|
||||
GClosure *child_watch;
|
||||
|
||||
/* leave if the closure is not the one we're watching */
|
||||
if (uca_provider->child_watch == closure
|
||||
|| closure == NULL)
|
||||
{
|
||||
/* reset child watch and path */
|
||||
if (G_UNLIKELY (uca_provider->child_watch != NULL))
|
||||
{
|
||||
child_watch = uca_provider->child_watch;
|
||||
uca_provider->child_watch = NULL;
|
||||
|
||||
g_closure_invalidate (child_watch);
|
||||
g_closure_unref (child_watch);
|
||||
}
|
||||
|
||||
g_free (uca_provider->child_watch_path);
|
||||
uca_provider->child_watch_path = NULL;
|
||||
}
|
||||
}
|
||||
45
plugins/thunar-uca/thunar-uca-provider.h
Normal file
45
plugins/thunar-uca/thunar-uca-provider.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
|
||||
*
|
||||
* 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 __THUNAR_UCA_PROVIDER_H__
|
||||
#define __THUNAR_UCA_PROVIDER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarUcaProviderClass ThunarUcaProviderClass;
|
||||
typedef struct _ThunarUcaProvider ThunarUcaProvider;
|
||||
|
||||
#define THUNAR_UCA_TYPE_PROVIDER (thunar_uca_provider_get_type ())
|
||||
#define THUNAR_UCA_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_UCA_TYPE_PROVIDER, ThunarUcaProvider))
|
||||
#define THUNAR_UCA_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_UCA_TYPE_PROVIDER, ThunarUcaProviderClass))
|
||||
#define THUNAR_UCA_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_UCA_TYPE_PROVIDER))
|
||||
#define THUNAR_UCA_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_UCA_TYPE_PROVIDER))
|
||||
#define THUNAR_UCA_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_UCA_TYPE_PROVIDER, ThunarUcaProviderClass))
|
||||
|
||||
GType
|
||||
thunar_uca_provider_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
thunar_uca_provider_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_UCA_PROVIDER_H__ */
|
||||
7
plugins/thunar-uca/thunar-uca.gresource.xml
Normal file
7
plugins/thunar-uca/thunar-uca.gresource.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/xfce/thunar/uca">
|
||||
<file compressed="true" alias="editor.ui">thunar-uca-editor.ui</file>
|
||||
<file compressed="true" alias="chooser.ui">thunar-uca-chooser.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
49
plugins/thunar-uca/uca.xml.in
Normal file
49
plugins/thunar-uca/uca.xml.in
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE actions [
|
||||
<!ELEMENT actions (action)+>
|
||||
|
||||
<!ELEMENT action (icon|patterns|name|unique-id|command|description|directories|audio-files|image-files|other-files|text-files|video-files)*>
|
||||
|
||||
<!ELEMENT icon (#PCDATA)>
|
||||
<!ELEMENT command (#PCDATA)>
|
||||
<!ELEMENT patterns (#PCDATA)>
|
||||
|
||||
<!ELEMENT name (#PCDATA)>
|
||||
<!ATTLIST name xml:lang CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT unique-id (#PCDATA)>
|
||||
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
<!ATTLIST description xml:lang CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT startup-notify EMPTY>
|
||||
|
||||
<!ELEMENT directories EMPTY>
|
||||
<!ELEMENT audio-files EMPTY>
|
||||
<!ELEMENT image-files EMPTY>
|
||||
<!ELEMENT other-files EMPTY>
|
||||
<!ELEMENT text-files EMPTY>
|
||||
<!ELEMENT video-files EMPTY>
|
||||
]>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||||
|
||||
Default thunar-uca configuration file, which gets installed system-wide.
|
||||
This should act more like an example, and is therefore kept simple.
|
||||
-->
|
||||
|
||||
<actions>
|
||||
|
||||
<action>
|
||||
<icon>utilities-terminal</icon>
|
||||
<patterns>*</patterns>
|
||||
<range></range>
|
||||
<name>Open Terminal Here</name>
|
||||
<command>exo-open --working-directory %f --launch TerminalEmulator</command>
|
||||
<description>Example for a custom action</description>
|
||||
<startup-notify/>
|
||||
<directories/>
|
||||
</action>
|
||||
|
||||
</actions>
|
||||
45
plugins/thunar-wallpaper/Makefile.am
Normal file
45
plugins/thunar-wallpaper/Makefile.am
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir) \
|
||||
-DG_LOG_DOMAIN=\"thunar-wallpaper-plugin\" \
|
||||
-DEXO_API_SUBJECT_TO_CHANGE \
|
||||
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
|
||||
$(PLATFORM_CPPFLAGS)
|
||||
|
||||
extensionsdir = $(libdir)/thunarx-$(THUNARX_VERSION_API)
|
||||
extensions_LTLIBRARIES = \
|
||||
thunar-wallpaper-plugin.la
|
||||
|
||||
thunar_wallpaper_plugin_la_SOURCES = \
|
||||
twp-provider.h \
|
||||
twp-provider.c \
|
||||
thunar-wallpaper-plugin.c
|
||||
|
||||
thunar_wallpaper_plugin_la_CFLAGS = \
|
||||
$(EXO_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(GTK_CFLAGS) \
|
||||
$(LIBX11_CFLAGS) \
|
||||
$(XFCONF_CFLAGS) \
|
||||
$(PLATFORM_CFLAGS)
|
||||
|
||||
thunar_wallpaper_plugin_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
-no-undefined \
|
||||
-export-symbols-regex "^thunar_extension_(shutdown|initialize|list_types)" \
|
||||
-module \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
thunar_wallpaper_plugin_la_LIBADD = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la \
|
||||
$(EXO_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(GTK_LIBS) \
|
||||
$(XFCONF_LIBS) \
|
||||
$(LIBX11_LIBS)
|
||||
|
||||
thunar_wallpaper_plugin_la_DEPENDENCIES = \
|
||||
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
|
||||
|
||||
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
|
||||
6
plugins/thunar-wallpaper/README.md
Normal file
6
plugins/thunar-wallpaper/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Thunar Wallpaper Plugin (thunar-wallpaper)
|
||||
===========================================
|
||||
|
||||
The Thunar Wallpaper plugin is an extension to Thunar. It depends on the xfconf-query command line to set the correct settings on the Xfce4 desktop.
|
||||
|
||||
To disable this plugin, pass `--disable-wallpaper-plugin` to ./configure.
|
||||
86
plugins/thunar-wallpaper/thunar-wallpaper-plugin.c
Normal file
86
plugins/thunar-wallpaper/thunar-wallpaper-plugin.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
|
||||
* Copyright (c) 2008 Mike Massonnet <mmassonnet@xfce.org>
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "twp-provider.h"
|
||||
|
||||
#include <exo/exo.h>
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void);
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types);
|
||||
|
||||
|
||||
|
||||
static GType type_list[1];
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_initialize (ThunarxProviderPlugin *plugin)
|
||||
{
|
||||
const gchar *mismatch;
|
||||
|
||||
/* verify that the thunarx versions are compatible */
|
||||
mismatch = thunarx_check_version (THUNARX_MAJOR_VERSION, THUNARX_MINOR_VERSION, THUNARX_MICRO_VERSION);
|
||||
if (G_UNLIKELY (mismatch != NULL))
|
||||
{
|
||||
g_warning ("Version mismatch: %s", mismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup i18n support */
|
||||
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
#endif
|
||||
|
||||
/* register the types provided by this plugin */
|
||||
twp_provider_register_type (plugin);
|
||||
|
||||
/* setup the plugin provider type list */
|
||||
type_list[0] = TWP_TYPE_PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_shutdown (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
thunar_extension_list_types (const GType **types,
|
||||
gint *n_types)
|
||||
{
|
||||
*types = type_list;
|
||||
*n_types = G_N_ELEMENTS (type_list);
|
||||
}
|
||||
384
plugins/thunar-wallpaper/twp-provider.c
Normal file
384
plugins/thunar-wallpaper/twp-provider.c
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
|
||||
* Copyright (c) 2008-2009 Mike Massonnet <mmassonnet@xfce.org>
|
||||
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "twp-provider.h"
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <xfconf/xfconf.h>
|
||||
|
||||
|
||||
#define XFDESKTOP_SELECTION_FMT "XFDESKTOP_SELECTION_%d"
|
||||
#define NAUTILUS_SELECTION_FMT "NAUTILUS_DESKTOP_WINDOW_ID"
|
||||
|
||||
|
||||
|
||||
static void
|
||||
twp_menu_provider_init (ThunarxMenuProviderIface *iface);
|
||||
static void
|
||||
twp_provider_finalize (GObject *object);
|
||||
static GList *
|
||||
twp_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
GList *files);
|
||||
static void
|
||||
twp_action_set_wallpaper (ThunarxMenuItem *item,
|
||||
gpointer user_data);
|
||||
static gint
|
||||
twp_get_active_workspace_number (GdkScreen *screen);
|
||||
|
||||
static gboolean _has_gsettings = FALSE;
|
||||
static GtkWidget *main_window = NULL;
|
||||
|
||||
struct _TwpProviderClass
|
||||
{
|
||||
GObjectClass __parent__;
|
||||
};
|
||||
|
||||
struct _TwpProvider
|
||||
{
|
||||
GObject __parent__;
|
||||
|
||||
gchar *child_watch_path;
|
||||
gint child_watch_id;
|
||||
};
|
||||
|
||||
|
||||
|
||||
THUNARX_DEFINE_TYPE_WITH_CODE (TwpProvider, twp_provider, G_TYPE_OBJECT, THUNARX_IMPLEMENT_INTERFACE (THUNARX_TYPE_MENU_PROVIDER, twp_menu_provider_init));
|
||||
|
||||
static void
|
||||
twp_menu_provider_init (ThunarxMenuProviderIface *iface)
|
||||
{
|
||||
iface->get_file_menu_items = twp_provider_get_file_menu_items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
twp_provider_class_init (TwpProviderClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = twp_provider_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
twp_provider_init (TwpProvider *twp_provider)
|
||||
{
|
||||
gchar *program;
|
||||
|
||||
program = g_find_program_in_path ("gsettings");
|
||||
if (G_LIKELY (program != NULL))
|
||||
{
|
||||
_has_gsettings = TRUE;
|
||||
g_free (program);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
twp_provider_finalize (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (twp_provider_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
twp_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
GList *files)
|
||||
{
|
||||
ThunarxMenuItem *item = NULL;
|
||||
GFile *location;
|
||||
GList *items = NULL;
|
||||
gchar *mime_type;
|
||||
|
||||
main_window = window;
|
||||
|
||||
/* we can only set a single wallpaper */
|
||||
if (files->next == NULL)
|
||||
{
|
||||
/* get the location of the file */
|
||||
location = thunarx_file_info_get_location (files->data);
|
||||
|
||||
/* unable to handle non-local files */
|
||||
if (G_UNLIKELY (!g_file_has_uri_scheme (location, "file")))
|
||||
{
|
||||
g_object_unref (location);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* release the location */
|
||||
g_object_unref (location);
|
||||
|
||||
if (!thunarx_file_info_is_directory (files->data))
|
||||
{
|
||||
/* get the mime type of the file */
|
||||
mime_type = thunarx_file_info_get_mime_type (files->data);
|
||||
|
||||
if (g_str_has_prefix (mime_type, "image/")
|
||||
&& (thunarx_file_info_has_mime_type (files->data, "image/jpeg")
|
||||
|| thunarx_file_info_has_mime_type (files->data, "image/png")
|
||||
|| thunarx_file_info_has_mime_type (files->data, "image/svg+xml")
|
||||
|| thunarx_file_info_has_mime_type (files->data, "image/svg+xml-compressed")))
|
||||
{
|
||||
item = thunarx_menu_item_new ("Twp::setwallpaper", _("Set as wallpaper"), NULL, "preferences-desktop-wallpaper");
|
||||
g_signal_connect (item, "activate", G_CALLBACK (twp_action_set_wallpaper), files->data);
|
||||
|
||||
items = g_list_append (items, item);
|
||||
}
|
||||
g_free (mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static void
|
||||
twp_action_set_wallpaper (ThunarxMenuItem *item,
|
||||
gpointer user_data)
|
||||
{
|
||||
ThunarxFileInfo *file_info = user_data;
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gint screen_nr = 0;
|
||||
gint n_monitors;
|
||||
gint monitor_nr = 0;
|
||||
gint workspace;
|
||||
GdkScreen *screen;
|
||||
GdkMonitor *monitor;
|
||||
gchar *image_path_prop;
|
||||
gchar *image_show_prop;
|
||||
gchar *image_style_prop;
|
||||
const char *monitor_name;
|
||||
gchar *file_uri;
|
||||
gchar *escaped_file_name;
|
||||
gchar *file_name = NULL;
|
||||
gchar *hostname = NULL;
|
||||
gchar *command;
|
||||
XfconfChannel *channel;
|
||||
gboolean is_single_workspace;
|
||||
gint current_image_style;
|
||||
const gchar *desktop_type = NULL;
|
||||
|
||||
screen = gdk_display_get_default_screen (display);
|
||||
|
||||
desktop_type = g_getenv ("XDG_CURRENT_DESKTOP");
|
||||
if (desktop_type == NULL)
|
||||
{
|
||||
g_warning ("Failed to set wallpaper: $XDG_CURRENT_DESKTOP is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
file_uri = thunarx_file_info_get_uri (file_info);
|
||||
file_name = g_filename_from_uri (file_uri, &hostname, NULL);
|
||||
if (hostname != NULL)
|
||||
{
|
||||
g_free (hostname);
|
||||
g_free (file_uri);
|
||||
g_free (file_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
workspace = twp_get_active_workspace_number (screen);
|
||||
n_monitors = gdk_display_get_n_monitors (display);
|
||||
|
||||
if (n_monitors > 1 && main_window)
|
||||
{
|
||||
monitor = gdk_display_get_monitor_at_window (display, gtk_widget_get_window (main_window));
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor = gdk_display_get_monitor (display, monitor_nr);
|
||||
}
|
||||
|
||||
monitor_name = gdk_monitor_get_model (monitor);
|
||||
escaped_file_name = g_shell_quote (file_name);
|
||||
|
||||
if (g_strcmp0 (desktop_type, "XFCE") == 0)
|
||||
{
|
||||
g_debug ("set on xfce");
|
||||
|
||||
channel = xfconf_channel_get ("xfce4-desktop");
|
||||
|
||||
/* This is the format for xfdesktop before 4.11 */
|
||||
image_path_prop = g_strdup_printf ("/backdrop/screen%d/monitor%d/image-path", screen_nr, monitor_nr);
|
||||
image_show_prop = g_strdup_printf ("/backdrop/screen%d/monitor%d/image-show", screen_nr, monitor_nr);
|
||||
image_style_prop = g_strdup_printf ("/backdrop/screen%d/monitor%d/image-style", screen_nr, monitor_nr);
|
||||
|
||||
/* Set the wallpaper and ensure that it's set to show */
|
||||
xfconf_channel_set_string (channel, image_path_prop, file_name);
|
||||
xfconf_channel_set_bool (channel, image_show_prop, TRUE);
|
||||
|
||||
/* If there isn't a wallpaper style set (-1), or it is set to 'None' (which is 0) then set one */
|
||||
current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
|
||||
if (current_image_style <= 0)
|
||||
{
|
||||
/* Lets hope that 5 = 'Zoomed' works fine for the selected picture */
|
||||
xfconf_channel_set_int (channel, image_style_prop, 5);
|
||||
}
|
||||
|
||||
g_free (image_path_prop);
|
||||
g_free (image_show_prop);
|
||||
g_free (image_style_prop);
|
||||
|
||||
|
||||
/* Xfdesktop 4.11+ has a concept of a single-workspace-mode where
|
||||
* the same workspace is used for everything but additionally allows
|
||||
* the user to use any current workspace as the single active
|
||||
* workspace, we'll need to check if it is enabled (which by default
|
||||
* it is) and use that. */
|
||||
is_single_workspace = xfconf_channel_get_bool (channel, "/backdrop/single-workspace-mode", TRUE);
|
||||
if (is_single_workspace)
|
||||
{
|
||||
workspace = xfconf_channel_get_int (channel, "/backdrop/single-workspace-number", 0);
|
||||
}
|
||||
|
||||
/* This is the format for xfdesktop post 4.11. A workspace number is
|
||||
* added and the monitor is referred to name. We set both formats so
|
||||
* that it works as the user expects. */
|
||||
if (monitor_name)
|
||||
{
|
||||
image_path_prop = g_strdup_printf ("/backdrop/screen%d/monitor%s/workspace%d/last-image", screen_nr, monitor_name, workspace);
|
||||
image_style_prop = g_strdup_printf ("/backdrop/screen%d/monitor%s/workspace%d/image-style", screen_nr, monitor_name, workspace);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* gdk_screen_get_monitor_plug_name can return NULL, in those
|
||||
* instances we fallback to monitor number but still include the
|
||||
* workspace number */
|
||||
image_path_prop = g_strdup_printf ("/backdrop/screen%d/monitor%d/workspace%d/last-image", screen_nr, monitor_nr, workspace);
|
||||
image_style_prop = g_strdup_printf ("/backdrop/screen%d/monitor%d/workspace%d/image-style", screen_nr, monitor_nr, workspace);
|
||||
}
|
||||
|
||||
xfconf_channel_set_string (channel, image_path_prop, file_name);
|
||||
|
||||
/* If there isn't a wallpaper style set (-1), or it is set to 'None' (which is 0) then set one */
|
||||
current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
|
||||
if (current_image_style <= 0)
|
||||
{
|
||||
/* Lets hope that 5 = 'Zoomed' works fine for the selected picture */
|
||||
xfconf_channel_set_int (channel, image_style_prop, 5);
|
||||
}
|
||||
|
||||
g_free (image_path_prop);
|
||||
g_free (image_style_prop);
|
||||
}
|
||||
else if (g_strcmp0 (desktop_type, "GNOME") == 0)
|
||||
{
|
||||
if (_has_gsettings)
|
||||
{
|
||||
g_debug ("set on gnome");
|
||||
|
||||
command = g_strdup_printf ("gsettings set "
|
||||
"org.gnome.desktop.background picture-uri "
|
||||
"'%s'",
|
||||
file_uri);
|
||||
g_spawn_command_line_async (command, NULL);
|
||||
g_free (command);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to set wallpaper: Missing executable 'gsettings'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning (("Failed to set wallpaper: $XDG_CURRENT_DESKTOP Desktop type '%s' not supported by thunar wallpaper plugin."), desktop_type);
|
||||
}
|
||||
|
||||
g_free (escaped_file_name);
|
||||
g_free (file_name);
|
||||
g_free (file_uri);
|
||||
}
|
||||
|
||||
/* Taken from xfce_spawn_get_active_workspace_number in xfce-spawn.c apart of
|
||||
* the libxfce4ui library.
|
||||
* https://git.xfce.org/xfce/libxfce4ui/tree/libxfce4ui/xfce-spawn.c#n193
|
||||
*/
|
||||
static gint
|
||||
twp_get_active_workspace_number (GdkScreen *screen)
|
||||
{
|
||||
GdkWindow *root;
|
||||
gulong bytes_after_ret = 0;
|
||||
gulong nitems_ret = 0;
|
||||
guint *prop_ret = NULL;
|
||||
Atom _NET_CURRENT_DESKTOP;
|
||||
Atom _WIN_WORKSPACE;
|
||||
Atom type_ret = None;
|
||||
gint format_ret;
|
||||
gint ws_num = 0;
|
||||
|
||||
if (!GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
|
||||
return 0;
|
||||
|
||||
gdk_x11_display_error_trap_push (gdk_display_get_default ());
|
||||
|
||||
root = gdk_screen_get_root_window (screen);
|
||||
|
||||
/* determine the X atom values */
|
||||
_NET_CURRENT_DESKTOP = XInternAtom (GDK_WINDOW_XDISPLAY (root), "_NET_CURRENT_DESKTOP", False);
|
||||
_WIN_WORKSPACE = XInternAtom (GDK_WINDOW_XDISPLAY (root), "_WIN_WORKSPACE", False);
|
||||
|
||||
if (XGetWindowProperty (GDK_WINDOW_XDISPLAY (root),
|
||||
gdk_x11_get_default_root_xwindow (),
|
||||
_NET_CURRENT_DESKTOP, 0, 32, False, XA_CARDINAL,
|
||||
&type_ret, &format_ret, &nitems_ret, &bytes_after_ret,
|
||||
(gpointer) &prop_ret)
|
||||
!= Success)
|
||||
{
|
||||
if (XGetWindowProperty (GDK_WINDOW_XDISPLAY (root),
|
||||
gdk_x11_get_default_root_xwindow (),
|
||||
_WIN_WORKSPACE, 0, 32, False, XA_CARDINAL,
|
||||
&type_ret, &format_ret, &nitems_ret, &bytes_after_ret,
|
||||
(gpointer) &prop_ret)
|
||||
!= Success)
|
||||
{
|
||||
if (G_UNLIKELY (prop_ret != NULL))
|
||||
{
|
||||
XFree (prop_ret);
|
||||
prop_ret = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (G_LIKELY (prop_ret != NULL))
|
||||
{
|
||||
if (G_LIKELY (type_ret != None && format_ret != 0))
|
||||
ws_num = *prop_ret;
|
||||
XFree (prop_ret);
|
||||
}
|
||||
|
||||
gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ());
|
||||
|
||||
return ws_num;
|
||||
}
|
||||
45
plugins/thunar-wallpaper/twp-provider.h
Normal file
45
plugins/thunar-wallpaper/twp-provider.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
|
||||
* Copyright (c) 2008 Mike Massonnet <mmassonnet@xfce.org>
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __TWP_PROVIDER_H__
|
||||
#define __TWP_PROVIDER_H__
|
||||
|
||||
#include <thunarx/thunarx.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _TwpProviderClass TwpProviderClass;
|
||||
typedef struct _TwpProvider TwpProvider;
|
||||
|
||||
#define TWP_TYPE_PROVIDER (twp_provider_get_type ())
|
||||
#define TWP_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TWP_TYPE_PROVIDER, TwpProvider))
|
||||
#define TWP_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TWP_TYPE_PROVIDER, TwpProviderClass))
|
||||
#define TWP_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TWP_TYPE_PROVIDER))
|
||||
#define TWP_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TWP_TYPE_PROVIDER))
|
||||
#define TWP_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TWP_TYPE_PROVIDER, TwpProviderClass))
|
||||
|
||||
GType
|
||||
twp_provider_get_type (void) G_GNUC_CONST;
|
||||
void
|
||||
twp_provider_register_type (ThunarxProviderPlugin *plugin);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__TWP_PROVIDER_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue