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_TRANSLATION_CONTEXT 39 #define B_TRANSLATION_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 AdoptParentColors(); 69 70 if (!fInitialized) { 71 fInitialized = true; 72 73 fCalendarView->SetTarget(this); 74 } 75 } 76 77 78 void 79 DateTimeView::MessageReceived(BMessage* message) 80 { 81 int32 change; 82 switch (message->what) { 83 case B_OBSERVER_NOTICE_CHANGE: 84 message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change); 85 switch (change) { 86 case H_TM_CHANGED: 87 _UpdateDateTime(message); 88 break; 89 90 default: 91 BView::MessageReceived(message); 92 break; 93 } 94 break; 95 96 case kDayChanged: 97 { 98 BMessage msg(*message); 99 msg.what = H_USER_CHANGE; 100 msg.AddBool("time", false); 101 Window()->PostMessage(&msg); 102 break; 103 } 104 105 case kMsgRevert: 106 _Revert(); 107 break; 108 109 case kChangeTimeFinished: 110 if (fClock->IsChangingTime()) 111 fTimeEdit->MakeFocus(false); 112 fClock->ChangeTimeFinished(); 113 break; 114 115 case kRTCUpdate: 116 break; 117 118 default: 119 BView::MessageReceived(message); 120 break; 121 } 122 } 123 124 125 bool 126 DateTimeView::CheckCanRevert() 127 { 128 // check for changed time 129 time_t unchangedNow = fTimeAtStart + _PrefletUptime(); 130 time_t changedNow; 131 time(&changedNow); 132 133 return changedNow != unchangedNow; 134 } 135 136 137 void 138 DateTimeView::_Revert() 139 { 140 // Set the clock and calendar as they were at launch time + 141 // time elapsed since application launch. 142 143 time_t timeNow = fTimeAtStart + _PrefletUptime(); 144 struct tm result; 145 struct tm* timeInfo; 146 timeInfo = localtime_r(&timeNow, &result); 147 148 BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); 149 BTime time = dateTime.Time(); 150 BDate date = dateTime.Date(); 151 time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60); 152 date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, 153 timeInfo->tm_mday); 154 dateTime.SetTime(time); 155 dateTime.SetDate(date); 156 157 set_real_time_clock(dateTime.Time_t()); 158 } 159 160 161 time_t 162 DateTimeView::_PrefletUptime() const 163 { 164 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000); 165 } 166 167 168 void 169 DateTimeView::_InitView() 170 { 171 fCalendarView = new BCalendarView("calendar"); 172 fCalendarView->SetWeekNumberHeaderVisible(false); 173 fCalendarView->SetSelectionMessage(new BMessage(kDayChanged)); 174 fCalendarView->SetInvocationMessage(new BMessage(kDayChanged)); 175 176 fDateEdit = new TDateEdit("dateEdit", 3); 177 fTimeEdit = new TTimeEdit("timeEdit", 5); 178 fClock = new TAnalogClock("analogClock"); 179 180 BTime time(BTime::CurrentTime(B_LOCAL_TIME)); 181 fClock->SetTime(time.Hour(), time.Minute(), time.Second()); 182 183 BBox* divider = new BBox(BRect(0, 0, 1, 1), 184 B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, 185 B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER); 186 divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED)); 187 188 BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_DEFAULT_SPACING) 189 .AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING) 190 .Add(fDateEdit) 191 .Add(fCalendarView) 192 .End() 193 .Add(divider) 194 .AddGroup(B_VERTICAL) 195 .Add(fTimeEdit) 196 .Add(fClock) 197 .End() 198 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, 199 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING); 200 } 201 202 203 void 204 DateTimeView::_UpdateDateTime(BMessage* message) 205 { 206 int32 day; 207 int32 month; 208 int32 year; 209 if (message->FindInt32("month", &month) == B_OK 210 && message->FindInt32("day", &day) == B_OK 211 && message->FindInt32("year", &year) == B_OK) { 212 static int32 lastDay; 213 static int32 lastMonth; 214 static int32 lastYear; 215 if (day != lastDay || month != lastMonth || year != lastYear) { 216 fDateEdit->SetDate(year, month, day); 217 fCalendarView->SetDate(year, month, day); 218 lastDay = day; 219 lastMonth = month; 220 lastYear = year; 221 } 222 } 223 224 int32 hour; 225 int32 minute; 226 int32 second; 227 if (message->FindInt32("hour", &hour) == B_OK 228 && message->FindInt32("minute", &minute) == B_OK 229 && message->FindInt32("second", &second) == B_OK) { 230 fClock->SetTime(hour, minute, second); 231 fTimeEdit->SetTime(hour, minute, second); 232 } 233 } 234 235