Package com.substanceofcode.rssreader.presentation

Source Code of com.substanceofcode.rssreader.presentation.RssReaderMIDlet$BMForm

/*
   TODO workaround Sony problems
   TODO handle OutOfMemoryError for save memory
   TODO handle Exceptions
   TODO unsupported encoding.  Need more info
   TODO Use 2nd obfuscator
   TODO Memory high water mark
   TODO Use mobility conversion Google Mobilizer
http://www.google.com/gwt/n?u=http%3A%2F%2Fsourceforge.net
   TODO no image
http://www.google.com/gwt/n?u=http%3A%2F%2Fsourceforge.net&_gwt_noimg=1
   TODO Do conditional get
   Or skeezer.net
http://www.skweezer.com/s.aspx?q=http%3A%2F%2Fsourceforge.net
connection.setRequestProperty(
          "If-Modified-Since", Last-Modified
connection.setRequestProperty(
          "If-Modified-Since", ETag
      HTTP_NOT_MODIFIED

*
* RssReaderMIDlet.java
*
* Copyright (C) 2005-2006 Tommi Laukkanen
* http://www.substanceofcode.com
*
* 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
*
*/

// Expand to define test define
@DTESTDEF@
// Expand to define test ui define
@DTESTUIDEF@
// Expand to define MIDP define
@DMIDPVERS@
// Expand to define CLDC define
@DCLDCVERS@
// Expand to define memory size define
@DMEMSIZEDEF@
// Expand to define itunes define
@DITUNESDEF@
// Expand to define logging define
@DLOGDEF@
// Expand to define DJSR75 define
@DJSR75@
// Expand to define compatibility
@DCOMPATDEF@


//#ifdef DCOMPATIBILITY1
//#define DCOMPATIBILITY
//#elifdef DCOMPATIBILITY2
//#define DCOMPATIBILITY
//#elifdef DCOMPATIBILITY3
//#define DCOMPATIBILITY
//#endif

package com.substanceofcode.rssreader.presentation;

//#ifdef DJSR75
import org.kablog.kgui.KFileSelectorMgr;
//#endif
import com.substanceofcode.rssreader.businessentities.RssItunesFeed;
import com.substanceofcode.rssreader.businessentities.RssFeed;
import com.substanceofcode.rssreader.businessentities.RssItunesItem;
import com.substanceofcode.rssreader.businessentities.RssFeedStore;
import com.substanceofcode.rssreader.businessentities.RssStoreInfo;
//#ifdef DCOMPATIBILITY1
import com.substanceofcode.rssreader.businessentities.CompatibilityRssFeed1;
//#elifdef DCOMPATIBILITY2
import com.substanceofcode.rssreader.businessentities.CompatibilityRssFeed2;
//#elifdef DCOMPATIBILITY3
import com.substanceofcode.rssreader.businessentities.CompatibilityRssItunesFeed3;
//#endif
import com.substanceofcode.rssreader.presentation.PromptList;
import com.substanceofcode.rssreader.presentation.PromptForm;
import com.substanceofcode.rssreader.businessentities.RssReaderSettings;
import com.substanceofcode.rssreader.businesslogic.Controller;
/* This functionality adds to jar size, so don't do it for small memory */
/* devices. */
import com.substanceofcode.rssreader.businesslogic.RssFeedParser;
import com.substanceofcode.rssreader.presentation.AllNewsList;
import com.substanceofcode.utils.Settings;
import com.substanceofcode.utils.EncodingUtil;
import com.substanceofcode.utils.StringUtil;
import com.substanceofcode.utils.CauseException;
import com.substanceofcode.utils.CauseMemoryException;
import com.substanceofcode.utils.CauseRecStoreException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Gauge;
// If not using the test UI define the J2ME UI's
//#ifndef DTESTUI
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.StringItem;
//#else
// If using the test UI define the Test UI's
import com.substanceofcode.testlcdui.Form;
import com.substanceofcode.testlcdui.List;
import com.substanceofcode.testlcdui.TextBox;
import com.substanceofcode.testlcdui.TextField;
import com.substanceofcode.testlcdui.StringItem;
//#endif
//#ifdef DTESTUI
import com.substanceofcode.testutil.presentation.TestingForm;
import com.substanceofcode.testutil.TestOutput;
//#endif

//#ifdef DJSR238
import javax.microedition.global.ResourceManager;
//#endif

//#ifdef DMIDP20
import cz.cacek.ebook.PageCustomItem;
//#endif
import cz.cacek.ebook.util.ResourceProviderME;

//#ifdef DLOGGING
import net.sf.jlogmicro.util.logging.Logger;
import net.sf.jlogmicro.util.logging.LogManager;
import net.sf.jlogmicro.util.logging.Level;
import net.sf.jlogmicro.util.logging.FormHandler;
//#endif

