xref: /haiku/src/apps/stylededit/StatusView.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2  * Copyright 2002-2012, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Vlad Slepukhin
7  *		Siarzhuk Zharski
8  */
9 
10 
11 #include "StatusView.h"
12 #include <StatusView.h>
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <Catalog.h>
19 #include <CharacterSet.h>
20 #include <CharacterSetRoster.h>
21 #include <ControlLook.h>
22 #include <MenuItem.h>
23 #include <Message.h>
24 #include <PopUpMenu.h>
25 #include <ScrollView.h>
26 #include <StringView.h>
27 #include <Window.h>
28 
29 #include <tracker_private.h>
30 #include "DirMenu.h"
31 
32 #include "Constants.h"
33 
34 
35 const float kHorzSpacing = 5.f;
36 #define UTF8_EXPAND_ARROW "\xe2\x96\xbe"
37 
38 using namespace BPrivate;
39 
40 
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "StatusView"
43 
44 
45 StatusView::StatusView(BScrollView* scrollView)
46 			:
47 			BView(BRect(), "statusview",
48 				B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW),
49 			fScrollView(scrollView),
50 			fPreferredSize(0., 0.),
51 			fReadOnly(false),
52 			fCanUnlock(false)
53 {
54 	memset(fCellWidth, 0, sizeof(fCellWidth));
55 }
56 
57 
58 StatusView::~StatusView()
59 {
60 }
61 
62 
63 void
64 StatusView::AttachedToWindow()
65 {
66 	SetFont(be_plain_font);
67 	BPrivate::AdoptScrollBarFontSize(this);
68 
69 	BMessage message(UPDATE_STATUS);
70 	message.AddInt32("line", 1);
71 	message.AddInt32("column", 1);
72 	message.AddString("encoding", "");
73 	SetStatus(&message);
74 
75 	BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
76 	MoveTo(0., scrollBar->Frame().top);
77 
78 	rgb_color color = B_TRANSPARENT_COLOR;
79 	BView* parent = Parent();
80 	if (parent != NULL)
81 		color = parent->ViewColor();
82 
83 	if (color == B_TRANSPARENT_COLOR)
84 		color = ui_color(B_PANEL_BACKGROUND_COLOR);
85 
86 	SetViewColor(color);
87 
88 	ResizeToPreferred();
89 }
90 
91 
92 void
93 StatusView::GetPreferredSize(float* _width, float* _height)
94 {
95 	_ValidatePreferredSize();
96 
97 	if (_width)
98 		*_width = fPreferredSize.width;
99 
100 	if (_height)
101 		*_height = fPreferredSize.height;
102 }
103 
104 
105 void
106 StatusView::ResizeToPreferred()
107 {
108 	float width, height;
109 	GetPreferredSize(&width, &height);
110 
111 	if (Bounds().Width() > width)
112 		width = Bounds().Width();
113 
114 	BView::ResizeTo(width, height);
115 }
116 
117 
118 void
119 StatusView::Draw(BRect updateRect)
120 {
121 	if (fPreferredSize.width <= 0)
122 		return;
123 
124 	if (be_control_look != NULL) {
125 		BRect bounds(Bounds());
126 		be_control_look->DrawMenuBarBackground(this,
127 			bounds, updateRect,	ViewColor());
128 	}
129 
130 	BRect bounds(Bounds());
131 	SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT));
132 	StrokeLine(bounds.LeftTop(), bounds.RightTop());
133 
134 	float x = bounds.left;
135 	for (size_t i = 0; i < kStatusCellCount - 1; i++) {
136 		x += fCellWidth[i];
137 		StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3));
138 	}
139 
140 	SetLowColor(ViewColor());
141 	SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
142 
143 	font_height fontHeight;
144 	GetFontHeight(&fontHeight);
145 
146 	x = bounds.left;
147 	float y = (bounds.bottom + bounds.top
148 		+ ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2;
149 
150 	for (size_t i = 0; i < kStatusCellCount; i++) {
151 		if (fCellText[i].Length() == 0)
152 			continue;
153 		DrawString(fCellText[i], BPoint(x + kHorzSpacing, y));
154 		x += fCellWidth[i];
155 	}
156 }
157 
158 
159 void
160 StatusView::MouseDown(BPoint where)
161 {
162 	if (where.x < fCellWidth[kPositionCell]) {
163 		_ShowDirMenu();
164 		return;
165 	}
166 
167 	if (!fReadOnly || !fCanUnlock)
168 		return;
169 
170 	float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell];
171 	if (where.x < left)
172 		return;
173 
174 	int32 clicks = 0;
175 	BMessage* message = Window()->CurrentMessage();
176 	if (message != NULL
177 		&& message->FindInt32("clicks", &clicks) == B_OK && clicks > 1)
178 			return;
179 
180 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
181 	menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"),
182 					new BMessage(UNLOCK_FILE)));
183 	where.x = left;
184 	where.y = Bounds().bottom;
185 
186 	ConvertToScreen(&where);
187 	menu->SetTargetForItems(this);
188 	menu->Go(where, true, true,	true);
189 }
190 
191 
192 void
193 StatusView::SetStatus(BMessage* message)
194 {
195 	int32 line = 0, column = 0;
196 	if (B_OK == message->FindInt32("line", &line)
197 		&& B_OK == message->FindInt32("column", &column))
198 	{
199 		char info[256];
200 		snprintf(info, sizeof(info),
201 				B_TRANSLATE("line %d, column %d"), line, column);
202 		fCellText[kPositionCell].SetTo(info);
203 	}
204 
205 	if (B_OK == message->FindString("encoding", &fEncoding)) {
206 		// sometime corresponding Int-32 "encoding" attrib is read as string :(
207 		if (fEncoding.Length() == 0
208 			|| fEncoding.Compare("\xff\xff") == 0
209 			|| fEncoding.Compare("UTF-8") == 0)
210 		{
211 			// do not display default UTF-8 encoding
212 			fCellText[kEncodingCell].Truncate(0);
213 			fEncoding.Truncate(0);
214 		} else {
215 			const BCharacterSet* charset
216 				= BCharacterSetRoster::FindCharacterSetByName(fEncoding);
217 			fCellText[kEncodingCell]
218 				= charset != NULL ? charset->GetPrintName() : "";
219 		}
220 	}
221 
222 	bool modified = false;
223 	fReadOnly = false;
224 	fCanUnlock = false;
225 	if (B_OK == message->FindBool("modified", &modified) && modified) {
226 		fCellText[kFileStateCell] = B_TRANSLATE("Modified");
227 	} else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) {
228 		fCellText[kFileStateCell] = B_TRANSLATE("Read-only");
229 	    if (B_OK == message->FindBool("canUnlock", &fCanUnlock) && fCanUnlock)
230 			fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW;
231 	} else
232 		fCellText[kFileStateCell].Truncate(0);
233 
234 	_ValidatePreferredSize();
235 	Invalidate();
236 }
237 
238 
239 void
240 StatusView::SetRef(const entry_ref& ref)
241 {
242 	fRef = ref;
243 }
244 
245 
246 void
247 StatusView::_ValidatePreferredSize()
248 {
249 	float orgWidth = fPreferredSize.width;
250 	// width
251 	fPreferredSize.width = 0.f;
252 	for (size_t i = 0; i < kStatusCellCount; i++) {
253 		if (fCellText[i].Length() == 0) {
254 			fCellWidth[i] = 0;
255 			continue;
256 		}
257 		float width = ceilf(StringWidth(fCellText[i]));
258 		if (width > 0)
259 			width += kHorzSpacing * 2;
260 		if (width > fCellWidth[i] || i != kPositionCell)
261 			fCellWidth[i] = width;
262 		fPreferredSize.width += fCellWidth[i];
263 	}
264 
265 	// height
266 	font_height fontHeight;
267 	GetFontHeight(&fontHeight);
268 
269 	fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent
270 		+ fontHeight.leading);
271 
272 	if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT)
273 		fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT;
274 
275 	float delta = fPreferredSize.width - orgWidth;
276 	ResizeBy(delta, 0);
277 	BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
278 	scrollBar->ResizeBy(-delta, 0);
279 	scrollBar->MoveBy(delta, 0);
280 }
281 
282 
283 void
284 StatusView::_ShowDirMenu()
285 {
286 	BEntry entry;
287 	status_t status = entry.SetTo(&fRef);
288 
289 	if (status != B_OK || !entry.Exists())
290 		return;
291 
292 	BPrivate::BDirMenu* menu = new BDirMenu(NULL,
293 		BMessenger(kTrackerSignature), B_REFS_RECEIVED);
294 
295 	menu->Populate(&entry, Window(), false, false, true, false, true);
296 
297 	BPoint point = Bounds().LeftBottom();
298 	point.y += 3;
299 	ConvertToScreen(&point);
300 	BRect clickToOpenRect(Bounds());
301 	ConvertToScreen(&clickToOpenRect);
302 	menu->Go(point, true, true, clickToOpenRect);
303 	delete menu;
304 }
305 
306