datavalidation.go 7.8 KB
Newer Older
xurime's avatar
xurime 已提交
1
// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
xurime's avatar
xurime 已提交
2 3 4 5 6 7
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
// and read from XLSX files. Support reads and writes XLSX file generated by
// Microsoft Excel™ 2007 and later. Support save file without losing original
8
// charts of XLSX. This library needs Go version 1.10 or later.
xurime's avatar
xurime 已提交
9

Reage--'s avatar
Reage-- 已提交
10 11 12 13 14 15 16
package excelize

import (
	"fmt"
	"strings"
)

xurime's avatar
xurime 已提交
17
// DataValidationType defined the type of data validation.
Reage--'s avatar
Reage-- 已提交
18 19
type DataValidationType int

xurime's avatar
xurime 已提交
20
// Data validation types.
Reage--'s avatar
Reage-- 已提交
21 22
const (
	_DataValidationType = iota
xurime's avatar
xurime 已提交
23
	typeNone            // inline use
Reage--'s avatar
Reage-- 已提交
24 25 26
	DataValidationTypeCustom
	DataValidationTypeDate
	DataValidationTypeDecimal
xurime's avatar
xurime 已提交
27
	typeList // inline use
Reage--'s avatar
Reage-- 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40
	DataValidationTypeTextLeng
	DataValidationTypeTime
	// DataValidationTypeWhole Integer
	DataValidationTypeWhole
)

const (
	// dataValidationFormulaStrLen 255 characters+ 2 quotes
	dataValidationFormulaStrLen = 257
	// dataValidationFormulaStrLenErr
	dataValidationFormulaStrLenErr = "data validation must be 0-255 characters"
)

xurime's avatar
xurime 已提交
41
// DataValidationErrorStyle defined the style of data validation error alert.
Reage--'s avatar
Reage-- 已提交
42 43
type DataValidationErrorStyle int

xurime's avatar
xurime 已提交
44
// Data validation error styles.
Reage--'s avatar
Reage-- 已提交
45 46
const (
	_ DataValidationErrorStyle = iota
47 48 49
	DataValidationErrorStyleStop
	DataValidationErrorStyleWarning
	DataValidationErrorStyleInformation
Reage--'s avatar
Reage-- 已提交
50 51
)

xurime's avatar
xurime 已提交
52
// Data validation error styles.
Reage--'s avatar
Reage-- 已提交
53 54 55 56 57 58
const (
	styleStop        = "stop"
	styleWarning     = "warning"
	styleInformation = "information"
)

xurime's avatar
xurime 已提交
59
// DataValidationOperator operator enum.
Reage--'s avatar
Reage-- 已提交
60 61
type DataValidationOperator int

xurime's avatar
xurime 已提交
62
// Data validation operators.
Reage--'s avatar
Reage-- 已提交
63 64 65 66 67 68 69 70 71 72 73 74
const (
	_DataValidationOperator = iota
	DataValidationOperatorBetween
	DataValidationOperatorEqual
	DataValidationOperatorGreaterThan
	DataValidationOperatorGreaterThanOrEqual
	DataValidationOperatorLessThan
	DataValidationOperatorLessThanOrEqual
	DataValidationOperatorNotBetween
	DataValidationOperatorNotEqual
)

xurime's avatar
xurime 已提交
75
// NewDataValidation return data validation struct.
Reage--'s avatar
Reage-- 已提交
76 77
func NewDataValidation(allowBlank bool) *DataValidation {
	return &DataValidation{
xurime's avatar
xurime 已提交
78 79 80
		AllowBlank:       allowBlank,
		ShowErrorMessage: false,
		ShowInputMessage: false,
Reage--'s avatar
Reage-- 已提交
81 82 83
	}
}

