Index: rhythmdb/rhythmdb-query-model.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-query-model.c,v
retrieving revision 1.92
diff -u -u -r1.92 rhythmdb-query-model.c
--- rhythmdb/rhythmdb-query-model.c	19 Dec 2005 22:06:46 -0000	1.92
+++ rhythmdb/rhythmdb-query-model.c	6 Jan 2006 03:39:01 -0000
@@ -365,7 +365,7 @@
 	case PROP_QUERY:
 		model->priv->query = rhythmdb_query_copy (g_value_get_pointer (value));
 		model->priv->original_query = rhythmdb_query_copy (model->priv->query);
-		rhythmdb_query_preprocess (model->priv->query);
+		rhythmdb_query_preprocess (model->priv->db, model->priv->query);
 		break;
 	case PROP_SORT_FUNC:
 		model->priv->sort_func = g_value_get_pointer (value);
Index: rhythmdb/rhythmdb-tree.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-tree.c,v
retrieving revision 1.86
diff -u -u -r1.86 rhythmdb-tree.c
--- rhythmdb/rhythmdb-tree.c	1 Jan 2006 11:39:44 -0000	1.86
+++ rhythmdb/rhythmdb-tree.c	6 Jan 2006 03:39:01 -0000
@@ -1489,6 +1489,9 @@
 			break;
 		case RHYTHMDB_QUERY_END:
 		case RHYTHMDB_QUERY_DISJUNCTION:
+		case RHYTHMDB_QUERY_PROP_YEAR_EQUALS:
+		case RHYTHMDB_QUERY_PROP_YEAR_LESS:
+		case RHYTHMDB_QUERY_PROP_YEAR_GREATER:
 			g_assert_not_reached ();
 			break;
 		}
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.152
diff -u -u -r1.152 rhythmdb.c
--- rhythmdb/rhythmdb.c	19 Dec 2005 10:17:12 -0000	1.152
+++ rhythmdb/rhythmdb.c	6 Jan 2006 03:39:02 -0000
@@ -61,6 +61,9 @@
 #define RB_PARSE_LESS (xmlChar *) "less"
 #define RB_PARSE_CURRENT_TIME_WITHIN (xmlChar *) "current-time-within"
 #define RB_PARSE_CURRENT_TIME_NOT_WITHIN (xmlChar *) "current-time-not-within"
+#define RB_PARSE_YEAR_EQUALS RB_PARSE_EQUALS
+#define RB_PARSE_YEAR_GREATER RB_PARSE_GREATER
+#define RB_PARSE_YEAR_LESS RB_PARSE_LESS
 
 #define RB_PARSE_NICK_START (xmlChar *) "["
 #define RB_PARSE_NICK_END (xmlChar *) "]"
@@ -2724,6 +2727,9 @@
 		case RHYTHMDB_QUERY_PROP_LESS:
 		case RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN:
 		case RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN:
+		case RHYTHMDB_QUERY_PROP_YEAR_EQUALS:
+		case RHYTHMDB_QUERY_PROP_YEAR_GREATER:
+		case RHYTHMDB_QUERY_PROP_YEAR_LESS:  
 			data->propid = va_arg (args, guint);
 			data->val = g_new0 (GValue, 1);
 			g_value_init (data->val, rhythmdb_get_property_type (db, data->propid));
@@ -2853,6 +2859,9 @@
 		case RHYTHMDB_QUERY_PROP_LESS:
 		case RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN:
 		case RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN:
+		case RHYTHMDB_QUERY_PROP_YEAR_EQUALS:
+		case RHYTHMDB_QUERY_PROP_YEAR_GREATER:
+		case RHYTHMDB_QUERY_PROP_YEAR_LESS:  
 			g_value_unset (data->val);
 			g_free (data->val);
 			break;
@@ -2995,6 +3004,11 @@
 			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
 			write_encoded_gvalue (subnode, data->val);
 			break;
+		case RHYTHMDB_QUERY_PROP_YEAR_EQUALS:
+			subnode = xmlNewChild (node, NULL, RB_PARSE_YEAR_EQUALS, NULL);
+			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
+			write_encoded_gvalue (subnode, data->val);
+			break;
 		case RHYTHMDB_QUERY_DISJUNCTION:
 			subnode = xmlNewChild (node, NULL, RB_PARSE_DISJ, NULL);
 			break;
@@ -3005,11 +3019,21 @@
 			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
 			write_encoded_gvalue (subnode, data->val);
 			break;
