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 <Entry.h> 25 #include <File.h> 26 #include <FindDirectory.h> 27 #include <Message.h> 28 #include <Path.h> 29 #include <StringView.h> 30 #include <Window.h> 31 32 #include "AnalogClock.h" 33 #include "DateTimeEdit.h" 34 #include "TimeMessages.h" 35 #include "TimeWindow.h" 36 37 38 #undef B_TRANSLATE_CONTEXT 39 #define B_TRANSLATE_CONTEXT "Time" 40 41 42 using BPrivate::BCalendarView; 43 using BPrivate::BDateTime; 44 using BPrivate::B_LOCAL_TIME; 45 46 47 DateTimeView::DateTimeView(const char* name) 48 : 49 BGroupView(name, B_HORIZONTAL, 5), 50 fInitialized(false), 51 fSystemTimeAtStart(system_time()) 52 { 53 _InitView(); 54 55 // record the current time to enable revert. 56 time(&fTimeAtStart); 57 } 58 59 60 DateTimeView::~DateTimeView() 61 { 62 } 63 64 65 void 66 DateTimeView::AttachedToWindow() 67 { 68 if (Parent()) 69 SetViewColor(Parent()->ViewColor()); 70 71 if (!fInitialized) { 72 fInitialized = true; 73 74 fCalendarView->SetTarget(this); 75 } 76 77 _NotifyClockSettingChanged(); 78 } 79 80 81 void 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 kDayChanged: 100 { 101 BMessage msg(*message); 102 msg.what = H_USER_CHANGE; 103 msg.AddBool("time", false); 104 Window()->PostMessage(&msg); 105 break; 106 } 107 108 case kMsgRevert: 109 _Revert(); 110 break; 111 112 case kChangeTimeFinished: 113 if (fClock->IsChangingTime()) 114 fTimeEdit->MakeFocus(false); 115 fClock->ChangeTimeFinished(); 116 break; 117 118 case kRTCUpdate: 119 break; 120 121 default: 122 BView::MessageReceived(message); 123 break; 124 } 125 } 126 127 128 bool 129 DateTimeView::CheckCanRevert() 130 { 131 // check for changed time 132 time_t unchangedNow = fTimeAtStart + _PrefletUptime(); 133 time_t changedNow; 134 time(&changedNow); 135 136 return changedNow != unchangedNow; 137 } 138 139 140 void 141 DateTimeView::_Revert() 142 { 143 // Set the clock and calendar as they were at launch time + 144 // time elapsed since application launch. 145 146 time_t timeNow = fTimeAtStart + _PrefletUptime(); 147 struct tm result; 148 struct tm* timeInfo; 149 timeInfo = localtime_r(&timeNow, &result); 150 151 BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); 152 BTime time = dateTime.Time(); 153 BDate date = dateTime.Date(); 154 time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60); 155 date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, 156 timeInfo->tm_mday); 157 dateTime.SetTime(time); 158 dateTime.SetDate(date); 159 160 set_real_time_clock(dateTime.Time_t()); 161 } 162 163 164 time_t 165 DateTimeView::_PrefletUptime() const 166 { 167 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000); 168 } 169 170 171 void 172 DateTimeView::_InitView() 173 { 174 fCalendarView = new BCalendarView("calendar"); 175 fCalendarView->SetWeekNumberHeaderVisible(false); 176 fCalendarView->SetSelectionMessage(new BMessage(kDayChanged)); 177 fCalendarView->SetInvocationMessage(new BMessage(kDayChanged)); 178 179 fDateEdit = new TDateEdit("dateEdit", 3); 180 fTimeEdit = new TTimeEdit("timeEdit", 4); 181 fClock = new TAnalogClock("analogClock"); 182 183 BTime time(BTime::CurrentTime(B_LOCAL_TIME)); 184 fClock->SetTime(time.Hour(), time.Minute(), time.Second()); 185 186 BBox* divider = new BBox(BRect(0, 0, 1, 1), 187 B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, 188 B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER); 189 divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED)); 190 191 const float kInset = be_control_look->DefaultItemSpacing(); 192 BLayoutBuilder::Group<>(this) 193 .AddGroup(B_VERTICAL, kInset / 2) 194 .Add(fDateEdit) 195 .Add(fCalendarView) 196 .End() 197 .Add(divider) 198 .AddGroup(B_VERTICAL, 0) 199 .Add(fTimeEdit) 200 .Add(fClock) 201 .End() 202 .SetInsets(kInset, kInset, kInset, kInset); 203 } 204 205 206 void 207 DateTimeView::_UpdateDateTime(BMessage* message) 208 { 209 int32 day; 210 int32 month; 211 int32 year; 212 if (message->FindInt32("month", &month) == B_OK 213 && message->FindInt32("day", &day) == B_OK 214 && message->FindInt32("year", &year) == B_OK) { 215 static int32 lastDay; 216 static int32 lastMonth; 217 static int32 lastYear; 218 if (day != lastDay || month != lastMonth || year != lastYear) { 219 fDateEdit->SetDate(year, month, day); 220 fCalendarView->SetDate(year, month, day); 221 lastDay = day; 222 lastMonth = month; 223 lastYear = year; 224 } 225 } 226 227 int32 hour; 228 int32 minute; 229 int32 second; 230 if (message->FindInt32("hour", &hour) == B_OK 231 && message->FindInt32("minute", &minute) == B_OK 232 && message->FindInt32("second", &second) == B_OK) { 233 fClock->SetTime(hour, minute, second); 234 fTimeEdit->SetTime(hour, minute, second); 235 } 236 } 237 238 239 void 240 DateTimeView::_NotifyClockSettingChanged() 241 { 242 BMessage msg(kMsgClockSettingChanged); 243 Window()->PostMessage(&msg); 244 } 245 246