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 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 63 DateTimeView::~DateTimeView() 64 { 65 } 66 67 68 void 69 DateTimeView::AttachedToWindow() 70 { 71 AdoptParentColors(); 72 73 if (!fInitialized) { 74 fInitialized = true; 75 76 fCalendarView->SetTarget(this); 77 } 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 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 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 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 169 DateTimeView::_PrefletUptime() const 170 { 171 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000); 172 } 173 174 175 void 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 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