1 /*
2 * Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Andrew McCall <mccall@@digitalparadise.co.uk>
7 * Mike Berg <mike@berg-net.us>
8 * Julun <host.haiku@gmx.de>
9 * Philippe Saint-Pierre <stpere@gmail.com>
10 * Hamish Morrison <hamish@lavabit.com>
11 */
12
13 #include "DateTimeView.h"
14
15 #include <time.h>
16 #include <syscalls.h>
17
18 #include <Box.h>
19 #include <CalendarView.h>
20 #include <Catalog.h>
21 #include <CheckBox.h>
22 #include <ControlLook.h>
23 #include <DateTime.h>
24 #include <DateTimeEdit.h>
25 #include <Entry.h>
26 #include <File.h>
27 #include <FindDirectory.h>
28 #include <LocaleRoster.h>
29 #include <Message.h>
30 #include <Path.h>
31 #include <StringView.h>
32 #include <Window.h>
33
34 #include "AnalogClock.h"
35 #include "TimeMessages.h"
36 #include "TimeWindow.h"
37
38
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "Time"
41
42
43 using BPrivate::BCalendarView;
44 using BPrivate::BDateTime;
45 using BPrivate::B_LOCAL_TIME;
46 using BPrivate::DateEdit;
47 using BPrivate::TimeEdit;
48
49
DateTimeView(const char * name)50 DateTimeView::DateTimeView(const char* name)
51 :
52 BGroupView(name, B_HORIZONTAL, 5),
53 fInitialized(false),
54 fSystemTimeAtStart(system_time())
55 {
56 _InitView();
57
58 // record the current time to enable revert.
59 time(&fTimeAtStart);
60 }
61
62
~DateTimeView()63 DateTimeView::~DateTimeView()
64 {
65 }
66
67
68 void
AttachedToWindow()69 DateTimeView::AttachedToWindow()
70 {
71 AdoptParentColors();
72
73 if (!fInitialized) {
74 fInitialized = true;
75
76 fCalendarView->SetTarget(this);
77 }
78 }
79
80
81 void
MessageReceived(BMessage * message)82 DateTimeView::MessageReceived(BMessage* message)
83 {
84 int32 change;
85 switch (message->what) {
86 case B_OBSERVER_NOTICE_CHANGE:
87 message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change);
88 switch (change) {
89 case H_TM_CHANGED:
90 _UpdateDateTime(message);
91 break;
92
93 default:
94 BView::MessageReceived(message);
95 break;
96 }
97 break;
98
99 case B_LOCALE_CHANGED:
100 fCalendarView->UpdateDayNameHeader();
101 break;
102
103 case kDayChanged:
104 {
105 BMessage msg(*message);
106 msg.what = H_USER_CHANGE;
107 msg.AddBool("time", false);
108 Window()->PostMessage(&msg);
109 break;
110 }
111
112 case kMsgRevert:
113 _Revert();
114 break;
115
116 case kChangeTimeFinished:
117 if (fClock->IsChangingTime())
118 fTimeEdit->MakeFocus(false);
119 fClock->ChangeTimeFinished();
120 break;
121
122 case kRTCUpdate:
123 break;
124
125 default:
126 BView::MessageReceived(message);
127 break;
128 }
129 }
130
131
132 bool
CheckCanRevert()133 DateTimeView::CheckCanRevert()
134 {
135 // check for changed time
136 time_t unchangedNow = fTimeAtStart + _PrefletUptime();
137 time_t changedNow;
138 time(&changedNow);
139
140 return changedNow != unchangedNow;
141 }
142
143
144 void
_Revert()145 DateTimeView::_Revert()
146 {
147 // Set the clock and calendar as they were at launch time +
148 // time elapsed since application launch.
149
150 time_t timeNow = fTimeAtStart + _PrefletUptime();
151 struct tm result;
152 struct tm* timeInfo;
153 timeInfo = localtime_r(&timeNow, &result);
154
155 BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
156 BTime time = dateTime.Time();
157 BDate date = dateTime.Date();
158 time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60);
159 date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1,
160 timeInfo->tm_mday);
161 dateTime.SetTime(time);
162 dateTime.SetDate(date);
163
164 set_real_time_clock(dateTime.Time_t());
165 }
166
167
168 time_t
_PrefletUptime() const169 DateTimeView::_PrefletUptime() const
170 {
171 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000);
172 }
173
174
175 void
_InitView()176 DateTimeView::_InitView()
177 {
178 fCalendarView = new BCalendarView("calendar");
179 fCalendarView->SetWeekNumberHeaderVisible(false);
180 fCalendarView->SetSelectionMessage(new BMessage(kDayChanged));
181 fCalendarView->SetInvocationMessage(new BMessage(kDayChanged));
182
183 fDateEdit = new DateEdit("dateEdit", 3, new BMessage(H_USER_CHANGE));
184 fTimeEdit = new TimeEdit("timeEdit", 5, new BMessage(H_USER_CHANGE));
185 fClock = new TAnalogClock("analogClock");
186
187 BTime time(BTime::CurrentTime(B_LOCAL_TIME));
188 fClock->SetTime(time.Hour(), time.Minute(), time.Second());
189
190 BBox* divider = new BBox(BRect(0, 0, 1, 1),
191 B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
192 B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER);
193 divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED));
194
195 BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_DEFAULT_SPACING)
196 .AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
197 .Add(fDateEdit)
198 .Add(fCalendarView)
199 .End()
200 .Add(divider)
201 .AddGroup(B_VERTICAL)
202 .Add(fTimeEdit)
203 .Add(fClock)
204 .End()
205 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
206 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING);
207 }
208
209
210 void
_UpdateDateTime(BMessage * message)211 DateTimeView::_UpdateDateTime(BMessage* message)
212 {
213 int32 day;
214 int32 month;
215 int32 year;
216 if (message->FindInt32("month", &month) == B_OK
217 && message->FindInt32("day", &day) == B_OK
218 && message->FindInt32("year", &year) == B_OK) {
219 static int32 lastDay;
220 static int32 lastMonth;
221 static int32 lastYear;
222 if (day != lastDay || month != lastMonth || year != lastYear) {
223 fDateEdit->SetDate(year, month, day);
224 fCalendarView->SetDate(year, month, day);
225 lastDay = day;
226 lastMonth = month;
227 lastYear = year;
228 }
229 }
230
231 int32 hour;
232 int32 minute;
233 int32 second;
234 if (message->FindInt32("hour", &hour) == B_OK
235 && message->FindInt32("minute", &minute) == B_OK
236 && message->FindInt32("second", &second) == B_OK) {
237 fClock->SetTime(hour, minute, second);
238 fTimeEdit->SetTime(hour, minute, second);
239 }
240 }
241
242