github.com/oam-dev/kubevela@v1.9.11/references/cli/top/model/stack.go (about) 1 /* 2 Copyright 2022 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package model 18 19 import "sync" 20 21 const ( 22 // stackPush is the "push" notify type 23 stackPush = iota 24 // StackPop is the "pop" notify type 25 StackPop 26 ) 27 28 // ViewListener listen notify from the main view of app and render itself again 29 type ViewListener interface { 30 // StackPop pop old component and render component 31 StackPop(old, new View) 32 // StackPush push a new component 33 StackPush(old, new View) 34 } 35 36 // Stack is a stack to store components and notify listeners of main view of app 37 type Stack struct { 38 views []View 39 listeners []ViewListener 40 mutex sync.RWMutex 41 } 42 43 // NewStack return a new stack instance 44 func NewStack() *Stack { 45 return &Stack{ 46 views: make([]View, 0), 47 listeners: make([]ViewListener, 0), 48 } 49 } 50 51 // AddListener add a new resource listener 52 func (s *Stack) AddListener(listener ViewListener) { 53 s.listeners = append(s.listeners, listener) 54 } 55 56 // RemoveListener remove the aim resource listener 57 func (s *Stack) RemoveListener(listener ViewListener) { 58 aimIndex := -1 59 for index, item := range s.listeners { 60 if item == listener { 61 aimIndex = index 62 } 63 } 64 if aimIndex == -1 { 65 return 66 } 67 s.listeners = append(s.listeners[:aimIndex], s.listeners[aimIndex+1:]...) 68 } 69 70 // TopView return top view of stack 71 func (s *Stack) TopView() View { 72 if s.Empty() { 73 return nil 74 } 75 return s.views[len(s.views)-1] 76 } 77 78 // IsLastView check whether stack only have one view now 79 func (s *Stack) IsLastView() bool { 80 return len(s.views) == 1 81 } 82 83 // PopView pop a view from stack 84 func (s *Stack) PopView() { 85 if s.Empty() { 86 return 87 } 88 89 s.mutex.Lock() 90 removeComponent := s.views[len(s.views)-1] 91 s.views = s.views[:len(s.views)-1] 92 s.mutex.Unlock() 93 94 s.notifyListener(StackPop, removeComponent, s.TopView()) 95 } 96 97 // PushView add a new view to stack 98 func (s *Stack) PushView(component View) { 99 old := s.TopView() 100 s.mutex.Lock() 101 s.views = append(s.views, component) 102 s.mutex.Unlock() 103 104 s.notifyListener(stackPush, old, component) 105 } 106 107 // Empty return whether stack is empty 108 func (s *Stack) Empty() bool { 109 return len(s.views) == 0 110 } 111 112 // Clear out the stack 113 func (s *Stack) Clear() { 114 for !s.Empty() { 115 s.PopView() 116 } 117 } 118 119 func (s *Stack) notifyListener(action int, old, new View) { 120 for _, listener := range s.listeners { 121 switch action { 122 case stackPush: 123 listener.StackPush(old, new) 124 case StackPop: 125 listener.StackPop(old, new) 126 } 127 } 128 }