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