+		case RHYTHMDB_QUERY_PROP_YEAR_GREATER:
+			subnode = xmlNewChild (node, NULL, RB_PARSE_YEAR_GREATER, NULL);
+			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
+			write_encoded_gvalue (subnode, data->val);
+			break;
 		case RHYTHMDB_QUERY_PROP_LESS:
 			subnode = xmlNewChild (node, NULL, RB_PARSE_LESS, NULL);
 			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
 			write_encoded_gvalue (subnode, data->val);
 			break;
+		case RHYTHMDB_QUERY_PROP_YEAR_LESS:  
+			subnode = xmlNewChild (node, NULL, RB_PARSE_YEAR_LESS, NULL);
+			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
+			write_encoded_gvalue (subnode, data->val);
+			break;
 		case RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN:
 			subnode = xmlNewChild (node, NULL, RB_PARSE_CURRENT_TIME_WITHIN, NULL);
 			xmlSetProp (subnode, RB_PARSE_PROP, rhythmdb_nice_elt_name_from_propid (db, data->propid));
@@ -3055,11 +3079,23 @@
 		} else if (!xmlStrcmp (child->name, RB_PARSE_NOT_LIKE)) {
 			data->type = RHYTHMDB_QUERY_PROP_NOT_LIKE;
 		} else if (!xmlStrcmp (child->name, RB_PARSE_EQUALS)) {
-			data->type = RHYTHMDB_QUERY_PROP_EQUALS;
+			if (!xmlStrcmp(xmlGetProp(child, RB_PARSE_PROP), 
+				       (xmlChar *)"date")) 
+				data->type = RHYTHMDB_QUERY_PROP_YEAR_EQUALS;
+			else 
+				data->type = RHYTHMDB_QUERY_PROP_EQUALS;
 		} else if (!xmlStrcmp (child->name, RB_PARSE_GREATER)) {
-			data->type = RHYTHMDB_QUERY_PROP_GREATER;
+			if (!xmlStrcmp(xmlGetProp(child, RB_PARSE_PROP), 
+				       (xmlChar *)"date")) 
+				data->type = RHYTHMDB_QUERY_PROP_YEAR_GREATER;
+			else 
+				data->type = RHYTHMDB_QUERY_PROP_GREATER;
 		} else if (!xmlStrcmp (child->name, RB_PARSE_LESS)) {
-			data->type = RHYTHMDB_QUERY_PROP_LESS;
+			if (!xmlStrcmp(xmlGetProp(child, RB_PARSE_PROP), 
+				       (xmlChar *)"date")) 
+				data->type = RHYTHMDB_QUERY_PROP_YEAR_LESS;
+			else 
+				data->type = RHYTHMDB_QUERY_PROP_LESS;
 		} else if (!xmlStrcmp (child->name, RB_PARSE_CURRENT_TIME_WITHIN)) {
 			data->type = RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN;
 		} else if (!xmlStrcmp (child->name, RB_PARSE_CURRENT_TIME_NOT_WITHIN)) {
@@ -3072,6 +3108,9 @@
 		    || !xmlStrcmp (child->name, RB_PARSE_EQUALS)
 		    || !xmlStrcmp (child->name, RB_PARSE_GREATER)
 		    || !xmlStrcmp (child->name, RB_PARSE_LESS)
+		    || !xmlStrcmp (child->name, RB_PARSE_YEAR_EQUALS)
+		    || !xmlStrcmp (child->name, RB_PARSE_YEAR_GREATER)
+		    || !xmlStrcmp (child->name, RB_PARSE_YEAR_LESS)
 		    || !xmlStrcmp (child->name, RB_PARSE_CURRENT_TIME_WITHIN)
 		    || !xmlStrcmp (child->name, RB_PARSE_CURRENT_TIME_NOT_WITHIN)) {
 			xmlChar *propstr = xmlGetProp (child, RB_PARSE_PROP);
@@ -3149,7 +3188,7 @@
 	RhythmDBEvent *result;
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (data->db);
 
-	rhythmdb_query_preprocess (data->query);
+	rhythmdb_query_preprocess (data->db, data->query);
 
 	rb_debug ("doing query");
 
@@ -3293,6 +3332,9 @@
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_LESS, "True if property1 <= property2"),
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN, "True if property1 is within property2 of the current time"),
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN, "True if property1 is not within property2 of the current time"),
+			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_YEAR_EQUALS, "Year equivalence: true if date within year"),
+			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_YEAR_GREATER, "True if date greater than year"),
+			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_YEAR_LESS, "True if date less than year"),
 			{ 0, 0, 0 }
 		};
 
