File indexing completed on 2024-04-28 05:08:22
0001 /*************************************************************************** 0002 Copyright (C) 2001-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "field.h" 0026 #include "fieldformat.h" 0027 #include "utils/string_utils.h" 0028 0029 #include <KLocalizedString> 0030 0031 #include <algorithm> 0032 0033 using namespace Tellico; 0034 using Tellico::Data::Field; 0035 0036 // this constructor is for anything but Choice type 0037 Field::Field(const QString& name_, const QString& title_, Type type_/*=Line*/) 0038 : QSharedData(), m_name(Tellico::shareString(name_)), m_title(title_), m_category(i18n("General")), m_desc(title_), 0039 m_type(type_), m_flags(0), m_formatType(FieldFormat::FormatNone) { 0040 0041 Q_ASSERT(m_type != Choice); 0042 // a paragraph's category is always its title, along with tables 0043 if(isSingleCategory()) { 0044 m_category = m_title; 0045 } 0046 switch(m_type) { 0047 case Table: 0048 case Table2: 0049 m_flags = AllowMultiple; 0050 if(m_type == Table2) { 0051 m_type = Table; 0052 setProperty(QStringLiteral("columns"), QStringLiteral("2")); 0053 } else { 0054 setProperty(QStringLiteral("columns"), QStringLiteral("1")); 0055 } 0056 break; 0057 case Date: // hidden from user 0058 m_formatType = FieldFormat::FormatDate; 0059 break; 0060 case Rating: 0061 setProperty(QStringLiteral("minimum"), QStringLiteral("1")); 0062 setProperty(QStringLiteral("maximum"), QStringLiteral("5")); 0063 break; 0064 case ReadOnly: 0065 m_flags = NoEdit; 0066 m_type = Line; 0067 break; 0068 case Dependent: 0069 m_flags = Derived; 0070 m_type = Line; 0071 break; 0072 default: // ssshhhhhhhh 0073 break; 0074 } 0075 } 0076 0077 // if this constructor is called, the type is necessarily Choice 0078 Field::Field(const QString& name_, const QString& title_, const QStringList& allowed_) 0079 : QSharedData(), m_name(Tellico::shareString(name_)), m_title(title_), m_category(i18n("General")), m_desc(title_), 0080 m_type(Field::Choice), m_allowed(allowed_), m_flags(0), m_formatType(FieldFormat::FormatNone) { 0081 } 0082 0083 Field::Field(const Field& field_) 0084 : QSharedData(field_), m_name(field_.name()), m_title(field_.title()), m_category(field_.category()), 0085 m_desc(field_.description()), m_type(field_.type()), m_allowed(field_.allowed()), 0086 m_flags(field_.flags()), m_formatType(field_.formatType()), 0087 m_properties(field_.propertyList()) { 0088 } 0089 0090 Field& Field::operator=(const Field& field_) { 0091 if(this == &field_) return *this; 0092 0093 // static_cast<QSharedData&>(*this) = static_cast<const QSharedData&>(field_); 0094 m_name = field_.name(); 0095 m_title = field_.title(); 0096 m_category = field_.category(); 0097 m_desc = field_.description(); 0098 m_type = field_.type(); 0099 m_allowed = field_.allowed(); 0100 m_flags = field_.flags(); 0101 m_formatType = field_.formatType(); 0102 m_properties = field_.propertyList(); 0103 return *this; 0104 } 0105 0106 Field::~Field() = default; 0107 0108 void Field::setTitle(const QString& title_) { 0109 m_title = title_; 0110 if(isSingleCategory()) { 0111 m_category = title_; 0112 } 0113 } 0114 0115 void Field::setType(Field::Type type_) { 0116 m_type = type_; 0117 if(m_type != Field::Choice) { 0118 m_allowed = QStringList(); 0119 } 0120 switch(m_type) { 0121 case Table: 0122 case Table2: 0123 m_flags |= AllowMultiple; 0124 if(m_type == Table2) { 0125 m_type = Table; 0126 setProperty(QStringLiteral("columns"), QStringLiteral("2")); 0127 } 0128 if(property(QStringLiteral("columns")).isEmpty()) { 0129 setProperty(QStringLiteral("columns"), QStringLiteral("1")); 0130 } 0131 break; 0132 case Date: 0133 m_formatType = FieldFormat::FormatDate; 0134 break; 0135 case ReadOnly: 0136 m_flags |= NoEdit; 0137 m_type = Line; 0138 break; 0139 case Dependent: 0140 m_flags |= Derived; 0141 m_type = Line; 0142 break; 0143 default: // ssshhhhhhhh 0144 break; 0145 } 0146 if(isSingleCategory()) { 0147 m_category = m_title; 0148 } 0149 } 0150 0151 void Field::setCategory(const QString& category_) { 0152 if(!isSingleCategory()) { 0153 m_category = category_; 0154 } 0155 } 0156 0157 void Field::setFlags(int flags_) { 0158 // tables always have multiple allowed 0159 if(m_type == Table) { 0160 m_flags = AllowMultiple | flags_; 0161 } else { 0162 m_flags = flags_; 0163 } 0164 } 0165 0166 bool Field::hasFlag(FieldFlag flag_) const { 0167 return m_flags & flag_; 0168 } 0169 0170 void Field::setFormatType(FieldFormat::Type type_) { 0171 // Choice and Data fields are not allowed a format type 0172 if(m_type != Choice && m_type != Date) { 0173 m_formatType = type_; 0174 } 0175 } 0176 0177 QString Field::defaultValue() const { 0178 return property(QStringLiteral("default")); 0179 } 0180 0181 void Field::setDefaultValue(const QString& value_) { 0182 if(value_.isEmpty() || m_type != Choice || m_allowed.contains(value_)) { 0183 setProperty(QStringLiteral("default"), value_); 0184 } 0185 } 0186 0187 bool Field::isSingleCategory() const { 0188 return (m_type == Para || m_type == Table || m_type == Image); 0189 } 0190 0191 // if these are changed, then CollectionFieldsDialog should be checked since it 0192 // checks for equality against some of these strings 0193 Field::FieldMap Field::typeMap() { 0194 FieldMap map; 0195 map[Field::Line] = i18n("Simple Text"); 0196 map[Field::Para] = i18n("Paragraph"); 0197 map[Field::Choice] = i18n("Choice"); 0198 map[Field::Bool] = i18n("Checkbox"); 0199 map[Field::Number] = i18n("Number"); 0200 map[Field::URL] = i18n("URL"); 0201 map[Field::Table] = i18n("Table"); 0202 map[Field::Image] = i18n("Image"); 0203 map[Field::Date] = i18n("Date"); 0204 map[Field::Rating] = i18n("Rating"); 0205 return map; 0206 } 0207 0208 // just for formatting's sake 0209 QStringList Field::typeTitles() { 0210 const FieldMap& map = typeMap(); 0211 QStringList list; 0212 list.append(map[Field::Line]); 0213 list.append(map[Field::Para]); 0214 list.append(map[Field::Choice]); 0215 list.append(map[Field::Bool]); 0216 list.append(map[Field::Number]); 0217 list.append(map[Field::URL]); 0218 list.append(map[Field::Date]); 0219 list.append(map[Field::Table]); 0220 list.append(map[Field::Image]); 0221 list.append(map[Field::Rating]); 0222 return list; 0223 } 0224 0225 void Field::addAllowed(const QString& value_) { 0226 if(m_type != Choice) { 0227 return; 0228 } 0229 if(!m_allowed.contains(value_)) { 0230 m_allowed += value_; 0231 } 0232 } 0233 0234 void Field::setProperty(const QString& key_, const QString& value_) { 0235 if(value_.isEmpty()) { 0236 m_properties.remove(key_); 0237 } else { 0238 m_properties.insert(key_, value_); 0239 } 0240 } 0241 0242 void Field::setPropertyList(const Tellico::StringMap& props_) { 0243 m_properties = props_; 0244 } 0245 0246 QString Field::property(const QString& key_) const { 0247 return m_properties.value(key_); 0248 } 0249 0250 void Field::convertOldRating(Tellico::Data::FieldPtr field_) { 0251 if(field_->type() != Data::Field::Choice) { 0252 return; // nothing to do 0253 } 0254 0255 if(field_->name() != QLatin1String("rating") 0256 && field_->property(QStringLiteral("rating")) != QLatin1String("true")) { 0257 return; // nothing to do 0258 } 0259 0260 int min = 10; 0261 int max = 1; 0262 bool ok; 0263 const QStringList& allow = field_->allowed(); 0264 for(QStringList::ConstIterator it = allow.begin(); it != allow.end(); ++it) { 0265 int n = Tellico::toUInt(*it, &ok); 0266 if(!ok) { 0267 return; // no need to convert 0268 } 0269 min = qMin(min, n); 0270 max = qMax(max, n); 0271 } 0272 min = qMax(max, 1); 0273 max = qMin(max, 10); 0274 if(min >= max) { 0275 min = 1; 0276 max = 5; 0277 } 0278 field_->setProperty(QStringLiteral("minimum"), QString::number(min)); 0279 field_->setProperty(QStringLiteral("maximum"), QString::number(max)); 0280 //remove any old property 0281 field_->setProperty(QStringLiteral("rating"), QString()); 0282 field_->setType(Rating); 0283 } 0284 0285 Tellico::Data::FieldPtr Field::createDefaultField(DefaultField fieldEnum) { 0286 Data::FieldPtr field; 0287 switch(fieldEnum) { 0288 case IDField: 0289 field = new Field(QStringLiteral("id"), i18nc("ID # of the entry", "ID"), Field::Number); 0290 field->setCategory(i18n("Personal")); 0291 field->setProperty(QStringLiteral("template"), QStringLiteral("%{@id}")); 0292 field->setFlags(Field::Derived); 0293 field->setFormatType(FieldFormat::FormatNone); 0294 break; 0295 case TitleField: 0296 field = new Field(QStringLiteral("title"), i18n("Title")); 0297 field->setCategory(i18n("General")); 0298 field->setFlags(Field::NoDelete); 0299 field->setFormatType(FieldFormat::FormatTitle); 0300 break; 0301 case CreatedDateField: 0302 field = new Field(QStringLiteral("cdate"), i18n("Date Created"), Field::Date); 0303 field->setCategory(i18n("Personal")); 0304 field->setFlags(Field::NoEdit); 0305 break; 0306 case ModifiedDateField: 0307 field = new Field(QStringLiteral("mdate"), i18n("Date Modified"), Field::Date); 0308 field->setCategory(i18n("Personal")); 0309 field->setFlags(Field::NoEdit); 0310 break; 0311 case IsbnField: 0312 field = new Field(QStringLiteral("isbn"), i18n("ISBN#")); 0313 field->setCategory(i18n("Publishing")); 0314 field->setDescription(i18n("International Standard Book Number")); 0315 break; 0316 case LccnField: 0317 field = new Field(QStringLiteral("lccn"), i18n("LCCN#")); 0318 field->setCategory(i18n("Publishing")); 0319 field->setDescription(i18n("Library of Congress Control Number")); 0320 break; 0321 case PegiField: 0322 { 0323 QStringList pegi = QStringLiteral("PEGI 3, PEGI 7, PEGI 12, PEGI 16, PEGI 18") 0324 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) 0325 .split(FieldFormat::commaSplitRegularExpression(), QString::SkipEmptyParts); 0326 #else 0327 .split(FieldFormat::commaSplitRegularExpression(), Qt::SkipEmptyParts); 0328 #endif 0329 field = new Field(QStringLiteral("pegi"), i18n("PEGI Rating"), pegi); 0330 } 0331 field->setCategory(i18n("General")); 0332 field->setFlags(Field::AllowGrouped); 0333 break; 0334 case ImdbField: 0335 field = new Field(QStringLiteral("imdb"), i18n("IMDb Link"), Field::URL); 0336 field->setCategory(i18n("General")); 0337 break; 0338 case EpisodeField: 0339 field = new Data::Field(QStringLiteral("episode"), i18n("Episodes"), Data::Field::Table); 0340 field->setFormatType(FieldFormat::FormatTitle); 0341 field->setProperty(QStringLiteral("columns"), QStringLiteral("3")); 0342 field->setProperty(QStringLiteral("column1"), i18n("Title")); 0343 field->setProperty(QStringLiteral("column2"), i18nc("TV Season", "Season")); 0344 field->setProperty(QStringLiteral("column3"), i18nc("TV Episode", "Episode")); 0345 break; 0346 case ScreenshotField: 0347 field = new Field(QStringLiteral("screenshot"), i18n("Screenshot"), Field::Image); 0348 break; 0349 case FrontCoverField: 0350 field = new Field(QStringLiteral("cover"), i18n("Front Cover"), Field::Image); 0351 break; 0352 } 0353 Q_ASSERT(field); 0354 return field; 0355 } 0356 0357 Tellico::Data::FieldList Tellico::listIntersection(const Tellico::Data::FieldList& list1, const Tellico::Data::FieldList& list2) { 0358 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) 0359 // QList::toSet is deprecated 0360 return list1.toSet().intersect(list2.toSet()).values(); 0361 #else 0362 // std::set_intersection requires sorted lists. Just do the set intersection manually 0363 Data::FieldList returnList; 0364 QSet<Tellico::Data::FieldPtr> set(list1.begin(), list1.end()); 0365 0366 std::for_each(list2.begin(), list2.end(), 0367 [&set, &returnList](const Data::FieldPtr& f) { 0368 if(set.contains(f)) { 0369 returnList.append(f); 0370 set.remove(f); 0371 } 0372 } 0373 ); 0374 return returnList; 0375 #endif 0376 }