? account_my_view_add.php
? account_my_view_delete.php
? account_my_view_page.php
? account_my_view_sequence.php
Index: config_defaults_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v
retrieving revision 1.365
diff -u -b -r1.365 config_defaults_inc.php
--- config_defaults_inc.php	4 Oct 2007 05:59:04 -0000	1.365
+++ config_defaults_inc.php	23 Oct 2007 19:23:21 -0000
@@ -1352,6 +1352,7 @@
 	$g_mantis_custom_field_string_table     = '%db_table_prefix%_custom_field_string%db_table_suffix%';
 	$g_mantis_upgrade_table					= '%db_table_prefix%_upgrade%db_table_suffix%';
 	$g_mantis_filters_table					= '%db_table_prefix%_filters%db_table_suffix%';
+	$g_mantis_filters_my_view_table			= '%db_table_prefix%_filters_my_view%db_table_suffix%';
 	$g_mantis_sponsorship_table				= '%db_table_prefix%_sponsorship%db_table_suffix%';
 	$g_mantis_tokens_table					= '%db_table_prefix%_tokens%db_table_suffix%';
 	$g_mantis_project_hierarchy_table		= '%db_table_prefix%_project_hierarchy%db_table_suffix%';
@@ -1675,19 +1676,37 @@
 	# Number of bugs shown in each box
 	$g_my_view_bug_count = 10;
 
-	# Boxes to be shown and their order
-	# A box that is not to be shown can have its value set to 0
+	# Boxes to be shown in "My View". Put them in the order you want them to appear
 	$g_my_view_boxes = array (
-		'assigned'      => '1',
-		'unassigned'    => '2',
-		'reported'      => '3',
-		'resolved'      => '4',
-		'recent_mod'	=> '5',
-		'monitored'		=> '6',
-		'feedback'		=> '0',
-		'verify'		=> '0'
+		FILTER_ASSIGNED,
+		FILTER_UNASSIGNED,
+		FILTER_REPORTED,
+		FILTER_RESOLVED,
+		FILTER_RECENT_MOD,
+		FILTER_MONITORED,
+		// FILTER_FEEDBACK,
+		// FILTER_VERIFY,
 	);
 
+	# Allows you to set a custom "My View" on an access level basis
+	# To do this, set the key of the first dimension to the access level, then
+	# make the value an array of filters. For example:
+	# $g_my_view_access_boxes = array (
+	# 	ADMINISTRATOR => array(
+	#		FILTER_UNASSIGNED,
+	#		FILTER_ASSIGNED
+	#	),
+	#   REPORTER => array(
+	#		FILTER_REPORTED,
+	#		FILTER_MONITORED
+	#	)
+	# );
+	$g_my_view_access_boxes = array (
+	);
+
+	# threshold needed to customize the 'My View' screen
+	$g_custom_my_view_threshold = ANYBODY;
+
 	# Toggle whether 'My View' boxes are shown in a fixed position (i.e. adjacent boxes start at the same vertical position)
 	$g_my_view_boxes_fixed_position = ON;
 
Index: my_view_page.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/my_view_page.php,v
retrieving revision 1.17
diff -u -b -r1.17 my_view_page.php
--- my_view_page.php	28 Jul 2007 10:15:15 -0000	1.17
+++ my_view_page.php	23 Oct 2007 19:23:21 -0000
@@ -17,6 +17,7 @@
 	require_once( $t_core_path . 'compress_api.php' );
 	require_once( $t_core_path . 'filter_api.php' );
 	require_once( $t_core_path . 'last_visited_api.php' );
+	require_once( $t_core_path . 'icon_api.php' );
 
 	auth_ensure_user_authenticated();
 
@@ -40,11 +41,6 @@
 	$t_bug_count = null;
 	$t_page_count = null;
 
-	$t_boxes = config_get( 'my_view_boxes' );
-	asort ($t_boxes);
-	reset ($t_boxes);
-	#print_r ($t_boxes);
-
 	$t_project_id = helper_get_current_project();
 ?>
 
@@ -61,52 +57,76 @@
 		echo '</td>';
 		echo '</tr>';
 	}
-?>
 
