1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/range.html">
9<link rel="import" href="/tracing/ui/side_panel/side_panel.html">
10<link rel='import' href='/tracing/ui/base/polymer_utils.html'>
11
12<polymer-element name='tr-ui-side-panel-container' is='HTMLUnknownElement'>
13  <template>
14    <style>
15    :host {
16      align-items: stretch;
17      display: -webkit-flex;
18    }
19
20    :host([expanded]) > active-panel-container {
21      -webkit-flex: 1 1 auto;
22      border-left: 1px solid black;
23      display: -webkit-flex;
24    }
25
26    :host(:not([expanded])) > active-panel-container {
27      display: none;
28    }
29
30    active-panel-container {
31      display: flex;
32    }
33
34    tab-strip {
35      -webkit-flex: 0 0 auto;
36      -webkit-flex-direction: column;
37      -webkit-user-select: none;
38      background-color: rgb(236, 236, 236);
39      border-left: 1px solid black;
40      cursor: default;
41      display: -webkit-flex;
42      min-width: 18px; /* workaround for flexbox and writing-mode mixing bug */
43      padding: 10px 0 10px 0;
44      font-size: 12px;
45    }
46
47    tab-strip > tab-strip-label {
48      -webkit-writing-mode: vertical-rl;
49      display: inline;
50      margin-right: 1px;
51      min-height: 20px;
52      padding: 15px 3px 15px 1px;
53    }
54
55    tab-strip >
56        tab-strip-label:not([enabled]) {
57      color: rgb(128, 128, 128);
58    }
59
60    tab-strip > tab-strip-label[selected] {
61      background-color: white;
62      border: 1px solid rgb(163, 163, 163);
63      border-left: none;
64      padding: 14px 2px 14px 1px;
65    }
66    </style>
67
68    <active-panel-container id='active_panel_container'>
69    </active-panel-container>
70    <tab-strip id='tab_strip'></tab-strip>
71  </template>
72
73  <script>
74  'use strict';
75  Polymer({
76    ready: function() {
77      this.activePanelContainer_ = this.$.active_panel_container;
78      this.tabStrip_ = this.$.tab_strip;
79
80      this.rangeOfInterest_ = new tr.b.Range();
81      this.brushingStateController_ = undefined;
82      this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
83      this.onModelChanged_ = this.onModelChanged_.bind(this);
84    },
85
86    get brushingStateController() {
87      return this.brushingStateController_;
88    },
89
90    set brushingStateController(brushingStateController) {
91      if (this.brushingStateController) {
92        this.brushingStateController_.removeEventListener(
93            'change', this.onSelectionChanged_);
94        this.brushingStateController_.removeEventListener(
95            'model-changed', this.onModelChanged_);
96      }
97      this.brushingStateController_ = brushingStateController;
98      if (this.brushingStateController) {
99        this.brushingStateController_.addEventListener(
100            'change', this.onSelectionChanged_);
101        this.brushingStateController_.addEventListener(
102            'model-changed', this.onModelChanged_);
103      }
104    },
105
106    get selection() {
107      return this.brushingStateController_.selection;
108    },
109
110    onSelectionChanged_: function() {
111      if (this.activePanel)
112        this.activePanel.selection = this.selection;
113    },
114
115    get model() {
116      return this.brushingStateController_.model;
117    },
118
119    onModelChanged_: function() {
120      this.activePanelType_ = undefined;
121      this.updateContents_();
122    },
123
124    get expanded() {
125      this.hasAttribute('expanded');
126    },
127
128    get activePanel() {
129      if (this.activePanelContainer_.children.length === 0)
130        return undefined;
131      return this.activePanelContainer_.children[0];
132    },
133
134    get activePanelType() {
135      return this.activePanelType_;
136    },
137
138    set activePanelType(panelType) {
139      if (this.model === undefined)
140        throw new Error('Cannot activate panel without a model');
141
142      var panel = undefined;
143      if (panelType)
144          panel = document.createElement(panelType);
145
146      if (panel !== undefined && !panel.supportsModel(this.model))
147        throw new Error('Cannot activate panel: does not support this model');
148
149      if (this.activePanelType) {
150        this.getLabelElementForPanelType_(
151            this.activePanelType).removeAttribute('selected');
152      }
153      this.activePanelContainer_.textContent = '';
154
155      if (panelType === undefined) {
156        this.removeAttribute('expanded');
157        this.activePanelType_ = undefined;
158        return;
159      }
160
161      this.getLabelElementForPanelType_(panelType).
162          setAttribute('selected', true);
163      this.setAttribute('expanded', true);
164
165      this.activePanelContainer_.appendChild(panel);
166      panel.rangeOfInterest = this.rangeOfInterest_;
167      panel.selection = this.selection_;
168      panel.model = this.model;
169
170      this.activePanelType_ = panelType;
171    },
172
173    getPanelTypeForConstructor_: function(constructor) {
174      for (var i = 0; i < this.tabStrip_.children.length; i++) {
175        if (this.tabStrip_.children[i].panelType.constructor == constructor)
176          return this.tabStrip_.children[i].panelType;
177      }
178    },
179
180    getLabelElementForPanelType_: function(panelType) {
181      for (var i = 0; i < this.tabStrip_.children.length; i++) {
182        if (this.tabStrip_.children[i].panelType == panelType)
183          return this.tabStrip_.children[i];
184      }
185      return undefined;
186    },
187
188    updateContents_: function() {
189      var previouslyActivePanelType = this.activePanelType;
190
191      this.tabStrip_.textContent = '';
192      var supportedPanelTypes = [];
193
194      var panelTypes =
195          tr.ui.b.getPolymerElementsThatSubclass('tr-ui-side-panel');
196      panelTypes.forEach(function(panelType) {
197        var labelEl = document.createElement('tab-strip-label');
198        var panel = document.createElement(panelType);
199
200        labelEl.textContent = panel.textLabel;
201        labelEl.panelType = panelType;
202
203        var supported = panel.supportsModel(this.model);
204        if (this.model && supported.supported) {
205          supportedPanelTypes.push(panelType);
206          labelEl.setAttribute('enabled', true);
207          labelEl.addEventListener('click', function() {
208            this.activePanelType =
209                this.activePanelType === panelType ? undefined : panelType;
210          }.bind(this));
211        } else {
212          labelEl.title = 'Not supported for the current trace: ' +
213              supported.reason;
214          labelEl.style.display = 'none';
215        }
216        this.tabStrip_.appendChild(labelEl);
217      }, this);
218
219      // Restore the active panel, or collapse
220      if (previouslyActivePanelType &&
221          supportedPanelTypes.indexOf(previouslyActivePanelType) != -1) {
222        this.activePanelType = previouslyActivePanelType;
223        this.setAttribute('expanded', true);
224      } else {
225        this.activePanelContainer_.textContent = '';
226        this.removeAttribute('expanded');
227      }
228    },
229
230    get rangeOfInterest() {
231      return this.rangeOfInterest_;
232    },
233
234    set rangeOfInterest(range) {
235      if (range == undefined)
236        throw new Error('Must not be undefined');
237      this.rangeOfInterest_ = range;
238      if (this.activePanel)
239        this.activePanel.rangeOfInterest = range;
240    }
241  });
242  </script>
243</polymer-element>
244
245