@@ -3690,7 +3732,7 @@
 }
 
 void
-rhythmdb_query_preprocess (GPtrArray *query)
+rhythmdb_query_preprocess (RhythmDB *db, GPtrArray *query)
 {
 	int i;	
 
@@ -3698,7 +3740,7 @@
 		RhythmDBQueryData *data = g_ptr_array_index (query, i);
 		
 		if (data->subquery) {
-			rhythmdb_query_preprocess (data->subquery);
+			rhythmdb_query_preprocess (db, data->subquery);
 		} else switch (data->propid) {
 			case RHYTHMDB_PROP_TITLE_FOLDED:
 			case RHYTHMDB_PROP_GENRE_FOLDED:
@@ -3727,6 +3769,56 @@
 				break;
 			}
 
+			case RHYTHMDB_PROP_DATE:
+			{
+				GDate *date;
+				gulong search_date;		
+				gulong begin;			
+				gulong end;
+				gulong year;
+
+				search_date = g_value_get_ulong (data->val);
+				date = g_date_new_julian (search_date);		
+				year = g_date_get_year (date);	
+				g_date_free (date);				
+
+				/* get Julian dates for beginning and end of year */ 
+				date = g_date_new_dmy (1, G_DATE_JANUARY, year); 
+				begin = g_date_get_julian (date);	
+				g_date_free (date);				
+
+				/* end the dat before the beginning of the next year */
+				date = g_date_new_dmy (1, G_DATE_JANUARY, year + 1); 
+				end =  g_date_get_julian (date) - 1;
+				g_date_free (date);				
+				
+				switch (data->type)
+				{
+				case RHYTHMDB_QUERY_PROP_YEAR_EQUALS:
+					data->type = RHYTHMDB_QUERY_SUBQUERY;
+					data->subquery = rhythmdb_query_parse (db,
+									       RHYTHMDB_QUERY_PROP_GREATER, data->propid, begin,
+									       RHYTHMDB_QUERY_PROP_LESS, data->propid, end,
+									       RHYTHMDB_QUERY_END);
+					break;
+
+				case RHYTHMDB_QUERY_PROP_YEAR_LESS:
+					data->type = RHYTHMDB_QUERY_PROP_LESS;
+					g_value_set_ulong (data->val, end);
+					break;
+
+				case RHYTHMDB_QUERY_PROP_YEAR_GREATER:
+					data->type = RHYTHMDB_QUERY_PROP_GREATER;
+					g_value_set_ulong (data->val, begin);
+					break;
+
+				default:
+					break;
+				}
+				
+				break;
+			}
+			
 			default:
 				break;
 		}
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.63
diff -u -u -r1.63 rhythmdb.h
--- rhythmdb/rhythmdb.h	27 Dec 2005 06:38:28 -0000	1.63
+++ rhythmdb/rhythmdb.h	6 Jan 2006 03:39:05 -0000
@@ -62,6 +62,9 @@
 	RHYTHMDB_QUERY_PROP_LESS,
 	RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
 	RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN,
+	RHYTHMDB_QUERY_PROP_YEAR_EQUALS,
+	RHYTHMDB_QUERY_PROP_YEAR_GREATER,   
+	RHYTHMDB_QUERY_PROP_YEAR_LESS,   
 } RhythmDBQueryType;
 
 /* If you modify this enum, don't forget to modify rhythmdb_prop_get_type */
@@ -537,7 +540,7 @@
 void		rhythmdb_query_append			(RhythmDB *db, GPtrArray *query, ...);
 void		rhythmdb_query_free			(GPtrArray *query);
 GPtrArray *	rhythmdb_query_copy			(GPtrArray *array);
-void		rhythmdb_query_preprocess		(GPtrArray *query);
+void		rhythmdb_query_preprocess		(RhythmDB *db, GPtrArray *query);
 
 void		rhythmdb_query_serialize		(RhythmDB *db, GPtrArray *query,
 							 xmlNodePtr node);
Index: widgets/rb-query-creator-properties.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/widgets/rb-query-creator-properties.c,v
retrieving revision 1.4
diff -u -u -r1.4 rb-query-creator-properties.c
--- widgets/rb-query-creator-properties.c	5 Nov 2005 05:03:19 -0000	1.4
+++ widgets/rb-query-creator-properties.c	6 Jan 2006 03:39:08 -0000
@@ -31,6 +31,7 @@
 const RBQueryCreatorPropertyType escaped_string_property_type;
 const RBQueryCreatorPropertyType rating_property_type;
 const RBQueryCreatorPropertyType integer_property_type;