-<?php
-	$t_number_of_boxes = count ( $t_boxes );
 	$t_boxes_position = config_get( 'my_view_boxes_fixed_position' );
-	$t_counter = 0;
 
-	while (list ($t_box_title, $t_box_display) = each ($t_boxes)) {
-		# don't display bugs that are set as 0
-		if ($t_box_display == 0) {
-			$t_number_of_boxes = $t_number_of_boxes - 1;
-		}
+	$t_custom_my_view_threshold = config_get('custom_my_view_threshold');
 
-		# don't display "Assigned to Me" bugs to users that bugs can't be assigned to
-		else if ( $t_box_title == 'assigned' && ( current_user_is_anonymous() OR user_get_assigned_open_bug_count( $t_current_user_id, $t_project_id ) == 0 ) ) {
-			$t_number_of_boxes = $t_number_of_boxes - 1;
-		}
+	# Make sure they have access to define a custom 'my view'
+	if (access_has_global_level($t_custom_my_view_threshold)) {
 
-		# don't display "Monitored by Me" bugs to users that can't monitor bugs
-		else if ( $t_box_title == 'monitored' && ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) {
-			$t_number_of_boxes = $t_number_of_boxes - 1;
-		}
+		# Get the list of custom my_view filters
+		$t_filters = filter_db_get_my_view( $t_current_user_id, TRUE );
 
-		# don't display "Reported by Me" bugs to users that can't report bugs
-		else if ( in_array( $t_box_title, array( 'reported', 'feedback', 'verify' ) ) && 
-				( current_user_is_anonymous() OR !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) {
-			$t_number_of_boxes = $t_number_of_boxes - 1;
-		}
+		# If they set no custom filters, then get the default view
+		if (count($t_filters) <= 0)
+			$t_filters = filter_get_default_my_view( $t_project_id );
 
-		# display the box
+	}
 		else {
+		$t_filters = filter_get_default_my_view( $t_project_id );
+	}
+
+
+	$t_number_of_boxes = count($t_filters);
+
+	$t_counter = 0;
+
+	foreach ($t_filters AS $filter) {
+
 			$t_counter++;
 
-			# check the style of displaying boxes - fixed (ie. each box in a separate table cell) or not
+		# If the filter is for a specific project, only use that project
+		if (array_key_exists('project_id', $filter) && $filter['project_id'] != 0)
+			$t_filter_project_id = $filter['project_id'];
+		else
+			$t_filter_project_id = $t_project_id;
+
 			if ( ON == $t_boxes_position ) {
+
 				# for even box number start new row and column
-				if ( 1 == $t_counter%2 ) {
+			if ( 1 == $t_counter % 2 ) {
 					echo '<tr><td valign="top" width="50%">';
-					include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' );
+
+				print_filter_my_view_box(
+						$filter['name'],
+						$f_page_number,
+						$t_per_page,
+						$filter['filter'],
+						$t_filter_project_id,
+						$t_current_user_id,
+						null,
+						array_key_exists('url', $filter)?"view_all_set.php?type=1&amp;temporary=y&amp;". $filter['url']:null
+					);
+
 					echo '</td>';
 				}
 
 				# for odd box number only start new column
 				elseif ( 0 == $t_counter%2 ) {
 					echo '<td valign="top" width="50%">';
-					include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' );
+
+				print_filter_my_view_box(
+						$filter['name'],
+						$f_page_number,
+						$t_per_page,
+						$filter['filter'],
+						$t_filter_project_id,
+						$t_current_user_id,
+						null,
+						array_key_exists('url', $filter)?"view_all_set.php?type=1&amp;temporary=y&amp;". $filter['url']:null
+					);
+
 					echo '</td></tr>';
 				}
 
@@ -114,8 +134,10 @@
 				if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter%2 ) {
 					echo '<td valign="top" width="50%"></td></tr>';
 				}
+
 			}
-			else if ( OFF == $t_boxes_position ) {
+		else {
+
 				# start new table row and column for first box
 				if ( 1 == $t_counter ) {
 					echo '<tr><td valign="top" width="50%">';
@@ -127,7 +149,18 @@
 				}
 
 				# display the required box
-				include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' );
+
+			print_filter_my_view_box(
+					$filter['name'],
+					$f_page_number,
+					$t_per_page,
+					$filter['filter'],
+					$t_filter_project_id,
+					$t_current_user_id,
+					null,
+					array_key_exists('url', $filter)?"view_all_set.php?type=1&amp;temporary=y&amp;". $filter['url']:null
+				);
+
 				echo '<br />';
 
 				# close the first column for first half of boxes
@@ -140,12 +173,9 @@
 					echo '</td></tr>';
 				}
 			}
-		}
-	}
 
-?>
+	}
 
