github.com/qlik-oss/gopherciser@v0.18.6/senseobjects/listbox.go (about)

     1  package senseobjects
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/goccy/go-json"
     8  	"github.com/pkg/errors"
     9  	"github.com/qlik-oss/enigma-go/v4"
    10  	"github.com/qlik-oss/gopherciser/senseobjdef"
    11  )
    12  
    13  type (
    14  	// ListBoxProperties listbox properties
    15  	ListBoxProperties struct {
    16  		Info    enigma.NxInfo    `json:"qInfo,omitempty"`
    17  		MetaDef enigma.NxMetaDef `json:"qMetaDef,omitempty"`
    18  	}
    19  
    20  	// ListBox container with listbox in sense app
    21  	ListBox struct {
    22  		Dirty bool // Set flag to have object update before accessing layout next time
    23  
    24  		EnigmaObject *enigma.GenericObject
    25  		layout       *enigma.GenericObjectLayout
    26  		listobject   *enigma.ListObject
    27  		properties   *ListBoxProperties
    28  		mutex        sync.Mutex
    29  	}
    30  )
    31  
    32  var (
    33  	DefaultListboxInitialDataFetch = []*enigma.NxPage{{Height: 20, Width: 1}}
    34  )
    35  
    36  func (listBox *ListBox) setLayout(layout *enigma.GenericObjectLayout, lock bool) {
    37  	if lock {
    38  		listBox.mutex.Lock()
    39  		defer listBox.mutex.Unlock()
    40  	}
    41  	listBox.layout = layout
    42  	listBox.listobject = layout.ListObject
    43  }
    44  
    45  func (listBox *ListBox) setProperties(properties *ListBoxProperties) {
    46  	listBox.mutex.Lock()
    47  	defer listBox.mutex.Unlock()
    48  	listBox.properties = properties
    49  }
    50  
    51  func (listBox *ListBox) setDataPages(datapages []*enigma.NxDataPage, lock bool) error {
    52  	if lock {
    53  		listBox.mutex.Lock()
    54  		defer listBox.mutex.Unlock()
    55  	}
    56  	if listBox.listobject == nil {
    57  		return errors.Errorf("listbox has no listobject")
    58  	}
    59  	listBox.listobject.DataPages = datapages
    60  	return nil
    61  }
    62  
    63  // UpdateLayout get and set a new layout for listbox
    64  func (listBox *ListBox) UpdateLayout(ctx context.Context) error {
    65  	return listBox.updateLayout(ctx, true)
    66  }
    67  
    68  // UpdateLayout get and set a new layout for listbox
    69  func (listBox *ListBox) updateLayout(ctx context.Context, lock bool) error {
    70  	if listBox.EnigmaObject == nil {
    71  		return errors.Errorf("listBox enigma object is nil")
    72  	}
    73  
    74  	layoutRaw, err := listBox.EnigmaObject.GetLayoutRaw(ctx)
    75  	if err != nil {
    76  		return errors.Wrap(err, "Failed to get listBox layout")
    77  	}
    78  
    79  	var layout enigma.GenericObjectLayout
    80  	err = json.Unmarshal(layoutRaw, &layout)
    81  	if err != nil {
    82  		return errors.Wrap(err, "Failed to unmarshal listBox layout")
    83  	}
    84  
    85  	listBox.setLayout(&layout, lock)
    86  
    87  	_, err = listBox.getListObjectData(ctx, lock)
    88  	return errors.WithStack(err)
    89  }
    90  
    91  // UpdateProperties get and set properties for listBox
    92  func (listBox *ListBox) UpdateProperties(ctx context.Context) error {
    93  	if listBox.EnigmaObject == nil {
    94  		return errors.Errorf("listBox enigma object is nil")
    95  	}
    96  
    97  	propertiesRaw, err := listBox.EnigmaObject.GetEffectivePropertiesRaw(ctx)
    98  	if err != nil {
    99  		return errors.Wrapf(err, "Failed to unmarshal listBox properties")
   100  	}
   101  
   102  	var properties ListBoxProperties
   103  	err = json.Unmarshal(propertiesRaw, &properties)
   104  	if err != nil {
   105  		return errors.Wrap(err, "Failed to unmarshal listBox properties")
   106  	}
   107  
   108  	listBox.setProperties(&properties)
   109  	return nil
   110  }
   111  
   112  // GetListObjectData get datapages
   113  func (listBox *ListBox) getListObjectData(ctx context.Context, lock bool) ([]*enigma.NxDataPage, error) {
   114  	objDef, err := senseobjdef.GetObjectDef("listbox")
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	datapages, err := listBox.EnigmaObject.GetListObjectData(ctx, string(objDef.Data[0].Requests[0].Path), []*enigma.NxPage{
   120  		{
   121  			Left:   0,
   122  			Top:    0,
   123  			Width:  1,
   124  			Height: listBox.layout.ListObject.Size.Cy,
   125  		},
   126  	})
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	if err := listBox.setDataPages(datapages, lock); err != nil {
   132  		return nil, errors.WithStack(err)
   133  	}
   134  
   135  	return datapages, nil
   136  }
   137  
   138  // Layout for listBox, if layout needs updating this will lock object and update synchronously
   139  func (listBox *ListBox) Layout(ctx context.Context) (*enigma.GenericObjectLayout, error) {
   140  	listBox.mutex.Lock()
   141  	defer listBox.mutex.Unlock()
   142  
   143  	if listBox.Dirty {
   144  		if err := listBox.updateLayout(ctx, false); err != nil {
   145  			return nil, errors.WithStack(err)
   146  		}
   147  	}
   148  
   149  	return listBox.layout, nil
   150  }
   151  
   152  // Properties for listBox
   153  func (listBox *ListBox) Properties() *ListBoxProperties {
   154  	listBox.mutex.Lock()
   155  	defer listBox.mutex.Unlock()
   156  	return listBox.properties
   157  }
   158  
   159  // ListObject for listBox
   160  func (listBox *ListBox) ListObject(ctx context.Context) (*enigma.ListObject, error) {
   161  	listBox.mutex.Lock()
   162  	defer listBox.mutex.Unlock()
   163  
   164  	if listBox.Dirty {
   165  		if err := listBox.updateLayout(ctx, false); err != nil {
   166  			return nil, errors.WithStack(err)
   167  		}
   168  	}
   169  	return listBox.listobject, nil
   170  }
   171  
   172  // CreateFieldListBoxObject create listbox session object
   173  func CreateFieldListBoxObject(ctx context.Context, doc *enigma.Doc, name string) (*ListBox, error) {
   174  	return createListBoxObject(ctx, doc, &enigma.ListObjectDef{
   175  		Def: &enigma.NxInlineDimensionDef{
   176  			FieldDefs:   []string{name},
   177  			FieldLabels: []string{name},
   178  		},
   179  		InitialDataFetch: DefaultListboxInitialDataFetch,
   180  	})
   181  }
   182  
   183  // CreateLibraryBoxObject create listbox session object from library ID
   184  func CreateLibraryBoxObject(ctx context.Context, doc *enigma.Doc, id string) (*ListBox, error) {
   185  	return createListBoxObject(ctx, doc, &enigma.ListObjectDef{
   186  		LibraryId:        id,
   187  		InitialDataFetch: DefaultListboxInitialDataFetch,
   188  	})
   189  }
   190  
   191  func createListBoxObject(ctx context.Context, doc *enigma.Doc, objDef *enigma.ListObjectDef) (*ListBox, error) {
   192  	properties := &enigma.GenericObjectProperties{
   193  		Info: &enigma.NxInfo{
   194  			Type: "listbox",
   195  		},
   196  		ListObjectDef: objDef,
   197  	}
   198  
   199  	obj, err := doc.CreateSessionObjectRaw(ctx, properties)
   200  	if err != nil {
   201  		return nil, errors.Wrapf(err, "Failed to create listbox session object in app<%s>", doc.GenericId)
   202  	}
   203  
   204  	return &ListBox{
   205  		EnigmaObject: obj,
   206  	}, nil
   207  }