1 /* 2 * Copyright 2004-2010, 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 */ 11 12 #include "DateTimeView.h" 13 #include "AnalogClock.h" 14 #include "DateTimeEdit.h" 15 #include "TimeMessages.h" 16 #include "TimeWindow.h" 17 18 #include <CalendarView.h> 19 #include <CheckBox.h> 20 #include <DateTime.h> 21 #include <Entry.h> 22 #include <File.h> 23 #include <FindDirectory.h> 24 #include <Message.h> 25 #include <Path.h> 26 #include <RadioButton.h> 27 #include <String.h> 28 #include <StringView.h> 29 #include <Window.h> 30 31 #include <time.h> 32 33 #include <syscalls.h> 34 35 36 using BPrivate::BCalendarView; 37 using BPrivate::BDateTime; 38 using BPrivate::B_LOCAL_TIME; 39 40 41 DateTimeView::DateTimeView(BRect frame) 42 : BView(frame, "dateTimeView", B_FOLLOW_NONE, B_WILL_DRAW 43 | B_NAVIGABLE_JUMP), 44 fGmtTime(NULL), 45 fUseGmtTime(false), 46 fInitialized(false), 47 fSystemTimeAtStart(system_time()) 48 { 49 _ReadRTCSettings(); 50 _InitView(); 51 52 // record the current time to enable revert. 53 time(&fTimeAtStart); 54 } 55 56 57 DateTimeView::~DateTimeView() 58 { 59 _WriteRTCSettings(); 60 } 61 62 63 void 64 DateTimeView::AttachedToWindow() 65 { 66 if (Parent()) 67 SetViewColor(Parent()->ViewColor()); 68 69 if (!fInitialized) { 70 fInitialized = true; 71 72 fCalendarView->SetTarget(this); 73 } 74 } 75 76 77 void 78 DateTimeView::Draw(BRect /*updateRect*/) 79 { 80 rgb_color viewcolor = ViewColor(); 81 rgb_color dark = tint_color(viewcolor, B_DARKEN_4_TINT); 82 rgb_color light = tint_color(viewcolor, B_LIGHTEN_MAX_TINT); 83 84 // draw a separator line 85 BRect bounds(Bounds()); 86 BPoint start(bounds.Width() / 2.0f, bounds.top + 5.0f); 87 BPoint end(bounds.Width() / 2.0, bounds.bottom - 5.0f); 88 89 BeginLineArray(2); 90 AddLine(start, end, dark); 91 start.x++; 92 end.x++; 93 AddLine(start, end, light); 94 EndLineArray(); 95 96 fTimeEdit->Draw(bounds); 97 fDateEdit->Draw(bounds); 98 } 99 100 101 void 102 DateTimeView::MessageReceived(BMessage* message) 103 { 104 int32 change; 105 switch (message->what) { 106 case B_OBSERVER_NOTICE_CHANGE: 107 message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change); 108 switch (change) { 109 case H_TM_CHANGED: 110 _UpdateDateTime(message); 111 break; 112 113 default: 114 BView::MessageReceived(message); 115 break; 116 } 117 break; 118 119 case kDayChanged: 120 { 121 BMessage msg(*message); 122 msg.what = H_USER_CHANGE; 123 msg.AddBool("time", false); 124 Window()->PostMessage(&msg); 125 break; 126 } 127 128 case kRTCUpdate: 129 fUseGmtTime = fGmtTime->Value() == B_CONTROL_ON; 130 _UpdateGmtSettings(); 131 break; 132 133 case kMsgRevert: 134 _Revert(); 135 break; 136 137 case kChangeTimeFinished: 138 if (fClock->IsChangingTime()) 139 fTimeEdit->MakeFocus(false); 140 fClock->ChangeTimeFinished(); 141 break; 142 143 default: 144 BView::MessageReceived(message); 145 break; 146 } 147 } 148 149 150 bool 151 DateTimeView::CheckCanRevert() 152 { 153 // check GMT vs Local setting 154 bool enable = fUseGmtTime != fOldUseGmtTime; 155 156 // check for changed time 157 time_t unchangedNow = fTimeAtStart + _PrefletUptime(); 158 time_t changedNow; 159 time(&changedNow); 160 161 return enable || (changedNow != unchangedNow); 162 } 163 164 165 void 166 DateTimeView::_Revert() 167 { 168 // Set the clock and calendar as they were at launch time + 169 // time elapsed since application launch. 170 171 fUseGmtTime = fOldUseGmtTime; 172 _UpdateGmtSettings(); 173 174 if (fUseGmtTime) 175 fGmtTime->SetValue(B_CONTROL_ON); 176 else 177 fLocalTime->SetValue(B_CONTROL_ON); 178 179 time_t timeNow = fTimeAtStart + _PrefletUptime(); 180 struct tm result; 181 struct tm* timeInfo; 182 timeInfo = localtime_r(&timeNow, &result); 183 184 BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); 185 BTime time = dateTime.Time(); 186 BDate date = dateTime.Date(); 187 time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60); 188 date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, 189 timeInfo->tm_mday); 190 dateTime.SetTime(time); 191 dateTime.SetDate(date); 192 193 set_real_time_clock(dateTime.Time_t()); 194 } 195 196 197 time_t 198 DateTimeView::_PrefletUptime() const 199 { 200 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000); 201 } 202 203 204 void 205 DateTimeView::_InitView() 206 { 207 font_height fontHeight; 208 be_plain_font->GetHeight(&fontHeight); 209 float textHeight = fontHeight.descent + fontHeight.ascent 210 + fontHeight.leading + 6.0; // 6px border 211 212 // left side 213 BRect bounds = Bounds(); 214 bounds.InsetBy(10.0, 10.0); 215 bounds.top += textHeight + 10.0; 216 217 fCalendarView = new BCalendarView(bounds, "calendar"); 218 fCalendarView->SetWeekNumberHeaderVisible(false); 219 fCalendarView->ResizeToPreferred(); 220 fCalendarView->SetSelectionMessage(new BMessage(kDayChanged)); 221 fCalendarView->SetInvocationMessage(new BMessage(kDayChanged)); 222 223 bounds.top -= textHeight + 10.0; 224 bounds.bottom = bounds.top + textHeight; 225 bounds.right = fCalendarView->Frame().right; 226 227 fDateEdit = new TDateEdit(bounds, "dateEdit", 3); 228 AddChild(fDateEdit); 229 AddChild(fCalendarView); 230 231 // right side, 2px extra for separator 232 bounds.OffsetBy(bounds.Width() + 22.0, 0.0); 233 fTimeEdit = new TTimeEdit(bounds, "timeEdit", 4); 234 AddChild(fTimeEdit); 235 236 bounds = fCalendarView->Frame(); 237 bounds.OffsetBy(bounds.Width() + 22.0, 0.0); 238 239 fClock = new TAnalogClock(bounds, "analogClock"); 240 AddChild(fClock); 241 BTime time(BTime::CurrentTime(B_LOCAL_TIME)); 242 fClock->SetTime(time.Hour(), time.Minute(), time.Second()); 243 244 // clock radio buttons 245 bounds.top = fClock->Frame().bottom + 10.0; 246 BStringView* text = new BStringView(bounds, "clockSetTo", "Clock set to:"); 247 AddChild(text); 248 text->ResizeToPreferred(); 249 250 bounds.left += 10.0f; 251 bounds.top = text->Frame().bottom; 252 fLocalTime = new BRadioButton(bounds, "localTime", "Local time", 253 new BMessage(kRTCUpdate)); 254 AddChild(fLocalTime); 255 fLocalTime->ResizeToPreferred(); 256 257 bounds.left = fLocalTime->Frame().right + 10.0; 258 fGmtTime = new BRadioButton(bounds, "greenwichMeanTime", "GMT", 259 new BMessage(kRTCUpdate)); 260 AddChild(fGmtTime); 261 fGmtTime->ResizeToPreferred(); 262 263 if (fUseGmtTime) 264 fGmtTime->SetValue(B_CONTROL_ON); 265 else 266 fLocalTime->SetValue(B_CONTROL_ON); 267 268 fOldUseGmtTime = fUseGmtTime; 269 270 ResizeTo(fClock->Frame().right + 10.0, fGmtTime->Frame().bottom + 10.0); 271 } 272 273 274 void 275 DateTimeView::_ReadRTCSettings() 276 { 277 BPath path; 278 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 279 return; 280 281 path.Append("RTC_time_settings"); 282 283 BEntry entry(path.Path()); 284 if (entry.Exists()) { 285 BFile file(&entry, B_READ_ONLY); 286 if (file.InitCheck() == B_OK) { 287 char buffer[6]; 288 file.Read(buffer, 6); 289 if (strncmp(buffer, "gmt", 3) == 0) 290 fUseGmtTime = true; 291 } 292 } 293 } 294 295 296 void 297 DateTimeView::_WriteRTCSettings() 298 { 299 BPath path; 300 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) 301 return; 302 303 path.Append("RTC_time_settings"); 304 305 BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); 306 if (file.InitCheck() == B_OK) { 307 if (fUseGmtTime) 308 file.Write("gmt", 3); 309 else 310 file.Write("local", 5); 311 } 312 } 313 314 315 void 316 DateTimeView::_UpdateGmtSettings() 317 { 318 _WriteRTCSettings(); 319 320 _kern_set_real_time_clock_is_gmt(fUseGmtTime); 321 } 322 323 324 void 325 DateTimeView::_UpdateDateTime(BMessage* message) 326 { 327 int32 day; 328 int32 month; 329 int32 year; 330 if (message->FindInt32("month", &month) == B_OK 331 && message->FindInt32("day", &day) == B_OK 332 && message->FindInt32("year", &year) == B_OK) { 333 fDateEdit->SetDate(year, month, day); 334 fCalendarView->SetDate(year, month, day); 335 } 336 337 int32 hour; 338 int32 minute; 339 int32 second; 340 if (message->FindInt32("hour", &hour) == B_OK 341 && message->FindInt32("minute", &minute) == B_OK 342 && message->FindInt32("second", &second) == B_OK) { 343 fClock->SetTime(hour, minute, second); 344 fTimeEdit->SetTime(hour, minute, second); 345 } 346 } 347