+const RBQueryCreatorPropertyType year_property_type;
 const RBQueryCreatorPropertyType duration_property_type;
 const RBQueryCreatorPropertyType relative_time_property_type;
 
@@ -45,6 +46,9 @@
 static GtkWidget * integerCriteriaCreateWidget (gboolean *constrain);
 static void integerCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
 static void integerCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
+static GtkWidget * yearCriteriaCreateWidget (gboolean *constrain);
+static void yearCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
+static void yearCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
 static GtkWidget * durationCriteriaCreateWidget (gboolean *constrain);
 static void durationCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
 static void durationCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
@@ -62,6 +66,7 @@
 	{ N_("Artist"), RHYTHMDB_PROP_ARTIST, RHYTHMDB_PROP_ARTIST_FOLDED, &string_property_type },
 	{ N_("Album"), RHYTHMDB_PROP_ALBUM, RHYTHMDB_PROP_ALBUM_FOLDED, &string_property_type },
 	{ N_("Genre"), RHYTHMDB_PROP_GENRE, RHYTHMDB_PROP_GENRE_FOLDED, &string_property_type },
+	{ N_("Year"), RHYTHMDB_PROP_DATE, RHYTHMDB_PROP_DATE, &year_property_type },
 	{ N_("Rating"), RHYTHMDB_PROP_RATING, RHYTHMDB_PROP_RATING, &rating_property_type },
 	{ N_("Path"), RHYTHMDB_PROP_LOCATION, RHYTHMDB_PROP_LOCATION, &escaped_string_property_type },
 
@@ -144,6 +149,20 @@
 	{ N_("at most"), 1, RHYTHMDB_QUERY_PROP_LESS }		/* matches if A <= B */
 };
 
+/*
+ * Property type for date quantities 
+ */
+
+const RBQueryCreatorCriteriaOption year_criteria_options[] =
+{
+	{ N_("in"), 1, RHYTHMDB_QUERY_PROP_YEAR_EQUALS }, 
+	/* matches if within 1-JAN-YEAR to 31-DEC-YEAR */
+	{ N_("after"), 1, RHYTHMDB_QUERY_PROP_YEAR_GREATER },	
+	/* matches if >= 31-DEC-YEAR */
+	{ N_("before"), 1, RHYTHMDB_QUERY_PROP_YEAR_LESS }		
+	/* matches if < 1-DEC-YEAR */
+};
+
 const RBQueryCreatorPropertyType rating_property_type =
 {
 	G_N_ELEMENTS (numeric_criteria_options),
@@ -162,6 +181,15 @@
 	integerCriteriaGetWidgetData
 };
 
+const RBQueryCreatorPropertyType year_property_type =
+{
+	G_N_ELEMENTS (year_criteria_options),
+	year_criteria_options,
+	yearCriteriaCreateWidget,
+	yearCriteriaSetWidgetData,
+	yearCriteriaGetWidgetData
+};
+
 const RBQueryCreatorPropertyType duration_property_type =
 {
 	G_N_ELEMENTS (numeric_criteria_options),
@@ -328,6 +356,45 @@
 	g_value_init (val, G_TYPE_ULONG);
 	g_value_set_ulong (val, (gulong)num);
 }
+
+/* Implementation for Year properties, using a single GtkSpinButton. */
+
+static GtkWidget *
+yearCriteriaCreateWidget (gboolean *constrain)
+{
+	return gtk_spin_button_new_with_range (0.0, (double)G_MAXINT, 1.0);
+}
+
+static void
+yearCriteriaSetWidgetData (GtkWidget *widget, GValue *val)
+{
+	GDate *date = NULL;
+	gulong num = g_value_get_ulong (val);
+	g_assert (num <= G_MAXINT);
+
+	/* Create a date structure to get year from */
+	date = g_date_new();
+	g_date_set_julian (date, num);
+	
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), (gint)g_date_get_year(date));
+	g_date_free(date);
+}
+
+static void
+yearCriteriaGetWidgetData (GtkWidget *widget, GValue *val)
+{
+	GDate *date = NULL;
+	gint num = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+	g_assert (num >=  0);
+
+	/* New date structure, use year set in widget */
+	date = g_date_new_dmy (1, G_DATE_JANUARY, num);
+
+	g_value_init (val, G_TYPE_ULONG);
+	g_value_set_ulong (val, (gulong) g_date_get_julian (date) );
+	g_date_free(date);
+}
+
 
 
 /*
