Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.332.2.9
diff -u -p -r1.332.2.9 views.module
--- views.module	15 Sep 2009 22:43:38 -0000	1.332.2.9
+++ views.module	19 Sep 2009 21:49:27 -0000
@@ -969,6 +969,11 @@ function views_exposed_form(&$form_state
     }
   }
   
+  // Check if items per page are exposed
+  if ($view->display_handler->items_per_page_exposed()) {
+    $form['items_per_page'] = $view->display_handler->items_per_page_exposed_form();
+  }
+  
   $form['submit'] = array(
     '#name' => '', // prevent from showing up in $_GET.
     '#type' => 'submit',
Index: plugins/views_plugin_display.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/views_plugin_display.inc,v
retrieving revision 1.20.2.7
diff -u -p -r1.20.2.7 views_plugin_display.inc
--- plugins/views_plugin_display.inc	15 Sep 2009 19:41:50 -0000	1.20.2.7
+++ plugins/views_plugin_display.inc	19 Sep 2009 21:49:34 -0000
@@ -71,6 +71,11 @@ class views_plugin_display extends views
    */
   function uses_exposed() {
     if (!isset($this->has_exposed)) {
+      if ($this->items_per_page_exposed()) {
+        $this->has_exposed = TRUE;
+        return TRUE;
+      }
+      
       foreach ($this->handlers as $type => $value) {
         foreach ($this->view->$type as $id => $handler) {
           if ($handler->can_expose() && $handler->is_exposed()) {
@@ -120,6 +125,33 @@ class views_plugin_display extends views
   }
 
   /**
+   * Does the display have items per page exposed?
+   */
+  function items_per_page_exposed() {
+    return $this->get_option('items_per_page_exposed');
+  }
+
+  function items_per_page_exposed_form() {
+    $options = explode(',', $this->get_option('items_per_page_exposed_options'));
+    
+    if (is_array($options)) {
+      foreach ($options as $option) {
+        $sanitized_options[intval($option)] = intval($option);
+      }
+    
+    $form = array(
+      '#type' => 'select',
+      '#title' => $this->get_option('items_per_page_label'),      
+      '#options' => $sanitized_options,
+      '#default_value' => $this->get_option('items_per_page'),
+    );
+    
+    return $form;
+    }
+    return array();
+  }
+
+  /**
    * Does the display have a more link enabled?
    */
   function use_more() {
@@ -164,8 +196,8 @@ class views_plugin_display extends views
       'footer' => array('footer', 'footer_format', 'footer_empty'),
       'empty' => array('empty', 'empty_format'),
       'use_ajax' => array('use_ajax'),
-      'items_per_page' => array('items_per_page', 'offset', 'use_pager', 'pager_element'),
-      'use_pager' => array('items_per_page', 'offset', 'use_pager', 'pager_element'),
+      'items_per_page' => array('items_per_page', 'offset', 'use_pager', 'pager_element', 'items_per_page_exposed', 'items_per_page_label', 'items_per_page_exposed_options'),
+      'use_pager' => array('items_per_page', 'offset', 'use_pager', 'pager_element', 'items_per_page_exposed', 'items_per_page_label', 'items_per_page_exposed_options'),
       'use_more' => array('use_more', 'use_more_text'),
       'link_display' => array('link_display'),
       'distinct' => array('distinct'),
@@ -236,6 +268,9 @@ class views_plugin_display extends views
 
           'use_ajax' => TRUE,
           'items_per_page' => TRUE,
+          'items_per_page_exposed' => TRUE,
+          'items_per_page_label' => TRUE,
+          'items_per_page_exposed_options' => TRUE,
           'offset' => TRUE,
           'use_pager' => TRUE,
           'pager_element'  => TRUE,
@@ -328,6 +363,16 @@ class views_plugin_display extends views
       'offset' => array(
         'default' => 0,
       ),
+      'items_per_page_exposed' => array(
+        'default' => FALSE,
+      ),
+      'items_per_page_label' => array(
+        'default' => 'Items per page',
+        'translatable' => TRUE,
+      ),      
+      'items_per_page_exposed_options' => array(
+        'default' => '10, 20, 30, 50, 100',
+      ),
       'use_pager' => array(
         'default' => FALSE,
       ),
@@ -683,10 +728,11 @@ class views_plugin_display extends views
     }
 
     $items = intval($this->get_option('items_per_page'));
+    $items_exposed = intval($this->get_option('items_per_page_exposed'));
     $options['items_per_page'] = array(
       'category' => 'basic',
       'title' => $this->use_pager() ? t('Items per page') : t('Items to display'),
-      'value' => $items ? $items : t('Unlimited'),
+      'value' => ($items ? $items : t('Unlimited')) . ($items_exposed?' <em>' . t('exposed') . '</em>':''),
       'desc' => t('Change how many items to display.'),
     );
 
@@ -889,6 +935,34 @@ class views_plugin_display extends views
           '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed. Offset can not be used if items to display is 0; instead use a very large number there.'),
           '#default_value' => intval($this->get_option('offset')),
         );
+        
+        $form['items_per_page_exposed'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Expose items per page'),
+          '#description' => t('When checked, users can determine how many items per page show in a view'),
+          '#default_value' => $this->get_option('items_per_page_exposed'),
+        );
+        $form['items_per_page_label'] = array(
+          '#type' => 'textfield',
+          '#title' => t('Label'),
+          '#description' => t('Label to use in the exposed items per page form element.'),
+          '#default_value' => $this->get_option('items_per_page_label'),
+          '#process' => array('views_process_dependency'),
+          '#dependency' => array(
+            'edit-items-per-page-exposed' => array(1)
+          ),
+        );
+        $form['items_per_page_exposed_options'] = array(
+          '#type' => 'textfield',
+          '#default_value' => $this->get_option('items_per_page_exposed_options'),
+          '#title' => t('Exposed items per page options'),
+          '#description' => t('Set between which values the user can choose when determining the items per page. Separated by colon.'),
+          '#process' => array('views_process_dependency'),
+          '#dependency' => array(
+            'edit-items-per-page-exposed' => array(1)
+          ),
+        );
+        
         break;
       case 'use_more':
         $form['#title'] .= t('Add a more link to the bottom of the display.');
@@ -1410,6 +1484,28 @@ class views_plugin_display extends views
           $plugin->options_validate($form['cache_options'], $form_state);
         }
         break;
+      case 'items_per_page':
+        // Only accept integer values.
+        $error = FALSE;
+        $exposed_options = $form_state['values']['items_per_page_exposed_options'];
+        if (strpos($exposed_options, '.') !== FALSE) {
+          $error = TRUE;
+        }
+        $options = explode(',',$exposed_options);
+        if (!$error && is_array($options)) {
+          foreach ($options as $option) {
+            if (!is_numeric($option) || intval($option) == 0) {
+              $error = TRUE;
+            }
+          }
+        }
+        else {
+          $error = TRUE;
+        }
+        if ($error) {
+          form_set_error('items_per_page_exposed_options', t('Please insert a list of integer numeric values separated by colons: e.g: 10, 20, 50, 100'));
+        }
+        break;
     }
   }
 
@@ -1487,6 +1583,9 @@ class views_plugin_display extends views
       case 'items_per_page':
         $this->set_option($section, intval($form_state['values'][$section]));
         $this->set_option('offset', intval($form_state['values']['offset']));
+        $this->set_option('items_per_page_exposed', $form_state['values']['items_per_page_exposed']);
+        $this->set_option('items_per_page_label', $form_state['values']['items_per_page_label']);
+        $this->set_option('items_per_page_exposed_options', $form_state['values']['items_per_page_exposed_options']);
         break;
       case 'use_more':
         $this->set_option($section, intval($form_state['values'][$section]));
@@ -1761,7 +1860,13 @@ class views_plugin_display extends views
     // Copy pager information from the display.
     $this->view->set_use_pager($this->use_pager());
     $this->view->set_pager_element($this->get_option('pager_element'));
-    $this->view->set_items_per_page($this->get_option('items_per_page'));
+
+    if ($this->items_per_page_exposed()) {
+        $this->view->set_items_per_page($_GET['items_per_page']);
+    }
+    else {
+      $this->view->set_items_per_page($this->get_option('items_per_page'));
+    }
     $this->view->set_offset($this->get_option('offset'));
     if ($this->use_more()) {
       $this->view->get_total_rows = TRUE;