xurime's avatar
xurime 已提交
84
// SetError set error notice.
85 86 87
func (dd *DataValidation) SetError(style DataValidationErrorStyle, title, msg string) {
	dd.Error = &msg
	dd.ErrorTitle = &title
Reage--'s avatar
Reage-- 已提交
88 89
	strStyle := styleStop
	switch style {
90
	case DataValidationErrorStyleStop:
Reage--'s avatar
Reage-- 已提交
91
		strStyle = styleStop
92
	case DataValidationErrorStyleWarning:
Reage--'s avatar
Reage-- 已提交
93
		strStyle = styleWarning
94
	case DataValidationErrorStyleInformation:
Reage--'s avatar
Reage-- 已提交
95 96 97
		strStyle = styleInformation

	}
xurime's avatar
xurime 已提交
98
	dd.ShowErrorMessage = true
Reage--'s avatar
Reage-- 已提交
99 100 101
	dd.ErrorStyle = &strStyle
}

xurime's avatar
xurime 已提交
102
// SetInput set prompt notice.
103
func (dd *DataValidation) SetInput(title, msg string) {
xurime's avatar
xurime 已提交
104
	dd.ShowInputMessage = true
105 106
	dd.PromptTitle = &title
	dd.Prompt = &msg
Reage--'s avatar
Reage-- 已提交
107 108
}

xurime's avatar
xurime 已提交
109
// SetDropList data validation list.
Reage--'s avatar
Reage-- 已提交
110
func (dd *DataValidation) SetDropList(keys []string) error {
111 112 113 114
	formula := "\"" + strings.Join(keys, ",") + "\""
	if dataValidationFormulaStrLen < len(formula) {
		return fmt.Errorf(dataValidationFormulaStrLenErr)
	}
115
	dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", formula)
Reage--'s avatar
Reage-- 已提交
116 117 118 119
	dd.Type = convDataValidationType(typeList)
	return nil
}

xurime's avatar
xurime 已提交
120
// SetRange provides function to set data validation range in drop list.
Reage--'s avatar
Reage-- 已提交
121 122 123
func (dd *DataValidation) SetRange(f1, f2 int, t DataValidationType, o DataValidationOperator) error {
	formula1 := fmt.Sprintf("%d", f1)
	formula2 := fmt.Sprintf("%d", f2)
124
	if dataValidationFormulaStrLen+21 < len(dd.Formula1) || dataValidationFormulaStrLen+21 < len(dd.Formula2) {
Reage--'s avatar
Reage-- 已提交
125 126 127
		return fmt.Errorf(dataValidationFormulaStrLenErr)
	}

128 129
	dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", formula1)
	dd.Formula2 = fmt.Sprintf("<formula2>%s</formula2>", formula2)
Reage--'s avatar
Reage-- 已提交
130 131 132 133 134
	dd.Type = convDataValidationType(t)
	dd.Operator = convDataValidationOperatior(o)
	return nil
}

135 136 137 138 139 140 141 142 143
// SetSqrefDropList provides set data validation on a range with source
// reference range of the worksheet by given data validation object and
// worksheet name. The data validation object can be created by
// NewDataValidation function. For example, set data validation on
// Sheet1!A7:B8 with validation criteria source Sheet1!E1:E3 settings, create
// in-cell dropdown by allowing list source:
//
//     dvRange := excelize.NewDataValidation(true)
//     dvRange.Sqref = "A7:B8"
144
//     dvRange.SetSqrefDropList("$E$1:$E$3", true)
xurime's avatar
xurime 已提交
145
//     f.AddDataValidation("Sheet1", dvRange)
146
//
147 148
func (dd *DataValidation) SetSqrefDropList(sqref string, isCurrentSheet bool) error {
	if isCurrentSheet {
149
		dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", sqref)
150 151 152
		dd.Type = convDataValidationType(typeList)
		return nil
	}
xurime's avatar
xurime 已提交
153
	return fmt.Errorf("cross-sheet sqref cell are not supported")
154 155
}

xurime's avatar
xurime 已提交
156
// SetSqref provides function to set data validation range in drop list.
Reage--'s avatar
Reage-- 已提交
157 158 159 160 161 162 163 164
func (dd *DataValidation) SetSqref(sqref string) {
	if dd.Sqref == "" {
		dd.Sqref = sqref
	} else {
		dd.Sqref = fmt.Sprintf("%s %s", dd.Sqref, sqref)
	}
}

