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