view content/collections.js @ 382:8460f746207e default tip

remove extraneous log statement
author Myk Melez <myk@mozilla.org>
date Sat, 08 Nov 2008 10:38:57 -0800
parents c00b3db58dcf
children
line wrap: on
line source

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Snowl.
 *
 * The Initial Developer of the Original Code is Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Myk Melez <myk@mozilla.org>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// modules that come with Firefox

// modules that are generic
Cu.import("resource://snowl/modules/log4moz.js");
Cu.import("resource://snowl/modules/Observers.js");
Cu.import("resource://snowl/modules/URI.js");

// modules that are Snowl-specific
Cu.import("resource://snowl/modules/service.js");
Cu.import("resource://snowl/modules/datastore.js");
Cu.import("resource://snowl/modules/source.js");
Cu.import("resource://snowl/modules/feed.js");
Cu.import("resource://snowl/modules/identity.js");
Cu.import("resource://snowl/modules/collection.js");
Cu.import("resource://snowl/modules/opml.js");

let gBrowserWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).
                     getInterface(Ci.nsIWebNavigation).
                     QueryInterface(Ci.nsIDocShellTreeItem).
                     rootTreeItem.
                     QueryInterface(Ci.nsIInterfaceRequestor).
                     getInterface(Ci.nsIDOMWindow);