-<?php
 	if ( $t_status_legend_position == STATUS_LEGEND_POSITION_BOTTOM || $t_status_legend_position == STATUS_LEGEND_POSITION_BOTH ) {
 		echo '<tr>';
 		echo '<td colspan="2">';
Index: core/constant_inc.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/constant_inc.php,v
retrieving revision 1.74
diff -u -b -r1.74 constant_inc.php
--- core/constant_inc.php	24 Sep 2007 19:24:30 -0000	1.74
+++ core/constant_inc.php	23 Oct 2007 19:23:21 -0000
@@ -321,6 +321,16 @@
 	define( 'FILTER_POSITION_BOTTOM',			2 );
 	define( 'FILTER_POSITION_BOTH',				3 );  // FILTER_POSITION_TOP | FILTER_POSITION_BOTTOM (bitwise OR)
 
+	    # Default Filters
+	define( 'FILTER_ASSIGNED',					-1 );
+	define( 'FILTER_RECENT_MOD',				-2 );
+	define( 'FILTER_REPORTED',					-3 );
+	define( 'FILTER_RESOLVED',					-4 );
+	define( 'FILTER_UNASSIGNED',				-5 );
+	define( 'FILTER_MONITORED',					-6 );
+	define( 'FILTER_FEEDBACK',					-7 );
+	define( 'FILTER_VERIFY',					-8 );
+
 	# Flags for settings E-mail categories
 	define( 'EMAIL_CATEGORY_PROJECT_CATEGORY',	1);
 
Index: core/filter_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/filter_api.php,v
retrieving revision 1.164
diff -u -b -r1.164 filter_api.php
--- core/filter_api.php	19 Oct 2007 06:13:00 -0000	1.164
+++ core/filter_api.php	23 Oct 2007 19:23:21 -0000
@@ -426,6 +426,7 @@
 			$t_project_id	= $p_project_id;
 		}
 
+
 		if ( $p_custom_filter === null ) {
 			# Prefer current_user_get_bug_filter() over user_get_filter() when applicable since it supports
 			# cookies set by previous version of the code.
@@ -3240,6 +3241,612 @@
 		return $p_filter_arr;
 	}
 
