<commit_before>/*
 * PanmirrorOutlineWidget.java
 *
 * Copyright (C) 2009-20 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */


package org.rstudio.studio.client.panmirror.outline;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.a11y.A11y;
import org.rstudio.core.client.dom.DomUtils;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.studio.client.RStudioGinjector;
import org.rstudio.studio.client.panmirror.PanmirrorSelection;
import org.rstudio.studio.client.panmirror.events.PanmirrorOutlineNavigationEvent;
import org.rstudio.studio.client.workbench.views.source.DocumentOutlineWidget;

import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;

public class PanmirrorOutlineWidget extends Composite
   implements PanmirrorOutlineNavigationEvent.HasPanmirrorOutlineNavigationHandlers
{
   public PanmirrorOutlineWidget()
   {
    
      emptyPlaceholder_ = new DocumentOutlineWidget.EmptyPlaceholder();
      
      container_ = new DockLayoutPanel(Unit.PX);
      container_.addStyleName(outlineStyles_.container());
      
      resizer_ = new DocumentOutlineWidget.VerticalSeparator();
      container_.addWest(resizer_, 4);
      resizer_.pad();
       
      tree_ = new Tree();
      tree_.addStyleName(outlineStyles_.tree());
      Roles.getTreeRole().setAriaLabelProperty(tree_.getElement(), "Document Outline");
      
      panel_ = new FlowPanel();
      panel_.addStyleName(outlineStyles_.panel());
      panel_.add(tree_);
      
      container_.add(panel_);
      
      RStudioGinjector.INSTANCE.injectMembers(this);
         
      initWidget(container_);
      
      addStyleName("ace_editor_theme");
   }
  
   @Override
   public HandlerRegistration addPanmirrorOutlineNavigationHandler(PanmirrorOutlineNavigationEvent.Handler handler)
   {
      return handlers_.addHandler(PanmirrorOutlineNavigationEvent.getType(), handler);
   }
   
   public void updateOutline(PanmirrorOutlineItem[] outline)
   {
      outline_ = flattenOutline(outline);
      rebuildOutline();
      updateActiveItem();
   }
   
   public void updateSelection(PanmirrorSelection selection)
   {
      selection_ = selection;
      updateActiveItem();
   }
   
   public Widget getResizer()
   {
      return resizer_;
   }
   
   public void setAriaVisible(boolean visible)
   {
      if (visible)
         A11y.setARIAVisible(getElement());
      else
         A11y.setARIAHidden(getElement());
   }   
   
   private void rebuildOutline()
   {
      // set empty placeholder if the outline is empty
      if (outline_.size() == 0)
      {
         setActiveWidget(emptyPlaceholder_);
         return;
      }
      
      // otherwise, set the tree as active 
      setActiveWidget(tree_);
      
      // determine the minimum level
      outlineMinLevel_ = Integer.MAX_VALUE;
      outline_.forEach(item -> {
         outlineMinLevel_ = Math.min(outlineMinLevel_, item.level);
      });
      if (outlineMinLevel_ == Integer.MAX_VALUE)
         outlineMinLevel_ = 1;
     
         
      // if the outline and existing tree have diffent sizes then rebuild
      if (outline_.size() != tree_.getItemCount())
      {
         tree_.clear();
         outline_.forEach(item -> {
            addToTree(item);
         });
      }
      else // otherwise update items
      {
         Iterator<TreeItem> treeIter = tree_.treeItemIterator();
         outline_.forEach(item -> {
            OutlineTreeItem outlineTreeItem = (OutlineTreeItem)treeIter.next();
            outlineTreeItem.getEntry().update(item);
         });
      }
   }
   
   private void addToTree(PanmirrorOutlineItem item)
   {
      OutlineTreeEntry entry = new OutlineTreeEntry(item);
      OutlineTreeItem treeItem = new OutlineTreeItem(entry);
      setTreeItemStyles(treeItem);
      tree_.addItem(treeItem);
   }
   
   private ArrayList<PanmirrorOutlineItem>  flattenOutline(PanmirrorOutlineItem[] items)
   {
      ArrayList<PanmirrorOutlineItem> flattenedItems = new ArrayList<PanmirrorOutlineItem>();
      doFlattenOutline(items, flattenedItems);
      return flattenedItems;
   }
   
   private void doFlattenOutline(PanmirrorOutlineItem[] items,  ArrayList<PanmirrorOutlineItem> flattenedItems)
   {
      Arrays.stream(items).forEach(item -> {
         if (item.type == PanmirrorOutlineItemType.Heading)
         {
            flattenedItems.add(item);
            doFlattenOutline(item.children, flattenedItems);
         }
      });
   }
   
   private void setActiveWidget(Widget widget)
   {
      panel_.clear();
      panel_.add(widget);
   }
   
   private void resetTreeStyles()
   {
      for (int i = 0; i < tree_.getItemCount(); i++)
        setTreeItemStyles((OutlineTreeItem)tree_.getItem(i));
   }<commit_msg>don't show empty outline items<commit_after>/*
 * PanmirrorOutlineWidget.java
 *
 * Copyright (C) 2009-20 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */


package org.rstudio.studio.client.panmirror.outline;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.a11y.A11y;
import org.rstudio.core.client.dom.DomUtils;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.studio.client.RStudioGinjector;
import org.rstudio.studio.client.panmirror.PanmirrorSelection;
import org.rstudio.studio.client.panmirror.events.PanmirrorOutlineNavigationEvent;
import org.rstudio.studio.client.workbench.views.source.DocumentOutlineWidget;

import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;

public class PanmirrorOutlineWidget extends Composite
   implements PanmirrorOutlineNavigationEvent.HasPanmirrorOutlineNavigationHandlers
{
   public PanmirrorOutlineWidget()
   {
    
      emptyPlaceholder_ = new DocumentOutlineWidget.EmptyPlaceholder();
      
      container_ = new DockLayoutPanel(Unit.PX);
      container_.addStyleName(outlineStyles_.container());
      
      resizer_ = new DocumentOutlineWidget.VerticalSeparator();
      container_.addWest(resizer_, 4);
      resizer_.pad();
       
      tree_ = new Tree();
      tree_.addStyleName(outlineStyles_.tree());
      Roles.getTreeRole().setAriaLabelProperty(tree_.getElement(), "Document Outline");
      
      panel_ = new FlowPanel();
      panel_.addStyleName(outlineStyles_.panel());
      panel_.add(tree_);
      
      container_.add(panel_);
      
      RStudioGinjector.INSTANCE.injectMembers(this);
         
      initWidget(container_);
      
      addStyleName("ace_editor_theme");
   }
  
   @Override
   public HandlerRegistration addPanmirrorOutlineNavigationHandler(PanmirrorOutlineNavigationEvent.Handler handler)
   {
      return handlers_.addHandler(PanmirrorOutlineNavigationEvent.getType(), handler);
   }
   
   public void updateOutline(PanmirrorOutlineItem[] outline)
   {
      outline_ = flattenOutline(outline);
      rebuildOutline();
      updateActiveItem();
   }
   
   public void updateSelection(PanmirrorSelection selection)
   {
      selection_ = selection;
      updateActiveItem();
   }
   
   public Widget getResizer()
   {
      return resizer_;
   }
   
   public void setAriaVisible(boolean visible)
   {
      if (visible)
         A11y.setARIAVisible(getElement());
      else
         A11y.setARIAHidden(getElement());
   }   
   
   private void rebuildOutline()
   {
      // set empty placeholder if the outline is empty
      if (outline_.size() == 0)
      {
         setActiveWidget(emptyPlaceholder_);
         return;
      }
      
      // otherwise, set the tree as active 
      setActiveWidget(tree_);
      
      // determine the minimum level
      outlineMinLevel_ = Integer.MAX_VALUE;
      outline_.forEach(item -> {
         outlineMinLevel_ = Math.min(outlineMinLevel_, item.level);
      });
      if (outlineMinLevel_ == Integer.MAX_VALUE)
         outlineMinLevel_ = 1;
     
         
      // if the outline and existing tree have diffent sizes then rebuild
      if (outline_.size() != tree_.getItemCount())
      {
         tree_.clear();
         outline_.forEach(item -> {
            addToTree(item);
         });
      }
      else // otherwise update items
      {
         Iterator<TreeItem> treeIter = tree_.treeItemIterator();
         outline_.forEach(item -> {
            OutlineTreeItem outlineTreeItem = (OutlineTreeItem)treeIter.next();
            outlineTreeItem.getEntry().update(item);
         });
      }
   }
   
   private void addToTree(PanmirrorOutlineItem item)
   {
      OutlineTreeEntry entry = new OutlineTreeEntry(item);
      OutlineTreeItem treeItem = new OutlineTreeItem(entry);
      setTreeItemStyles(treeItem);
      tree_.addItem(treeItem);
   }
   
   private ArrayList<PanmirrorOutlineItem>  flattenOutline(PanmirrorOutlineItem[] items)
   {
      ArrayList<PanmirrorOutlineItem> flattenedItems = new ArrayList<PanmirrorOutlineItem>();
      doFlattenOutline(items, flattenedItems);
      return flattenedItems;
   }
   
   private void doFlattenOutline(PanmirrorOutlineItem[] items,  ArrayList<PanmirrorOutlineItem> flattenedItems)
   {
      Arrays.stream(items).forEach(item -> {
         if (item.type == PanmirrorOutlineItemType.Heading && 
             !StringUtil.isNullOrEmpty(item.title))
         {
            flattenedItems.add(item);
            doFlattenOutline(item.children, flattenedItems);
         }
      });
   }
   
   private void setActiveWidget(Widget widget)
   {
      panel_.clear();
      panel_.add(widget);
   }
   
   private void resetTreeStyles()
   {
      for (int i = 0; i < tree_.getItemCount(); i++)
        setTreeItemStyles((OutlineTreeItem)tree_.getItem(i));
   }
{'fraction_non_alphanumeric': 0.09951298701298701, 'fraction_numerical': 0.003409090909090909, 'mean_word_length': 3.1695431472081217, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 21, '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': '833906', 'n_tokens_mistral': 3747, 'n_tokens_neox': 3705, 'n_words': 677}