1// Copyright (C) 2023 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import m from 'mithril'; 16import {copyToClipboard} from '../../base/clipboard'; 17import {assertExists} from '../../base/logging'; 18import {Icons} from '../../base/semantic_icons'; 19import {time, Time} from '../../base/time'; 20import {AppImpl} from '../../core/app_impl'; 21import {Anchor} from '../../widgets/anchor'; 22import {MenuDivider, MenuItem, PopupMenu2} from '../../widgets/menu'; 23import {Trace} from '../../public/trace'; 24import {TimestampFormatMenuItem} from './timestamp_format_menu'; 25import {renderTimecode} from '../time_utils'; 26import {TimestampFormat} from '../../public/timeline'; 27 28// import {MenuItem, PopupMenu2} from './menu'; 29 30interface TimestampAttrs { 31 // The timestamp to print, this should be the absolute, raw timestamp as 32 // found in trace processor. 33 ts: time; 34 // Custom text value to show instead of the default HH:MM:SS.mmm uuu nnn 35 // formatting. 36 display?: m.Children; 37 extraMenuItems?: m.Child[]; 38} 39 40export class Timestamp implements m.ClassComponent<TimestampAttrs> { 41 private readonly trace: Trace; 42 43 constructor() { 44 // TODO(primiano): the Trace object should be injected into the attrs, but 45 // there are too many users of this class and doing so requires a larger 46 // refactoring CL. Either that or we should find a different way to plumb 47 // the hoverCursorTimestamp. 48 this.trace = assertExists(AppImpl.instance.trace); 49 } 50 51 view({attrs}: m.Vnode<TimestampAttrs>) { 52 const {ts} = attrs; 53 const timeline = this.trace.timeline; 54 return m( 55 PopupMenu2, 56 { 57 trigger: m( 58 Anchor, 59 { 60 onmouseover: () => (timeline.hoverCursorTimestamp = ts), 61 onmouseout: () => (timeline.hoverCursorTimestamp = undefined), 62 }, 63 attrs.display ?? this.formatTimestamp(timeline.toDomainTime(ts)), 64 ), 65 }, 66 m(MenuItem, { 67 icon: Icons.Copy, 68 label: `Copy raw value`, 69 onclick: () => { 70 copyToClipboard(ts.toString()); 71 }, 72 }), 73 m(TimestampFormatMenuItem, {trace: this.trace}), 74 attrs.extraMenuItems ? [m(MenuDivider), attrs.extraMenuItems] : null, 75 ); 76 } 77 78 private formatTimestamp(time: time): m.Children { 79 const fmt = this.trace.timeline.timestampFormat; 80 switch (fmt) { 81 case TimestampFormat.UTC: 82 case TimestampFormat.TraceTz: 83 case TimestampFormat.Timecode: 84 return renderTimecode(time); 85 case TimestampFormat.TraceNs: 86 return time.toString(); 87 case TimestampFormat.TraceNsLocale: 88 return time.toLocaleString(); 89 case TimestampFormat.Seconds: 90 return Time.formatSeconds(time); 91 case TimestampFormat.Milliseconds: 92 return Time.formatMilliseconds(time); 93 case TimestampFormat.Microseconds: 94 return Time.formatMicroseconds(time); 95 default: 96 const x: never = fmt; 97 throw new Error(`Invalid timestamp ${x}`); 98 } 99 } 100} 101