Index: feedapi.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/Attic/feedapi.admin.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 feedapi.admin.inc
--- feedapi.admin.inc	17 Feb 2009 14:58:40 -0000	1.1.2.1
+++ feedapi.admin.inc	4 Jun 2009 17:49:29 -0000
@@ -12,7 +12,6 @@
 function feedapi_admin_overview() {
   $header = array(
     t('Title'),
-    t('Last refresh'),
     t('New items added per update'),
     t('Update rate'),
     t('Number of items'),
@@ -20,7 +19,7 @@ function feedapi_admin_overview() {
     t('Commands'),
   );
   $rows = array();
-  $result = pager_query("SELECT nid from {feedapi} ORDER BY checked DESC", 50, 0, "SELECT count(*) FROM {feedapi}");
+  $result = pager_query("SELECT nid from {feedapi} ORDER BY next_refresh_time DESC", 50, 0, "SELECT count(*) FROM {feedapi}");
   while ($nid = db_fetch_array($result)) {
     $nid = $nid['nid'];
     $node = node_load($nid);
@@ -38,7 +37,6 @@ function feedapi_admin_overview() {
         $update_rate = _feedapi_update_rate($node->feed->statistics['update_times']);
         $rows[] = array(
           l($node->title, "node/$node->nid"),
-          $node->feed->checked == 0 ? t('Never') : t('%time ago', array('%time' => format_interval(time() - $node->feed->checked))),
           round(array_sum($node->feed->statistics['new']) / count($node->feed->statistics['new']), 2),
           is_numeric($update_rate) ? format_interval($update_rate) : $update_rate,
           round((array_sum($node->feed->statistics['download_num']) / count($node->feed->statistics['download_num'])), 2),
@@ -49,7 +47,6 @@ function feedapi_admin_overview() {
       else {
         $rows[] = array(
           l($node->title, "node/$node->nid"),
-          $node->feed->checked == 0 ? t('Never') : t('%time ago', array('%time' => format_interval(time() - $node->feed->checked))),
           '', '', t('No enough data for statistics'), '',
           theme('item_list', $commands),
         );
Index: feedapi.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi.install,v
retrieving revision 1.5.2.21.2.14
diff -u -p -r1.5.2.21.2.14 feedapi.install
--- feedapi.install	4 Jun 2009 16:46:57 -0000	1.5.2.21.2.14
+++ feedapi.install	4 Jun 2009 17:49:29 -0000
@@ -37,8 +37,9 @@ function feedapi_schema() {
         'not null' => TRUE,
         'default' => '',
         'length' => '255'),
-      'checked' => array(
+      'next_refresh_time' => array(
         'type' => 'int',
+        'unsigned' => TRUE,
         'default' => 0,
         'not null' => TRUE),
       'hash' => array(
@@ -52,16 +53,11 @@ function feedapi_schema() {
       'half_done' => array(
         'type' => 'int',
         'size' => 'tiny'),
-      'skip' => array(
-        'type' => 'int',
-        'size' => 'tiny',
-        'default' => 0,
-      ),
     ),
     'primary key' => array('vid'),
     'indexes' => array(
       'nid' => array('nid'),
-      'feedapi_skip' => array('skip')),
+      'next_refresh_time' => array('next_refresh_time')),
   );
   $schema['feedapi_stat'] = array(
     'description' => 'Statistics values over the time about the feeds',
@@ -196,3 +192,54 @@ function feedapi_update_6105() {
   db_add_index($ret, 'feedapi', 'nid', array('nid'));
   return $ret;
 }
+
+/**
+ * Convert checked to next_refresh_time and consolidate skip and 
+ * next_refresh_time, add an index on next_refresh_time, make next_refresh_time
+ * unsigned.
+ */
+function feedapi_update_6106() {
+  $spec = array(
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'default' => 0,
+    'not null' => TRUE,
+  );
+  db_change_field($ret, 'feedapi', 'checked', 'next_refresh_time', $spec);
+
+  // Convert the value in next_refresh_time from the last time a feed has been
+  // to the next time it should be checked.
+  $ret[] = update_sql('UPDATE {feedapi} SET next_refresh_time = (next_refresh_time + '. FEEDAPI_CRON_DEFAULT_REFRESH_TIME .')');
+
+  // Set next_refresh_time to FEEDAPI_CRON_NEVER_REFRESH where skip = 1.
+  $ret[] = update_sql('UPDATE {feedapi} SET next_refresh_time = '. FEEDAPI_CRON_NEVER_REFRESH .' WHERE skip = 1');
+
+  // Drop skip row
+  db_drop_field($ret, 'feedapi', 'skip');
+
+  // Update all settings.
+  $node_types = node_get_types('types');
+
+  // Update all node type settings.
+  foreach ($node_types as $node_type) {
+    if (feedapi_enabled_type($node_type)) {
+      if ($settings = feedapi_get_settings($node_type)) {
+        $settings['refresh_time'] = $settings['skip'] ? FEEDAPI_CRON_NEVER_REFRESH : FEEDAPI_CRON_DEFAULT_REFRESH_TIME;
+        unset($settings['skip']);
+        _feedapi_store_settings(array('node_type' => $node_type), $settings);
+      }
+    }
+  }
+
+  // Update all node settings.
+  $result = db_query('SELECT n.type, f.vid FROM {node} n JOIN {feedapi} f ON f.nid = n.nid');
+  while ($node = db_fetch_object($result)) {
+    if ($settings = feedapi_get_settings($node->type, $node->vid)) {
+      $settings['refresh_time'] = $settings['skip'] ? FEEDAPI_CRON_NEVER_REFRESH : FEEDAPI_CRON_DEFAULT_REFRESH_TIME;
+      unset($settings['skip']);
+      _feedapi_store_settings(array('node_type' => $node->type, 'vid' => $node->vid), $settings);
+    }
+  }
+
+  return $ret;
+}
\ No newline at end of file
Index: feedapi.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi.module,v
retrieving revision 1.23.2.119.2.56
diff -u -p -r1.23.2.119.2.56 feedapi.module
--- feedapi.module	4 Jun 2009 16:46:57 -0000	1.23.2.119.2.56
+++ feedapi.module	4 Jun 2009 17:49:30 -0000
@@ -11,8 +11,10 @@ define('FEEDAPI_NEVER_DELETE_OLD', 0);
 define('FEEDAPI_TIMEOUT', 1);
 // Number of feeds to process for each step in cron.
 define('FEEDAPI_CRON_FEEDS', 100);
-// Minimum time that must elapse before a feed can be refreshed again on cron.
-define('FEEDAPI_CRON_MIN_REFRESH_TIME', 1800);
+// Default time that should elapse before a feed can be refreshed again on cron.
+define('FEEDAPI_CRON_DEFAULT_REFRESH_TIME', 1800);
+// Denotes that a feed should never be refreshed.
+define('FEEDAPI_CRON_NEVER_REFRESH', 0);
 // Prune FeedAPI stats 4 weeks
 define('FEEDAPI_CRON_STAT_LIFETIME', 28*24*3600);
 
@@ -641,14 +643,18 @@ function feedapi_feedapi_settings_form($
       '#description' => t('If checked, existing feed items will be updated when feed is refreshed.'),
       '#default_value' => 1,
     );
-    $form['skip'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Pause automatic feed update'),
-      '#description' => t('If checked, feed will not be updated automatically on cron.'),
-      '#default_value' => 0,
+    $period = drupal_map_assoc(array(1, 900, 1800, 3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
+    $period[FEEDAPI_CRON_NEVER_REFRESH] = t('Never refresh');
+    $period[1] = t('As often as possible');
+    $form['refresh_time'] = array(
+      '#type' => 'select',
+      '#title' => t('Minimum refresh period'),
+      '#description' => t('Select the minimum time that should elapse between two refreshes of the same feed. For news feeds, don\'t go under 30 minutes. Note that FeedAPI cannot guarantee that a feed will be refreshed at the rate of the selected time. The actual refresh rate depends on many factors such as number of feeds in system and your hardware.'),
+      '#options' => $period,
+      '#default_value' => FEEDAPI_CRON_DEFAULT_REFRESH_TIME,
     );
     $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
-    $period[FEEDAPI_NEVER_DELETE_OLD] = t('Never');
+    $period[FEEDAPI_NEVER_DELETE_OLD] = t('Never delete');
     $form['items_delete'] = array(
       '#type' => 'select',
       '#title' => t('Delete news items older than'),
@@ -675,12 +681,12 @@ function feedapi_cron() {
   
   // We get feeds in small lots, this will save memory and have the process adjusting to the
   // time limit even when we have many thousands of them.
-  $start = time() - FEEDAPI_CRON_MIN_REFRESH_TIME;
+  $now = time();
   $process = 0;
   // The counter process will be > 0 if we've selected less feeds
   while (!$process && feedapi_cron_time()) {
     $process = FEEDAPI_CRON_FEEDS;
-    $result = db_query_range("SELECT DISTINCT nid FROM {feedapi} WHERE checked <= %d AND skip = 0 ORDER BY checked", $start, 0, FEEDAPI_CRON_FEEDS);
+    $result = db_query_range("SELECT DISTINCT nid FROM {feedapi} WHERE next_refresh_time < %d AND next_refresh_time <> %d ORDER BY next_refresh_time ASC", $now, FEEDAPI_CRON_NEVER_REFRESH, 0, FEEDAPI_CRON_FEEDS);
 
     while (feedapi_cron_time() && $feed = db_fetch_object($result)) {
       // Call the refresh process for each feed and store counters
@@ -853,10 +859,19 @@ function feedapi_refresh($node, $destina
  * Insert feedapi data to the DB when it's a new for for FeedAPI
  */
 function _feedapi_insert(&$node, $teaser, $page) {
+
   if (isset($node->feed->url) && isset($node->feed->feed_type)) {
+    if (isset($node->feedapi)) {
+      $values = $node->feedapi;
+    }
+    else {
+      // On revert revision, settings are on $node->feed->settings
+      // @todo: verify, settings shouldn't be NOT an array here anyway.
+      $values = (array) $node->feed->settings;
+    }
     db_query("INSERT INTO {feedapi} (
             nid, vid, url, link, feed_type, processors,
-            parsers, checked, settings) VALUES
+            parsers, next_refresh_time, settings) VALUES
             (%d, %d, '%s', '%s', '%s', '%s', '%s', %d, '%s')",
       $node->nid,
       $node->vid,
@@ -865,16 +880,12 @@ function _feedapi_insert(&$node, $teaser
       $node->feed->feed_type,
       serialize($node->feed->processors),
       serialize($node->feed->parsers),
-      0,
+      $values['refresh_time'] == FEEDAPI_CRON_NEVER_REFRESH ? $values['refresh_time'] : time() + $values['refresh_time'],
       serialize(array())
     );
     // Store add on module's settings if user has permission to do so.
     if (user_access('advanced feedapi options')) {
-      // At revision revert
-      if (!isset($node->feedapi)) {
-         $node->feedapi = (array) $node->feed->settings;
-      }
-      _feedapi_store_settings(array('vid' => $node->vid), $node->feedapi);
+      _feedapi_store_settings(array('vid' => $node->vid), $values);
     }
     // Refresh feed if the user would like to do that
     $settings = feedapi_get_settings($node->type, $node->vid);
@@ -895,6 +906,7 @@ function _feedapi_insert(&$node, $teaser
 function _feedapi_update(&$node, $teaser, $page) {
   if (isset($node->feed)) {
     $old_config = node_load($node->nid);
+
     // In that case this feed has never have feed data. Should be created then, this is not really an update
     if (!is_numeric($old_config->feed->nid)) {
       $node->feed = _feedapi_build_feed_object($node->type, $node->feed->url);
@@ -906,14 +918,32 @@ function _feedapi_update(&$node, $teaser
       _feedapi_insert($node, 'insert', $teaser, $page);
       return;
     }
+    // Only change next_refresh_time if refresh_time changed 
+    // or if $next_refresh_time is FEEDAPI_CRON_NEVER_REFRESH.
+    $next_refresh_time = $old_config->feed->next_refresh_time;
+    if (isset($node->feedapi['refresh_time'])) {
+      if ($node->feedapi['refresh_time'] == FEEDAPI_CRON_NEVER_REFRESH) {
+        $next_refresh_time = FEEDAPI_CRON_NEVER_REFRESH;
+      }
+      elseif ($old_config->feed->settings['refresh_time'] != $node->feedapi['refresh_time'] || $next_refresh_time == FEEDAPI_CRON_NEVER_REFRESH) {
+        $next_refresh_time = time() + $node->feedapi['refresh_time'];
+      }
+    }
+    
     db_query("UPDATE {feedapi} SET
-            url = '%s', feed_type = '%s', processors = '%s',
-            parsers = '%s', link = '%s' WHERE vid = %d",
+            url = '%s', 
+            feed_type = '%s', 
+            processors = '%s',
+            parsers = '%s', 
+            link = '%s',
+            next_refresh_time = %d
+            WHERE vid = %d",
       isset($node->feed->url) ? $node->feed->url : $node->feedapi['feedapi_url'],
       isset($node->feed->feed_type) ? $node->feed->feed_type : '',
       isset($node->feed->processors) ? serialize($node->feed->processors) : serialize($old_config->feed->processors),
       isset($node->feed->parsers) ? serialize($node->feed->parsers) : serialize($old_config->feed->parsers),
       isset($node->feed->options->link) ? $node->feed->options->link : '',
+      $next_refresh_time,
       $node->vid
     );
     // Store add on module's settings if user has permission to do so.
@@ -1035,7 +1065,7 @@ function _feedapi_process_text($text, $a
  */
 function _feedapi_store_settings($args, $settings) {
   if (isset($args['vid'])) {
-    db_query("UPDATE {feedapi} SET settings = '%s', skip = %d WHERE vid = %d", serialize($settings), $settings['skip'], $args['vid']);
+    db_query("UPDATE {feedapi} SET settings = '%s' WHERE vid = %d", serialize($settings), $args['vid']);
     module_invoke_all('feedapi_after_settings', $args['vid'], $settings);
     // This ensures that next time, not the cached, but the updated value will be used.
     feedapi_get_settings(NULL, $args['vid'], TRUE);
@@ -1134,8 +1164,8 @@ function _feedapi_invoke_refresh(&$feed,
   
   // Step 3: See, whether feed has been modified.
   if ($feed === FALSE || $hash_old == $feed->hash) {
-    // Updated the checked field in any case.
-    db_query("UPDATE {feedapi} SET checked = %d, half_done = %d WHERE nid = %d", time(), FALSE, $nid);
+    // Updated the next_refresh_time field in any case.
+    db_query("UPDATE {feedapi} SET next_refresh_time = %d, half_done = %d WHERE nid = %d", time() + $settings['refresh_time'], FALSE, $nid);
     if (!$cron) {
       if (is_object($feed) && $hash_old == $feed->hash) {
         drupal_set_message(t('There are no new items in the feed.'), 'status');
@@ -1202,8 +1232,11 @@ function _feedapi_invoke_refresh(&$feed,
     _feedapi_store_stat($nid, 'download_num', count($items), $timestamp);
     _feedapi_store_stat($nid, 'process_time', timer_read('feedapi_'. $feed->nid), $timestamp);
   }
-  db_query("UPDATE {feedapi} SET checked = %d, half_done = %d, hash = '%s' WHERE nid = %d", time(), $half_done, $feed->hash, $feed->nid);
-  
+
+  // Set next_refresh_time to FEEDAPI_CRON_NEVER_REFRESH if refresh_time is FEEDAPI_CRON_NEVER_REFRESH.
+  $next_refresh_time = $settings['refresh_time'] == FEEDAPI_CRON_NEVER_REFRESH ? $settings['refresh_time'] : (time() + $settings['refresh_time']);
+  db_query("UPDATE {feedapi} SET next_refresh_time = %d, half_done = %d, hash = '%s' WHERE nid = %d", $next_refresh_time, $half_done, $feed->hash, $feed->nid);
+
   if (!$cron) {
     if ($new == 0 && $updated == 0) {
       drupal_set_message(t('There are no new items in the feed.'), 'status');
Index: feedapi_node/tests/feedapi_node.module.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/feedapi_node/tests/Attic/feedapi_node.module.test,v
retrieving revision 1.1.4.20
diff -u -p -r1.1.4.20 feedapi_node.module.test
--- feedapi_node/tests/feedapi_node.module.test	4 Jun 2009 16:46:57 -0000	1.1.4.20
+++ feedapi_node/tests/feedapi_node.module.test	4 Jun 2009 17:49:30 -0000
@@ -205,11 +205,11 @@ class FeedAPI_Node_Tests extends DrupalT
       $this->assertEqual(is_numeric($nid), TRUE, 'The feed node is in the database');
 
       if (is_numeric($nid)) {
-        $values = db_fetch_array(db_query("SELECT settings, feed_type, checked, half_done FROM {feedapi} WHERE nid = %d", $nid));
+        $values = db_fetch_array(db_query("SELECT settings, feed_type, next_refresh_time, half_done FROM {feedapi} WHERE nid = %d", $nid));
         $sane_default = TRUE;
         $sane_default = $sane_default || (is_array($values['settings']) && count($values['settings']) > 1);
         $sane_default = $sane_default || ($values['feed_type'] == 'XML feed');
-        $sane_default = $sane_default || ($values['checked'] == 0);
+        $sane_default = $sane_default || ($values['next_refresh_time'] == 0);
         $sane_default = $sane_default || ($values['half_done'] == 0);
         $this->assertIdentical($sane_default, TRUE, "The feed has sane default values in the database table");
         node_delete($nid);
Index: views/feedapi.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/views/Attic/feedapi.views.inc,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 feedapi.views.inc
--- views/feedapi.views.inc	26 Feb 2009 06:49:09 -0000	1.1.2.6
+++ views/feedapi.views.inc	4 Jun 2009 17:49:30 -0000
@@ -34,9 +34,9 @@ function feedapi_views_data() {
       'click sortable' => TRUE,
      ),
   );
-  $data['feedapi']['checked'] = array(
-    'title' => t('Last refresh'),
-    'help' => t('The date when the feed was last refreshed.'),
+  $data['feedapi']['next_refresh_time'] = array(
+    'title' => t('Next refresh'),
+    'help' => t('The date when the feed is scheduled to be refreshed earliest.'),
     'field' => array(
       'handler' => 'views_handler_field_date',
       'click sortable' => TRUE,
Index: views/feedapi.views_default.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi/views/Attic/feedapi.views_default.inc,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 feedapi.views_default.inc
--- views/feedapi.views_default.inc	3 Feb 2009 10:18:16 -0000	1.1.2.2
+++ views/feedapi.views_default.inc	4 Jun 2009 17:49:30 -0000
@@ -30,14 +30,14 @@ function feedapi_views_default_views() {
       'field' => 'title',
       'relationship' => 'none',
     ),
-    'checked' => array(
-      'label' => 'Last refresh',
-      'date_format' => 'time ago',
+    'next_refresh_time' => array(
+      'label' => 'Scheduled refresh',
+      'date_format' => 'small',
       'custom_date_format' => '',
       'exclude' => 0,
-      'id' => 'checked',
+      'id' => 'next_refresh_time',
       'table' => 'feedapi',
-      'field' => 'checked',
+      'field' => 'next_refresh_time',
       'relationship' => 'none',
     ),
     'delete_node' => array(
@@ -84,12 +84,12 @@ function feedapi_views_default_views() {
     ),
   ));
   $handler->override_option('sorts', array(
-    'checked' => array(
+    'next_refresh_time' => array(
       'order' => 'DESC',
       'granularity' => 'second',
-      'id' => 'checked',
+      'id' => 'next_refresh_time',
       'table' => 'feedapi',
-      'field' => 'checked',
+      'field' => 'next_refresh_time',
       'relationship' => 'none',
     ),
   ));
@@ -126,7 +126,7 @@ function feedapi_views_default_views() {
     'order' => 'asc',
     'columns' => array(
       'title' => 'title',
-      'checked' => 'checked',
+      'next_refresh_time' => 'next_refresh_time',
       'delete_node' => 'delete_node',
       'purge_node' => 'delete_node',
       'refresh_node' => 'delete_node',
@@ -137,7 +137,7 @@ function feedapi_views_default_views() {
         'sortable' => 0,
         'separator' => '',
       ),
-      'checked' => array(
+      'next_refresh_time' => array(
         'sortable' => 0,
         'separator' => '',
       ),
