<commit_before>// ==========================================================================
//                      DG.CaseTableController
//
//  The controller for tables.
//
//  Authors:  <NAME>, <NAME>
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('controllers/component_controller');
sc_require('components/case_table/attribute_editor_view');

/** @class

  DG.CaseTableController provides controller functionality for DG.TableViews.

  @extends DG.ComponentController
*/
DG.CaseTableController = DG.ComponentController.extend(
/** @scope DG.CaseTableController.prototype */
  (function() {
    return {

      /**
        Called when the currently selected game context changes.
       */
      currentGameContextDidChange: function( iNotifier, iKey) {
        // 'gameIsReady' affects our labels, which affects our group headers
        if( iKey === 'gameIsReady') {
          var hierTableView = this.getPath('view.contentView');
          if( hierTableView)
            hierTableView.refresh();
        }
      },

      /**
        The table will reflect the contents of this data context.
        @property   {DG.DataContext} or derived class
       */
      dataContext: null,

      /**
        @private
        Used internally to track changes to the data context.
       */
      _prevDataContext: null,

      /**
        The set of DG.CaseTableAdapters for the subtables in parent-->child order.
        @property {Array of DG.CaseTableAdapter}
       */
      caseTableAdapters: null,

      /**
        The content view for this controller, i.e. the DG.HierTableView.
        @property {DG.HierTableView}
       */
      contentView: null,

      newAttributeDialog: null,

      /**
        Initialization function.
       */
      init: function() {
        sc_super();
        this.get('specialTitleBarButtons').push(
            DG.CaseCardToggleButton.create()
        );
        this.caseTableAdapters = [];
        // Init is called when the case table controller may not be fully
        // constructed, so, delay to the next Run Loop.
        this.invokeLater(function () {
          if( this.get('dataContext') && this.get('model')) {
            this.dataContextDidChange();
          } else {
            DG.logWarn('Case table controller unable to complete initialization: missing dataContext or model');
          }
        });
      },

      /**
        Destruction function.
       */
      destroy: function() {
        var dataContext = this.get('dataContext');
        if( dataContext)
          dataContext.removeObserver('changeCount', this, 'contextDataDidChange');
        this.caseTableAdapters = null;
        sc_super();
      },

      // Utility function for identifying existing adapters for the specified collection
      findAdapterForCollection: function(iCollectionID) {
        var i, count, adapters = this.caseTableAdapters;
        if (adapters) {
          count = adapters.length;
          for( i = 0; i < count; ++i) {
            if( adapters[i] && (adapters[i].getPath('collection.id') === iCollectionID))
              return adapters[i];
          }
        }
        return null;
      },

      /**
        Builds an appropriate DG.CaseTableAdapter for each collection.
       */
      updateTableAdapters: function() {
        var dataContext = this.get('dataContext'),
            collectionRecords = dataContext && dataContext.get('collections') || [],
            newAdapters = [],
            // The controller model is a component object. We want the model for the
            // component's content.
            caseTableModel = this.model && this.model.get('content');

        this.caseTableAdapters = newAdapters;

        // Utility function for finding or creating (if necessary) an appropriate
        // adapter for the specified collection.
        var guaranteeAdapterForCollectionRecord = function( iCollectionRecord) {
          var collectionID = iCollectionRecord.get('id'),
              collection = dataContext.getCollectionByID( collectionID),
              // try to find an existing adapter for the specified collection
              adapter = this.findAdapterForCollection( collectionID);
          if( !adapter) {
            // create a new adapter for the specified collection
            adapter = DG.CaseTableAdapter.create({
              dataContext: dataContext,
              collection: collection,
              model: caseTableModel
            });

          }
          // add the new/found adapter to the adapter array
          newAdapters.push( adapter);
        }.bind(this);

        collectionRecords.forEach( guaranteeAdapterForCollectionRecord);
      },

      /**
        Configure the table for the new data context.
       */
      dataContextDidChange: function() {
        var dataContext = this.get('dataContext');

        this.updateTableAdapters();

        var contentView = this.getPath('view.contentView');

        // Handle divider views for the drag-attribute listener setup.
        if (contentView) {
          var dividerDropDataCallback = function (iDivider) {
            var dropData = iDivider.getPath('dropData');
            if (SC.none(dropData)) {
              return;
            }
            var context = iDivider.getPath('dataContext');
            var parentTable = iDivider.getPath('leftTable');

            // TODO: Add the rest of UNDO procedures in createCollectionCommand.
            DG.UndoHistory.execute(DG.DataContextUtilities.createCollectionCommand(dropData.attribute, dropData.collection, context, parentTable.getPath('gridAdapter.collection.id')));

            iDivider.setPath('dropData', null);
          };

          // Remove the observer and destroy stray divider views before the new setup.
          var oldDividerViews = contentView.getPath('dividerViews');
          oldDividerViews.forEach(function (iDividerView) {
            iDividerView.removeObserver('dropData', dividerDropDataCallback);
            iDividerView.destroy();
          });

          // This creates new divider views along other stuff.
          contentView.setCaseTableAdapters(this.get('caseTableAdapters'));

          // Setup an observer for the drop-target divider views.
          var dividerViews = contentView.getPath('dividerViews');
          dividerViews.forEach(function (iDividerView) {
            iDividerView.addObserver('dropData', dividerDropDataCallback);
          });
        }

        if( dataContext !== this._prevDataContext) {
          if( this._prevDataContext)
            this._prevDataContext.removeObserver('changeCount', this, 'contextDataDidChange');
          if( dataContext)
            dataContext.addObserver('changeCount', this, 'contextDataDidChange');<commit_msg>[#141778481] Feature: The user can drag an attribute to the space between two levels of the hierarchy, thus creating an intermediate level.<commit_after>// ==========================================================================
//                      DG.CaseTableController
//
//  The controller for tables.
//
//  Authors:  <NAME>, <NAME>
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('controllers/component_controller');
sc_require('components/case_table/attribute_editor_view');

/** @class

  DG.CaseTableController provides controller functionality for DG.TableViews.

  @extends DG.ComponentController
*/
DG.CaseTableController = DG.ComponentController.extend(
/** @scope DG.CaseTableController.prototype */
  (function() {
    return {

      /**
        Called when the currently selected game context changes.
       */
      currentGameContextDidChange: function( iNotifier, iKey) {
        // 'gameIsReady' affects our labels, which affects our group headers
        if( iKey === 'gameIsReady') {
          var hierTableView = this.getPath('view.contentView');
          if( hierTableView)
            hierTableView.refresh();
        }
      },

      /**
        The table will reflect the contents of this data context.
        @property   {DG.DataContext} or derived class
       */
      dataContext: null,

      /**
        @private
        Used internally to track changes to the data context.
       */
      _prevDataContext: null,

      /**
        The set of DG.CaseTableAdapters for the subtables in parent-->child order.
        @property {Array of DG.CaseTableAdapter}
       */
      caseTableAdapters: null,

      /**
        The content view for this controller, i.e. the DG.HierTableView.
        @property {DG.HierTableView}
       */
      contentView: null,

      newAttributeDialog: null,

      /**
        Initialization function.
       */
      init: function() {
        sc_super();
        this.get('specialTitleBarButtons').push(
            DG.CaseCardToggleButton.create()
        );
        this.caseTableAdapters = [];
        // Init is called when the case table controller may not be fully
        // constructed, so, delay to the next Run Loop.
        this.invokeLater(function () {
          if( this.get('dataContext') && this.get('model')) {
            this.dataContextDidChange();
          } else {
            DG.logWarn('Case table controller unable to complete initialization: missing dataContext or model');
          }
        });
      },

      /**
        Destruction function.
       */
      destroy: function() {
        var dataContext = this.get('dataContext');
        if( dataContext)
          dataContext.removeObserver('changeCount', this, 'contextDataDidChange');
        this.caseTableAdapters = null;
        sc_super();
      },

      // Utility function for identifying existing adapters for the specified collection
      findAdapterForCollection: function(iCollectionID) {
        var i, count, adapters = this.caseTableAdapters;
        if (adapters) {
          count = adapters.length;
          for( i = 0; i < count; ++i) {
            if( adapters[i] && (adapters[i].getPath('collection.id') === iCollectionID))
              return adapters[i];
          }
        }
        return null;
      },

      /**
        Builds an appropriate DG.CaseTableAdapter for each collection.
       */
      updateTableAdapters: function() {
        var dataContext = this.get('dataContext'),
            collectionRecords = dataContext && dataContext.get('collections') || [],
            newAdapters = [],
            // The controller model is a component object. We want the model for the
            // component's content.
            caseTableModel = this.model && this.model.get('content');

        this.caseTableAdapters = newAdapters;

        // Utility function for finding or creating (if necessary) an appropriate
        // adapter for the specified collection.
        var guaranteeAdapterForCollectionRecord = function( iCollectionRecord) {
          var collectionID = iCollectionRecord.get('id'),
              collection = dataContext.getCollectionByID( collectionID),
              // try to find an existing adapter for the specified collection
              adapter = this.findAdapterForCollection( collectionID);
          if( !adapter) {
            // create a new adapter for the specified collection
            adapter = DG.CaseTableAdapter.create({
              dataContext: dataContext,
              collection: collection,
              model: caseTableModel
            });

          }
          // add the new/found adapter to the adapter array
          newAdapters.push( adapter);
        }.bind(this);

        collectionRecords.forEach( guaranteeAdapterForCollectionRecord);
      },

      /**
        Configure the table for the new data context.
       */
      dataContextDidChange: function() {
        var dataContext = this.get('dataContext');

        this.updateTableAdapters();

        var contentView = this.getPath('view.contentView');

        // Handle divider views for the drag-attribute listener setup.
        if (contentView) {
          var dividerDropDataCallback = function (iDivider) {
            var dropData = iDivider.getPath('dropData');
            if (SC.none(dropData)) {
              return;
            }
            var context = iDivider.getPath('dataContext');
            var parentTable = iDivider.getPath('leftTable');

            DG.UndoHistory.execute(DG.DataContextUtilities.createCollectionCommand(dropData.attribute, dropData.collection, context, parentTable.getPath('gridAdapter.collection.id')));

            iDivider.setPath('dropData', null);
          };

          // Remove the observer and destroy stray divider views before the new setup.
          var oldDividerViews = contentView.getPath('dividerViews');
          oldDividerViews.forEach(function (iDividerView) {
            iDividerView.removeObserver('dropData', dividerDropDataCallback);
            iDividerView.destroy();
          });

          // This creates new divider views along other stuff.
          contentView.setCaseTableAdapters(this.get('caseTableAdapters'));

          // Setup an observer for the drop-target divider views.
          var dividerViews = contentView.getPath('dividerViews');
          dividerViews.forEach(function (iDividerView) {
            iDividerView.addObserver('dropData', dividerDropDataCallback);
          });
        }

        if( dataContext !== this._prevDataContext) {
          if( this._prevDataContext)
            this._prevDataContext.removeObserver('changeCount', this, 'contextDataDidChange');
          if( dataContext)
            dataContext.addObserver('changeCount', this, 'contextDataDidChange');
{'fraction_non_alphanumeric': 0.11573236889692586, 'fraction_numerical': 0.0018083182640144665, 'mean_word_length': 2.32413178984862, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1457644', 'n_tokens_mistral': 3782, 'n_tokens_neox': 3605, 'n_words': 1051}