xurime's avatar
xurime 已提交
165
// convDataValidationType get excel data validation type.
Reage--'s avatar
Reage-- 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
func convDataValidationType(t DataValidationType) string {
	typeMap := map[DataValidationType]string{
		typeNone:                   "none",
		DataValidationTypeCustom:   "custom",
		DataValidationTypeDate:     "date",
		DataValidationTypeDecimal:  "decimal",
		typeList:                   "list",
		DataValidationTypeTextLeng: "textLength",
		DataValidationTypeTime:     "time",
		DataValidationTypeWhole:    "whole",
	}

	return typeMap[t]

}

xurime's avatar
xurime 已提交
182
// convDataValidationOperatior get excel data validation operator.
Reage--'s avatar
Reage-- 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
func convDataValidationOperatior(o DataValidationOperator) string {
	typeMap := map[DataValidationOperator]string{
		DataValidationOperatorBetween:            "between",
		DataValidationOperatorEqual:              "equal",
		DataValidationOperatorGreaterThan:        "greaterThan",
		DataValidationOperatorGreaterThanOrEqual: "greaterThanOrEqual",
		DataValidationOperatorLessThan:           "lessThan",
		DataValidationOperatorLessThanOrEqual:    "lessThanOrEqual",
		DataValidationOperatorNotBetween:         "notBetween",
		DataValidationOperatorNotEqual:           "notEqual",
	}

	return typeMap[o]

}

xurime's avatar
xurime 已提交
199 200 201 202 203
// AddDataValidation provides set data validation on a range of the worksheet
// by given data validation object and worksheet name. The data validation
// object can be created by NewDataValidation function.
//
// Example 1, set data validation on Sheet1!A1:B2 with validation criteria
xurime's avatar
xurime 已提交
204
// settings, show error alert after invalid data is entered with "Stop" style
xurime's avatar
xurime 已提交
205 206 207
// and custom title "error body":
//
//     dvRange := excelize.NewDataValidation(true)
xurime's avatar
xurime 已提交
208
//     dvRange.Sqref = "A1:B2"
xurime's avatar
xurime 已提交
209 210
//     dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorBetween)
//     dvRange.SetError(excelize.DataValidationErrorStyleStop, "error title", "error body")
xurime's avatar
xurime 已提交
211
//     err := f.AddDataValidation("Sheet1", dvRange)
xurime's avatar
xurime 已提交
212 213 214 215 216 217 218 219
//
// Example 2, set data validation on Sheet1!A3:B4 with validation criteria
// settings, and show input message when cell is selected:
//
//     dvRange = excelize.NewDataValidation(true)
//     dvRange.Sqref = "A3:B4"
//     dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorGreaterThan)
//     dvRange.SetInput("input title", "input body")
xurime's avatar
xurime 已提交
220
//     err = f.AddDataValidation("Sheet1", dvRange)
xurime's avatar
xurime 已提交
221
//
xurime's avatar
xurime 已提交
222
// Example 3, set data validation on Sheet1!A5:B6 with validation criteria
223
// settings, create in-cell dropdown by allowing list source:
xurime's avatar
xurime 已提交
224 225 226 227
//
//     dvRange = excelize.NewDataValidation(true)
//     dvRange.Sqref = "A5:B6"
//     dvRange.SetDropList([]string{"1", "2", "3"})
xurime's avatar
xurime 已提交
228
//     err = f.AddDataValidation("Sheet1", dvRange)
xurime's avatar
xurime 已提交
229
//
xurime's avatar
xurime 已提交
230 231 232 233 234
func (f *File) AddDataValidation(sheet string, dv *DataValidation) error {
	xlsx, err := f.workSheetReader(sheet)
	if err != nil {
		return err
	}
Reage--'s avatar
Reage-- 已提交
235 236 237 238 239
	if nil == xlsx.DataValidations {
		xlsx.DataValidations = new(xlsxDataValidations)
	}
	xlsx.DataValidations.DataValidation = append(xlsx.DataValidations.DataValidation, dv)
	xlsx.DataValidations.Count = len(xlsx.DataValidations.DataValidation)
xurime's avatar
xurime 已提交
240
	return err
Reage--'s avatar
Reage-- 已提交
241
}