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  }