农历日历 v1.0.4
载入中...
搜索中...
未找到
LunarCalendarModel.cpp
1
6#include "LunarCalendarModel.h"
7#include "CalendarLunar.h"
8#include "RabbitCommonDir.h"
9
10#include <QStandardPaths>
11#include <QTextCharFormat>
12#include <QDebug>
13#include <QPalette>
14#include <QApplication>
15#include <QStyle>
16#include <QDir>
17#include <QSqlError>
18#include <QSqlQuery>
19#include <QSqlRecord>
20#include <QFile>
21#include <QLoggingCategory>
22
23static Q_LOGGING_CATEGORY(Logger, "Rabbit.LunarCalendar.Model")
24static Q_LOGGING_CATEGORY(LogDB, "Rabbit.LunarCalendar.Model.Database")
25
27 : QAbstractTableModel(parent),
28 m_Date(QDate::currentDate()),
29 m_MinimumDate(-2000, 1, 1), //儒略日数(Julian Day Number,JDN)的计算是从格林威治标准时间的中午开始,包含一个整天的时间,起点的时间(0日)回溯至儒略历的公元前4713年1月1日中午12点(在格里历是公元前4714年11月24日)
30 m_MaximumDate(3000, 12, 31),
31 m_ShownYear(m_Date.year()),
32 m_ShownMonth(m_Date.month()),
33 m_ShowWeek(1),
34 m_bEnableHolidays(true),
35 m_bEnableSolarTerm(true),
36 m_bEnableToolTip(true)
37{
38 SetCalendarType(static_cast<CLunarCalendar::_CalendarType>(
41
42 SetViewType(static_cast<CLunarCalendar::_VIEW_TYPE>(
44
45 m_RowCount = 5;
46 m_ColumnCount = 7;
47 m_Locale = QLocale::system();
48 m_FirstDay = Qt::Monday; // m_Locale.firstDayOfWeek();
49 InitHoliday();
50
51 QString szSqlPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation)
52 + QDir::separator() + "Rabbit"
53 + QDir::separator() + "LunarCalendar";
54 QDir d;
55 if(!d.exists(szSqlPath))
56 d.mkpath(szSqlPath);
57 QString szChineseHolidaysSql = szSqlPath + QDir::separator() + "chinese_holidays.sql";
58 m_ChineseHolidaysSql.setFileName(szChineseHolidaysSql);
59 QVector<QUrl> urls;
60 urls << QUrl("https://sourceforge.net/p/lunarcalendar/code/ci/master/tree/Src/Resource/database/chinese_holidays.sql?format=raw")
61 << QUrl("https://gitee.com/kl222/LunarCalendar/raw/master/Src/Resource/database/chinese_holidays.sql")
62 << QUrl("https://github.com/KangLin/LunarCalendar/raw/master/Src/Resource/database/chinese_holidays.sql")
63 << QUrl("https://gitlab.com/kl222/LunarCalendar/-/raw/master/Src/Resource/database/chinese_holidays.sql");
64 DownloadChineseHolidaysSqlFile(urls);
65
66 m_HolidaysSql.setFileName(szSqlPath + QDir::separator() + "holidays.sql");
67 urls.clear();
68 urls << QUrl("https://sourceforge.net/p/lunarcalendar/code/ci/master/tree/Src/Resource/database/holidays.sql?format=raw")
69 << QUrl("https://gitee.com/kl222/LunarCalendar/raw/master/Src/Resource/database/holidays.sql")
70 << QUrl("https://github.com/KangLin/LunarCalendar/raw/master/Src/Resource/database/holidays.sql")
71 << QUrl("https://gitlab.com/kl222/LunarCalendar/-/raw/master/Src/Resource/database/holidays.sql");
72 DownloadHolidaysSqlFile(urls);
73
74 OpenDatabase();
75
76 slotUpdate();
77}
78
79CLunarCalendarModel::~CLunarCalendarModel()
80{
81 if(m_Database.isOpen())
82 m_Database.close();
83}
84
85QVariant CLunarCalendarModel::headerData(int section, Qt::Orientation orientation, int role) const
86{
87 switch (role) {
88 case Qt::TextAlignmentRole:
89 return static_cast<int>(Qt::AlignCenter);
90 case Qt::ForegroundRole:
91 if(Qt::Horizontal == orientation)
92 {
93 int day = section + m_FirstDay;
94 if(day > 7)
95 day %= 7;
96 if(Qt::Saturday == day || Qt::Sunday == day)
97 return GetHeight();
98 }
99 break;
100 case Qt::BackgroundRole:
101 {
102 QPalette palette = QApplication::style()->standardPalette();
103#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
104 return palette.window();
105#else
106 return palette.background();
107#endif
108 }
109 case Qt::DisplayRole:
110 switch (orientation) {
111 case Qt::Horizontal:
112 {
113 int day = section + m_FirstDay;
114 if(day > 7)
115 day %= 7;
116 return m_Locale.dayName(day, QLocale::NarrowFormat);
117 }
118 case Qt::Vertical:
119 QDate date = dateForCell(section, columnForDayOfWeek(Qt::Monday));
120 if (date.isValid())
121 return date.weekNumber();
122 else
123 return QVariant();
124 }
125 break;
126 default:
127 //qDebug(Logger) << "headerData:section:" << section << "role:" << role;
128 break;
129 };
130 return QVariant();
131}
132
133bool CLunarCalendarModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
134{
135 if (value != headerData(section, orientation, role)) {
136 return QAbstractTableModel::setHeaderData(section, orientation, value, role);
137 emit headerDataChanged(orientation, section, section);
138 return true;
139 }
140 return false;
141}
142
143int CLunarCalendarModel::rowCount(const QModelIndex &parent) const
144{
145 if (parent.isValid())
146 return 0;
147 return m_RowCount;
148}
149
150int CLunarCalendarModel::columnCount(const QModelIndex &parent) const
151{
152 if (parent.isValid())
153 return 0;
154 return m_ColumnCount;
155}
156
163QVariant CLunarCalendarModel::data(const QModelIndex &index, int role) const
164{
165 if (!index.isValid())
166 return QVariant();
167
168 int row = index.row();
169 int column = index.column();
170 QDate d = dateForCell(row, column);
171 if(!d.isValid())
172 return QVariant();
173
174 switch (role) {
175 case Qt::TextAlignmentRole:
176 return static_cast<int>(Qt::AlignCenter);
177 case Qt::DisplayRole:
178 case Qt::EditRole:
179 case ROLE::SolarRole:
180 return d.day();
181 case ROLE::SolarColorRole:
182 {
183 if(d.month() != m_ShownMonth
185 return _COLOR_ROLE::ColorDisable;
186
187 if(d.dayOfWeek() == Qt::Saturday
188 || Qt::Sunday == d.dayOfWeek()
189 //|| d == QDate::currentDate()
190 || !GetDay(row, column).SolarHoliday.isEmpty())
191 return _COLOR_ROLE::ColorHighlight;
192
193 return _COLOR_ROLE::ColorNormal;
194 }
195 case ROLE::SolarFontRole:
196 if(GetDay(row, column).SolarHoliday.isEmpty())
197 return _FONT_ROLE::FontNormal;
198
199 return _FONT_ROLE::FontBold;
200 case ROLE::TodayRole:
201 return d == QDate::currentDate();
202 case ROLE::LunarColorRole:
203 {
204 if(d.month() != m_ShownMonth
206 return _COLOR_ROLE::ColorDisable;
207
208 if(GetDay(row, column).LunarHoliday.isEmpty())
209 return _COLOR_ROLE::ColorNormal;
210
211 return _COLOR_ROLE::ColorHighlight;
212 }
213 case ROLE::LunarFontRole:
214 {
215 if(GetDay(row, column).LunarHoliday.isEmpty())
216 return _FONT_ROLE::FontNormal;
217
218 return _FONT_ROLE::FontBold;
219 }
220 case ROLE::LunarRole:
221 {
223 _DAY day = GetDay(row, column);
224 if(!day.SolarHoliday.isEmpty()) {
225 foreach(auto h, day.SolarHoliday) {
226 if(!h.isEmpty() && "" != h)
227 return h;
228 }
229 }
230 if(!day.LunarHoliday.isEmpty()) {
231 foreach (auto h, day.LunarHoliday) {
232 if(!h.isEmpty() && "" != h)
233 return h;
234 }
235 }
236 if(!day.Tasks.isEmpty()) {
237 foreach (auto h, day.Tasks) {
238 if(!h.isEmpty() && "" != h)
239 return h;
240 }
241 }
242 return day.szLunarDay;
243 }
244 case Qt::ToolTipRole:
245 {
250 if(!m_bEnableToolTip)
251 break;
252 int nTotals = 5;
253 int nCounts = 0;
254 QString szTip;
255 _DAY day = GetDay(row, column);
256 szTip = d.toString(m_Locale.dateFormat(QLocale::LongFormat));
257 szTip += "\n" + day.szLunar;
258 nCounts = 2;
259 if(!day.SolarHoliday.isEmpty()) {
260 foreach(auto h, day.SolarHoliday) {
261 if(h.isEmpty() || "" == h)
262 continue;
263 if(nCounts > nTotals)
264 break;
265 if(nCounts == nTotals)
266 {
267 nCounts++;
268 szTip += "\n……";
269 break;
270 }
271 nCounts++;
272 szTip += "\n" + h;
273 }
274 }
275 if(!day.LunarHoliday.isEmpty()) {
276 foreach (auto h, day.LunarHoliday) {
277 if(h.isEmpty() || "" == h)
278 continue;
279 if(nCounts > nTotals)
280 break;
281 if(nCounts == nTotals)
282 {
283 nCounts++;
284 szTip += "\n……";
285 break;
286 }
287 nCounts++;
288 szTip += "\n" + h;
289 }
290 }
291 if(!day.Tasks.isEmpty()) {
292 foreach (auto h, day.Tasks) {
293 if(h.isEmpty() || "" == h)
294 continue;
295 if(nCounts > nTotals)
296 break;
297 if(nCounts == nTotals)
298 {
299 nCounts++;
300 szTip += "\n……";
301 break;
302 }
303 nCounts++;
304 szTip += "\n" + h;
305 }
306 }
307 return szTip;
308 }
309 case ROLE::Tasks:
310 {
314 _DAY day = GetDay(row, column);
315 return day.TaskCounts + day.Tasks.size();
316 }
317 case ROLE::TasksColorRole:
318 if(d.month() != m_ShownMonth
320 return _COLOR_ROLE::ColorDisable;
321 return _COLOR_ROLE::ColorHighlight;
322 case ROLE::BackgroupImage:
323 return GetDay(row, column).szImageBackgroup;
324 case ROLE::WorkDayRole:
325 {
326 switch(GetDay(row, column).WorkDay)
327 {
328 case __WORK_DAY::WORK:
329 return "班";
330 case __WORK_DAY::REST:
331 return "休";
332 default:
333 break;
334 }
335 return "";
336 }
337 case ROLE::WorkDayColorRole:
338 if(d.month() != m_ShownMonth
340 return _COLOR_ROLE::ColorDisable;
341 if(__WORK_DAY::WORK == GetDay(row, column).WorkDay)
342 return _COLOR_ROLE::ColorHighlight;
343 /*if(d.dayOfWeek() == Qt::Saturday
344 || Qt::Sunday == d.dayOfWeek()
345 //|| d == QDate::currentDate()
346 || !GetDay(row, column).SolarHoliday.isEmpty())
347 return ColorHighlight;//*/
348 return _COLOR_ROLE::ColorNormal;
349 case ROLE::CalendarTypeRole:
350 return static_cast<int>(GetCalendarType());
351 default:
352 //qDebug(Logger) << "index:" << index << "role:" << role;
353 break;
354 };
355 return QVariant();
356}
357
358bool CLunarCalendarModel::setData(const QModelIndex &index, const QVariant &value, int role)
359{
360 bool bRet = true;
361 if (data(index, role) == value)
362 {
363 qDebug(Logger) << role << value << "value is same.";
364 return false;
365 }
366 switch(role)
367 {
368 case ROLE::CalendarTypeRole:
369 SetCalendarType(static_cast<CLunarCalendar::_CalendarType>(value.toInt()));
370 break;
371 default:
372 return QAbstractTableModel::setData(index, value, role);
373 }
374 return bRet;
375}
376
377Qt::ItemFlags CLunarCalendarModel::flags(const QModelIndex &index) const
378{
379 if (!index.isValid())
380 return Qt::NoItemFlags;
381 QDate date = dateForCell(index.row(), index.column());
382 if (!date.isValid())
383 return QAbstractTableModel::flags(index);
384 if (date < m_MinimumDate)
385 return Qt::NoItemFlags;
386 if (date > m_MaximumDate)
387 return Qt::NoItemFlags;
388 return QAbstractTableModel::flags(index);
389}
390
391int CLunarCalendarModel::showWeek(int year, int week, bool bForce)
392{
393 if (m_ShownYear == year && m_ShowWeek == week && !bForce)
394 return 0;
395 m_ShownYear = year;
396 m_ShowWeek = week;
397 return slotUpdate();
398}
399
400int CLunarCalendarModel::showMonth(int year, int month, bool bForce)
401{
402 if (m_ShownYear == year && m_ShownMonth == month && !bForce)
403 return 0;
404
405 m_ShownYear = year;
406 m_ShownMonth = month;
407 return slotUpdate();
408}
409
415int CLunarCalendarModel::slotUpdate()
416{
417 switch(m_viewType)
418 {
420 m_RowCount = 1;
421 break;
423 m_RowCount = WeeksOfMonth();
424 break;
425 }
426
427 //QTime tStart = QTime::currentTime();
428 m_Day.clear();
429 QDate d;
430 int row = 0;
431 do{
432 for(int col = 0; col < 7; col++)
433 {
434 //QTime tOnceStart = QTime::currentTime();
435
436 d = dateForCell(row, col);
437 if(!d.isValid())
438 break;
439 _DAY day = {0};
440 day.Solar = d.day();
441
442 if(m_bEnableHolidays) {
443 auto szHoliday = GetHoliday(d);
444 if(!szHoliday.isEmpty())
445 day.SolarHoliday << szHoliday;
446 }
447
448 //qDebug() << "exec dateForCell time:" << tOnceStart.msecsTo(QTime::currentTime());
449
450 if(static_cast<int>(m_calendarType)
452 {
453 CCalendarLunar lunar(d);
454 day.nLunarMonth = lunar.GetMonth();
455 day.nLunarDay = lunar.GetDay();
456 day.szLunar = lunar.GetLunar();
457 day.szLunarDay = lunar.GetLunarDay();
458
459 if(m_bEnableHolidays){
460 // 除夕
461 if(12 == day.nLunarMonth && 29 <= day.nLunarDay) {
462 CCalendarLunar l(d.addDays(1));
463 if(1 == l.GetMonth())
464 day.LunarHoliday << "除夕";
465 }
466 auto szLunarHoliday = GetLunarHoliday(lunar.GetMonth(), lunar.GetDay());
467 if(!szLunarHoliday.isEmpty())
468 day.LunarHoliday << szLunarHoliday;
469 }
470 if(m_bEnableSolarTerm && !lunar.GetJieQi().isEmpty()) {
471 day.LunarHoliday << lunar.GetJieQi();
472 }
473
474 day.szImageBackgroup = lunar.GetJieQiImage();
475 }
476
477 if(m_GetTaskHandler)
478 day.TaskCounts += m_GetTaskHandler->onHandle(d, day.Tasks);
479
480#if HAS_CPP_11
481 if(m_cbTaskHandler)
482 day.TaskCounts += m_cbTaskHandler(d, day.Tasks);
483#endif
484
485 day.WorkDay = GetChineseHolidays(d);
486 m_Day.push_back(day);
487
488 //qDebug() << "once time:" << tOnceStart.msecsTo(QTime::currentTime());
489 }
490
491 row++;
492 } while(d.isValid());
493 //qDebug() << "showMonth init totle time:" << tStart.msecsTo(QTime::currentTime());
494
495 internalUpdate();
496 return 0;
497}
498
499const int CLunarCalendarModel::GetShowYear() const
500{
501 return m_ShownYear;
502}
503
504const int CLunarCalendarModel::GetShowMonth() const
505{
506 return m_ShownMonth;
507}
508
509const int CLunarCalendarModel::GetShowWeek() const
510{
511 return m_ShowWeek;
512}
513
514int CLunarCalendarModel::setDate(const QDate &d)
515{
516 if(!d.isValid())
517 return -1;
518 m_Date = d;
519 if (m_Date < m_MinimumDate)
520 m_Date = m_MinimumDate;
521 else if (m_Date > m_MaximumDate)
522 m_Date = m_MaximumDate;
523 //TODO:这里可以不必要,因为会触发信号void sigSelectionChanged();
524 /*if(m_GetTaskHandler)
525 {
526 CCalendarLunar l(m_Date);
527 m_GetTaskHandler->onHandle(m_Date);
528 }//*/
529 return 0;
530}
531
532int CLunarCalendarModel::SetMinimumDate(const QDate &d)
533{
534 if (!d.isValid() || d == m_MinimumDate)
535 return 0;
536
537 m_MinimumDate = d;
538 if (m_MaximumDate < m_MinimumDate)
539 m_MaximumDate = m_MinimumDate;
540 if (m_Date < m_MinimumDate)
541 m_Date = m_MinimumDate;
542
543 internalUpdate();
544 return 0;
545}
546
547const QDate CLunarCalendarModel::GetMinimumDate() const
548{
549 return m_MinimumDate;
550}
551
552int CLunarCalendarModel::SetMaximumDate(const QDate &d)
553{
554 if (!d.isValid() || d == m_MaximumDate)
555 return 0;
556
557 m_MaximumDate = d;
558 if (m_MinimumDate > m_MaximumDate)
559 m_MinimumDate = m_MaximumDate;
560 if (m_Date > m_MaximumDate)
561 m_Date = m_MaximumDate;
562 internalUpdate();
563 return 0;
564}
565
566const QDate CLunarCalendarModel::GetMaximumDate() const
567{
568 return m_MaximumDate;
569}
570
571const Qt::DayOfWeek CLunarCalendarModel::firstDayOfWeek() const
572{
573 return m_FirstDay;
574}
575
576//void CLunarCalendarModel::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
577//{
578// m_FirstDay = dayOfWeek;
579//}
580
581int CLunarCalendarModel::setRange(const QDate &min, const QDate &max)
582{
583 m_MinimumDate = min;
584 m_MaximumDate = max;
585 if (m_MinimumDate > m_MaximumDate)
586 qSwap(m_MinimumDate, m_MaximumDate);
587 if (m_Date < m_MinimumDate)
588 m_Date = m_MinimumDate;
589 if (m_Date > m_MaximumDate)
590 m_Date = m_MaximumDate;
591 internalUpdate();
592 return 0;
593}
594
595const QDate CLunarCalendarModel::GetDate() const
596{
597 return m_Date;
598}
599
600void CLunarCalendarModel::internalUpdate()
601{
602 QModelIndex begin = index(0, 0);
603 QModelIndex end = index(m_RowCount - 1, m_ColumnCount - 1);
604 emit dataChanged(begin, end);
605 emit headerDataChanged(Qt::Vertical, 0, m_RowCount - 1);
606 emit headerDataChanged(Qt::Horizontal, 0, m_ColumnCount - 1);
607}
608
609const QDate CLunarCalendarModel::dateForCell(int row, int column) const
610{
611 switch (m_viewType) {
613 return dateForCellMonth(row, column);
615 return dateForCellWeek(row, column);
616 }
617 return QDate();
618}
619
620const QDate CLunarCalendarModel::dateForCellMonth(int row, int column) const
621{
622 if (row < 0 || row > m_RowCount - 1
623 || column < 0 || column > m_ColumnCount - 1)
624 return QDate();
625 const QDate refDate = firstDateMonth();
626 if (!refDate.isValid())
627 return QDate();
628
629 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
630 if (columnForFirstOfShownMonth < 0)
631 row -= 1;
632
633 const int requestedDay = 7 * (row) + column - columnForFirstOfShownMonth - refDate.day() + 1;
634 return refDate.addDays(requestedDay);
635}
636
637const QDate CLunarCalendarModel::dateForCellWeek(int row, int column) const
638{
639 if (row != 0 || column < 0 || column > m_ColumnCount - 1)
640 return QDate();
641
642 QDate firstOfYear(m_ShownYear, 1, 1);
643 QDate date;
644 int year = 0;
645 int weeks = m_ShowWeek;
646
647 if(1 != firstOfYear.weekNumber(&year))
648 weeks++;
649
650 date = firstOfYear.addDays((weeks -1 )* 7);
651 int col = columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek()));
652 QDate firstDayOfWeek = date.addDays(-col);
653 return firstDayOfWeek.addDays(column);
654}
655
656void CLunarCalendarModel::cellForDate(const QDate &date, int *row, int *column) const
657{
658 if (!row && !column)
659 return;
660
661 if (row)
662 *row = -1;
663 if (column)
664 *column = -1;
665
666 switch (m_viewType) {
668 return cellForDateMonth(date, row, column);
670 return cellForDateWeek(date, row, column);
671 }
672}
673
674void CLunarCalendarModel::cellForDateMonth(const QDate &date, int *row, int *column) const
675{
676 if (!row && !column)
677 return;
678
679 if (row)
680 *row = -1;
681 if (column)
682 *column = -1;
683
684 const QDate refDate = firstDateMonth();
685 if (!refDate.isValid())
686 return;
687
688 const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
689 const int requestedPosition = refDate.daysTo(date) + columnForFirstOfShownMonth + refDate.day() - 1;
690
691 int c = requestedPosition % 7;
692 int r = requestedPosition / 7;
693 if (c < 0) {
694 c += 7;
695 r -= 1;
696 }
697
698 if (columnForFirstOfShownMonth < 0)
699 r += 1;
700
701 if (r < 0 || r > m_RowCount - 1 || c < 0 || c > m_ColumnCount - 1)
702 return;
703
704 if (row)
705 *row = r;
706 if (column)
707 *column = c;
708}
709
710void CLunarCalendarModel::cellForDateWeek(const QDate &date, int *row, int *column) const
711{
712 if (!row && !column)
713 return;
714
715 if (row)
716 *row = -1;
717 if (column)
718 *column = -1;
719
720 int year;
721 int weeks = date.weekNumber(&year);
722 if(weeks != m_ShowWeek)
723 return;
724 if(date.year() != m_ShownYear && date.year() != year)
725 return;
726
727 *row = 0;
728 *column = columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek()));
729}
730
743const QDate CLunarCalendarModel::firstDateMonth() const
744{
745 int refDay = 1;
746 while (refDay <= 31) {
747 QDate refDate(m_ShownYear, m_ShownMonth, refDay);
748 if (refDate.isValid())
749 return refDate;
750 refDay += 1;
751 }
752 return QDate();
753}
754
755const QDate CLunarCalendarModel::endDateMonth() const
756{
757 int day = 31;
758 while(day >= 1)
759 {
760 QDate date(m_ShownYear, m_ShownMonth, day);
761 if(date.isValid())
762 return date;
763 day--;
764 }
765 return QDate();
766}
767
768const int CLunarCalendarModel::WeeksOfMonth() const
769{
770 if(1 == m_ShownMonth)
771 {
772 int y;
773 firstDateMonth().weekNumber(&y);
774 if(firstDateMonth().year() != y)
775 return endDateMonth().weekNumber() + 1;
776 }
777 if(12 == m_ShownMonth)
778 {
779 QDate date;
780 bool bNext = false;
781 int day = 31;
782 while(day >= 1)
783 {
784 QDate d(m_ShownYear, m_ShownMonth, day);
785 if(d.isValid())
786 {
787 int y;
788 d.weekNumber(&y);
789 if(d.year() == y)
790 {
791 date = d;
792 break;
793 } else
794 bNext = true;
795 }
796 day--;
797 }
798 if(bNext)
799 {
800 return date.weekNumber() - firstDateMonth().weekNumber() + 1 + 1;
801 }
802 }
803 return endDateMonth().weekNumber() - firstDateMonth().weekNumber() + 1;
804}
805
806const int CLunarCalendarModel::GetWeeksOfYear(int year) const
807{
808 QDate date(year, 1, 1);
809 QDate endDate = date.addDays(date.daysInYear());
810 int y = 0;
811 int nWeeks = endDate.weekNumber(&y);
812 if(m_ShownYear != y)
813 nWeeks = endDate.addDays(-7).weekNumber();
814 return nWeeks;
815}
816
817const int CLunarCalendarModel::columnForFirstOfMonth(const QDate &date) const
818{
819 return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek()))
820 - (date.day() % 7) + 8) % 7;
821}
822
823const int CLunarCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
824{
825 if (day < 1 || unsigned(day) > unsigned(7))
826 return -1;
827 int column = static_cast<int>(day) - static_cast<int>(m_FirstDay);
828 if (column < 0)
829 column += 7;
830 return column;
831}
832
833const QTextCharFormat CLunarCalendarModel::formatForCell(QDate d, int row, int col) const
834{
835 QTextCharFormat format;
836 QPalette pal = QApplication::style()->standardPalette();
837 QPalette::ColorGroup cg = QPalette::Active;
838
839 if(d.month() != m_ShownMonth)
840 {
841 cg = QPalette::Disabled;
842 }
843
844 format.setBackground(pal.brush(cg, QPalette::Window));
845 format.setForeground(pal.brush(cg, QPalette::Text));
846
847 if(d.dayOfWeek() == Qt::Saturday
848 || Qt::Sunday == d.dayOfWeek()
849 || d == QDate::currentDate()
850 || !GetDay(row, col).SolarHoliday.isEmpty())
851 {
852 format.setForeground(QBrush(GetHeight()));
853 }
854 if(!GetDay(row, col).SolarHoliday.isEmpty())
855 {
856 QFont font = format.font();
857 font.setBold(true);
858 format.setFont(font);
859 }
860 return format;
861}
862
863const QColor CLunarCalendarModel::GetHeight() const
864{
865 //return QColor(Qt::red);
866 QPalette pal = QApplication::style()->standardPalette();
867 QPalette::ColorGroup cg = QPalette::Active;
868 return pal.color(cg, QPalette::Highlight);
869}
870
871bool CLunarCalendarModel::EnableHolidays(bool bEnable)
872{
873 bool old = m_bEnableHolidays;
874 m_bEnableHolidays = bEnable;
875 return old;
876}
877
878bool CLunarCalendarModel::EnableSolarTerm(bool bEnable)
879{
880 bool old = m_bEnableSolarTerm;
881 m_bEnableSolarTerm = bEnable;
882 return old;
883}
884
885int CLunarCalendarModel::SetTaskHandle(QSharedPointer<CLunarCalendar::CTaskHandler> handler)
886{
887 m_GetTaskHandler = handler;
888 return 0;
889}
890
891#if HAS_CPP_11
895int CLunarCalendarModel::SetTaskHandle(
896 std::function<uint (/*in*/const QDate &,
897 /*out*/QStringList &)> cbHandler)
898{
899 m_cbTaskHandler = cbHandler;
900 return 0;
901}
902#endif
903
904CLunarCalendarModel::_DAY CLunarCalendarModel::GetDay(int row, int col) const
905{
906 return m_Day[row * 7 + col];
907}
908
909int CLunarCalendarModel::SetViewType(CLunarCalendar::_VIEW_TYPE type)
910{
911 m_viewType = type;
912 slotUpdate();
913 return 0;
914}
915
916const CLunarCalendar::_VIEW_TYPE CLunarCalendarModel::GetViewType() const
917{
918 return m_viewType;
919}
920
921int CLunarCalendarModel::SetCalendarType(CLunarCalendar::_CalendarType type)
922{
923 m_calendarType = type;
924 slotUpdate();
925 return 0;
926}
927
928void CLunarCalendarModel::EnableToolTip(bool enable) {
929 m_bEnableToolTip = enable;
930}
931
932const CLunarCalendar::_CalendarType CLunarCalendarModel::GetCalendarType() const
933{
934 return m_calendarType;
935}
936
937int CLunarCalendarModel::InitHoliday()
938{
939
940 /*
941 https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100?fromModule=disambiguation
942 https://baike.baidu.com/item/中国传统节日
943
944 节日名称 节日时间
945 春节 正月初一
946 元宵节(上元节)正月十五
947 龙抬头 二月初二
948 社日节(土地诞) 二月初二
949 花朝 南方一般2月12日,北方2月15日。但是新化叫“花烛节”为2月15日。难道祖先是从北方迁移过来的。
950 上巳节 三月初三
951 寒食节 清明节前一天
952 清明节 阳历4月5日前后
953 端午节 五月初五
954 天贶节 六月初六,晒衣节, 晒伏节“六月六,晒红绿。” “姑姑节”“六月六,请姑姑”。在古代还是另外一个节日,名叫天贶(赐赠的意思)节,六月六也是佛寺的一个节日,叫做翻经节,祭祀山神。
955 七夕节 七月初七
956 七月半(中元节) 七月十四/十五
957 中秋节 八月十五
958 重阳节 九月初九
959 寒衣节 十月初一
960 下元节 十月十五
961 冬至节 阳历12月22日前后
962 腊八节 腊月初八
963 祭灶节(小年) 腊月廿三或廿四
964 岁除(除夕)腊月廿九或三十
965 */
966
967 return 0;
968}
969
970int CLunarCalendarModel::OpenDatabase()
971{
972 int nRet = 0;
973 QString szDatabaseFile;
974 szDatabaseFile = RabbitCommon::CDir::Instance()->GetDirUserDatabase()
975 + QDir::separator() + "holidays.sqlite";
976 m_Database = QSqlDatabase::addDatabase("QSQLITE");
977 m_Database.setDatabaseName(szDatabaseFile);
978 QDir d;
979 if(d.exists(szDatabaseFile))
980 qDebug(LogDB) << "Database file is exists:" << szDatabaseFile;
981 else
982 {
983 qDebug(LogDB) << "Database file isn't exists:" << szDatabaseFile;
984 if(!m_Database.open())
985 {
986 qCritical(LogDB) << "Open database fail:" << m_Database.lastError()
987 << "database file: " << szDatabaseFile;
988 return m_Database.lastError().type();
989 }
990
991 nRet = InitTableHolidays();
992
993 nRet = InitTableChineseHolidays();
994
995 m_Database.close();
996 }
997
998 if(!m_Database.open())
999 {
1000 qCritical(LogDB) << "Open datebase fail. database name:"
1001 << m_Database.databaseName()
1002 << "database file:" << szDatabaseFile;
1003 return -3;
1004 }
1005
1006 return nRet;
1007}
1008
1009int CLunarCalendarModel::ExecSqlFile(const QString& szFile)
1010{
1011 QFile sqlFile(szFile);
1012 if(!sqlFile.open(QFile::ReadOnly))
1013 {
1014 qCritical(LogDB) << "Open sql file fail:" << szFile;
1015 return -1;
1016 }
1017
1018 QSqlQuery query(m_Database);
1019 QString szSql(sqlFile.readAll());
1020 QStringList sql = szSql.split(";");
1021 for(int i = 0; i < sql.size(); i++)
1022 {
1023 qDebug(LogDB) << "sql:" << sql[i];
1024 if(!query.exec(sql[i])
1025 && m_Database.lastError().type() != QSqlError::NoError)
1026 {
1027 qCritical(LogDB) << "Exec sql fail:" << m_Database.lastError();
1028 sqlFile.close();
1029 return -2;
1030 }
1031 }
1032
1033 sqlFile.close();
1034
1035 return 0;
1036}
1037
1038int CLunarCalendarModel::InitTableHolidays()
1039{
1040 if(!m_Database.isOpen())
1041 {
1042 qCritical(LogDB) << "The database isn't open." << m_Database.databaseName();
1043 return -1;
1044 }
1045
1046 QString szSqlFile = ":/database/Holidays";
1047#if !(defined (_DEBUG) || defined(DEBUG))
1048 szSqlFile = RabbitCommon::CDir::Instance()->GetDirUserDatabase()
1049 + QDir::separator() + "holidays.sql";
1050 if(!QFile::exists(szSqlFile))
1051 {
1052 QFile file(RabbitCommon::CDir::Instance()->GetDirDatabase(true)
1053 + QDir::separator() + "holidays.sql");
1054 if(file.copy(szSqlFile))
1055 qInfo(Logger) << "Copy holidays sql file success. from"
1056 << file.fileName() << "to" << szSqlFile;
1057 else
1058 qCritical(Logger) << "Copy holidays sql file fail. from"
1059 << file.fileName() << "to" << szSqlFile;
1060 }
1061#endif
1062
1063 return ExecSqlFile(szSqlFile);
1064}
1065
1069int CLunarCalendarModel::InitTableChineseHolidays()
1070{
1071 if(!m_Database.isOpen())
1072 {
1073 qCritical(LogDB) << "The database isn't open." << m_Database.databaseName();
1074 return -1;
1075 }
1076
1077 QString szSqlFile = ":/database/ChineseHolidays";
1078#if !(defined (_DEBUG) || defined(DEBUG))
1079 szSqlFile = RabbitCommon::CDir::Instance()->GetDirUserDatabase()
1080 + QDir::separator() + "chinese_holidays.sql";
1081 if(!QFile::exists(szSqlFile))
1082 {
1083 QFile file(RabbitCommon::CDir::Instance()->GetDirDatabase(true)
1084 + QDir::separator() + "chinese_holidays.sql");
1085 if(file.copy(szSqlFile))
1086 qInfo(Logger) << "Copy chinese holidays sql file success. from"
1087 << file.fileName() << "to" << szSqlFile;
1088 else
1089 qCritical(Logger) << "Copy chinese holidays sql file fail. from"
1090 << file.fileName() << "to" << szSqlFile;
1091 }
1092#endif
1093
1094 return ExecSqlFile(szSqlFile);
1095}
1096
1097void CLunarCalendarModel::CheckUpdateChineseHolidaysTable()
1098{
1099 bool bSame = true;
1100 QString szNativeSqlFile = RabbitCommon::CDir::Instance()->GetDirUserDatabase()
1101 + QDir::separator() + "chinese_holidays.sql";
1102
1103 QFile sqlNative(szNativeSqlFile);
1104
1105 do{
1106 if(m_ChineseHolidaysSql.size() == 0)
1107 break;
1108
1109 if(!m_ChineseHolidaysSql.isOpen())
1110 if(!m_ChineseHolidaysSql.open(QIODevice::ReadOnly))
1111 {
1112 qCritical(LogDB) << "Open update sql file fail."
1113 << m_ChineseHolidaysSql.fileName();
1114 break;
1115 }
1116
1117 QCryptographicHash md5Update(QCryptographicHash::Md5);
1118 if(!md5Update.addData(&m_ChineseHolidaysSql))
1119 {
1120 qCritical(Logger) << "Update sql file md5sum fail";
1121 break;
1122 }
1123
1124 if(!sqlNative.isOpen())
1125 if(!sqlNative.open(QIODevice::ReadOnly))
1126 {
1127 qCritical(LogDB) << "Open native sql file fail."
1128 << sqlNative.fileName();
1129 bSame = false;
1130 break;
1131 }
1132
1133 QCryptographicHash md5Native(QCryptographicHash::Md5);
1134 if(md5Native.addData(&sqlNative))
1135 {
1136 if(md5Update.result() == md5Native.result())
1137 {
1138 qInfo(Logger) << "The files is same:"
1139 << sqlNative.fileName()
1140 << m_ChineseHolidaysSql.fileName();
1141 break;
1142 }
1143 bSame = false;
1144 }
1145 }while(0);
1146
1147 if(sqlNative.isOpen())
1148 sqlNative.close();
1149 if(m_ChineseHolidaysSql.isOpen())
1150 m_ChineseHolidaysSql.close();
1151
1152 if(bSame) return;
1153
1154 qDebug(Logger) << "Update chinese_holidays.sql:"
1155 << sqlNative.fileName() << "from"
1156 << m_ChineseHolidaysSql.fileName();
1157
1158 if(QFile::exists(szNativeSqlFile))
1159 QFile::remove(szNativeSqlFile);
1160 if(m_ChineseHolidaysSql.copy(szNativeSqlFile))
1161 qInfo(Logger) << "Update chinese_holidays.sql success. from"
1162 << m_ChineseHolidaysSql.fileName()
1163 << "to" << sqlNative.fileName();
1164 else
1165 qCritical(Logger) << "Update chinese_holidays.sql fail. from"
1166 << m_ChineseHolidaysSql.fileName()
1167 << "to" << sqlNative.fileName();
1168
1169 InitTableChineseHolidays();
1170}
1171
1172void CLunarCalendarModel::slotDownloadChineseHolidaysSqlFileError(int nErr, const QString szError)
1173{
1174 qCritical(Logger) << "Download chinese holidays sql file error:" << nErr << szError;
1175 QString szMsg = szError;
1176 if(szMsg.isEmpty()) szMsg = tr("Download chinese holidays sql file fail");
1177 m_ChineseHolidaysSql.close();
1178}
1179
1180void CLunarCalendarModel::slotDownloadChineseHolidaysSqlFileFinished(const QString szFile)
1181{
1182 if(m_ChineseHolidaysSql.isOpen())
1183 m_ChineseHolidaysSql.close();
1184
1185 QString f = m_ChineseHolidaysSql.fileName();
1186 if(QFile::exists(f))
1187 QFile::remove(f);
1188 if(QFile::rename(szFile, f))
1189 qInfo(Logger) << "Download chinese_holidays.sql success: rename"
1190 << szFile << "to" << f;
1191 else
1192 qCritical(Logger) << "Download chinese_holidays.sql success. but rename fail from"
1193 << szFile << "to" << f;
1194 CheckUpdateChineseHolidaysTable();
1195 internalUpdate();
1196}
1197
1198int CLunarCalendarModel::DownloadChineseHolidaysSqlFile(const QVector<QUrl> &urls)
1199{
1200 int nRet = 0;
1201
1202 if(m_ChineseHolidaysSql.isOpen())
1203 m_ChineseHolidaysSql.close();
1204 if(!urls.isEmpty())
1205 {
1206 m_DownloadChineseHolidaysSql = QSharedPointer<RabbitCommon::CDownload>(
1207 new RabbitCommon::CDownload());
1208 bool check = connect(m_DownloadChineseHolidaysSql.data(), SIGNAL(sigFinished(const QString)),
1209 this, SLOT(slotDownloadChineseHolidaysSqlFileFinished(const QString)));
1210 Q_ASSERT(check);
1211 check = connect(m_DownloadChineseHolidaysSql.data(), SIGNAL(sigError(int, const QString)),
1212 this, SLOT(slotDownloadChineseHolidaysSqlFileError(int, const QString)));
1213 Q_ASSERT(check);
1214 m_DownloadChineseHolidaysSql->Start(urls);
1215 }
1216 return nRet;
1217}
1218
1219CLunarCalendarModel::__WORK_DAY CLunarCalendarModel::GetChineseHolidays(const QDate &d)
1220{
1221 __WORK_DAY day = __WORK_DAY::NO;
1222 if(!m_Database.isOpen())
1223 {
1224 qWarning(LogDB) << "The dababase isn't open."
1225 << m_Database.databaseName();
1226 return day;
1227 }
1228
1229 QSqlQuery query(m_Database);
1230 QString szSql = "select * from chinese_holidays where date='"
1231 + d.toString("yyyy-MM-dd") + "'";
1232 //qDebug(LogDB) << "Sql:" << szSql;
1233 if(query.exec(szSql))
1234 {
1235 while(query.next())
1236 {
1237 QVariant v = query.value("iswork");
1238 //qDebug(LogDB) << query.value("date") << "isWork:" << v;
1239 if(v.isValid())
1240 {
1241 if(v.toInt() == 1)
1242 day = __WORK_DAY::WORK;
1243 else
1244 day = __WORK_DAY::REST;
1245 }
1246 }
1247 } else
1248 qCritical(LogDB) << "Get chinese holiday fail."
1249 << query.lastError() << szSql;
1250
1251 return day;
1252}
1253
1254const QStringList CLunarCalendarModel::GetHoliday(const QDate &d) const
1255{
1256 QStringList lstHolidays;
1257 if(!m_Database.isOpen())
1258 {
1259 qWarning(LogDB) << "The dababase isn't open."
1260 << m_Database.databaseName();
1261 return QStringList();
1262 }
1263
1264 QString szFilter;
1265 QSqlQuery query(m_Database);
1266 QString szSql = "select * from holiday_filter where table_name='holidays'";
1267 //qDebug(LogDB) << "Sql:" << szSql;
1268 if(query.exec(szSql))
1269 {
1270 while(query.next())
1271 {
1272 QVariant v = query.value("filter");
1273 if(v.isValid())
1274 {
1275 szFilter = v.toString();
1276 }
1277 }
1278 } else
1279 qWarning(LogDB) << "Get holiday filter fail."
1280 << query.lastError() << szSql;
1281
1282 szSql = "select * from holidays where month="
1283 + QString::number(d.month())
1284 + " and day=" + QString::number(d.day());
1285 if(!szFilter.isEmpty())
1286 szSql += " " + szFilter;
1287 //qDebug(LogDB) << "Sql:" << szSql;
1288 if(query.exec(szSql))
1289 {
1290 while(query.next())
1291 {
1292 QVariant v = query.value("name");
1293 if(v.isValid())
1294 {
1295 QString szHoliday = v.toString();
1296 if(!szHoliday.isEmpty())
1297 lstHolidays << szHoliday;
1298 }
1299 }
1300 } else
1301 qCritical(LogDB) << "Get holiday fail."
1302 << query.lastError() << szSql;
1303
1304 return lstHolidays;
1305}
1306
1307const QStringList CLunarCalendarModel::GetLunarHoliday(int month, int day) const
1308{
1309 QStringList lstHolidays;
1310 if(!m_Database.isOpen())
1311 {
1312 qWarning(LogDB) << "The dababase isn't open."
1313 << m_Database.databaseName();
1314 return QStringList();
1315 }
1316
1317 QString szFilter;
1318 QSqlQuery query(m_Database);
1319 QString szSql = "select * from holiday_filter where table_name='holidays_lunar'";
1320 //qDebug(LogDB) << "Sql:" << szSql;
1321 if(query.exec(szSql))
1322 {
1323 while(query.next())
1324 {
1325 QVariant v = query.value("filter");
1326 if(v.isValid())
1327 {
1328 szFilter = v.toString();
1329 }
1330 }
1331 } else
1332 qWarning(LogDB) << "Get holiday filter fail."
1333 << query.lastError() << szSql;
1334 szSql = "select * from holidays_lunar where month="
1335 + QString::number(month)
1336 + " and day=" + QString::number(day);
1337 if(!szFilter.isEmpty())
1338 szSql += " " + szFilter;
1339 //qDebug(LogDB) << "Sql:" << szSql;
1340 if(query.exec(szSql))
1341 {
1342 while(query.next())
1343 {
1344 QVariant v = query.value("name");
1345 if(v.isValid())
1346 {
1347 QString szHoliday = v.toString();
1348 if(!szHoliday.isEmpty())
1349 lstHolidays << szHoliday;
1350 }
1351 }
1352 } else
1353 qCritical(LogDB) << "Get lunar holiday fail."
1354 << query.lastError() << szSql;
1355
1356 return lstHolidays;
1357}
1358
1359int CLunarCalendarModel::DownloadHolidaysSqlFile(const QVector<QUrl> &urls)
1360{
1361 int nRet = 0;
1362
1363 if(m_ChineseHolidaysSql.isOpen())
1364 m_ChineseHolidaysSql.close();
1365 if(!urls.isEmpty())
1366 {
1367 m_DownloadHolidaysSql = QSharedPointer<RabbitCommon::CDownload>(
1368 new RabbitCommon::CDownload());
1369 bool check = connect(m_DownloadHolidaysSql.data(), SIGNAL(sigFinished(const QString)),
1370 this, SLOT(slotDownloadHolidaysSqlFileFinished(const QString)));
1371 Q_ASSERT(check);
1372 check = connect(m_DownloadHolidaysSql.data(), SIGNAL(sigError(int, const QString)),
1373 this, SLOT(slotDownloadHolidaysSqlFileError(int, const QString)));
1374 Q_ASSERT(check);
1375 m_DownloadHolidaysSql->Start(urls);
1376 }
1377 return nRet;
1378}
1379
1380void CLunarCalendarModel::slotDownloadHolidaysSqlFileError(int nErr, const QString szError)
1381{
1382 qCritical(Logger) << "Download holidays sql file error:" << nErr << szError;
1383 QString szMsg = szError;
1384 if(szMsg.isEmpty()) szMsg = tr("Download holidays sql file fail");
1385 m_ChineseHolidaysSql.close();
1386}
1387
1388void CLunarCalendarModel::slotDownloadHolidaysSqlFileFinished(const QString szFile)
1389{
1390 if(m_ChineseHolidaysSql.isOpen())
1391 m_ChineseHolidaysSql.close();
1392
1393 QString f = m_ChineseHolidaysSql.fileName();
1394 if(QFile::exists(f))
1395 QFile::remove(f);
1396 if(QFile::rename(szFile, f))
1397 qInfo(Logger) << "Download holidays.sql success: rename"
1398 << szFile << "to" << f;
1399 else
1400 qCritical(Logger) << "Download holidays.sql success. but rename fail from"
1401 << szFile << "to" << f;
1402 CheckUpdateHolidaysTable();
1403 internalUpdate();
1404}
1405
1406void CLunarCalendarModel::CheckUpdateHolidaysTable()
1407{
1408 bool bSame = true;
1409 QString szNativeSqlFile = RabbitCommon::CDir::Instance()->GetDirUserDatabase()
1410 + QDir::separator() + "holidays.sql";
1411
1412 QFile sqlNative(szNativeSqlFile);
1413
1414 do{
1415 if(m_HolidaysSql.size() == 0)
1416 break;
1417
1418 if(!m_HolidaysSql.isOpen())
1419 if(!m_HolidaysSql.open(QIODevice::ReadOnly))
1420 {
1421 qCritical(LogDB) << "Open update sql file fail."
1422 << m_HolidaysSql.fileName();
1423 break;
1424 }
1425
1426 QCryptographicHash md5Update(QCryptographicHash::Md5);
1427 if(!md5Update.addData(&m_HolidaysSql))
1428 {
1429 qCritical(Logger) << "Update sql file md5sum fail";
1430 break;
1431 }
1432
1433 if(!sqlNative.isOpen())
1434 if(!sqlNative.open(QIODevice::ReadOnly))
1435 {
1436 qCritical(LogDB) << "Open native sql file fail."
1437 << sqlNative.fileName();
1438 bSame = false;
1439 break;
1440 }
1441
1442 QCryptographicHash md5Native(QCryptographicHash::Md5);
1443 if(md5Native.addData(&sqlNative))
1444 {
1445 if(md5Update.result() == md5Native.result())
1446 {
1447 qInfo(Logger) << "The files is same:"
1448 << sqlNative.fileName()
1449 << m_HolidaysSql.fileName();
1450 break;
1451 }
1452 bSame = false;
1453 }
1454 }while(0);
1455
1456 if(sqlNative.isOpen())
1457 sqlNative.close();
1458 if(m_HolidaysSql.isOpen())
1459 m_HolidaysSql.close();
1460
1461 if(bSame) return;
1462
1463 qDebug(Logger) << "Update holidays.sql:"
1464 << sqlNative.fileName() << "from"
1465 << m_HolidaysSql.fileName();
1466
1467 if(QFile::exists(szNativeSqlFile))
1468 QFile::remove(szNativeSqlFile);
1469 if(m_HolidaysSql.copy(szNativeSqlFile))
1470 qInfo(Logger) << "Update holidays.sql success. from"
1471 << m_HolidaysSql.fileName()
1472 << "to" << sqlNative.fileName();
1473 else
1474 qCritical(Logger) << "Update holidays.sql fail. from"
1475 << m_HolidaysSql.fileName()
1476 << "to" << sqlNative.fileName();
1477
1478 InitTableHolidays();
1479}
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
得到数据
_VIEW_TYPE
视图类型
_CalendarType
日历类型