let CollectionsView = {
  _log: null,

  get _tree() {
    delete this._tree;
    return this._tree = document.getElementById("sourcesView");
  },

  get _children() {
    delete this._children;
    return this._children = this._tree.getElementsByTagName("treechildren")[0];
  },

  isHierarchical: gBrowserWindow.Snowl._prefs.get("collection.hierarchicalView"),

  //**************************************************************************//
  // Initialization & Destruction

  init: function() {
    this._log = Log4Moz.Service.getLogger("Snowl.Sidebar");
    Observers.add(this, "snowl:sources:changed");
    this._getCollections();
    this._buildCollectionTree();

    // Ensure collection selection maintained, if in List sidebar
    if (document.getElementById("snowlSidebar"))
      this._tree.view.selection.select(SnowlUtils.gListViewCollectionIndex);
  },


  //**************************************************************************//
  // nsITreeView

  selection: null,

  get rowCount() {
    return this._rows.length;
  },

  // FIXME: consolidate these two references.
  _treebox: null,
  setTree: function(treeBox) {
    this._treeBox = treeBox;
  },

  getCellText : function(row, column) {
    return this._rows[row].name;
  },

  isContainer: function(row) {
    //this._log.info("isContainer: " + (this._rows[row].groups ? true : false));
    return (this._rows[row].groups ? true : false);
  },
  isContainerOpen: function(row) {
    //this._log.info("isContainerOpen: " + this._rows[row].isOpen);
    return this._rows[row].isOpen;
  },
  isContainerEmpty: function(row) {
    //this._log.info("isContainerEmpty: " + row + " " + this._rows[row].groups.length + " " + (this._rows[row].groups.length == 0));
    return (this._rows[row].groups.length == 0);
  },

  isSeparator: function(row)         { return false },
  isSorted: function()               { return false },

  // FIXME: make this return true for collection names that are editable,
  // and then implement name editing on the new architecture.
  isEditable: function(row, column)  { return false },

  getParentIndex: function(row) {
    //this._log.info("getParentIndex: " + row);

    let thisLevel = this.getLevel(row);

    if (thisLevel == 0)
      return -1;
    for (let t = row - 1; t >= 0; t--)
      if (this.getLevel(t) < thisLevel)
        return t;

    throw "getParentIndex: couldn't figure out parent index for row " + row;
  },

  getLevel: function(row) {
    //this._log.info("getLevel: " + row);

    if (!this.isHierarchical)
      return 0;

    return this._rows[row].level;
  },

  hasNextSibling: function(idx, after) {
    //this._log.info("hasNextSibling: " + idx + " " + after);

    let thisLevel = this.getLevel(idx);
    for (let t = idx + 1; t < this._rows.length; t++) {
      let nextLevel = this.getLevel(t);
      if (nextLevel == thisLevel)
        return true;
      if (nextLevel < thisLevel)
        return false;
    }

    return false;
  },

  getImageSrc: function(row, column) {
    if (column.id == "nameCol") {
      let iconURL = this._rows[row].iconURL;
      if (iconURL)
        return iconURL.spec;
    }

    return null;
  },

  toggleOpenState: function(idx) {
    //this._log.info("toggleOpenState: " + idx);

    let item = this._rows[idx];
    if (!item.groups)
      return;

    if (item.isOpen) {
      item.isOpen = false;

      let thisLevel = this.getLevel(idx);
      let numToDelete = 0;
      for (let t = idx + 1; t < this._rows.length; t++) {
        if (this.getLevel(t) > thisLevel)
          numToDelete++;
        else
          break;
      }
      if (numToDelete) {
        this._rows.splice(idx + 1, numToDelete);
        this._treeBox.rowCountChanged(idx + 1, -numToDelete);
      }
    }
    else {
      item.isOpen = true;

      let groups = this._rows[idx].groups;
      for (let i = 0; i < groups.length; i++)
        this._rows.splice(idx + 1 + i, 0, groups[i]);
      this._treeBox.rowCountChanged(idx + 1, groups.length);
    }
  },

  getRowProperties: function (row, properties) {},
  getCellProperties: function (row, column, properties) {},
  getColumnProperties: function(columnID, column, properties) {},

  setCellText: function(aRow, aCol, aValue) {
    let statement = SnowlDatastore.createStatement("UPDATE sources SET name = :name WHERE id = :id");
    statement.params.name = this._rows[aRow].name = aValue;
    statement.params.id = this._rows[aRow].id;

    try {
      statement.execute();
    }
    finally {
      statement.reset();
    }
  },


  //**************************************************************************//
  // Misc XPCOM Interfaces

  // nsIObserver
  observe: function(subject, topic, data) {
    switch (topic) {
      case "snowl:sources:changed":
        this._getCollections();
        // Rebuild the view to reflect the new collection of messages.
        // Since the number of rows might have changed, we do this by reinitializing
        // the view instead of merely invalidating the box object (which doesn't
        // expect changes to the number of rows).
        this._buildCollectionTree();
        break;
    }
  },

  _collections: null,
  _getCollections: function() {
    this._collections = [];

    let statement = SnowlDatastore.createStatement(
      "SELECT id, name, iconURL, grouped, groupIDColumn, groupNameColumn, " +
      "groupHomeURLColumn, groupIconURLColumn FROM collections ORDER BY orderKey"
    );

    statement.QueryInterface(Ci.mozIStorageStatementWrapper);

    try {
      while (statement.step()) {
        this._collections.push(new SnowlCollection(statement.row.id,
                                                   statement.row.name,
                                                   URI.get(statement.row.iconURL),
                                                   null,
                                                   null,
                                                   statement.row.grouped ? true : false,
                                                   statement.row.groupIDColumn,
                                                   statement.row.groupNameColumn,
                                                   statement.row.groupHomeURLColumn,
                                                   statement.row.groupIconURLColumn));
      }
    }
    finally {
      statement.reset();
    }
  },

  // Build the list of rows in the tree.  By default, all containers
  // are closed, so this is the same as the list of collections, although
  // in the future we might persist and restore the open state.
  _buildCollectionTree: function() {
    if (this.isHierarchical) {
      this._rows = [collection for each (collection in this._collections)];
    }
    else {
      this._rows = [];
      for each (let collection in this._collections) {
        if (collection.grouped)
          for each (let group in collection.groups)
            this._rows.push(group);
        else
          this._rows.push(collection);
      }
    }

    this._tree.view = this;
  },

  onSelect: function(aEvent) {
    if (this._tree.currentIndex == -1 || SnowlUtils.gRightMouseButtonDown)
      return;

    let collection = this._rows[this._tree.currentIndex];
    SnowlUtils.gListViewCollectionIndex = this._tree.currentIndex;
    gMessageViewWindow.SnowlMessageView.setCollection(collection);
  },

  onCollectionsTreeMouseDown: function(aEvent) {
    SnowlUtils.onTreeMouseDown(aEvent, this._tree);
  },

  onTreeContextPopupHidden: function() {
    if (!SnowlUtils.gSelectOnRtClick)
      SnowlUtils.RestoreSelectionWithoutContentLoad(this._tree);
  },

  unsubscribe: function() {
    let collection = this._rows[this._tree.currentIndex];

    if (!collection.parent || collection.parent.groupIDColumn != "sources.id")
      return;

    let sourceID = this._rows[this._tree.currentIndex].groupID;

    SnowlDatastore.dbConnection.beginTransaction();
    try {
      SnowlDatastore.dbConnection.executeSimpleSQL("DELETE FROM metadata WHERE messageID IN (SELECT id FROM messages WHERE sourceID = " + sourceID + ")");
      SnowlDatastore.dbConnection.executeSimpleSQL("DELETE FROM parts WHERE messageID IN (SELECT id FROM messages WHERE sourceID = " + sourceID + ")");
      SnowlDatastore.dbConnection.executeSimpleSQL("DELETE FROM messages WHERE sourceID = " + sourceID);
      SnowlDatastore.dbConnection.executeSimpleSQL("DELETE FROM sources WHERE id = " + sourceID);
      SnowlDatastore.dbConnection.commitTransaction();
    }
    catch(ex) {
      SnowlDatastore.dbConnection.rollbackTransaction();
      throw ex;
    }

    Observers.notify(null, "snowl:sources:changed", null);
    Observers.notify(null, "snowl:messages:changed", null);
  }

};

window.addEventListener("load", function() { CollectionsView.init() }, true);