+	# Returns an array of the pre-defined filters
+	function filter_get_predefined ( $p_filter = false ) {
+		static $cache;
+
+		if (!isset($cache)) {
+
+			$t_bug_resolved_status_threshold = config_get( 'bug_resolved_status_threshold' );
+			$t_hide_status_default = config_get( 'hide_status_default' );
+			$t_default_show_changed = config_get( 'default_show_changed' );
+			$t_current_user_id = auth_get_current_user_id();
+
+			$cache = array();
+
+			$cache[ FILTER_ASSIGNED ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => META_FILTER_ANY ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'handler_id'		=> Array ( '0' => $t_current_user_id ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_bug_resolved_status_threshold ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_assigned' ),
+					'url' => 'handler_id=' . $t_current_user_id . '&amp;hide_status=' . $t_bug_resolved_status_threshold,
+					'id' => FILTER_ASSIGNED
+				);
+
+			$cache[ FILTER_RECENT_MOD ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => META_FILTER_ANY ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => META_FILTER_NONE ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_recent_mod' ),
+					'url' => 'hide_status=none',
+					'id' => FILTER_RECENT_MOD
+				);
+
+			$cache[ FILTER_REPORTED ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => META_FILTER_ANY ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => $t_current_user_id ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'sort'			=> 'last_updated',
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_reported' ),
+					'url' => 'reporter_id=' . $t_current_user_id . '&amp;hide_status=' . $t_hide_status_default,
+					'id' => FILTER_REPORTED
+				);
+
+			$cache[ FILTER_RESOLVED ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => $t_bug_resolved_status_threshold ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_resolved' ),
+					'url' => 'show_status=' . $t_bug_resolved_status_threshold . '&amp;hide_status=' . $t_bug_resolved_status_threshold,
+					'id' => FILTER_RESOLVED
+				);
+
+			$cache[ FILTER_UNASSIGNED ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => META_FILTER_ANY ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'handler_id'		=> Array ( '0' => META_FILTER_NONE ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_unassigned' ),
+					'url' => 'handler_id=[none]' . '&amp;hide_status=' . $t_hide_status_default,
+					'id' => FILTER_UNASSIGNED
+				);
+
+			$cache[ FILTER_MONITORED ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => META_FILTER_ANY ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => $t_current_user_id )
+						),
+					'name' => lang_get( 'my_view_title_monitored' ),
+					'url' => 'user_monitor=' . $t_current_user_id . '&amp;hide_status=' . $t_hide_status_default,
+					'id' => FILTER_MONITORED
+				);
+
+
+			$cache[ FILTER_FEEDBACK ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => FEEDBACK ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => $t_current_user_id ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_feedback' ),
+					'url' => 'reporter_id=' . $t_current_user_id . '&amp;show_status=' . FEEDBACK . '&amp;hide_status=' . $t_hide_status_default,
+					'id' => FILTER_FEEDBACK
+				);
+
+			$cache[ FILTER_VERIFY ] = array(
+					'filter' => array(
+							'show_category'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_severity'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_status'		=> Array ( '0' => $t_bug_resolved_status_threshold ),
+							'highlight_changed'	=> $t_default_show_changed,
+							'reporter_id'		=> Array ( '0' => $t_current_user_id ),
+							'handler_id'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_resolution'	=> Array ( '0' => META_FILTER_ANY ),
+							'show_build'		=> Array ( '0' => META_FILTER_ANY ),
+							'show_version'		=> Array ( '0' => META_FILTER_ANY ),
+							'hide_status'		=> Array ( '0' => $t_hide_status_default ),
+							'user_monitor'		=> Array ( '0' => META_FILTER_ANY )
+						),
+					'name' => lang_get( 'my_view_title_verify' ),
+					'url' => 'reporter_id=' . $t_current_user_id . '&amp;show_status=' . $t_bug_resolved_status_threshold,
+					'id' => FILTER_VERIFY
+				);
+
+		}
+
+		if (is_bool($p_filter) || empty($p_filter))
+			return $cache;
+		else if (array_key_exists($p_filter, $cache))
+			return $cache[ $p_filter ];
+		else
+			return false;
+
+	}
+
+	# Returns an array of the default filters for my view
+	function filter_get_default_my_view ( $p_project_id = ALL_PROJECTS ) {
+
+		$t_current_user_id = auth_get_current_user_id();
+
+		# Pull the list of My View boxes per access level
+		$t_access_boxes = config_get( 'my_view_access_boxes' );
+		$t_user_level = access_get_project_level( $p_project_id );
+
+		# If they don't have a custom view by access level, give them the default
+		if (array_key_exists($t_user_level, $t_access_boxes))
+			$t_config_boxes = $t_access_boxes[ $t_user_level ];
+		else
+			$t_config_boxes = config_get( 'my_view_boxes' );
+
+
+		$return = array();
+
+		foreach ($t_config_boxes AS $box) {
+
+			# if box is less than 0, that means it's a predefined box
+			if ($box < 0) {
+				$return[ $box ] = filter_get_predefined( $box );
+			}
+
+			# otherwise, we need to get this filter from the database
+			else {
+				$return[ $box ] = filter_get_row( $box );
+				if (!$return[ $box ])
+					unset ($return[ $box ]);
+				else
+					$return[ $box ]['filter'] = filter_deserialize( $return[ $box ]['filter_string'] );
+			}
+		}
+
+		# don't display "Assigned to Me" bugs to users that bugs can't be assigned to
+		if ( current_user_is_anonymous() || user_get_assigned_open_bug_count( $t_current_user_id, $p_project_id ) == 0 )
+			unset( $return[FILTER_ASSIGNED] );
+
+		# don't display "Monitored by Me" bugs to users that can't monitor bugs
+		if ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $p_project_id, $t_current_user_id ) )
+			unset( $return[FILTER_MONITORED] );
+
+
+		# don't display "Reported by Me" bugs to users that can't report bugs
+		if ( current_user_is_anonymous() || !access_has_project_level( config_get( 'report_bug_threshold' ), $p_project_id, $t_current_user_id ) ) {
+			unset( $return[FILTER_REPORTED] );
+			unset( $return[FILTER_FEEDBACK] );
+			unset( $return[FILTER_VERIFY] );
+		}
+
+		return $return;
+	}
+
+	# Returns a list of filters specific to a user for their my_view page
+	function filter_db_get_my_view ( $p_user_id = false ) {
+
+		if (is_bool($p_user_id) || empty($p_user_id))
+			$p_user_id = auth_get_current_user_id();
+
+		$t_filters_my_view_table    = config_get( 'mantis_filters_my_view_table' );
+		$t_filters_table            = config_get( 'mantis_filters_table' );
+
+		$t_user_id = db_prepare_int( $p_user_id );
+
+		$query = "SELECT *
+
+					FROM $t_filters_my_view_table
+					  AS FMV
+
+			   LEFT JOIN $t_filters_table
+					  AS FM
+					  ON FMV.filter_id = FM.id
+
+				   WHERE FMV.user_id = $t_user_id
+					 AND ( "
+
+					 # If the user doesn't have access rights to stored queries, return only predefined filters
+					 .(access_has_project_level( config_get( 'stored_query_use_threshold' ) )?"FM.id IS NOT NULL OR ":"")
+
+					 ." FMV.filter_id < 0 )
+				ORDER BY FMV.sequence ASC";
+
+		$result = db_query( $query );
+		$query_count = db_num_rows( $result );
+
+		if ($query_count <= 0)
+			return array();
+
+		$t_filter_arr = array();
+
+		for ( $i = 0; $i < $query_count; $i++ ) {
+			$row = db_fetch_array( $result );
+
+			# if it is less than 0, that means it is a predefined filter
+			if (intval($row['filter_id']) < 0) {
+				$t_filter_arr[ intval($row['filter_id']) ] = filter_get_predefined( intval($row['filter_id']) );
+			}
+			else {
+				$t_filter_arr[ intval($row['filter_id']) ] = $row;
+				$t_filter_arr[ intval($row['filter_id']) ]['filter'] = filter_deserialize( $row['filter_string'] );
+			}
+
+			// Perform some sequence cleanup
+			if ($row['sequence'] != $i + 1)
+				filter_set_filter_sequence( $i + 1, $row['filter_id'], $t_user_id );
+
+			$t_filter_arr[ intval($row['filter_id']) ]['sequence'] = $i + 1;
+		}
+
+		return $t_filter_arr;
+	}
+
+	# Returns the next sequence value for a user
+	function filter_get_next_sequence ( $p_user_id ) {
+
+		$t_filters_my_view_table    = config_get( 'mantis_filters_my_view_table' );
+		$t_user_id = db_prepare_int( $p_user_id );
+
+		$query = "SELECT MAX(sequence) AS max
+					FROM $t_filters_my_view_table
+				   WHERE user_id = ". $t_user_id;
+
+		$result = db_query($query);
+		$row = db_fetch_array( $result );
+
+		return intval($row['max']) + 1;
+	}
+
+	# Returns boolean whether a filter exists
+	# $p_predefined allows you to set whether or not a predefined filter ID will return true or not
+	function filter_exists ( $p_filter_id, $p_user_id = null, $p_project_id = null, $p_predefined = true) {
+
+		# If less than zero, it must be a predefined filter ID
+		if ($p_filter_id < 0) {
+			if ($p_predefined && filter_get_predefined($p_filter_id))
+				return true;
+			else
+				return false;
+		}
+
+		# I used filter_cache_row instead of filter_get_row so I can control the errors
+		$filter = filter_cache_row( $p_filter_id, false );
+
+		if (!$filter)
+			return false;
+
+		else if (!is_null($p_user_id) && $p_user_id != $filter['user_id'])
+			return false;
+
+		else if (!is_null($p_project_id) && $p_project_id != $filter['project_id'])
+			return false;
+
+		return true;
+	}
+
+	# Removes a filter from a users 'My View'
+	function filter_remove_from_my_view ( $p_filter_id, $p_user_id = null ) {
+
+		if ( empty($p_user_id) || is_bool($p_user_id) )
+			$p_user_id = auth_get_current_user_id();
+
+		$t_filters_my_view_table    = config_get( 'mantis_filters_my_view_table' );
+
+		$c_user_id		= db_prepare_int( $p_user_id );
+		$c_filter_id	= db_prepare_int( $p_filter_id );
+
+		# First, we need to get the sequence of this filter so we can adjust order
+		$query = "SELECT sequence
+					FROM $t_filters_my_view_table
+				   WHERE filter_id = $c_filter_id
+					 AND user_id = $c_user_id
+				   LIMIT 1";
+
+		$result = db_query($query);
+
+		if (db_num_rows( $result ) <= 0)
+			return true;
+
+		$t_sequence = db_fetch_array( $result );
+		$t_sequence = db_prepare_int($t_sequence['sequence']);
+
+		$query = "DELETE FROM $t_filters_my_view_table
+						WHERE filter_id = $c_filter_id
+						  AND user_id = $c_user_id
+						LIMIT 1";
+
+		db_query($query);
+
+		$query = "UPDATE $t_filters_my_view_table
+					 SET sequence = sequence - 1
+				   WHERE sequence > $t_sequence
+					 AND user_id = $c_user_id";
+
+		db_query( $query );
+
+		return true;
+	}
+
+	# adds a new filter to a users 'My View'
+	function filter_add_to_my_view ($p_filter_id, $p_user_id = null) {
+
+		if ( empty($p_user_id) || is_bool($p_user_id) )
+			$p_user_id = auth_get_current_user_id();
+
+		$c_filter_id		= db_prepare_int( $p_filter_id );
+		$c_user_id			= db_prepare_int( $p_user_id );
+
+		# We can't add a non-existent filter
+		if ( !filter_exists( $c_filter_id, $c_user_id ) )
+			return false;
+
+		$t_filters_my_view_table    = config_get( 'mantis_filters_my_view_table' );
+
+		$query = "INSERT INTO $t_filters_my_view_table
+						  SET filter_id = $c_filter_id,
+							  user_id = $c_user_id,
+							  sequence = ". filter_get_next_sequence( $c_user_id );
+
+		db_query( $query );
+
+		return true;
+
+	}
+
+	# updates the sequence for a filter
+	function filter_set_filter_sequence ($p_sequence, $p_filter_id, $p_user_id = null) {
+
+		if ( empty($p_user_id) || is_bool($p_user_id) )
+			$p_user_id = auth_get_current_user_id();
+
+		$c_filter_id		= db_prepare_int( $p_filter_id );
+		$c_user_id			= db_prepare_int( $p_user_id );
+		$c_sequence			= db_prepare_int( $p_sequence );
+
+		$t_filters_my_view_table    = config_get( 'mantis_filters_my_view_table' );
+
+		$query = "UPDATE $t_filters_my_view_table
+					 SET sequence = $c_sequence
+				   WHERE filter_id = $c_filter_id
+					 AND user_id = $c_user_id
+				   LIMIT 1";
+
+		db_query( $query );
+
+	}
+
+	# Prints a select box for adding filters
+	function print_filter_my_view_inactive ( $p_show_empty = true ) {
+
+		$p_user_id = auth_get_current_user_id();
+
+		# Get the filters the user currently displays on their My View
+		$t_active = array_keys( filter_db_get_my_view() );
+
+		# Get all the predefined filters, then weed out the ones they have already set
+		$t_predefined = filter_get_predefined();
+		foreach ($t_predefined AS $key => $filter) {
+			if (in_array($key, $t_active))
+				unset($t_predefined[$key]);
+			else
+				$t_predefined[ $key ] = $filter['name'];
+		}
+
+		if ( access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) {
+
+			# Get all the available filters, then weed out the ones already in use
+			$t_available = filter_db_get_available_queries( ALL_PROJECTS, $p_user_id );
+			foreach ($t_available AS $key => $filter) {
+				if (in_array($key, $t_active))
+					unset($t_available[$key]);
+			}
+
+		} else {
+			$t_available = array();
+		}
+
+		# If both lists are empty, don't show the form unless they want us to
+		if (count($t_predefined) <= 0 && count($t_available) <= 0 && !$p_show_empty)
+			return;
+
+		?>
+		<form action="account_my_view_add.php" method="post">
+		<select name="filter_id">
+			<?php
+
+			if (count($t_available) > 0) {
+				echo "<optgroup label='". lang_get('custom_filters') ."'>";
+
+				foreach ($t_available AS $f_key => $f_title) {
+					echo "<option value='". $f_key ."'>" . string_display_line($f_title) . "</option>";
+				}
+				echo "</optgroup>";
+			}
+
+			if (count($t_predefined) > 0) {
+				echo "<optgroup label='". lang_get('predefined_filters') ."'>";
+
+				foreach ($t_predefined AS $f_key => $f_title) {
+					echo "<option value='". $f_key ."'>". string_display_line($f_title) ."</option>";
+				}
+				echo "</optgroup>";
+			}
+
+			?>
+		</select>
+		<input type="submit" class="button" value="<?php echo lang_get('add_my_view_filter'); ?>" />
+		</form>
+		<?php
+	}
+
+	# Prints a my view box from a set of query results
+	function print_filter_my_view_box ( $p_title, $p_page_number, $p_per_page, $p_custom_filter,
+										$p_project_id, $p_user_id, $p_show_sticky = null, $p_url = null, $p_show_empty = TRUE ) {
+
+		$t_page_count = 0;
+		$t_bug_count = 0;
+
+		# Run the filter query
+		$result = filter_get_bug_rows( $p_page_number, $p_per_page, $t_page_count, $t_bug_count,
+									$p_custom_filter, $p_project_id, $p_user_id, $p_show_sticky );
+
+		if (count($result) == 0 && !$p_show_empty)
+			return;
+
+		if (is_null($p_url))
+			$p_url = filter_get_url( $p_custom_filter );
+
+		$t_icon_path = config_get( 'icon_path' );
+		$t_update_bug_threshold = config_get( 'update_bug_threshold' );
+
+		?>
+		<table class="width100" cellspacing="1">
+			<tr>
+				<td class="form-title" colspan="2">
+					<a class="subtle" href="<?php echo $p_url; ?>"><?php echo string_display_line($p_title); ?></a>
+					[<a class="subtle" href="<?php echo $p_url; ?>" target="_blank">^</a>]
+					( <?php echo string_display_line(project_get_name( $p_project_id )); ?> )
+					<?php
+						if ( count( $result ) > 0 ) {
+							$v_start = $p_per_page * ($p_page_number - 1) + 1;
+							$v_end   = $v_start + count( $result ) - 1;
+						} else {
+							$v_start = 0;
+							$v_end   = 0;
+						}
+						echo "($v_start - $v_end / $t_bug_count)";
+					?>
+				</td>
+			</tr>
+			<?php
+			foreach ($result AS $row) {
+
+				?>
+				<tr bgcolor="<?php echo get_status_color($row['status']) ?>">
+
+					<td class="center">
+						<span class="small">
+						<?php
+							print_bug_link( $row['id'] );
+
+							echo '<br />';
+
+							if ( !bug_is_readonly( $row['id'] ) && access_has_bug_level( $t_update_bug_threshold, $row['id'] ) ) {
+								echo '<a href="' . string_get_bug_update_url( $row['id'] ) . '"><img border="0" src="' . $t_icon_path . 'update.png' . '" alt="' . lang_get( 'update_bug_button' ) . '" /></a>';
+							}
+
+							if ( ON == config_get( 'show_priority_text' ) ) {
+								print_formatted_priority_string( $row['status'], $row['priority'] );
+							} else {
+								print_status_icon( $row['priority'] );
+							}
+
+							$t_attachment_count = 0;
+							if (  ( file_can_view_bug_attachments( $row['id'] ) ) ) {
+							   $t_attachment_count = file_bug_attachment_count( $row['id'] );
+							}
+
+							if ( 0 < $t_attachment_count ) {
+								echo '<a href="' . string_get_bug_view_url( $row['id'] ) . '#attachments">';
+								echo '<img border="0" src="' . $t_icon_path . 'attachment.png' . '"';
+								echo ' alt="' . lang_get( 'attachment_alt' ) . '"';
+								echo ' title="' . $t_attachment_count . ' ' . lang_get( 'attachments' ) . '"';
+								echo ' />';
+								echo '</a>';
+							}
+							if ( VS_PRIVATE == $row['view_state'] ) {
+								echo '<img src="' . $t_icon_path . 'protected.gif" width="8" height="15" alt="' . lang_get( 'private' ) . '" />';
+							}
+						?>
+						</span>
+					</td>
+					<td class="left" valign="top" width="100%">
+						<span class="small">
+						<?php
+
+							echo string_attribute( $row['summary'] )
+								.'<br />';
+							# show project name if viewing 'all projects' or bug is in subproject
+							if ( ON == config_get( 'show_bug_project_links' ) &&
+								helper_get_current_project() != $row['project_id'] ) {
+								echo '['. project_get_name($row['project_id']) .'] ';
+							}
+
+							echo string_display( $row['category'] );
+
+							$t_last_updated = date( config_get( 'normal_date_format' ), $row['last_updated'] );
+
+							if ( $row['last_updated'] > strtotime( '-'. $p_custom_filter['highlight_changed'] .' hours' ) ) {
+								echo ' - <b>' . $t_last_updated . '</b>';
+							} else {
+								echo ' - ' . $t_last_updated;
+							}
+
+						?>
+						</span>
+					</td>
+				</tr>
+				<?php
+			}
+			?>
+		</table>
+
+		<?
+
+	}
+
+
 
 	/**
 	 * The following functions each print out an individual filter field.
Index: core/html_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/html_api.php,v
retrieving revision 1.219
diff -u -b -r1.219 html_api.php
--- core/html_api.php	22 Oct 2007 07:05:45 -0000	1.219
+++ core/html_api.php	23 Oct 2007 19:23:21 -0000
@@ -750,18 +750,25 @@
 	function print_account_menu( $p_page='' ) {
 		$t_account_page 				= 'account_page.php';
 		$t_account_prefs_page 			= 'account_prefs_page.php';
+		$t_account_my_view_page 		= 'account_my_view_page.php';
 		$t_account_profile_menu_page 	= 'account_prof_menu_page.php';
 		$t_account_sponsor_page			= 'account_sponsor_page.php';
 
 		switch ( $p_page ) {
 			case $t_account_page				: $t_account_page 				= ''; break;
 			case $t_account_prefs_page			: $t_account_prefs_page 		= ''; break;
+			case $t_account_my_view_page		: $t_account_my_view_page 		= ''; break;
 			case $t_account_profile_menu_page	: $t_account_profile_menu_page 	= ''; break;
 			case $t_account_sponsor_page		: $t_account_sponsor_page		= ''; break;
 		}
 
 		print_bracket_link( $t_account_page, lang_get( 'account_link' ) );
 		print_bracket_link( $t_account_prefs_page, lang_get( 'change_preferences_link' ) );
+
+
+		if (access_has_global_level(config_get('custom_my_view_threshold')))
+			print_bracket_link( $t_account_my_view_page, lang_get( 'my_view_link' ) );
+
 		if ( access_has_project_level( config_get( 'add_profile_threshold' ) ) ) {
 			print_bracket_link( $t_account_profile_menu_page, lang_get( 'manage_profiles_link' ) );
 		}
Index: lang/strings_english.txt
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v
retrieving revision 1.316
diff -u -b -r1.316 strings_english.txt
--- lang/strings_english.txt	22 Sep 2007 22:51:15 -0000	1.316
+++ lang/strings_english.txt	23 Oct 2007 19:23:21 -0000
@@ -1432,4 +1432,10 @@
 $s_graph_page = 'Graph Bug History';
 $s_graph_bug_page_link = 'Graph';
 
+# Custom Filtering
+$s_add_my_view_filter = 'Add Filter to My View';
+$s_my_view_filters = 'My View Filters';
+$s_predefined_filters = 'Predefined Filters';
+$s_custom_filters = 'Custom Filters';
+
 ?>