/**
* RSS feed reader MIDlet
*
* RssReaderMIDlet is an application that can read RSS feeds. User can store
* multiple RSS feeds as bookmarks into application's record store.
*
* @author  Tommi Laukkanen
* @version 1.0
*/
public class RssReaderMIDlet extends MIDlet
        implements CommandListener,
        Runnable {
   
    final static public char CFEED_SEPARATOR = (char)4;
    final static public char OLD_FEED_SEPARATOR = '^';
    // Attributes
    private Display     m_display;          // The display for this MIDlet
    private Displayable m_prevDisp;         // The displayable to return to
    private Settings    m_settings;         // The settings
    private RssReaderSettings m_appSettings;// The application settings
    private RssFeedStore m_rssFeeds;         // The bookmark URLs
    private Thread      m_netThread;        // The thread for networking
    final static public boolean     JSR75_ENABLED =
            (System.getProperty(
      "microedition.io.file.FileConnection.version") != null);
    private boolean     m_debugOutput = false; // Flag to write to output for test
    private boolean     m_process = true;   // Flag to continue looping
    private boolean     m_needWakeup = false;   // Flag to show need to wakeup
    private boolean     m_getPage;          // The noticy flag for HTTP
    private boolean     m_openPage;         // Open the headers
    private boolean     m_saveBookmarks;    // The save bookmarks flag
    private boolean     m_showItem;         // Show the item
  //#ifdef DTEST
    private boolean     m_testSaveBookmarks;// The save bookmarks flag
  //#endif
    // The go back to bookmarks from header flag
    private boolean     m_backFrHdr;
    private boolean     m_exit;             // The exit application flag
    private boolean     m_saving;           // The saving settings flag
    private boolean     m_stored;           // The data stored flag
    private boolean     m_getModPage;       // The noticy flag for modified HTTP
    private boolean     m_getSettingsForm;  // Flag to get settings form
  //#ifndef DSMALLMEM
    private boolean     m_getHelpForm;      // Flag to get help form
  //#endif
    private boolean     m_getAddBMForm;     // Flag to get add bookmark form
    private boolean     m_getEditBMForm;    // Flag to get edit bookmark form
    private boolean     m_mainBmk;          // Flag to show main bookmarks
    private boolean     m_platformReq;      // Flag to get platform req open link
    private boolean     m_refreshAllFeeds;  // The notify flag for all feeds
    private boolean     m_refreshUpdFeeds;  // The notify flag for updated feeds
    private boolean     m_getImportForm;    // The noticy flag for going to Import Feed list
    private boolean     m_getFile;          // The noticy flag for getting find files form
    private boolean     m_runNews = false// Run AllNewsList form.
  //#ifdef DTEST
    // Get import form using URL from current bookmark
    private boolean     m_getTestImportForm = false; // Get import form
  //#endif
  //#ifdef DTESTUI
  boolean m_headerNext = false; // Flag to control opening the next header
  boolean m_itemNext = false; // Flag to control opening the next item
  //#endif
    private byte[]      m_addBMSave = null; // Edit bookmark form save
  //#ifdef DTESTUI
  private int         m_headerIndex = -1; // Index in headers to auto test
    // Index in bookmarks to auto test by opening in edit
  // This counts up until the bookmark size is reached.
    private int         m_bookmarkIndex = -1;


    private int         m_bookmarkLastIndex = -1; // Last place when import current was selected
  //#endif
  // Tells us if this is the first time program was used.  This is
  // done by seeing if max item count is set.  We also set it after
  // showing the about.
    private boolean     m_firstTime = false;
    private boolean     m_itunesEnabled = false;
  //#ifdef DLOGGING
    private boolean fineLoggable;
    private boolean finestLoggable;
  //#endif
  // This is a mark (icon) next to unread items (except on unread items
  // screen).  Given that many screens are small, it is optional as
  // we don't want to reduce space for text.
    private Image           m_unreadImage;
    private Image           m_readImage;
   
  private int             m_addBkmrk; // Place to add (insert) imported bookmarks
    // Currently selected bookmark
    private int             m_curBookmark;  // The currently selected item
    private RssFeedParser   m_curRssParser; // The currently selected RSS
  //#ifdef DLOGGING
  private RecordStore     m_recStore = null; // Rec store
  //#endif
   
    // GUI items
    private PromptList  m_bookmarkList;     // The bookmark list
  //#ifdef DTESTUI
    private HeaderList  m_headerTestList;       // The header list
    private AllNewsList m_unreadHeaderTestList; // The test header list for unread items
  //#endif
    private RssReaderMIDlet m_midlet;       // The RssReaderMIDlet midlet
    private List        m_itemRtnList;      // The list to return from for item
  //#ifdef DTEST
    private PromptForm  m_itemForm;         // The item form
  //#else
    private Form        m_itemForm;         // The item form
  //#endif
    protected LoadingForm m_loadForm = null// The "loading..." form
    private TextField   m_boxRtnItem;       // The item to return to
    private TextField   m_fileURL;          // The file URL field from a form
    private Form        m_boxRtnForm;       // The form to return to
    private Form        m_fileRtnForm;      // The form to return to for file
  //#ifdef DTESTUI
    private TestingForm m_testingForm;    // The testing form
  //#endif
   
    // Commands
  //#ifdef DTESTUI
  private Command     m_testRssCmd;       // Test UI rss headers command
  private Command     m_testBMCmd;        // Test UI bookmarks list command
  private Command     m_testRtnCmd;       // Test UI return to prev command
  //#endif
    private Command     m_exitCommand = null;// The exit command
    private Command     m_saveCommand;      // The save without exit command
  //#ifdef DTEST
    private Command     m_testSaveCommand;  // The test save without exit command
  //#endif
    private Command     m_addNewBookmark;   // The add new bookmark command
    private Command     m_openBookmark;     // The open bookmark command
    private Command     m_readUnreadItems;  // The read unread items command
    private Command     m_editBookmark;     // The edit bookmark command
    private Command     m_delBookmark;      // The delete bookmark command
    private Command     m_backCommand = null;// The back to header list command
  //#ifdef DMIDP20
    private Command     m_openLinkCmd;      // The open link command
    private Command     m_openEnclosureCmd; // The open enclosure command
  //#endif
    private Command     m_copyLinkCmd;    // The copy link command
    private Command     m_copyEnclosureCmd; // The copy enclosure command
  //#ifndef DSMALLMEM
    private Command     m_rssItemHelpCmd; // The RSS item command
  //#endif
    private Command     m_importFeedListCmd;// The import feed list command
  //#ifdef DTEST
    private Command     m_importCurrFeedListCmd;// The import feed list command and default current seleected feed
  private Command     m_testClearCmd;    // Test quit and clear database
  //#endif
  //#ifdef DTESTUI
    private Command     m_testEncCmd;     // The test encoding
  //#endif
  //#ifdef DLOGGING
    private Command     m_debugCmd; // The back to bookmark list command
                                        // from debug form
    private Command     m_clearDebugCmd; // The back to bookmark list command
                                        // from debug form
  //#endif
    private Command     m_settingsCmd;      // The show settings command
  //#ifndef DSMALLMEM
    private Command     m_helpCmd;          // The show help
  //#endif
    private Command     m_manageBkmrk;      // The manage bookmarks command
    private Command     m_updateAllCmd;     // The update all command
    private Command     m_updateAllModCmd;  // The update all modified command
   
    // The controller of the application
    private Controller m_controller;
    private int citemLnkNbr = -1;
    private int citemEnclNbr = -1;
    private RssItunesItem citem = null;
    private String m_platformURL;           // Platform request URL
  //#ifdef DLOGGING
    private javax.microedition.lcdui.Form m_debug;
    private Logger logger;
  //#endif
   
    public RssReaderMIDlet() {
        m_display = Display.getDisplay(this);
       
    //#ifdef DTESTUI
    TestOutput.init(System.out, "UTF-8");
    //#endif

    //#ifdef DLOGGING
    try {
      LogManager.getLogManager().readConfiguration(this);
      /* Must be here as ResourceProviderME uses logging. */
      /* Loading items... */
      Form loadForm = new Form(super.getAppProperty(
            "resourceproviderme-text-l-load"));
      loadForm.append(super.getAppProperty(
            "resourceproviderme-text-l-items"));
      setCurrent( loadForm );
      logger = Logger.getLogger("RssReaderMIDlet");
      for (Enumeration eHandlers = logger.getParent().getHandlers().elements();
          eHandlers.hasMoreElements();) {
        Object ohandler = eHandlers.nextElement();
        if (ohandler instanceof FormHandler) {
          m_debug = ((FormHandler)ohandler).getForm();
          logger.finest("form=" + m_debug);
          setCurrent( m_debug );
        }
      }
      logger = Logger.getLogger("RssReaderMIDlet");
      logger.info("RssReaderMIDlet started.");
      logger.info("RssReaderMIDlet has form handler=" + (m_debug != null));
    } catch (Throwable t) {
      /* Initialize ResourceProviderME. */
      ResourceProviderME.initialize();
      /* Must be here as ResourceProviderME uses logging. */
      /* Loading items... */
      initializeLoadingFormRsc("text.l.items", null);
      m_loadForm.appendMsg("Error initiating logging " +
          t.getClass().getName() + "," + t.getMessage());
      m_loadForm.addExc(t);
      String [] msgs = LogManager.getLogManager().getStartMsgs();
      if (msgs == null) {
        m_loadForm.appendMsg("Startup msgs=" + msgs);
      } else {
        m_loadForm.appendMsg("msgs.length" + msgs.length);
        for (int ic = 0; ic < msgs.length; ic++) {
          m_loadForm.appendMsg(msgs[ic]);
        }
        System.out.println("Error initiating logging" + t);
        t.printStackTrace();
        return;
      }
    }
    //#endif

    try {

      /** Initialize controller */
      m_controller = new Controller( this );
     
      /* Loading items... */
      if (m_loadForm == null) {
        /* Need to use app property because using ResourceProviderME
           takes too long.  We want the loading screen to happen
           very quickly. */
        String loading = super.getAppProperty(
              "resourceproviderme-text-l-load");
        /* Have defaults to make Netbeans emulator testing easier
           as you do not have to add the entries everywhere. */
        if ( loading == null) {
          loading = "Loading...";
        }
        Form loadForm = new Form(loading);
        String loadingItems = super.getAppProperty(
              "resourceproviderme-text-l-items");
        if ( loadingItems == null) {
          loadingItems = "Loading items...";
        }
        loadForm.append(loadingItems);
        //#ifndef DLOGGING
        setCurrent( loadForm );
        //#endif
      }


      m_midlet = this;
      m_mainBmk = true;
      m_getPage = false;
      m_exit = false;
      m_backFrHdr = false;
      m_stored = false;
      m_saving = false;
      m_openPage = false;
      m_showItem = false;
      m_saveBookmarks = false;
      m_getModPage = false;
      m_getSettingsForm = false;
      //#ifndef DSMALLMEM
      m_getHelpForm = false;
      //#endif
      m_getAddBMForm = false;
      m_getEditBMForm = false;
      m_platformReq = false;
      m_refreshAllFeeds = false;
      m_refreshUpdFeeds = false;
      m_getImportForm = false;
      m_getFile = false;
      m_curBookmark = -1;
     
      /* Initialize ResourceProviderME. */
      ResourceProviderME.initialize();

      /* Loading items... */
      try {
        initializeLoadingFormRsc("text.l.items", null);
      } catch (Throwable t) {
        recordExcFormRsc("exc.tr", t);
      }

      m_appSettings = RssReaderSettings.getInstance(this);
      if (m_appSettings.getLoadExc() != null) {
        recordExcForm("Error while loading settings.",
              m_appSettings.getLoadExc());
      } else {
        m_itunesEnabled =
          m_appSettings.getItunesEnabled();
      }

      // To get proper initialization, need to
      try {
        m_settings = Settings.getInstance(this);
        m_firstTime = !m_settings.isInitialized();
      } catch(Exception e) {
        recordExcForm("Error while loading settings.", e);
      }

      //#ifdef DLOGGING
      if (m_appSettings.getLogLevel().length() == 0) {
        m_appSettings.setLogLevel(
            logger.getParent().getLevel().getName());
      } else {
        logger.getParent().setLevel(
        Level.parse(m_appSettings.getLogLevel()));
      }
      fineLoggable = logger.isLoggable(Level.FINE);
      logger.fine("obj,fineLoggable=" + this + "," + fineLoggable);
      finestLoggable = logger.isLoggable(Level.FINEST);
      logger.fine("obj,finestLoggable=" + this + "," + finestLoggable);
      //#endif

      try {
        m_unreadImage = UiUtil.getImage("/icons/unread.png");
        m_readImage = UiUtil.getImage("/icons/read.png");
      } catch(Exception e) {
        System.err.println("Error while getting mark image: " + e.toString());
      }
     
      /** Initialize thread for http connection operations */
      m_process = true;
      //#ifdef DCLDCV11
      m_netThread = new Thread(this, "RssReaderMIDlet");
      //#else
      m_netThread = new Thread(this);
      //#endif
      m_netThread.start();

    }catch(Throwable t) {
      //#ifdef DLOGGING
      logger.severe("RssReaderMIDlet constructor ", t);
      //#endif
      /** Error while executing constructor */
      System.out.println("RssReaderMIDlet constructor " + t.getMessage());
      t.printStackTrace();
      m_loadForm.appendMsg("Internal error starting applicaiton.");
            m_loadForm.addExc(t);
    }
    }
   
  /** Initialize commands.  This indirectly causes translation to be loaded */
  final private void initializeCommands() {
    //#ifdef DTESTUI
    /* Test headers/items */
    m_testRssCmd        = UiUtil.getCmdRsc("cmd.t.hdr", Command.SCREEN,
        9);
    /* Test bookmarks shown */
    m_testBMCmd         = UiUtil.getCmdRsc("cmd.t.bmk", Command.SCREEN,
        9);
    /* Test go back to last */
    m_testRtnCmd        = UiUtil.getCmdRsc("cmd.t.gb", Command.SCREEN, 10);
    //#endif
    if (m_backCommand == null) {
      m_backCommand   = UiUtil.getCmdRsc("cmd.back", Command.BACK, 1);
    }
    initExit();
    /* Save without exit */
    m_saveCommand       = UiUtil.getCmdRsc("cmd.sve", Command.SCREEN, 11);
    //#ifdef DTEST
    m_testSaveCommand   = UiUtil.getCmdRsc("cmd.t.sve", Command.SCREEN, 16);
    /* Quit and delete RMS */
    m_testClearCmd = UiUtil.getCmdRsc("cmd.q.del", Command.SCREEN, 17);
    //#endif
    /* Add new feed */
    m_addNewBookmark    = UiUtil.getCmdRsc("cmd.a.fd", Command.SCREEN, 3);
    /* Open feed */
    m_openBookmark      = UiUtil.getCmdRsc("cmd.o.fd", Command.SCREEN, 2);
    /* River of news */
    m_readUnreadItems   = UiUtil.getCmdRsc("cmd.rvr", Command.SCREEN, 4);
    /* Edit feed */
    m_editBookmark      = UiUtil.getCmdRsc("cmd.e.fd", Command.SCREEN, 5);
    /* Delete feed */
    m_delBookmark       = UiUtil.getCmdRsc("cmd.d.fd", Command.SCREEN, 6);
    //#ifdef DMIDP20
    /* Open link */
    m_openLinkCmd       = UiUtil.getCmdRsc("cmd.o.lk", Command.SCREEN, 2);
    /* Open enclosure */
    m_openEnclosureCmd  = UiUtil.getCmdRsc("cmd.o.en", Command.SCREEN, 3);
    //#endif
    /* Copy link */
    m_copyLinkCmd       = UiUtil.getCmdRsc("cmd.c.lk", Command.SCREEN, 4);
    /* Copy enclosure */
    m_copyEnclosureCmd  = UiUtil.getCmdRsc("cmd.c.en", Command.SCREEN, 5);
    //#ifndef DSMALLMEM
    /* Item help */
    m_rssItemHelpCmd  = UiUtil.getCmdRsc("cmd.help", Command.HELP, 6);
    //#endif
    /* Import feeds */
    m_importFeedListCmd = UiUtil.getCmdRsc("cmd.im.fd", Command.SCREEN, 7);
    //#ifdef DTEST
    /* Import current feeds */
    m_importCurrFeedListCmd = UiUtil.getCmdRsc("cmd.im.cfd",
        Command.SCREEN, 7);
    //#endif
    /* Settings */
    m_settingsCmd       = UiUtil.getCmdRsc("cmd.set", Command.SCREEN, 12);
    //#ifndef DSMALLMEM
    m_helpCmd           = UiUtil.getCmdRsc("cmd.help", Command.HELP, 13);
    //#endif
    /* Manage bookmarks */
    m_manageBkmrk       = UiUtil.getCmdRsc("cmd.m.bk", Command.SCREEN, 3);
    /* Update all */
    m_updateAllCmd      = UiUtil.getCmdRsc("cmd.ua", Command.SCREEN, 8);
    /* Update modified all */
    m_updateAllModCmd   = UiUtil.getCmdRsc("cmd.uma", Command.SCREEN, 9);
    //#ifdef DTESTUI
    /* Testing Form */
    m_testEncCmd        = UiUtil.getCmdRsc("cmd.tf", Command.SCREEN, 4);
    //#endif

  //#ifdef DLOGGING
    /* Debug Log */
    m_debugCmd          = UiUtil.getCmdRsc("cmd.dbl", Command.SCREEN, 4);
    /* Clear */
    m_clearDebugCmd     = UiUtil.getCmdRsc("cmd.clr", Command.SCREEN, 1);
  //#endif
  }

  /* Create exit command based on if it's a standard exit. */
  final public void initExit() {
    boolean prevExit = (m_exitCommand != null);
    if (prevExit) {
      m_bookmarkList.removeCommand( m_exitCommand );
    }
    m_exitCommand       = UiUtil.getCmdRsc("cmd.exit",
          (m_appSettings.getUseStandardExit() ? Command.EXIT
           : Command.SCREEN), 14);
    if (prevExit) {
      m_bookmarkList.addPromptCommand( m_exitCommand,
          ResourceProviderME.get("text.w.exit") );
    }
  }
 
  /* Initialize the forms that are not dynamic. */
  final private void initForms() {
    try {
      /** Initialize GUI items */
      initializeBookmarkList();
      //initializeLoadingForm();
      //#ifdef DLOGGING
      if (m_debug != null) {
        initializeDebugForm();
      }
      //#endif
      //#ifdef DTEST
      System.gc();
      long beginMem = Runtime.getRuntime().freeMemory();
      //#endif
      //#ifdef DTESTUI
      m_testingForm = new TestingForm(this);
      //#endif
      //#ifdef DTEST
      System.gc();
      System.out.println("TestingForm size=" + (beginMem - Runtime.getRuntime().freeMemory()));
      //#endif
     
      if( m_firstTime ) {
        try {
          m_firstTime = false;
          // Set Max item count to default so that it is initialized.
          m_appSettings.setMaximumItemCountInFeed(
              m_appSettings.getMaximumItemCountInFeed());
          final boolean saveMemoryEnabled =
              m_appSettings.getSaveMemoryEnabled();
          saveBkMrkSettings(saveMemoryEnabled,
              System.currentTimeMillis(),
              true, true, "label.init.d", false);
          Alert m_about = HelpForm.getAbout(this);
          if (m_loadForm.hasExc()) {
            setCurrent( m_about, m_loadForm );
          } else {
            setCurrent( m_about, m_bookmarkList );
          }
        } catch(RecordStoreFullException e) {
          /* Error while storing settings. */
          recordExcFormFinRsc("exc.sv.set", e);
        } catch(Exception e) {
          /* Internal error while storing settings. */
          recordExcFormFinRsc("exc.int.set", e);
        }
      } else {
        if (m_loadForm.hasExc()) {
          recordFin();
          setCurrent( m_loadForm );
        } else {
          setCurrent( m_bookmarkList );
        }
      }

    }catch(Throwable t) {
      //#ifdef DLOGGING
      logger.severe("initForms ", t);
      //#endif
      /** Error while initializing forms */
      System.out.println("initForms " + t.getMessage());
      t.printStackTrace();
    }
    //#ifdef DTEST
    System.gc();
    System.out.println("Initial used memory size=" + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024L) + "kb");
    //#endif
    }
   
    /** Get application settings */
    final public RssReaderSettings getSettings() {
        return m_appSettings;
    }
   
    /** Show bookmark list */
    final public void showBookmarkList() {
    //#ifdef DLOGGING
    if (fineLoggable) {logger.fine("before m_itunesEnabled=" + m_itunesEnabled);}
    //#endif
    setCurrent( m_bookmarkList );
    m_itunesEnabled = m_appSettings.getItunesEnabled();
    //#ifdef DLOGGING
    if (fineLoggable) {logger.fine("after m_itunesEnabled=" + m_itunesEnabled);}
    //#endif
    }
   
    /** Load bookmarks from record store */
    final private void initializeBookmarkList() {
    //#ifdef DTEST
    System.gc();
    long beginMem = Runtime.getRuntime().freeMemory();
    //#endif
    Gauge gauge = new Gauge(ResourceProviderME.get("label.init.b"),
        false, m_settings.MAX_REGIONS, 0);
    int pl = m_loadForm.append(gauge);
        try {
            m_bookmarkList = new PromptList(this, "Bookmarks", List.IMPLICIT);
      updBookmarkList();
            m_bookmarkList.setCommandListener( this );
      //#ifdef DTEST
      System.gc();
      System.out.println("empty bookmarkList size=" + (beginMem - Runtime.getRuntime().freeMemory()));
      //#endif
           
            int i = 1;
           
            final boolean saveMemoryEnabled =
          m_appSettings.getSaveMemoryEnabled();
            m_rssFeeds = new RssFeedStore(saveMemoryEnabled);
      for (int ic = 1; ic < m_settings.MAX_REGIONS; ic++) {
        boolean stop = false;
        final String vers = m_settings.getStringProperty(ic,
            m_settings.SETTINGS_NAME, "");
        final boolean firstSettings =
           vers.equals(m_settings.FIRST_SETTINGS_VERS);
        final boolean itunesCapable = ((vers.length() > 0) &&
           (vers.compareTo(m_settings.ITUNES_CAPABLE_VERS) >= 0));
        final boolean latestSettings = vers.equals(
            m_settings.ENCODING_VERS);
        final boolean itemsEncoded =
          m_settings.getBooleanProperty(m_settings.ITEMS_ENCODED,
              true);
        final long storeDate = m_settings.getLongProperty(
            m_settings.STORE_DATE, 0L);
        final char feedSeparator =
          latestSettings ? CFEED_SEPARATOR : OLD_FEED_SEPARATOR;
        //#ifdef DLOGGING
        if (fineLoggable) {logger.fine("Settings region,vers,firstSettings,itunescapable,latestSettings,itemsEncoded,storeDate=" + ic + "," + vers + "," + firstSettings + "," + itunesCapable + "," + latestSettings + "," + itemsEncoded + "," + storeDate);}
        //#endif
        //#ifdef DTEST
        if (m_debugOutput) System.out.println("Settings region,vers,firstSettings,itunescapable,latestSettings,itemsEncoded,storeDate=" + ic + "," + vers + "," + firstSettings + "," + itunesCapable + "," + latestSettings + "," + itemsEncoded + "," + storeDate);
        //#endif
        String bms = m_settings.getStringProperty(ic, "bookmarks", "");
        //#ifdef DLOGGING
        if (fineLoggable) {logger.fine("bms.length()=" + bms.length());}
        //#endif
        // Save memory by setting bookmarks to "" now that
        // we will convert them to objects.
        m_settings.setStringProperty("bookmarks", "");
       
        if(bms.length()>0) {
          do{
           
            String part = "";
            int pos = bms.indexOf(feedSeparator);
            if(pos > 0) {
              part = bms.substring(0, pos);
            }
            bms = bms.substring(pos+1);
            if(part.length()>0) {
              RssStoreInfo rsi = null;
              //#ifdef DCOMPATIBILITY1
              RssFeed bm1 = new CompatibilityRssFeed1( part );
              RssItunesFeed bm = new RssItunesFeed( bm1 );
              //#elifdef DCOMPATIBILITY2
              RssFeed bm2 = new CompatibilityRssFeed2( part );
              RssItunesFeed bm = new RssItunesFeed( bm2 );
              //#elifdef DCOMPATIBILITY3
              RssItunesFeed bm2 =
                CompatibilityRssItunesFeed3.deserialize3(
                true, part );
              RssItunesFeed bm = new RssItunesFeed( bm2 );
              //#else
              RssItunesFeed bm = null;
              if (itunesCapable) {
                if (saveMemoryEnabled) {
                  rsi = RssItunesFeed.getStoreStringInfo(
                      true, false, part, itemsEncoded );
                } else {
                  bm = RssItunesFeed.deserialize(
                      itemsEncoded, part );
                }
              } else {
                bm = new RssItunesFeed(new RssFeed(
                      firstSettings, itemsEncoded, part ));
              }

              //#endif
              if((bm != null) && (bm.getName().length()>0)){
                final String fname = bm.getName();
                m_bookmarkList.append(fname,null);
                m_rssFeeds.put(fname, bm);
              } else {
                final String fname = rsi.getName();
                m_bookmarkList.append(fname,null);
                m_rssFeeds.put(fname,
                    rsi.getStoreString(), false);
              }
            }
            if( part.length()==0)
              stop = true;
          }while(!stop);
        }
        gauge.setValue(ic);
            }
      pl = -1;
      gauge.setValue(m_settings.MAX_REGIONS);
      //#ifdef DTEST
      System.gc();
      System.out.println("full bookmarkList size=" + (beginMem - Runtime.getRuntime().freeMemory()));
      //#endif
    } catch(CauseRecStoreException e) {
      /* Database error while loading saved feeds. */
      recordExcFormFinRsc("exc.dbe.sv", e);
        } catch(CauseMemoryException e) {
      System.gc();
      /* Free memory by getting rid of items. */
      m_loadForm.appendMsg("Trying to free memory.");
      freeFeedItems();
      recordExcFormFin("Out of memory while loading saved feeds.", e);
        } catch(Exception e) {
      recordExcFormFin("Internal error while loading saved feeds.", e);
        } catch(OutOfMemoryError e) {
      System.gc();
      /* Free memory by getting rid of items. */
      m_loadForm.appendMsg("Trying to free memory.");
      freeFeedItems();
      recordExcFormFin("Out of memory while loading saved feeds.", e);
    } catch(Throwable t) {
      recordExcFormFin("Internal error while loading saved feeds.", t);
    } finally {
      m_loadForm.addStartCmd( m_bookmarkList );
      if (pl >= 0) {
        m_loadForm.delete(pl);
      }
      // Do this here in case load of settings failed.
      // Reset internal region to 0.
      m_settings.getStringProperty("bookmarks", "");
    }
    }
   
  /**
   * Update/initialize the bookmarkList title and commands
   *
   */
  final private void updBookmarkList() {
    Command[] allCmds = {m_addNewBookmark, m_openBookmark, m_backCommand
      ,m_readUnreadItems, m_editBookmark, m_delBookmark, m_manageBkmrk
      ,m_importFeedListCmd
    //#ifdef DTEST
      ,m_importCurrFeedListCmd
    //#endif
      ,m_updateAllCmd, m_updateAllModCmd, m_saveCommand, m_settingsCmd
    //#ifndef DSMALLMEM
      ,m_helpCmd
    //#endif
      ,m_exitCommand
    //#ifdef DTEST
      ,m_testClearCmd
      ,m_testSaveCommand
    //#endif
    //#ifdef DTESTUI
      ,m_testBMCmd, m_testRtnCmd, m_testEncCmd
    //#endif
    //#ifdef DLOGGING
      ,m_debugCmd
    //#endif
    };
    Command[] mainCmds = {m_openBookmark
      ,m_manageBkmrk, m_readUnreadItems
      ,m_updateAllCmd, m_updateAllModCmd, m_saveCommand, m_settingsCmd
    //#ifndef DSMALLMEM
      ,m_helpCmd
    //#endif
      ,m_exitCommand
    //#ifdef DTEST
      ,m_testClearCmd
      ,m_testSaveCommand
    //#endif
    //#ifdef DTESTUI
      ,m_testBMCmd, m_testRtnCmd, m_testEncCmd
    //#endif
    //#ifdef DLOGGING
      ,m_debugCmd
    //#endif
    };
    Command[] manageCmds = {m_addNewBookmark, m_backCommand
      ,m_openBookmark, m_readUnreadItems, m_editBookmark, m_delBookmark
      ,m_importFeedListCmd
    //#ifdef DTEST
      ,m_importCurrFeedListCmd
    //#endif
      ,m_saveCommand
    //#ifndef DSMALLMEM
      ,m_helpCmd
    //#endif
    //#ifdef DTESTUI
      ,m_testBMCmd, m_testRtnCmd, m_testEncCmd
    //#endif
      ,m_exitCommand
    };
    String[] mainPrompts = {null
      ,null, null
      ,null, null, null, null
    //#ifndef DSMALLMEM
      ,null
    //#endif
      ,"text.w.exit"
    //#ifdef DTEST
      ,"text.w.clear"
      ,null
    //#endif
    //#ifdef DTESTUI
      ,null, null, null
    //#endif
    //#ifdef DLOGGING
      ,null
    //#endif
    };
    String[] managePrompts = {null, null
      ,null ,null, null, "text.w.del"
      ,null
    //#ifdef DTEST
      ,null
    //#endif
      ,null
    //#ifndef DSMALLMEM
      ,null
    //#endif
    //#ifdef DTESTUI
      ,null, null, null
    //#endif
      ,"text.w.exit"
    };
    Command[] cmds = (m_mainBmk ? mainCmds : manageCmds);
    String[] prompts = (m_mainBmk ? mainPrompts : managePrompts);
    if (cmds.length != prompts.length) {
      Exception e = new Exception("Error cmds and prompts settings wrong " +
          cmds.length + "!=" + prompts.length);
      //#ifdef DLOGGING
      logger.severe(e.getMessage(), e);
      //#endif
      System.err.println(e.getMessage());
      e.printStackTrace();
    }
    UiUtil.delCmds(m_bookmarkList, allCmds);
    for (int ic = 0; ic < cmds.length; ic++) {
      if (cmds[ic] != null) {
        if (prompts[ic] != null) {
          m_bookmarkList.addPromptCommand( cmds[ic],
              ResourceProviderME.get(prompts[ic]) );
        } else {
          m_bookmarkList.addCommand( cmds[ic] );
        }
      }
    }
    m_bookmarkList.setTitle(ResourceProviderME.get((m_mainBmk ?
            "title.book" : "title.m.book")));
  }

  /* Free memory by getting rid of items. */
  final private void freeFeedItems() {
    try {
      m_rssFeeds.freeFeedItems();
    } catch(Exception ex) {
      recordExcForm("Error tyring to free memory.", ex);
    } catch(OutOfMemoryError ex) {
      recordExcForm("Out Of Memory tyring to free memory.", ex);
    }
  }

    /** Show loading form */
    final public void showLoadingForm() {
        setCurrent( m_loadForm );
    }
   
    /** Initialize loading form */
    final public void initializeLoadingForm(final String desc,
                     Displayable disp) {
    m_loadForm = new LoadingForm(ResourceProviderME.get("text.l.load"),
        disp);
    m_loadForm.appendMsg( desc + "\n" );
        setCurrent( m_loadForm );
    }
   
    /** Initialize loading form */
    final public void initializeLoadingFormRsc(final String key,
                     Displayable disp) {
    initializeLoadingForm(ResourceProviderME.get(key), disp);
  }

    /** Show loading form */
    final public void showLoadingFormRsc(final String key,
                     Displayable disp)
  throws Exception {
    if ((m_netThread != null) &&
        Thread.currentThread().equals(m_netThread)) {
      /* If same thread as midlet thread, do show loading form right
         away */
      //#ifdef DTEST
      System.out.println("showLoadingFormRsc called from midlet thread.");
      //#endif
      initializeLoadingFormRsc(key, disp);
      setCurrent( m_loadForm );
    } else {
      /* Request show loading as doing it in commandAction may hang
         or in N95's case it is not shown. */
      //#ifdef DTEST
      System.out.println("showLoadingForm called make request.");
      //#endif
      throw new Exception("Must be called from midlet thread.");
    }
  }

    /** Set title and addmessage for loading form */
    final public void setLoadingFinished(final String title, String msg) {
    if (title != null) {
      m_loadForm.setTitle(title);
    }
    if (msg != null) {
      m_loadForm.appendMsg(msg);
    }
    }
   
  //#ifdef DLOGGING
    final public void initializeDebugForm() {
        m_debug.addCommand( m_backCommand );
        m_debug.addCommand( m_clearDebugCmd );
        m_debug.setCommandListener(this);
  }
  //#endif

    /** Run method is used to get RSS feed with HttpConnection */
    public void run(){
        /* Use networking if necessary */
        long lngStart;
        long lngTimeTaken;
        while(m_process) {
            try {
        // Initialize bookmarks here since it does some work.
        if (m_bookmarkList == null) {
          synchronized (this) {
            if (m_exitCommand == null) {
              /** Initialize commands commands. */
              initializeCommands();
            }

            if (m_bookmarkList == null) {
              initForms();
            }
          }
        }

        //#ifdef DTESTUI
        // If there are headers, and the header index is >= 0,
        // open the header so that it's items can be listed
        // with test UI classes.
        // Need to change the selection to match the m_headerIndex.
        if (m_headerNext && (m_headerIndex >= 0) &&
            (m_headerTestList != null) &&
            (m_headerIndex < m_headerTestList.size()) &&
          (m_display.getCurrent() == m_headerTestList)) {
          m_headerNext = false;
          if (m_headerTestList.getSelectedIndex() >= 0) {
            m_headerTestList.setSelectedIndex(
                m_headerTestList.getSelectedIndex(), false);
          }
          m_headerTestList.setSelectedIndex(m_headerIndex, true);
          m_headerTestList.commandAction(List.SELECT_COMMAND,
              m_headerTestList);
        }
        // After intializing the form (which was already logged by
        // testui classes), simulate the back command
        if (m_itemNext && (m_headerIndex >= 0) &&
            (m_headerTestList != null) &&
          (m_headerIndex < m_headerTestList.size()) &&
          (m_display.getCurrent() == m_itemForm )) {
          m_itemNext = false;
          commandAction( m_backCommand, m_itemForm );
          m_headerIndex++;
          if (m_headerIndex >= m_headerTestList.size()) {
            System.out.println("Test UI Test Rss items last");
            m_headerIndex = -1;
          }
        }
        //#endif

        // Open existing bookmark and show headers (items).
                if( m_openPage || m_getPage || m_getModPage ) {
                    try {
            RssItunesFeed feed = null;
            if( m_openPage ) {
              m_curBookmark = UiUtil.getSelectedIndex(m_bookmarkList);
            }
            if( m_curBookmark<0 ){
              continue;
            }
            if( m_openPage ) {
              String parm = m_bookmarkList.getString(
                  m_curBookmark);
              feed = (RssItunesFeed)m_rssFeeds.get(parm);
              m_curRssParser = new RssFeedParser( feed );
              m_openPage = ( feed.getItems().size() > 0 );
              m_getPage = !m_openPage;
              m_prevDisp = m_bookmarkList;
            } else {
              feed = m_curRssParser.getRssFeed();
            }
            if( m_openPage ) {
              /* Loading feed... */
              initializeLoadingFormRsc("text.l.feed",
                  m_bookmarkList);
            } else {
              /* Updating feed... */
              initializeLoadingFormRsc(
                  m_getModPage ? "text.u.mfeed" :
                  "text.u.feed", m_prevDisp);
            }
            if(feed.getUrl().length() == 0) {
              recordExcFormFin("Unable to open feed.  No URL.",
                  new Exception(
                  "Feed has no URL cannot load."));
              continue;
            }
            if (!m_openPage) {
              /** Get RSS feed */
              final int maxItemCount =
                m_appSettings.getMaximumItemCountInFeed();
              final boolean convHtml =
                !m_appSettings.getHtmlEnabled();
              //#ifdef DTEST
              System.gc();
              long beginMem = Runtime.getRuntime().freeMemory();
              //#endif
              m_curRssParser.parseRssFeed( m_getModPage, convHtml,
                  maxItemCount );
              //#ifdef DTEST
              System.gc();
              System.out.println("RssItunesFeed size=" + (beginMem - Runtime.getRuntime().freeMemory()));
              //#endif
              feed = m_curRssParser.getRssFeed();
              //#ifdef DTEST
              System.gc();
              beginMem = Runtime.getRuntime().freeMemory();
              //#endif
              m_rssFeeds.put(feed.getName(), feed);
              //#ifdef DTEST
              System.gc();
              System.out.println("RssItunesFeed store size=" + (beginMem - Runtime.getRuntime().freeMemory()));
              //#endif
            }
            //#ifdef DTEST
            System.gc();
            long beginMem = Runtime.getRuntime().freeMemory();
            //#endif
            final HeaderList hdrList = new HeaderList(this, feed);
            //#ifdef DTEST
            System.gc();
            System.out.println("headerList size=" + (beginMem - Runtime.getRuntime().freeMemory()));
            //#endif
                        hdrList.fillHeadersList();
                        setCurrent( hdrList );
            //#ifdef DTEST
            hdrList.testFeed(true);
            hdrList.testFeed(false);
            hdrList.testFeed2(true);
            hdrList.testFeed2(false);
            //#endif
                    }catch(CauseMemoryException e) {
            System.gc();
            if ((m_curRssParser != null) &&
                (m_curRssParser.getRssFeed() != null)) {
              m_curRssParser.getRssFeed().setItems(new Vector());
            }
            recordExcFormFinRsc(
                            /* \nOut of memory loading/parsing feed on:\n */
                            (m_openPage ? "exc.om.ld" : "exc.om.pse"),
                                m_curRssParser.getRssFeed().getUrl(), e);
                    }catch(Exception e) {
            /* Error loading/parsing  feed on:\n \1 */
            recordExcFormFinRsc(
                            (m_openPage ? "exc.er.ld" : "exc.er.pse"),
                                m_curRssParser.getRssFeed().getUrl(), e);

                    }catch(OutOfMemoryError e) {
            System.gc();
            if ((m_curRssParser != null) &&
                (m_curRssParser.getRssFeed() != null)) {
              m_curRssParser.getRssFeed().setItems(new Vector());
            }
            recordExcFormFinRsc(
                            /* Out of memory loading/parsing feed on:\n */
                            (m_openPage ? "exc.om.ld" : "exc.om.pse"),
                                m_curRssParser.getRssFeed().getUrl(), e);
                    }catch(Throwable t) {
            recordExcFormFinRsc(
                            /* Internal error loading/parsing feed on:\n */
                            (m_openPage ? "exc.int.ld" : "exc.int.pse"),
                                m_curRssParser.getRssFeed().getUrl(), t);
          } finally {
            m_getPage = false;
            m_openPage = false;
            m_getModPage = false;
                    }
                }

        /* Handle going to settings form. */
                if( m_getSettingsForm ) {
          m_getSettingsForm = false;
          /* Loading settings... */
          initializeLoadingFormRsc("text.l.s", m_bookmarkList);
                    try{
            //#ifdef DTEST
            System.gc();
            long beginMem = Runtime.getRuntime().freeMemory();
            //#endif
            final SettingsForm settingsForm = new SettingsForm(this);
            //#ifdef DTEST
            System.gc();
            System.out.println("SettingsForm size=" +
                (beginMem - Runtime.getRuntime().freeMemory()));
            //#endif
            if (m_loadForm.hasExc()) {
              m_loadForm.addStartCmd( settingsForm );
            } else {
              setCurrent( settingsForm );
            }
                    } catch(OutOfMemoryError t) {
            System.gc();
            /* \nOut Of Memory Error loading settings form */
            recordExcFormFinRsc("exc.om.set", t);
                    } catch(Throwable t) {
            /* \nInternal error loading settings form */
            recordExcFormFinRsc("exc.int.lset", t);
          }
        }

        //#ifndef DSMALLMEM
        /* Handle going to help form. */
                if( m_getHelpForm ) {
          m_getHelpForm = false;
          /* Loading help... */
          initializeLoadingFormRsc("text.l.h", m_bookmarkList);
                    try{
            final HelpForm helpForm = initializeHelp();
            setCurrent( helpForm );
                    } catch(OutOfMemoryError t) {
            System.gc();
            /* \nOut Of Memory Error loading help form */
            recordExcFormFinRsc("exc.om.bhlp", t);
                    } catch(Throwable t) {
            /* \nInternal error loading help form */
            recordExcFormFinRsc("exc.int.bhlp", t);
          }
        }
        //#endif

        /* Handle going to bookmark form. */
                if( m_getAddBMForm || m_getEditBMForm ) {
          try {
            if( m_getEditBMForm ) {
              m_curBookmark = UiUtil.getSelectedIndex(m_bookmarkList);
              if( m_curBookmark<0 ){
                continue;
              }
            }
            if( m_getAddBMForm ) {
              /* Loading add bookmark... */
              initializeLoadingFormRsc("text.l.bmrk",
                  m_bookmarkList);
            } else {
              /* Loading edit bookmark... */
              initializeLoadingFormRsc("text.edit",
                  m_bookmarkList);
            }
            //#ifdef DTEST
            System.gc();
            long beginMem = Runtime.getRuntime().freeMemory();
            //#endif
            BMForm bmForm = new BMForm(m_getAddBMForm);
            //#ifdef DTEST
            System.gc();
            System.out.println("BMForm size=" +
                (beginMem - Runtime.getRuntime().freeMemory()));
            //#endif
            if (m_getEditBMForm) {
              final RssItunesFeed bm = (RssItunesFeed)m_rssFeeds.get(
                  m_bookmarkList.getString(m_curBookmark));
              bmForm.updateBM(bm);
            }
            setCurrent( bmForm );
          } catch(OutOfMemoryError t) {
            System.gc();
            /* \nOut Of Memory Error loading bookmark form */
            recordExcFormFinRsc("exc.om.bmk", t);
          } catch(Throwable t) {
            /* \nInternal error loading bookmark form */
            recordExcFormFinRsc("exc.int.bmk", t);
          } finally {
            m_getAddBMForm = false;
            m_getEditBMForm = false;
          }
        }

                if( m_refreshAllFeeds || m_refreshUpdFeeds ) {
          /* Updating all or modified feeds... */
          initializeLoadingFormRsc((m_refreshUpdFeeds ?
                "text.um.feed" : "text.ua.feed"),
              m_bookmarkList);
          /* Updating all (modified) feeds...*/
          Gauge gauge = new Gauge(ResourceProviderME.get(
                m_refreshAllFeeds ? "text.ua.feed" :
                "text.um.feed"),
              false, m_rssFeeds.size(), 0);
          int pl = m_loadForm.append(gauge);
                    try{
            boolean errFound = false;
                        final int maxItemCount =
                m_appSettings.getMaximumItemCountInFeed();
            final boolean convHtml =
              !m_appSettings.getHtmlEnabled();
                        Enumeration keyEnum = m_rssFeeds.keys();
            int ic = 1;
                        while(keyEnum.hasMoreElements()) {
                            final String fname =
                (String)keyEnum.nextElement();
                            RssItunesFeed feed =
                (RssItunesFeed)m_rssFeeds.get(fname);
                            try{
                                m_loadForm.appendMsg(fname + "...");
                                RssFeedParser parser = new RssFeedParser( feed );
                                parser.parseRssFeed( m_refreshUpdFeeds,
                    convHtml, maxItemCount);
                m_rssFeeds.put( fname, feed );
                                m_loadForm.appendMsg("ok\n");
                            } catch(CauseMemoryException ex) {
                throw ex;
                            } catch(Exception ex) {
                recordExcForm("Error parsing feed " +
                    feed.getName(), ex);
                errFound = true;
                            }
              gauge.setValue(ic);
              ic++;
                        }
            if (errFound) {
              setLoadingFinished(
                  /* Finished with one or more exceptions */
                  /* or errors below. */
                  ResourceProviderME.get("text.fin.errb"),
                  /* Updating finished with one or more */
                  /* exceptions or errors above*/
                  ResourceProviderME.get("text.fin.erra"));
              setCurrent( m_loadForm );
            } else {
              setLoadingFinished("Updating finished",
                  "Updating finished use back to return.");
              setCurrent( m_bookmarkList );
            }
            pl = -1;
                    } catch(CauseMemoryException ex) {
            recordExcForm("Out Of Memory Error parsing feeds", ex);
            m_loadForm.appendMsg("Trying to free memory.");
            freeFeedItems();
            recordFin();
                    } catch(Exception ex) {
            recordExcFormFin("Error parsing feeds", ex);
                    } catch(OutOfMemoryError ex) {
            System.gc();
            recordExcForm("Out Of Memory Error parsing feeds", ex);
            m_loadForm.appendMsg("Trying to free memory.");
            freeFeedItems();
            recordFin();
                    } catch(Throwable t) {
            recordExcFormFin("Internal error parsing feeds", t);
          } finally {
            if (pl >= 0) {
              m_loadForm.delete(pl);
            }
            m_refreshAllFeeds = false;
            m_refreshUpdFeeds = false;
          }
                }

        // Go to import feed form
        if( m_getImportForm ) {
          try {
            /* Loading import form... */
            initializeLoadingFormRsc("text.l.imp",
                m_bookmarkList);
            //#ifdef DTEST
            System.gc();
            long beginMem = Runtime.getRuntime().freeMemory();
            //#endif
            ImportFeedsForm importFeedsForm;
            //#ifdef DTEST
            if (m_getTestImportForm) {
              RssItunesFeed bm = (RssItunesFeed)m_rssFeeds.get(
                  m_bookmarkList.getString(m_curBookmark));
              importFeedsForm = new ImportFeedsForm(this,
                  m_bookmarkList, m_rssFeeds, m_appSettings,
                  m_loadForm, bm.getUrl());
            } else
            //#endif
              importFeedsForm = new ImportFeedsForm(this,
                  m_bookmarkList, m_rssFeeds, m_appSettings,
                  m_loadForm, m_appSettings.getImportUrl());
            //#ifdef DTEST
            System.gc();
            System.out.println("ImportForm size=" + (beginMem - Runtime.getRuntime().freeMemory()));
            //#endif
            setCurrent( importFeedsForm );
                    } catch(Exception ex) {
            recordExcFormFin("Error loading import form\n", ex);
                    } catch(OutOfMemoryError ex) {
            System.gc();
            recordExcFormFin("Out Of Memory loading import form\n",
                                ex);
                    } catch(Throwable t) {
            recordExcFormFin("Internal loading import form\n", t);
          } finally {
            m_getImportForm = false;
            //#ifdef DTEST
            m_getTestImportForm = false;
            //#endif
          }
        }

        //#ifdef DTESTUI
        if ((m_bookmarkIndex < m_bookmarkList.size()) &&
            (m_bookmarkIndex >= 0)) {
          if (m_bookmarkList.getSelectedIndex() >= 0) {
            m_bookmarkList.setSelectedIndex(
                m_bookmarkList.getSelectedIndex(), false);
          }
          m_bookmarkList.setSelectedIndex(m_bookmarkIndex, true);
          commandAction(m_editBookmark, m_bookmarkList);
          m_bookmarkIndex++;
          if (m_bookmarkIndex >= m_bookmarkList.size()) {
            m_bookmarkIndex = -1;
            System.out.println("Test UI Test Rss feeds last");
          }
        }

        //#endif

        //#ifdef DJSR75
        /* Find files in the file system to get for bookmark or
           import from. */
                if( m_getFile ) {
          if (m_fileRtnForm instanceof ImportFeedsForm) {
            /* Loading files to import from... */
            initializeLoadingFormRsc("text.l.f.imp",
                m_fileRtnForm);
          } else {
            /* Loading files to bookmark from... */
            initializeLoadingFormRsc("text.l.f.bk",
                m_fileRtnForm);
          }

          try {
            final KFileSelectorMgr fileSelectorMgr =
              new KFileSelectorMgr();
            fileSelectorMgr.doLaunchSelector(this,
                  m_fileRtnForm, m_fileURL);
          } catch(OutOfMemoryError ex) {
            System.gc();
            /* Out Of Memory Error getting file form. */
            recordExcFormFinRsc("exc.om.flf", ex);
          } catch (Throwable t) {
            /* Internal error getting file form. */
            recordExcFormFinRsc("exc.int.flf", t);
          } finally {
            m_getFile = false;
          }
        }
        //#endif

        /* Handle going to link (platform request.). */
        //#ifdef DMIDP20
        if (m_platformReq) {
          try {

            /* Loading web page... */
            initializeLoadingFormRsc("text.l.wp", m_itemForm);
            if( super.platformRequest(m_platformURL) ) {
              initializeLoadingForm("Exiting saving data...",
                  m_itemRtnList);
              m_exit = true;
              exitApp();
            } else {
              setCurrent( m_itemRtnList );
            }
          } catch (ConnectionNotFoundException e) {
            //#ifdef DLOGGING
            logger.severe("Error opening link " + m_platformURL, e);
            //#endif
            final Alert badLink = new Alert("Could not connect to link",
                "Bad link:  " + m_platformURL,
                null, AlertType.ERROR);
            badLink.setTimeout(Alert.FOREVER);
            setCurrent( badLink, m_itemRtnList );
          } finally {
            m_platformReq = false;
          }
        }
        //#endif

        /* Sort the read or unread items. */
        if ( m_runNews ) {
          try {
            /* Sorting items... */
            initializeLoadingFormRsc("text.s.item",
                m_bookmarkList);
            AllNewsList unreadHeaderList = new AllNewsList(this,
              m_bookmarkList, m_rssFeeds,
                  m_appSettings.getMarkUnreadItems() ?
                  m_unreadImage : null,
                  m_appSettings.getMarkUnreadItems() ?
                  m_readImage : null);
            //#ifdef DTESTUI
            m_unreadHeaderTestList = unreadHeaderList;
            //#endif
            unreadHeaderList.initializeUnreadHhdrsList();
            unreadHeaderList.sortUnreadItems( true,
                m_bookmarkList, m_rssFeeds );
            setCurrent( unreadHeaderList );
                    }catch(OutOfMemoryError t) {
            System.gc();
            recordExcFormFin("\nOut Of Memory Error sorting items", t);
                    }catch(Throwable t) {
            recordExcFormFin("\nInternal error sorting items", t);
          } finally {
            m_runNews = false;
          }
        }

        if ( m_backFrHdr ) {
          m_backFrHdr = false;
          /* Updating feed... */
          initializeLoadingFormRsc("text.u.feed", m_bookmarkList);
          try {
            m_rssFeeds.put(m_curRssParser.getRssFeed());
          } catch (Throwable t) {
            recordExcFormFin("Internal error updating feed.", t);
          }
          setCurrent( m_bookmarkList );
        }

        if ( m_showItem ) {
          m_showItem = false;
          initializeLoadingFormRsc( "text.l.it", m_itemRtnList );
          RssItunesFeed feed = m_curRssParser.getRssFeed();
          citem.setUnreadItem(false);
          initializeItemForm( feed, citem, m_itemRtnList );
          //#ifdef DTESTUI
          m_itemNext = true;
          //#endif
        }

        if ( m_exit || m_saveBookmarks
          //#ifdef DTEST
             || m_testSaveBookmarks
          //#endif
        ) {
          if ( m_exit ) {
            /* Exiting saving data... */
            initializeLoadingFormRsc("text.exit", m_bookmarkList);
          } else {
            /* Saving data... */
            initializeLoadingFormRsc("text.savd", m_bookmarkList);
          }
          exitApp();
        }

                lngStart = System.currentTimeMillis();
                lngTimeTaken = System.currentTimeMillis()-lngStart;
                if(lngTimeTaken<100L) {
          synchronized(this) {
            if (!m_needWakeup) {
              super.wait(75L-lngTimeTaken);
            }
            m_needWakeup = false;
          }
        }
            } catch (InterruptedException e) {
                break;
            } catch (Throwable t) {
        try {
          if (m_loadForm == null) {
            synchronized(this) {
              if (m_loadForm == null) {
                /* Processing... */
                initializeLoadingFormRsc("text.proc",
                    m_bookmarkList);
              }
            }
          }
          recordExcForm("Internal error while processing", t);
        } catch (Throwable e) {
          t.printStackTrace();
          final Alert internalAlert = new Alert(
              /* Internal error */
              ResourceProviderME.get("exc.int.err"),
              /* Internal error while processing */
              ResourceProviderME.get("exc.int.proc"),
              null,
              AlertType.ERROR);
          internalAlert.setTimeout(Alert.FOREVER);
          setCurrent( internalAlert );
        }
            }
        }
    }
 
  /** Save data and exit the application. This accesses the database,
      so it must not be called by commandAction as it may hang.  It must
      be called by a separate thread.  */
  final private void exitApp() {
    try {
      //#ifdef DLOGGING
      if (fineLoggable) {logger.fine("m_exit,m_saveBookmarks=" + m_exit + "," + m_saveBookmarks);}
      //#endif
      storeSettings(true, true, m_exit);
      if (m_loadForm.hasExc()
        //#ifdef DTEST
          || m_testSaveBookmarks
        //#endif
      ) {
        if (m_exit) {
          m_loadForm.addQuit();
        }
        setCurrent( m_loadForm );
      } else if (m_exit) {
        try {
          destroyApp(true);
        } catch (MIDletStateChangeException e) {
          //#ifdef DLOGGING
          if (fineLoggable) {logger.fine("MIDletStateChangeException=" + e.getMessage());}
          //#endif
        }
        m_process = false;
        super.notifyDestroyed();
        m_exit = false;
      } else {
        setCurrent( m_bookmarkList );
      }
    } finally {
      m_exit = false;
      m_saveBookmarks = false;
      //#ifdef DTEST
      m_testSaveBookmarks  = false;
      //#endif
    }
  }

  //#ifndef DSMALLMEM
    /**
   * Create help form.
   * @author  Irving Bunton
   * @version 1.0
   */
  final private HelpForm initializeHelp() {
    //#ifdef DTEST
    System.gc();
    long beginMem = Runtime.getRuntime().freeMemory();
    //#endif
    final HelpForm helpForm = new HelpForm(this,
        m_bookmarkList);
    /* To start, go to add feed or import feed */
    helpForm.appendRsc(m_mainBmk ? "text.m.help" : "text.bk.help");
    if (m_mainBmk) {
      /* Manage bookmarks. */
      helpForm.appendCmdHelpRsc(m_manageBkmrk, "text.mge.help");
      /* Update all feeds. */
      helpForm.appendCmdHelpRsc(m_updateAllCmd, "text.ua.help");
      /* Update modified feeds. */
      helpForm.appendCmdHelpRsc(m_updateAllModCmd, "text.um.help");
      /* Go to settings. */
      helpForm.appendCmdHelpRsc(m_settingsCmd, "text.set.help");
    } else {
      /* Go back to main bookmarks. */
      helpForm.appendCmdHelpRsc(m_backCommand, "text.bbk.help");
    }
    /* Save without exiting. */
    helpForm.appendCmdHelpRsc(m_saveCommand, "text.save.help");
    /* Exit. */
    helpForm.appendCmdHelpRsc(m_exitCommand, "text.exit.help");
    //#ifdef DTEST
    System.gc();
    System.out.println("Main HelpForm size=" +
        (beginMem - Runtime.getRuntime().freeMemory()));
    //#endif
    return helpForm;
  }
  //#endif

  /** Store the settings. */
  final private void storeSettings(final boolean saveHdr,
      final boolean saveItems, final boolean exitingApp) {
    m_saving = true;
    boolean saveMemoryEnabled = m_appSettings.getSaveMemoryEnabled();
    try {
      saveBkMrkSettings(saveMemoryEnabled, System.currentTimeMillis(),
          saveHdr, saveItems, "label.save.d", m_exit);
    } catch (RecordStoreFullException e) {
      recordExcFormFinRsc(
          /* Unrecoverable error saving feeds again. */
          "exc.sv.ursf", e);
    } catch (Exception e) {
      recordExcFormFin(
          "Internal error saving feeds", e);
    } catch (OutOfMemoryError e) {
      recordExcFormFin(
          "Out of memory error saving feeds", e);
    } catch (Throwable e) {
      recordExcFormFin(
          "Internal error saving feeds", e);
    }
    m_stored = exitingApp;
    m_saving = false;
  }

  /* Record the message in the loading form, */
  final public void recordMsg(final String msg) {
    m_loadForm.appendMsg(msg);
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordFin() {
    m_loadForm.setTitle("Finished with errors or esceptions below");
    m_loadForm.appendMsg("Finished with errors or esceptions above");
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordExcFormRsc(final String key, final Throwable e) {
    recordExcForm(ResourceProviderME.get(key), e);
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordExcForm(final String causeMsg, final Throwable e) {
    final CauseException ce = new CauseException(causeMsg, e);
    m_loadForm.addExc(ce);
    //#ifdef DLOGGING
    logger.severe(ce.getMessage(), e);
    //#endif
    /** Error while parsing RSS feed */
    System.out.println(e.getClass().getName() + " " + ce.getMessage());
    e.printStackTrace();
    m_loadForm.appendMsg(ce.getMessage());
    setCurrent( m_loadForm );
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordExcFormFinRsc(final String key, final Throwable e) {
    recordExcFormFin(ResourceProviderME.get(key), e);
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordExcFormFinRsc(final String key, final String parm,
      final Throwable e) {
    recordExcFormFin(ResourceProviderME.get(key, parm), e);
  }

  /* Record the exception in the loading form, log it and give std error. */
  final public void recordExcFormFin(final String causeMsg, final Throwable e) {
    recordExcForm(causeMsg, e);
    recordFin();
  }

  //#ifdef DMIDP20
  final public void setCurrentItem(Item item) {
    Display.getDisplay(this).setCurrentItem(item);
    m_display.setCurrentItem(item);
    wakeUp();
  }
  //#endif

  /* Set current displayable and wake up the thread. */
  final public void setCurrent(Displayable disp) {

    //#ifdef DTESTUI
    String title = "";
    if (disp instanceof Form) {
      title = ((Form)disp).getTitle();
    } else if (disp instanceof List) {
      title = ((List)disp).getTitle();
    }
    System.out.println("Test UI setCurrent " + disp.getClass().getName() + "," + title);
    //#endif
        Display.getDisplay(this).setCurrent( disp );
    m_display.setCurrent( disp );
    wakeUp();
  }

  //#ifdef DTESTUI
  /* Get current displayable. */
  final public Displayable getCurrent() {
    return m_display.getCurrent();
  }
  //#endif

  /* Set current displayable and wake up the thread. */
  final public void setCurrent(Alert alert, Displayable disp) {
    Display.getDisplay(this).setCurrent( alert, disp );
    m_display.setCurrent( alert, disp );
    wakeUp();
  }

  /* Notify us that we are finished. */
  final public void wakeUp() {
   
    synchronized(this) {
      m_needWakeup = true;
      super.notify();
    }
  }

    /** Show item form */
    final public void showItemForm() {
    setCurrent( m_itemForm );
    }
   
  //#ifdef DTESTUI
  /** Cause item form to go back to the prev form. */
    final public void backFrItemForm() {
    commandAction( m_backCommand, m_itemForm );
    }
   
    /** Show item form */
    final public boolean isItemForm() {
        return (m_display.getCurrent() == m_itemForm);
    }
  //#endif
   
    /** Initialize RSS item form */
    final public void initializeItemForm(final RssItunesFeed feed,
                   final RssItunesItem item,
                   List prevList) {
        System.out.println("Create new item form");
    String title = item.getTitle();
    boolean hasTitle = true;
    //#ifdef DTEST
    System.gc();
    long beginMem = Runtime.getRuntime().freeMemory();
    //#endif
    if (title.length() == 0) {
      hasTitle = false;
      title = getItemDescription(item.getDescription());
    }
    //#ifdef DTEST
    m_itemForm = new PromptForm( this, title );
    //#else
    m_itemForm = new Form( title );
    //#endif
    final boolean pageEnabled = m_appSettings.getPageEnabled();
    final boolean htmlEnabled = m_appSettings.getHtmlEnabled();
    int fontSize = pageEnabled ? getFontSize() : 0;
    m_itemForm.addCommand( m_backCommand );
    final String sienclosure = item.getEnclosure();
    String desc = item.getDescription();
    String descLabel;
    if (hasTitle) {
      if (desc.length()>0) {
        descLabel = title;
      } else {
        descLabel = "Title\n";
        desc = title;
      }
    } else {
      descLabel = "Description\n";
    }
    Item descItem = getTextItem(pageEnabled, htmlEnabled, descLabel, desc,
        fontSize, false, m_itemForm, prevList);
    m_itemForm.append(descItem);
    citem = item;
    //#ifdef DITUNES
    if (m_itunesEnabled && (item.isItunes() || feed.isItunes())) {
      final String author = item.getAuthor();
      if (author.length() > 0) {
        m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Author:", author, fontSize, false, m_itemForm,
              prevList));
      }
      final String subtitle = item.getSubtitle();
      if (subtitle.length() > 0) {
        m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Subtitle:", subtitle, fontSize, false, m_itemForm,
              prevList));
      }
      final String summary = item.getSummary();
      if (summary.length() > 0) {
        m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Summary:", summary, fontSize, false, m_itemForm,
              prevList));
      }
      final String duration = item.getDuration();
      if (duration.length() > 0) {
        m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Duration:", duration, fontSize, false, m_itemForm,
              prevList));
      }
      String expLabel = "Explicit:";
      String explicit = item.getExplicit();
      if (explicit.equals(RssItunesItem.UNSPECIFIED)) {
        expLabel = "Feed explicit:";
        explicit = feed.getExplicit();
      }
      m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
            expLabel, explicit, fontSize, false, m_itemForm,
            prevList));
    }
    //#endif
    String linkLabel = "Link:";
        String link = item.getLink();
    //#ifdef DITUNES
    if (link.length() == 0) {
      link = feed.getLink();
      linkLabel = "Feed link:";
    }
    //#endif
    if (link.length() > 0) {
      // Always use page enabled since the link contains no html.
      // However if page is enabled, it can get underlined.
      citemLnkNbr  = m_itemForm.append(
          getTextItem(pageEnabled || htmlEnabled, false,
              linkLabel, link, fontSize, true, m_itemForm,
                prevList));
    } else {
      citemLnkNbr  = -1;
    }
    if (sienclosure.length() > 0) {
      citemEnclNbr = m_itemForm.append(
          getTextItem(pageEnabled || htmlEnabled, false,
          "Enclosure:", sienclosure, fontSize, true, m_itemForm,
          prevList));
    } else {
      citemEnclNbr  = -1;
    }
       
        // Add item's date if it is available
    String dateLabel = "Date:";
        Date itemDate = item.getDate();
    //#ifdef DITUNES
        if(itemDate==null) {
      itemDate = feed.getDate();
      dateLabel = "Feed date:";
    }
    //#endif
        if(itemDate!=null) {
      m_itemForm.append(getTextItem(pageEnabled, htmlEnabled,
            dateLabel, itemDate.toString(), fontSize, false,
            m_itemForm, prevList));
        }

    m_itemRtnList = prevList;
    //#ifdef DMIDP20
    if (link.length() > 0) {
      m_itemForm.addCommand( m_openLinkCmd );
    }
    if (sienclosure.length() > 0) {
      m_itemForm.addCommand( m_openEnclosureCmd );
    }
    //#endif
    if (link.length() > 0) {
      m_itemForm.addCommand( m_copyLinkCmd );
    }
    if (sienclosure.length() > 0) {
      m_itemForm.addCommand( m_copyEnclosureCmd );
    }
    //#ifndef DSMALLMEM
    m_itemForm.addCommand( m_rssItemHelpCmd );
    //#endif
    //#ifdef DTEST
    m_itemForm.addPromptCommand( m_testClearCmd,
          ResourceProviderME.get("text.w.q") );
    //#endif
        m_itemForm.setCommandListener( this );
    //#ifdef DTEST
    System.gc();
    System.out.println("itemForm size=" + (beginMem - Runtime.getRuntime().freeMemory()));
    //#endif
    //#ifdef DMIDP20
    setCurrentItem( descItem );
    //#else
    setCurrent( m_itemForm );
    //#endif
    }

  /* Get the font size. */
  final int getFontSize() {
    int fontSize;
    switch (m_appSettings.getFontSize()) {
      case 0:
        fontSize = Font.getDefaultFont().getSize();
        break;
      case 1:
        fontSize = Font.SIZE_SMALL;
        break;
      case 2:
        fontSize = Font.SIZE_MEDIUM;
        break;
      case 3:
        fontSize = Font.SIZE_LARGE;
        break;
      default:
        fontSize = Font.getDefaultFont().getSize();
        break;
    }
    return fontSize;
  }

  /** Get page custom item or StringItem if or not pageEnabled or
      PageCustomItem gives an error. */
  final private Item getTextItem(boolean pageEnabled, boolean htmlEnabled,
      String textLabel,
      String text, int fontSize, boolean underlined, Form descForm,
      List prevList) {
    //#ifdef DMIDP20
    if (pageEnabled || htmlEnabled) {
      /* This is a custom item only present in MIDP 2.0 */
      try {
        return new PageCustomItem(textLabel,
              descForm.getWidth(), descForm.getHeight(),
              fontSize, underlined, htmlEnabled, text, prevList,
              this);
      } catch (Exception e) {
      }
    }
    if (underlined) {
      return new StringItem(textLabel, text, Item.HYPERLINK);
    } else {
    //#endif
      return new StringItem(textLabel, text);
    //#ifdef DMIDP20
    }
    //#endif
  }

  /** Get the max words configured from the descritption. */
  final public String getItemDescription( final String desc ) {
    final String [] parts = StringUtil.split(desc, ' ');
    StringBuffer sb = new StringBuffer();
        final int wordCount = Math.min(parts.length,
        m_appSettings.getMaxWordCountInDesc());
    for (int ic = 0; ic < wordCount; ic++) {
      if (ic > 0) {
        sb.append(" ");
      }
      sb.append(parts[ic]);
    }
    return sb.toString();
  }
   
    /**
     * Start up the Hello MIDlet by creating the TextBox and associating
     * the exit command and listener.
     */
    public void startApp() {
    if (!m_netThread.isAlive()) {
      m_process = true;
      try {
        //#ifdef DCLDCV11
        m_netThread = new Thread(this, "RssReaderMIDlet");
        //#else
        m_netThread = new Thread(this);
        //#endif
        m_netThread.start();
      } catch (Exception e) {
        System.err.println("Could not restart thread.");
        e.printStackTrace();
        //#ifdef DLOGGING
        logger.severe("Could not restart thread.", e);
        //#endif
      }
      //#ifdef DLOGGING
      logger.info("RssReaderMIDlet thread not started.  Started now.");
      //#endif
    }
    }
   
    /**
     * Pause is a no-op since there are no background activities or
     * record stores that need to be closed.
     */
    public void pauseApp() {
    m_process = false;
    wakeUp();
    }
   
    /**
     * Destroy must cleanup everything not handled by the garbage collector.
     * In this case we need to save the bookmarks/feeds:w
     */
    public void destroyApp(boolean unconditional)
    throws MIDletStateChangeException {
    //#ifdef DLOGGING
    logger.info("RecordStore.listRecordStores() != null=" + (RecordStore.listRecordStores() != null));
    //#endif
    if (!m_exit && !m_stored && !m_saving) {
      //#ifdef DLOGGING
      logger.getParent().setLevel(Level.OFF);
      //#endif
      // Show that we are exiting.  Since the application is destroyed
      // this may cause an error.
      try {
        /* Exiting saving data... */
        initializeLoadingFormRsc("text.e.sav", m_bookmarkList);
      } catch (Throwable t) {
      }
      storeSettings(false, false, true);
    }
      if (unconditional) {
      // If unconditional, we are to release all resources and stop
      // threads.
      m_process = false;
    }
    }
   
    /** Save bookmarks to record store
        releaseMemory use true if exiting as we do not need
    the rss feeds anymore, so we can save memory and avoid
    having extra memory around.  */
    final public void saveBookmarks(final boolean saveMemoryEnabled,
      final long storeDate, final boolean saveHdr,
      final boolean saveItems, final int region,
                  boolean releaseMemory) {
    //#ifdef DLOGGING
    if (finestLoggable) {logger.finest("saveHdr,saveItems,region,releaseMemory=" + saveHdr + "," + saveItems + "," + region + "," + releaseMemory);}
    //#endif
    StringBuffer bookmarks = new StringBuffer();
    m_settings.setStringProperty("bookmarks", bookmarks.toString());
    final int bsize = m_bookmarkList.size();
    if (bsize == 0) {
      return;
    }
    //#ifdef DTEST
    long storeTime = 0L;
    long encodeTime = 0L;
    long splitTime = 0L;
    long joinTime = 0L;
    //#endif
    final int bookRegion = region - 1;
    final int iparts = m_settings.MAX_REGIONS - 1;
    final int firstIx = bookRegion * bsize / iparts;
    final int endIx = (bookRegion + 1) * bsize / iparts - 1;
        try {
      //#ifdef DLOGGING
      if (finestLoggable) {logger.finest("firstIx,endIx=" + firstIx + "," + endIx);}
      //#endif
      Vector vstored = new Vector();
      try {
        /** Try to save feeds including items */
        for( int i=firstIx; i<=endIx; i++) {
          final String name = m_bookmarkList.getString(i);
          //#ifdef DLOGGING
          if (finestLoggable) {logger.finest("i,name=" + i + "," + name);}
          //#endif
          if (!m_rssFeeds.containsKey( name )) {
            continue;
          }
          if( name.length()>0) {
            String store = null;
            //#ifdef DTEST
            long beginStore = System.currentTimeMillis();
            //#endif
            //#ifdef DCOMPATIBILITY
            appendCompatBmk(i, name, bookmarks);
            //#else
            RssItunesFeed rss = null;
            /* This is where things are normally done when not */
            /* testing compatibility. */
            if (saveMemoryEnabled) {
              /* Get unencoded store string. */
              store = m_rssFeeds.getRoStoreStr( name );
              /* Get encoded store string. */
              RssStoreInfo rsi = RssItunesFeed.getStoreStringInfo(true,
                  true, store, false);
              //#ifdef DTEST
              encodeTime += rsi.getEncodeTime();
              splitTime += rsi.getSplitTime();
              joinTime += rsi.getJoinTime();
              //#endif
              store = rsi.getStoreString();
            } else {
              rss = (RssItunesFeed)m_rssFeeds.get( name );
            }
            if (saveMemoryEnabled) {
              bookmarks.append(store);
            } else {
              bookmarks.append(rss.getStoreString(saveHdr,
                    saveItems, true));
            }
            //#endif
            //#ifdef DTEST
            storeTime += System.currentTimeMillis() - beginStore;
            //#endif
            //#ifdef DCOMPATIBILITY1
            bookmarks.append(OLD_FEED_SEPARATOR);
            //#elifdef DCOMPATIBILITY2
            bookmarks.append(OLD_FEED_SEPARATOR);
            //#elifdef DCOMPATIBILITY3
            bookmarks.append(OLD_FEED_SEPARATOR);
            //#else
            bookmarks.append(CFEED_SEPARATOR);
            //#endif
            if (releaseMemory) {
              vstored.addElement( name );
            }
          }
        }
      } catch(OutOfMemoryError error) {
        /* Don't release memory so that we can re-try. */
        releaseMemory = false;
        bookmarks.setLength(0);
        System.gc();
        recordExcForm("Out of memory error saving feeds.", error);
        throw error;
       
      } finally {
        if (!saveMemoryEnabled && releaseMemory) {
          final int vslen = vstored.size();
          for (int ic = 0; ic < vslen; ic++) {
            final RssItunesFeed rss =
              (RssItunesFeed)m_rssFeeds.get(
             (String)vstored.elementAt( ic ));
            rss.setItems(new Vector(0));
          }
        }
      }
      //#ifdef DTEST
      System.out.println("storeTime=" + storeTime);
      //#endif
      //#ifdef DTEST
      m_loadForm.appendMsg("Str len=" + bookmarks.toString().length());
      //#endif
            m_settings.setStringProperty("bookmarks", bookmarks.toString());
      //#ifdef DLOGGING
      if (fineLoggable) {logger.fine("bookmarks.length()=" + bookmarks.length());}
      //#endif
      //#ifndef DCOMPATIBILITY
      m_settings.setBooleanProperty(m_settings.ITEMS_ENCODED, true);
      m_settings.setLongProperty(m_settings.STORE_DATE, storeDate);
      //#endif
    } catch(OutOfMemoryError error) {
      throw error;
    } catch (Throwable t) {
            m_settings.setStringProperty("bookmarks", bookmarks.toString());
      //#ifdef DTEST
      System.out.println("storeTime=" + storeTime);
      //#endif
//#ifdef DLOGGING
      logger.severe("saveBookmarks could not save.", t);
//#endif
      System.out.println("saveBookmarks could not save." + t + " " +
                     t.getMessage());
      t.printStackTrace();
        }
    //#ifdef DTEST
    m_loadForm.appendMsg("storeTime=" + storeTime);
    m_loadForm.appendMsg("encodeTime=" + encodeTime);
    m_loadForm.appendMsg("splitTime=" + splitTime);
    m_loadForm.appendMsg("joinTime=" + joinTime);
    //#endif
    }

  //#ifdef DCOMPATIBILITY
  /* Append compatibility store to allow testing from previous stores. */
  final private void appendCompatBmk(final int i, final String name,
      StringBuffer bookmarks)
  throws Exception {
    //#ifdef DCOMPATIBILITY1
    final RssItunesFeed rss =
      (RssItunesFeed)m_rssFeeds.get( name );
    CompatibilityRssFeed1 rss1 = new CompatibilityRssFeed1(rss);
    //#ifdef DTEST
    String prevStore = rss1.getStoreString( true );
    RssItunesFeed nrss = RssItunesFeed.deserialize( true, prevStore );
    if (!rss1.equals(nrss)) {
      //#ifdef DLOGGING
      logger.severe("itunes store stings not backwards compatible i=" + i);
      //#endif
    }
    long beginStore = System.currentTimeMillis();
    //#endif
    bookmarks.append(rss1.getStoreString(true));
    //#elifdef DCOMPATIBILITY2
    final RssItunesFeed rss =
      (RssItunesFeed)m_rssFeeds.get( name );
    CompatibilityRssFeed2 rss2 = new CompatibilityRssFeed2(rss);
    final String prevStore = rss2.getStoreString(true);
    bookmarks.append(prevStore);
    //#ifdef DTEST
    RssItunesFeed nrss = new RssItunesFeed(new RssFeed(
              false, true, prevStore ));
    if (!rss2.equals(nrss)) {
      //#ifdef DLOGGING
      logger.severe("itunes store stings not backwards compatible i=" + i);
      //#endif
    }
    long beginStore = System.currentTimeMillis();
    //#endif
    //#elifdef DCOMPATIBILITY3
    final RssItunesFeed rss =
      (RssItunesFeed)m_rssFeeds.get( name );
    CompatibilityRssItunesFeed3 rss3 =
      new CompatibilityRssItunesFeed3(rss);
    final String prevStore = rss3.getStoreString(
        true, true);
    bookmarks.append(prevStore);
    //#ifdef DTEST
    RssItunesFeed nrss = new RssItunesFeed(new RssFeed(
              false, true, prevStore ));
    if (!rss3.equals(nrss)) {
      //#ifdef DLOGGING
      logger.severe("itunes store stings not backwards compatible i=" + i);
      //#endif
    }
    long beginStore = System.currentTimeMillis();
    //#endif
    //#endif
  }
  //#endif

  /* (Req)est set flag to show go to item form.
     itemRtnForm - Form to return to after display item finished.
  */
  final public void reqItemForm(final List itemRtnList,
                    RssItunesFeed feed) {
    m_itemRtnList = itemRtnList;
    if ( feed != null ) {
      m_curRssParser = new RssFeedParser( feed );
    }
    m_showItem = true;
  }

  //#ifdef DJSR75
  /* Set flag to show find files list.
     fileRtnForm - Form to return to after file finished.
     fileURL - Text field that has URL to put file URL into as well
            as field to go back to if 2.0 is valid.
  */
  final public void reqFindFiles( final Form fileRtnForm,
                     final TextField fileURL) {
    m_fileRtnForm = fileRtnForm;
    m_fileURL = fileURL;
    m_getFile = true;
  }
  //#endif

  /* Save the current bookmarks and other properties.
     saveItems  - true if want to save items (use false if running out
               of memory.
     releaseMemory - true if memory used is to be released as the
                bookmarks are saved.  Used when exitiing as true.
  */
  final private void saveBkMrkSettings(boolean saveMemoryEnabled,
      final long storeDate,
      final boolean saveHdr,
      final boolean saveItems, final String mkey,
      final boolean releaseMemory)
  throws RecordStoreFullException, Throwable {
    Gauge gauge = new Gauge(ResourceProviderME.get(mkey),
        false, m_settings.MAX_REGIONS + 1, 0);
    int pl = m_loadForm.append(gauge);
    try {
      try {
        m_settings.setStringProperty("bookmarks","");
        //#ifndef DCOMPATIBILITY
        m_settings.setLongProperty(m_settings.STORE_DATE, storeDate);
        m_settings.setBooleanProperty(m_settings.ITEMS_ENCODED, true);
        //#endif
        //#ifdef DTEST
                long lngStart = System.currentTimeMillis();
        //#endif
        m_settings.save(0, false);
        gauge.setValue(1);
        //#ifdef DTEST
                m_loadForm.appendMsg("Save time=" +
            (System.currentTimeMillis()-lngStart));
        //#endif
        for (int ic = 1; ic < m_settings.MAX_REGIONS; ic++) {
          saveBookmarks(saveMemoryEnabled, storeDate, saveHdr,
              saveItems, ic, releaseMemory);
          //#ifdef DTEST
          lngStart = System.currentTimeMillis();
          //#endif
          m_settings.save(ic, false);
          //#ifdef DTEST
          m_loadForm.appendMsg("Save time=" +
              (System.currentTimeMillis()-lngStart));
          //#endif
          gauge.setValue(ic + 1);
        }
        // Set internal region back to 0.
        m_settings.setStringProperty("bookmarks","");
        gauge.setValue(m_settings.MAX_REGIONS + 1);
        pl = -1;
      } catch(OutOfMemoryError e) {
        /* Error during save out of memory. */
        throw new CauseMemoryException(ResourceProviderME.get("exc.sv.om"), e);
      }
    } catch(CauseRecStoreException e) {
      if ((e.getFirstCause() != null) &&
        !(e.getFirstCause() instanceof RecordStoreFullException)) {
        /* Error saving feeds to database.  Database error. */
        recordExcFormRsc("exc.sv.dbe", e);
      } else {
        /* Error saving feeds to database.  Database full. */
        recordExcFormRsc("exc.sv.dbf", e);
        if (saveItems) {
          /* Retrying without saving items to save space in database. */
          m_loadForm.appendMsg(ResourceProviderME.get("text.sv.rwo"));
          if (pl >= 0) {
            m_loadForm.delete(pl);
            pl = -1;
          }
          saveBkMrkSettings(saveMemoryEnabled, storeDate, true,
              false, "label.save.d", releaseMemory);
          m_loadForm.appendMsg("Retry successful.");
        } else {
          throw e;
        }
      }
  } catch(CauseMemoryException e) {
    recordExcForm("Error saving feeds.  Out of memory error.", e);
    if (saveItems) {
      /* Retrying without saving items to save space in memory. */
      m_loadForm.appendMsg(ResourceProviderME.get("text.sv.rwo"));
      if (pl >= 0) {
        m_loadForm.delete(pl);
        pl = -1;
      }
      saveBkMrkSettings(saveMemoryEnabled, System.currentTimeMillis(),
          true, false, "label.save.d", m_exit);
      m_loadForm.appendMsg("Retry successful.");
    } else {
      throw e;
    }
    } catch(Exception e) {
      recordExcForm("Internal error saving feeds.", e);
      throw e;
    } catch(Throwable t) {
      recordExcForm("Internal error saving feeds.", t);
      throw t;
    } finally {
      if (pl >= 0) {
        m_loadForm.delete(pl);
      }
    }
  }

  /** Remove the ref to this displayable so that the memory can be freed. */
  final public void removeRef(final Displayable disp) {
    m_loadForm.removeRef(disp);
  }

    /** Respond to commands */
    public void commandAction(final Command c, final Displayable s) {
    int ctype = c.getCommandType();
    //#ifdef DLOGGING
    //#ifdef DMIDP20
    if (finestLoggable) {logger.finest("command,ctype,displayable=" + c.getLabel() + "," + ctype + "," + s.getTitle());}
    //#else
    if (finestLoggable) {logger.finest("command,displayable=" + c.getLabel());}
    //#endif
    //#endif

        /** Manage bookmarks */
        if( c == m_manageBkmrk ){
      m_mainBmk = false;
      updBookmarkList();
        }
       
        /** Main bookmarks */
        if( c == m_backCommand ){
      m_mainBmk = true;
      updBookmarkList();
        }
       
        /** Add new RSS feed bookmark */
        if( c == m_addNewBookmark ){
      m_curBookmark = UiUtil.getSelectedIndex(m_bookmarkList);
      m_getAddBMForm = true;
        }
       
        /** Exit from MIDlet and save bookmarks */
        if( c == m_exitCommand ){
      if (!m_saving && !m_stored) {
        m_exit = true;
        synchronized (this) {
          if ( !m_netThread.isAlive() ) {
            m_netThread.start();
            //#ifdef DLOGGING
            if (finestLoggable) {logger.finest("Thread started.");}
            //#endif
          }
        }
      }
        }
       
    //#ifdef DTEST
        /** Exit from MIDlet and save bookmarks */
        if( c == m_testClearCmd ){
      /* Trick to think that data was stored.  We want to remove the
         database. */
      m_stored = true;
      try {
        Settings.deleteStore();
        destroyApp(true);
      } catch (MIDletStateChangeException e) {
      }
      super.notifyDestroyed();
    }
    //#endif

        /** Save bookmarks without exit (don't free up bookmarks)  */
        if( c == m_saveCommand ){
      m_saveBookmarks = true;
        }
       
    //#ifdef DTEST
        /** Save bookmarks without exit (don't free up bookmarks)  */
        if( c == m_testSaveCommand ){
      m_testSaveBookmarks  = true;
        }
    //#endif
       
        /** Edit currently selected RSS feed bookmark */
        if( c == m_editBookmark ){
      m_getEditBMForm = true;
        }
       
        /** Delete currently selected RSS feed bookmark */
        if( c == m_delBookmark ){
      m_curBookmark = m_bookmarkList.getSelectedIndex();
            if( m_curBookmark>=0 ){
                String name = m_bookmarkList.getString(m_curBookmark);
                m_bookmarkList.delete( m_curBookmark );
        if (m_rssFeeds.containsKey( name )) {
          m_rssFeeds.remove( name );
        }
            }
        }
       
        /** Open RSS feed bookmark */
        if( c == m_openBookmark || (c == List.SELECT_COMMAND &&
                m_display.getCurrent()==m_bookmarkList)){
      m_openPage = true;
        }
       
        /** Read unread items date sorted */
        if( c == m_readUnreadItems ) {
      if (m_bookmarkList.size() > 0) {
        m_runNews = true;
      }
        }
       
        /** Open RSS feed's selected topic */
        /** Get back to RSS feed headers */
        if( (s instanceof Form) &&
            (((Form)s) == m_itemForm) && (ctype == Command.BACK) ){
            if ( m_itemRtnList != null) {
        setCurrent( m_itemRtnList );
        m_itemRtnList  = null;
      }
      //#ifdef DTESTUI
      if (m_headerIndex >= 0) {
        m_headerNext = true;
      } else if (m_unreadHeaderTestList != null) {
        m_unreadHeaderTestList.gotoNews();
      }
      //#endif
        }
       
        /** Copy link to clipboard.  */
        if( c == m_copyLinkCmd ){
      String link = citem.getLink();
      m_itemForm.set(citemLnkNbr, new TextField("Link:", link,
          link.length(), TextField.URL));
      //#ifdef DMIDP10
      setCurrent(m_itemForm);
      //#else
      setCurrentItem(m_itemForm.get(citemLnkNbr));
      //#endif
        }
       
        /** Copy enclosure to clipboard.  */
        if( c == m_copyEnclosureCmd ){
      final String link = citem.getEnclosure();
      m_itemForm.set(citemEnclNbr, new TextField("Enclosure:",
                link, link.length(), TextField.URL));
      //#ifdef DMIDP10
      setCurrent(m_itemForm);
      //#else
      setCurrentItem(m_itemForm.get(citemEnclNbr));
      //#endif
        }

    //#ifndef DSMALLMEM
    /** Help for RSS item. */
        if( c == m_rssItemHelpCmd ){
      final HelpForm helpForm = new HelpForm(this, m_itemForm);
      helpForm.appendRsc("text.kpd.help");
    }
    //#endif
       
    //#ifdef DMIDP20
        /** Go to link and get back to RSS feed headers */
        if( c == m_openLinkCmd ){
      final String link = citem.getLink();
      m_platformReq = true;
      m_platformURL = link;
      wakeUp();
    }
    //#endif

    //#ifdef DMIDP20
        /** Go to link and get back to RSS feed headers */
        if( c == m_openEnclosureCmd ){
      m_platformReq = true;
      m_platformURL = citem.getEnclosure();
      wakeUp();
    }
    //#endif
       
        /** Update all RSS feeds */
        if( c == m_updateAllCmd ) {
      m_refreshAllFeeds = true;
        }
       
        /** Update all RSS feeds */
        if( c == m_updateAllModCmd ) {
      m_refreshUpdFeeds = true;
        }
       
        /** Show import feed list form */
        if( c == m_importFeedListCmd ) {
      // Set current bookmark so that the added feeds go after
      // the current boolmark.
      m_curBookmark = UiUtil.getSelectedIndex(m_bookmarkList);
      m_getImportForm = true;
      wakeUp();
        }
       
    //#ifdef DTEST
    /** Show import feed list form and default file */
    if( c == m_importCurrFeedListCmd ) {
      if( m_bookmarkList.size()>0 ) {
        m_curBookmark = UiUtil.getSelectedIndex(m_bookmarkList);
        //#ifdef DTESTUI
        m_bookmarkLastIndex = m_curBookmark;
        //#endif
        m_getImportForm = true;
        m_getTestImportForm = true;
        wakeUp();
      }
        }
    //#endif

    //#ifdef DTESTUI
        /** Auto edit feeds/bookmarks to */
        if( c == m_testBMCmd ) {
      m_bookmarkIndex = 0;
      System.out.println("Test UI Test Rss feeds m_bookmarkIndex=" + m_bookmarkIndex);
    }
    //#endif

    //#ifdef DTESTUI
        /** Go back to last position */
        if( c == m_testRtnCmd ) {
      if (m_bookmarkLastIndex != 1) {
        if (m_bookmarkList.getSelectedIndex() >= 0) {
          m_bookmarkList.setSelectedIndex(
              m_bookmarkList.getSelectedIndex(), false);
        }
        m_bookmarkList.setSelectedIndex( m_bookmarkLastIndex, true );
      }
    }
    //#endif

        /** Settings form */
        if( c == m_settingsCmd ) {
      m_getSettingsForm = true;
      wakeUp();
        }
       
    //#ifndef DSMALLMEM
        /** Show help */
    if( c == m_helpCmd ) {
      m_getHelpForm = true;
    }
    //#endif

    //#ifdef DTESTUI
        /** Show encodings list */
    if( c == m_testEncCmd ) {
      try {
        /* Loading test form... */
        showLoadingFormRsc("text.l.t", m_bookmarkList);
        setCurrent( m_testingForm );
      } catch (Exception e) {
      }
    }
    //#endif

  //#ifdef DLOGGING
        /** Show about */
    if( c == m_debugCmd ) {
      if (m_debug == null) {
        Alert invalidAlert = new Alert(
            "No FormHandler",
            "No FormHandler.",
            null,
            AlertType.WARNING);
        invalidAlert.setTimeout(Alert.FOREVER);
        setCurrent( invalidAlert, m_bookmarkList );
      } else {
        setCurrent( m_debug );
      }
    }

        /** Clear form */
    if( c == m_clearDebugCmd ) {
      UiUtil.delItems(m_debug);
    }

        /** Back to bookmarks */
        if ((s instanceof Form) &&
            (((Form)s) == m_debug) && (ctype == Command.BACK) ){
      setCurrent( m_bookmarkList );
    }

    //#endif
    wakeUp();

    }
   
  //#ifdef DTESTUI
    public void setBookmarkIndex(int bookmarkIndex) {
        this.m_bookmarkIndex = bookmarkIndex;
    }

    public int getBookmarkIndex() {
        return (m_bookmarkIndex);
    }
  //#endif

  /* Form to add new/edit existing bookmark. */
  final private class HeaderList extends List implements CommandListener {

    private RssReaderMIDlet m_midlet;       // RssReaderMIDlet midlet
    private Command     m_openHeaderCmd;    // The open header command
    private Command     m_backHeaderCmd;    // The back to bookmark list command
    private Command     m_updateCmd;        // The update headers command
    private Command     m_updateModCmd;     // The update modified headers command
    //#ifdef DITUNES
    private Command     m_bookmarkDetailsCmd;   // The show feed details
    //#endif

    /* Constructor */
    private HeaderList(RssReaderMIDlet midlet, final RssItunesFeed feed) {
      super("Headers", List.IMPLICIT);
      this.m_midlet = midlet;
      final boolean open1st = m_appSettings.getFeedListOpen();
      //#ifdef DLOGGING
      if (fineLoggable) {logger.fine("initheader open1st=" + open1st);}
      //#endif
      if (open1st) {
        // Initialize m_backHeaderCmd in form initialization so that we can
        // change it per user request.
        /* Open item */
        m_openHeaderCmd = UiUtil.getCmdRsc("cmd.op.i", Command.SCREEN, 1);
        m_backHeaderCmd = UiUtil.getCmdRsc("cmd.back", Command.BACK, 2);
        super.addCommand(m_openHeaderCmd);
        super.addCommand(m_backHeaderCmd);
      } else {
        m_backHeaderCmd = UiUtil.getCmdRsc("cmd.back", Command.BACK, 1);
        /* Open item */
        m_openHeaderCmd = UiUtil.getCmdRsc("cmd.op.i", Command.SCREEN, 2);
        super.addCommand(m_backHeaderCmd);
        super.addCommand(m_openHeaderCmd);
      }
      /* Update feed */
      m_updateCmd         = UiUtil.getCmdRsc("cmd.u.fd", Command.SCREEN, 2);
      /* Update modified feed */
      m_updateModCmd      = UiUtil.getCmdRsc("cmd.um.fd",
                        Command.SCREEN, 2);
      super.addCommand(m_updateCmd);
      super.addCommand(m_updateModCmd);
      //#ifdef DTESTUI
      super.addCommand(m_testRssCmd);
      //#endif
      //#ifdef DITUNES
      if (m_itunesEnabled && feed.isItunes()) {
        /* Show bookmark details */
        m_bookmarkDetailsCmd    = UiUtil.getCmdRsc("cmd.s.bdt",
            Command.SCREEN, 4);
        super.addCommand(m_bookmarkDetailsCmd);
      }
      //#endif
      super.setCommandListener(this);
    }
   
    /** Fill RSS header list */
    final private void fillHeadersList() {
      UiUtil.delItems(this);
      RssItunesFeed feed = m_curRssParser.getRssFeed();
      super.setTitle( feed.getName() );
      final boolean markUnreadItems = m_appSettings.getMarkUnreadItems();
      final Vector vitems = feed.getItems();
      final int itemLen = vitems.size();
      for(int i=0; i < itemLen; i++){
        RssItunesItem r = (RssItunesItem)vitems.elementAt(i);
        String text = r.getTitle();
        if (text.length() == 0) {
          text = getItemDescription(r.getDescription());
        }
        if (markUnreadItems) {
          if (r.isUnreadItem()) {
            super.append( text, m_unreadImage );
          } else {
            super.append( text, m_readImage );
          }
        } else {
          super.append( text, null );
        }
      }
    }
   
    //#ifdef DTEST
    /** Test that the feed is not ruined by being stored and restored. */
    final private void testFeed(final boolean encoded) {
      RssItunesFeed feed = m_curRssParser.getRssFeed();
      String store = feed.getStoreString(true, true, encoded);
      boolean feedEq;
      RssItunesFeed feed2;
      try {
        feed2 = RssItunesFeed.deserialize( encoded, store );
        feedEq = feed.equals(feed2);
      } catch (Throwable t) {
        recordExcForm("Error while deserialize feed.", t);
        feedEq = false;
      }
      //#ifdef DLOGGING
      if (finestLoggable) {logger.finest("feed1,2 encoded,eq=" + encoded + "," + feedEq);}
      //#endif
      if (!feedEq) {
        //#ifdef DLOGGING
        logger.severe("Itunes feed does not match name=" + feed.getName());
        //#endif
        System.out.println("feed=" + feed + "," + feed.toString());
        System.out.println("feed store=" + store);
      }
    }
    //#endif

    //#ifdef DTEST
    /** Test that the feed is not ruined by being stored and transformed. */
    final private void testFeed2(final boolean encoded) {
      RssItunesFeed feed = m_curRssParser.getRssFeed();
      String store1 = feed.getStoreString(true, true, encoded);
      String store2 = feed.getStoreString(true, true, !encoded);
      String name1 = feed.getName();
      boolean feedEq;
      boolean feedEq2;
      String store2b = "";
      String name2 = "";
      try {
        RssStoreInfo ri = RssItunesFeed.getStoreStringInfo( true,
            !encoded, store1, encoded );
        store2b = ri.getStoreString();
        name2 = ri.getName();
        feedEq = store2.equals(store2b);
        feedEq2 = name1.equals(name2);
      } catch (Throwable t) {
        recordExcForm("Error while deserialize feed.", t);
        feedEq = false;
        feedEq2 = false;
      }
      //#ifdef DLOGGING
      if (finestLoggable) {logger.finest("feed1,2 encoded,eq,2=" + encoded + "," + feedEq + "," + feedEq2);}
      //#endif
      if (!feedEq || !feedEq2) {
        //#ifdef DLOGGING
        logger.severe("Itunes feed does not match name=" + feed.getName());
        //#endif
        System.out.println("store2=\n" + store2);
        System.out.println("store2b=\n" + store2b);
        System.out.println("name1=" + name1);
        System.out.println("name2=" + name2);
      }
    }
    //#endif

    //#ifdef DITUNES
    /** Initialize RSS bookmark feed details form */
    final private Form initializeDetailsForm( final RssItunesFeed feed ) {
      //#ifdef DTEST
      System.gc();
      long beginMem = Runtime.getRuntime().freeMemory();
      //#endif
      Form displayDtlForm = new Form( feed.getName() );
      displayDtlForm.addCommand( m_backCommand );
      displayDtlForm.setCommandListener(this);
      final boolean pageEnabled = m_appSettings.getPageEnabled();
      final boolean htmlEnabled = m_appSettings.getHtmlEnabled();
      int fontSize = pageEnabled ? getFontSize() : 0;
      if (m_itunesEnabled && feed.isItunes()) {
        final String language = feed.getLanguage();
        if (language.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "Language:", language, fontSize, false,
                displayDtlForm, this));
        }
        final String author = feed.getAuthor();
        if (author.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "Author:", author, fontSize, false,
                displayDtlForm, this));
        }
        final String subtitle = feed.getSubtitle();
        if (subtitle.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "Subtitle:",
                subtitle, fontSize, false, displayDtlForm, this));
        }
        final String summary = feed.getSummary();
        if (summary.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "Summary:", summary, fontSize, false,
                displayDtlForm, this));
        }
        displayDtlForm.append(new StringItem("Explicit:", feed.getExplicit()));
        final String title = feed.getTitle();
        if (title.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "title:", title, fontSize, false,
                displayDtlForm, this));
        }
        final String description = feed.getDescription();
        if (description.length() > 0) {
          displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
                "Description:", description, fontSize, false,
                displayDtlForm, this));
        }
      }
      final String link = feed.getLink();
      if (link.length() > 0) {
        displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Link:", link, fontSize, true,
              displayDtlForm, this));
      }
      final Date feedDate = feed.getDate();
      if (feedDate != null) {
        displayDtlForm.append(getTextItem(pageEnabled, htmlEnabled,
              "Date:", feedDate.toString(), fontSize, false,
              displayDtlForm, this));
      }
      //#ifdef DTEST
      System.gc();
      System.out.println("displayDtlForm size=" + (beginMem - Runtime.getRuntime().freeMemory()));
      //#endif
      return displayDtlForm;
    }
    //#endif
   
    /** Respond to commands */
    public void commandAction(final Command c, final Displayable s) {

      //#ifdef DTESTUI
      super.outputCmdAct(c, s,
          javax.microedition.lcdui.List.SELECT_COMMAND);
      //#endif

      /** Open RSS feed's selected topic */
      if( c == m_openHeaderCmd || (c == List.SELECT_COMMAND &&
          m_display.getCurrent()==this)) {
        final int selIdx = UiUtil.getSelectedIndex(this);
        if( selIdx >= 0 ) {
          RssItunesFeed feed = m_curRssParser.getRssFeed();
          citem = (RssItunesItem)feed.getItems().elementAt(selIdx);
          final boolean markUnreadItems =
            m_appSettings.getMarkUnreadItems();
          if (markUnreadItems) {
            super.set(selIdx, super.getString(selIdx),
                  m_readImage );
          }
          reqItemForm(this, null);
        }
      }
     
      /** Update currently selected RSS feed's headers */
      if( c == m_updateCmd ) {
        m_prevDisp = this;
        m_getPage = true;
      }

      if( c == m_updateModCmd ) {
        m_prevDisp = this;
        m_getModPage = true;
      }
     
      /** Get back to RSS feed bookmarks */
      if( c == m_backHeaderCmd ){
        m_backFrHdr = true;
        //#ifdef DTESTUI
        m_headerTestList = null;
        m_headerIndex = -1;
        m_headerNext = false;
        m_itemNext = false;
        //#endif
      }
     
      //#ifdef DITUNES
      /** Display Itune's feed detail */
      if( c == m_bookmarkDetailsCmd ) {
        Form displayDtlForm = initializeDetailsForm(
            m_curRssParser.getRssFeed() );
        setCurrent( displayDtlForm );
      }
      //#endif

      /* Back from details form. */
      if( (s instanceof Form) &&
        (c.getCommandType() == Command.BACK) ){
        setCurrent( this );
      }
     
      //#ifdef DTESTUI
      /** Indicate that we want to test the headers/items.  */
      if( c == m_testRssCmd) {
        if( super.size()>0 ) {
          m_headerTestList = this;
          m_headerNext = true;
          m_itemNext = false;
          m_headerIndex = 0;
          System.out.println("Test UI Test Rss items start m_headerIndex=" + m_headerIndex);
        }
      }
      //#endif

    }
  }

  /* Form to add new/edit existing bookmark. */
  final private class BMForm extends Form
  implements CommandListener, Runnable {
    private boolean     m_addForm;          // Flag to indicate is add form
    private String      m_editName;         // Original bookmark name
    private Command     m_addInsCmd;   // The add before the current point?
    private Command     m_addAddCmd;        // The add after the current point?
    private Command     m_addAppndCmd;      // The add append
    private Command     m_clearCmd;         // The clear
    private Command     m_editOkCmd;        // The edit is OK
    private Command     m_addCancelCmd;     // The Cancel command
    //#ifndef DSMALLMEM
    private Command     m_pasteURLCmd;      // The allow paste command
    //#endif
    //#ifndef DSMALLMEM
    private Command     m_helpCmd;          // The help command
    //#endif
    private Command     m_BMFileCmd;        // The find files command
    private TextField   m_bmName;           // The RSS feed name field
    private TextField   m_bmURL;            // The RSS feed URL field
    private TextField   m_bmUsername;       // The RSS feed username field
    private TextField   m_bmPassword;       // The RSS feed password field

    /* Constructor */
    private BMForm(final boolean addForm) {
      super(addForm ? "New Bookmark" : "Edit Bookmark");
      m_bmName = new TextField("Name", "", 64, TextField.ANY);
      m_bmURL  = new TextField("URL", "http://", 256, TextField.URL);
      m_bmUsername  = new TextField("Username (optional)", "", 64, TextField.ANY);
      m_bmPassword  = new TextField("Password (optional)", "", 64, TextField.PASSWORD);
      super.append( m_bmName );
      super.append( m_bmURL );
      super.append( m_bmUsername );
      super.append( m_bmPassword );
      if (addForm) {
        /* Insert bookmark */
        /* Insert current bookmark */
        m_addInsCmd      = UiUtil.getCmdRsc("cmd.i.bmk", "cmd.li.bmk",
            Command.SCREEN, 1);
        /* Add bookmark */
        /* Add current bookmark */
        m_addAddCmd      = UiUtil.getCmdRsc("cmd.a.bmk", "cmd.la.bmk",
            Command.SCREEN, 2);
        /* Append bookmark */
        /* Append end bookmark */
        m_addAppndCmd    = UiUtil.getCmdRsc("cmd.ap.bmk", "cmd.lap.bmk",
            Command.SCREEN, 3);
        /* Clear */
        /* Clear screen */
        m_clearCmd    = UiUtil.getCmdRsc("cmd.clear", "cmd.lclear",
            Command.SCREEN, 4);
        super.addCommand( m_addInsCmd );
        super.addCommand( m_addAddCmd );
        super.addCommand( m_addAppndCmd );
        super.addCommand( m_clearCmd );
      } else {
        m_editOkCmd     = UiUtil.getCmdRsc("cmd.ok", Command.OK, 1);
        super.addCommand( m_editOkCmd );
      }
      m_addCancelCmd      = UiUtil.getCmdRsc("cmd.cancel",
          Command.CANCEL, 5);
      super.addCommand( m_addCancelCmd );
      //#ifdef DJSR75
      /* Find files */
      m_BMFileCmd         = UiUtil.getCmdRsc("cmd.f.fl", Command.SCREEN, 3);
      super.addCommand(m_BMFileCmd);
      //#endif
      //#ifndef DSMALLMEM
      if (m_appSettings.getUseTextBox()) {
        /* Allow paste */
        m_pasteURLCmd       = UiUtil.getCmdRsc("cmd.a.pst", Command.SCREEN, 4);
        super.addCommand(m_pasteURLCmd);
      }
      //#endif
      //#ifndef DSMALLMEM
      m_helpCmd         = UiUtil.getCmdRsc("cmd.help", Command.HELP, 5);
      super.addCommand(m_helpCmd);
      //#endif
      super.setCommandListener( this );
      this.m_addForm = addForm;
      if (addForm && (m_addBMSave != null)) {
        Item[] items = {m_bmName, m_bmURL,
          m_bmUsername, m_bmPassword};
        UiUtil.restorePrevValues(items, m_addBMSave);
      }
    }

    /* Update bookmark info. */
    final private void updateBM(final RssItunesFeed bm) {
      final String name = bm.getName();
      m_editName = name;
      m_bmName.setString( name );
      m_bmURL.setStringbm.getUrl() );
      m_bmUsername.setString( bm.getUsername() );
      m_bmPassword.setString( bm.getPassword() );
    }

    /** Save bookmark into record store and bookmark list */
    final private void saveBookmark()
    throws CauseMemoryException, CauseException {
      final String name = m_bmName.getString();
     
      final String url  = m_bmURL.getString().trim();
     
      final String username = m_bmUsername.getString();
     
      final String password = m_bmPassword.getString();
      /* If name changed, need to remove the previous name. */
      if (!m_addForm && !m_editName.equals(name)) {
        m_rssFeeds.remove(m_editName);
      }
     
      final RssItunesFeed bm = new RssItunesFeed(name, url, username, password);
     
      if (m_addForm) {
        m_bookmarkList.insert(m_addBkmrk, bm.getName(), null);
      } else {
        m_bookmarkList.set(m_curBookmark, bm.getName(), null);
      }
      m_rssFeeds.put(bm.getName(), bm);
    }
   
    /** Respond to commands */
    public void commandAction(final Command c, final Displayable s) {

      /** Save currently added RSS feed's properties */
      m_addBkmrk = UiUtil.getPlaceIndex(c, m_addBkmrk, m_addInsCmd,
          m_addAddCmd, m_addAppndCmd, m_bookmarkList);
      if( m_addBkmrk >= 0 ) {

        try {
          saveBookmark();
          if (m_addForm) {
            Item[] items = {m_bmName, m_bmURL,
              m_bmUsername, m_bmPassword};
            m_addBMSave = UiUtil.storeValues(items);
          }
          setCurrent( m_bookmarkList );
          m_loadForm.removeRef(this);
        } catch (CauseException e) {
          recordExcFormFin("Error while " + (m_addForm ? "adding" :
                "updating") + " bookmark", e);
        }
      }

      /** Save currently edited (or added) RSS feed's properties */
      if( c == m_editOkCmd ){
        try {
          saveBookmark();
          if (m_addForm) {
            Item[] items = {m_bmName, m_bmURL,
              m_bmUsername, m_bmPassword};
            m_addBMSave = UiUtil.storeValues(items);
          }
          m_loadForm.removeRef(this);
          setCurrent( m_bookmarkList );
        } catch (CauseException e) {
          recordExcFormFin("Error while " + (m_addForm ? "adding" :
                "updating") + " bookmark", e);
        }
      }

      /** Clear data. */
      if ( c == m_clearCmd ) {
        m_bmName.setString("");
        m_bmURL.setString("http://");
        m_bmUsername.setString("");
        m_bmPassword.setString("");
      }
     
      /** Cancel currently edited (or added) RSS feed's properties */
      if( c == m_addCancelCmd ){
        m_loadForm.removeRef(this);
        setCurrent( m_bookmarkList );
      }
     
      //#ifndef DSMALLMEM
      /** Put current bookmark URL into URL box.  */
      if( c == m_pasteURLCmd ) {
        new UiUtil().initializeURLBox( m_midlet, m_bmURL.getString(),
            this, m_bmURL );
      }
      //#endif

      //#ifdef DJSR75
      /** Find bookmark file in file system */
      if( c == m_BMFileCmd ) {
        if (!JSR75_ENABLED) {
          Alert invalidAlert = new Alert(
              "JSR-75 not enabled",
              "Find files (JSR-75) not enabled on the phone.",
              null,
              AlertType.WARNING);
          invalidAlert.setTimeout(Alert.FOREVER);
          setCurrent( invalidAlert, this );
          return;
        }
        try {
          reqFindFiles( this, m_bmURL);
          wakeUp();
        }catch(Throwable t) {
          //#ifdef DLOGGING
          logger.severe("RssReaderMIDlet find files ", t);
          //#endif
          /** Error while executing find files */
          System.out.println("RssReaderMIDlet find files " + t.getMessage());
          t.printStackTrace();
        }
      }
      //#endif
         
      //#ifndef DSMALLMEM
      if( c == m_helpCmd ) {
        new Thread(this).start();
      }
      //#endif
    }

    public void run() {
    //#ifndef DSMALLMEM
      final HelpForm helpForm = new HelpForm(m_midlet, this);
      helpForm.appendRsc(m_addForm ? "text.abm.help" : "text.ebm.help");
      helpForm.appendItemHelpRsc(m_bmName, "text.bbmc.help");
      helpForm.appendItemHelpRsc(m_bmURL, "text.lbm.help");
      if (m_addForm) {
        helpForm.appendCmdHelpRsc(m_addInsCmd, "text.ibmc.help");
        helpForm.appendCmdHelpRsc(m_addAddCmd, "text.abmc.help");
        helpForm.appendCmdHelpRsc(m_addAppndCmd, "text.pbmc.help");
      }
      setCurrent( helpForm );
    //#endif
    }

  }

  /* Form to show data being loaded.  Save messages and exceptions to
     allow them to be viewed separately as well as diagnostics for
     reporting errors. */
  final public class LoadingForm extends PromptForm
  implements CommandListener {
    //#ifdef DMIDP10
    private String      m_title;         // Store title.
    //#endif
    private Command     m_loadStartCmd;  // The load form start to displayable command
    private Command     m_loadMsgsCmd;   // The load form messages command
    private Command     m_loadDiagCmd;   // The load form diagnostic command
    private Command     m_loadErrCmd;    // The load form error command
    private Command     m_loadQuitCmd;   // The load form quit command
    private Vector m_msgs = new Vector(); // Original messages
    private Vector m_excs = new Vector(); // Only errors
    private Displayable m_disp;

    /* Constructor */
    LoadingForm(final String title, final Displayable disp) {
      super(m_midlet, title);
      //#ifdef DMIDP10
      this.m_title = title;
      //#endif
      if (disp != null) {
        m_disp = disp;
      }
      if (m_backCommand == null) {
        m_backCommand   = UiUtil.getCmdRsc("cmd.back", Command.BACK, 1);
      }
      /* Messages */
      m_loadMsgsCmd       = UiUtil.getCmdRsc("cmd.msg", Command.SCREEN, 3);
      /* Errors */
      m_loadErrCmd        = UiUtil.getCmdRsc("cmd.err", Command.SCREEN, 4);
      /* Diagnostics */
      m_loadDiagCmd       = UiUtil.getCmdRsc("cmd.diag", Command.SCREEN, 5);
      if (disp != null) {
        super.addCommand( m_backCommand );
      }
      super.addCommand( m_loadMsgsCmd );
      super.addCommand( m_loadErrCmd );
      super.addCommand( m_loadDiagCmd );
      super.setCommandListener( this );
    }

    /* Add start command and where it goes when clicked.  */
    public void addStartCmd(final Displayable disp) {
      m_disp = disp;
      if (disp != null) {
        /* Start */
        m_loadStartCmd = UiUtil.getCmdRsc("cmd.st", Command.SCREEN, 1);
        super.addCommand( m_loadStartCmd );
      }
    }

    /* Add quit command used for errors during exit. */
    public void addQuit() {
      /* Quit */
      m_loadQuitCmd = UiUtil.getCmdRsc("cmd.q", Command.EXIT, 1);
      super.addPromptCommand( m_loadQuitCmd,
          ResourceProviderME.get("text.w.q") );
    }

    /** Respond to commands */
    public void commandAction(final Command c, final Displayable s) {
      //#ifdef DTESTUI
      super.outputCmdAct(c, s);
      //#endif

      if(( c == m_backCommand ) || ( c == m_loadStartCmd )){
        setCurrent( m_disp );
      }

      if( c == m_loadQuitCmd ){
        try {
          destroyApp(true);
        } catch (Exception e) {
        }
        notifyDestroyed();
      }

      /** Give messages for loading */
      if( c == m_loadMsgsCmd ) {
        showMsgs();
      }

      /** Give errors for loading */
      if( c == m_loadErrCmd ) {
        showErrMsgs(true);
      }

      /** Give diagnostics for loading */
      if( c == m_loadDiagCmd ) {
        showErrMsgs(false);
      }

    }
    /* Show errors and diagnostics. */
    final private void showMsgs() {
      try {
        UiUtil.delItems(this);
        final int elen = m_msgs.size();
        for (int ic = 0; ic < elen; ic++) {
          super.append((String)m_msgs.elementAt(ic));
        }
      }catch(Throwable t) {
        //#ifdef DLOGGING
        logger.severe("showMsgs", t);
        //#endif
        /** Error while executing constructor */
        System.out.println("showMsgs " + t.getMessage());
        t.printStackTrace();
      }
    }

    /* Show errors and diagnostics. */
    final private void showErrMsgs(final boolean showErrsOnly) {
      try {
        UiUtil.delItems(this);
        final int elen = m_excs.size();
        for (int ic = 0; ic < elen; ic++) {
          Throwable nexc = (Throwable)m_excs.elementAt(ic);
          while (nexc != null) {
            String msg = nexc.getMessage();
            if (msg != null) {
              super.append(nexc.getMessage());
              // If showing errs only, only show the first error found
              if (showErrsOnly) {
                break;
              }
            } else if (!showErrsOnly) {
              super.append("Error " + nexc.getClass().getName());
            }
            if (nexc instanceof CauseException) {
              nexc = ((CauseException)nexc).getCause();
            } else {
              break;
            }
          }
        }
        if (!showErrsOnly) {
          super.append(new StringItem("Active Threads:",
                Integer.toString(Thread.activeCount())));
        }
      }catch(Throwable t) {
        //#ifdef DLOGGING
        logger.severe("showErrMsgs", t);
        //#endif
        /** Error while executing constructor */
        System.out.println("showErrMsgs " + t.getMessage());
        t.printStackTrace();
      }
    }

    /* Append message to form and save in messages. */
    final public void appendMsg(final String msg) {
      if (msg != null) {
        super.append(msg + "\n");
        m_msgs.addElement(msg);
      }
    }

    /* Add exception. */
    final public void addExc(final Throwable exc) {
      m_excs.addElement(exc);
    }

    /* Check for exceptions. */
    final public boolean hasExc() {
      return (m_excs.size() > 0);
    }

    /* Remove reference to displayable to free memory. */
    final public void removeRef(final Displayable disp) {
      synchronized (this) {
        if (m_disp == disp) {
          m_disp = m_bookmarkList;
          //#ifdef DLOGGING
          if (finestLoggable) {logger.finest("Ref removed " + disp);}
          //#endif
        }
      }
    }

    //#ifdef DMIDP10
    public String getTitle() {
      return m_title;
    }
    //#endif

  }

}
TOP

Related Classes of com.substanceofcode.rssreader.presentation.RssReaderMIDlet$BMForm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.